MELJUN CORTES Jedi course notes web programming-lesson9-javaserver faces

  • 256 views
Uploaded on

MELJUN CORTES Jedi course notes web programming-lesson9-javaserver faces

MELJUN CORTES Jedi course notes web programming-lesson9-javaserver faces

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
256
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
3
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. MVC Frameworks II – JavaServer FacesIn the previous chapters, we have looked at Struts, an open-source framework for webapplications implementing the Model – 2 Architecture. Let us now take a look at anotherframework: Java Server Faces (JSF). Introduction to JSFJSF is a framework for building user interfaces for web applications. It builds on conceptsintroduced by the Struts framework and brings together the benefits of an architecturethat cleanly separates presentation from business logic and a standard component-baseduser interface set similar in many ways to that of Swing widgets.Below is a figure detailing how the Faces framework works.
  • 2. Figure 1: JavaServerFaces Framework (image from Mastering JavaServerFaces, Wiley Publishing)As we can see, JSF also has a clean separation between the components for the Model,View, and Controller layers. Like Struts, JSF has a front controller servlet, calledFacesServlet, that is responsible for receiving requests from clients and then performingthe appropriate actions needed as dictated by the framework. Another similarity betweenStruts and JSF is that they both make use of action handlers separate from the frontcontroller servlet, although, Faces handles this a bit differently as compared to Struts.Faces and Struts similarity ends with regard to the View layer. Here, Struts only providesonly a set of tag libraries that added on top of standard HTML functionality. Faces, on theother hand, provides its own set of interface components, along with a set of taglibraries to express these components as tags and a rendering component that translatesthe UI components into HTML.
  • 3. Let us go into the different aspects of Faces. CONTROLLERThe controller layer of Faces is made up of the controller servlet (FacesServlet), a set ofXML configuration files, and a set of action handlers. . FacesServletFacesServlet is responsible for accepting requests from the client and performingoperations needed to produce the response. These operations include preparing the UIcomponents required for the request, updating the state of the components, calling therequired action handlers (if any), and rendering the UI components that are part of theresponse.FacesServlet is provided to us by the JSF framework, and only requires configuration inan applications deployment descriptor before it is ready for use.Below is a snippet that shows us how to configure FacesServlet for our application....<servlet><servlet-name>FacesServlet</servlet-name><servlet-class>javax.faces.webapp.FacesServlet</servlet-class><load-on-startup>1</load-on-startup></servlet>...<servlet-mapping><servlet-name>FacesServlet</servlet-name><url-pattern>*.jsf</url-pattern></servlet-mapping>... . Action HandlersIt was been mentioned earlier that Faces makes use of action handlers independent fromthe front controller servlet, similar to Struts. Faces performs this function differentlythough.In Faces, there are two possible ways of creating an action handler. One is by binding amethod of a JavaBean to serve as the action handler. Another is by creating an instanceof a class implementing the ActionListener interface.Application methodA method that has been bound to a UI component to serve as its action handler is calledan application method. Later, in the View section, we will see how this binding is done.
  • 4. Meantime, there are some rules required for creating an application method: • The method must be declared public. • The method must take no parameters. • The return type of the method must be a String.Below is a method that we could possibly use for handling an event resulting from a userattempting to login....public String performLogin() {// forward user to failure use case if loginName is emptyif (loginName == null || loginName.length() < 1) {return "failure"}User user = null;// create business object that will handle actual authorization checkUserService service = new UserService();user = service.login(loginName, password);// forward user to failure use case if user is not authorizedif (user == null) {return "failure";}// retrieve an instance of the FacesContext object// that will give us access to other contextsFacesContext ctx = FacesContext.getCurrentInstance();// place the result into session scope for use by other componentsMap sessionMap = ctx.getExternalContext().getSessionMap();sessionMap.put(ApplicationConstants.USER_OBJECT, user);// since user has successfully completed login, forward to successreturn "success";}}...One of the advantages of this type of action handling is that it lessens the number ofobjects that developers need to maintain. This method can be in any JavaBeanrecognized by the framework, though commonly, it can be found in the bean used asbacking model for a particular form page. (More on backing models later).The String returned by the method informs the FacesServlet which view will next beseen by the user. The Strings are logical names, sometimes called outcomes. Theseoutcomes are matched against navigation rules defined in the configuration file.
  • 5. WORKING WITH SESSION SCOPE OBJECTS IN FACESThe JSF framework has a different method of accessing session scope compared towhatever we have seen before. Previous examples we have seen so far have retrievedinstances of the HttpSession object in order to work with session scope. For example, inStruts, we retrieve it using the HttpServletRequest object passed in as a parameter toits execute method.Since application methods are defined such that they do not take in any parameters, wedo NOT have any valid instances of the HttpServletRequest object from which toretrieve an HttpSession object. JSF goes around this limitation by providing access tothe session context (as well as other contexts) with the use of a FacesContext object.Our earlier example used this method to save an object into session scope. The relevantcode is reproduced below:FacesContext ctx = FacesContext.getCurrentInstance();...Map sessionMap = ctx.getExternalContext().getSessionMap();sessionMap.put(ApplicationConstants.USER_OBJECT, user);As we can see from the example, obtaining a valid instance of the FacesContext objectis simple. Just call a static method from the FacesContext class. A Map representingobjects placed in session scope can then be retrieved by calling on.There are other scopes that can be accessed. For more information, check out theJavaDoc entry for the FacesContext object.ActionListenerThe other way of implementing an action handler in JSF is to create a class implementingthe ActionListener interface. This interface defines a single method: public void processAction(ActionEvent event)The ActionEvent object passed as a parameter in the method provides the implementingclass access to the component that caused the event. This is similar in a way to howEvent objects work in Swing programming.Below is an example of an ActionListener implementation used for logging user actions.
  • 6. public class PerformedActionListener implements ActionListener {public void processAction(ActionEvent event) {// retrieve the component that fired the eventUICommand component = (UICommand)event.getComponent();// retrieve the name of the button or linkString commandName = (String)component.getValue();// create the business object performing functionalityLoggingService service = new LoggingService();// perform logging operationservice.logUserAction(commandName);}}Most of the time, it is more appropriate to use application methods to serve as actionhandlers. For one, they can be located in the same class which serves as the backingmodel of a form, and thus have easier access to user-provided data. Second, being inthe backing model allows the developer to group together the data and the methods thatoperate on it in one class, making it easier to maintain. Third, application methods areable to return "outcomes" which inform the FacesServlet the next view to display.ActionListeners cannot, and so can only bring the user back to the original page afterhandling the event.ActionListeners are the more appropriate choice though, if you want to refactor commonfunctionality that you can reuse across multiple action sources.As we can see later, it is possible to have an application method and one or moreActionListeners to act as handlers for a particular action. It is then possible to gain thebest aspects of both approaches: have an application method to perform handlingspecific to the action, and then have ActionListeners to perform general-purposefunctionality. . faces-config.xmlThis serves as the primary configuration file for the controller layer of the JSFFramework. As opposed to its counterpart in the Struts framework, it does NOT containany configuration entries for its action handlers. It does contain configuration entries fornavigation rules, as well as for JavaBeans that will be recognized by the framework.Below is a complete sample of such configuration file, for an imaginary applicationimplementing the login use case.
  • 7. <!DOCTYPE faces-config PUBLIC“-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN”“http://java.sun.com/dtd/web-facesconfig_1_0.dtd”><faces-config><managed-bean><description>This bean serves as the backing model for our login form</description><managed-bean-name>loginPage</managed-bean-name><managed-bean-class>sample.LoginPageBean</managed-bean-class><managed-bean-scope>request</managed-bean-scope><managed-property><description>The property that will store the users login name</description><property-name>loginName</property-name><null-value/></managed-property><managed-property><description>The property that will store the users password</description><property-name>password</property-name><null-value/></managed-property></managed-bean><navigation-rule><from-view-id>/login.jsf</from-view-id><navigation-case><description>Any failure result should bring the user to an error page</description><from-outcome>failure</from-outcome><to-view-id>/error.jsp</to-view-id></navigation-case><navigation-case><description>Successful login should bring user to welcome page</description><from-outcome>success</from-outcome><to-view-id>/welcome.jsp</to-view-id></navigation-case></navigation-rule></faces-config>Lets go through the above elements one at a time.
  • 8. <!DOCTYPE ...Used to indicate that this file serves as a configuration file for JSF. Failure to include thisline, or mistyping it, will result in an error.<faces-config>Serves as the root element for this XML file. All other elements should be children of thiselement.<managed-bean>Each managed-bean element serves to define a JavaBean that will be managed andrecognized by the framework. It has the following child elements: • <description> - does not serve any purpose except to improve readability of the configuration file. • <managed-bean-name> - serves as the logical name by which an instance of this bean can be accessed / used within the framework. Must be unique for each bean. • <managed-bean-class> - the fully qualified class name of the JavaBean to be managed. • <managed-bean-scope> - the scope in which this bean is to be stored. Can be request, session, application, or none. Having a value of none means that the beans state will not be stored in between requests. • <managed-property> - declares values to be used for initializing properties in the JavaBean. It is not necessary to create <managed-property> entries for each property in the JavaBean, only for those that you want to initialize. Has the following child elements: • <property-name> - the JavaBean property to be managed. • <property-class> - defines the fully qualified type of the property. (optional) • <null-value/> - sets the value of the property to null. Instead of using null-value, developers can use • <value> - sets the value of the property to the specified value.<navigation-rule>This element is used to define logical mappings for the turning points in your application.It can either be used to define rules specific to a particular page, or to define rules thatcan be used by any page in the application. Has the following child elements: • <from-view-id> - defines the page containing the component tree for which this rule will apply. If not specified, then the rule will apply within the application. (Optional) • <navigation-case> - defines one outcome for the navigation rule. Has the following child elements: • <from-outcome> - defines the outcome that is returned from an action which will determine if the navigation case becomes active. • <to-view-id> - defines the next page that will become active if this navigation case becomes active.There are other elements available for the JSF configuration file. Consult your JSFimplementations documentation for further details.Summary of things to do for the Controller Layer:
  • 9. For one time setup: • Configure the FacesServlet for use in your application.For each web page containing JSF UI Components: • Create a configuration entry for the managed bean that will serve as the pages backing model. • Create navigation rules which define where application could possibly go next after the page. MODELIn Faces it is required to have classes that will store the state of the UI components ineach of the pages. These classes are called the backing model.These classes are not Model classes when viewed strictly under the perspective of theMVC architecture. MVC defines the Model to be the set of classes that implement thecore business logic of the application. However, when thinking only of UI components, itmakes sense to call these classes part of the Model, especially if we are to compare it tothe MVC implementation of Swing UI component classes. Remember, in Swing, therendering layer is called the View, the components state is the Model, and the actionhandler part is the Controller.Even though they are called part of the Model, care must be taken in the development ofthese classes such that they do not influence the core functionality of your application(the real Model). It is best to keep in mind that these components are meant to savestate for UI components and perhaps define basic operations that access the data itstores which can serve as application methods. They are NOT meant to perform heavy-duty processing, or any processing that can be reused in other applications.Creating a backing model for pages containing JSF UI components is very easy. It is assimple as creating a JavaBean with properties corresponding to each component in thepage. They are very similar to ActionForm objects in the Struts framework, with theexception that they do not need to extend any base class provided by the framework.Below is an example of a backing model for a login form.
  • 10. public class LoginPageBean {private String loginName;private String password;public String getLoginName() {return loginName;}public void setLoginName(String loginName) {this.loginName = loginName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}}This model can then be accessed by our pages after it has been configured properly inthe faces-config.xml configuration file. The configuration entry for this bean is replicatedbelow for reference.<managed-bean><description>This bean serves as the backing model for our login form</description><managed-bean-name>loginPage</managed-bean-name><managed-bean-class>sample.LoginPageBean</managed-bean-class><managed-bean-scope>request</managed-bean-scope><managed-property><description>The property that will store the users login name</description><property-name>loginName</property-name><null-value/></managed-property><managed-property><description>The property that will store the users password</description><property-name>password</property-name><null-value/></managed-property></managed-bean> VIEW
  • 11. The View is undoubtedly the layer where JSF mostly makes its mark. In this layer, JSFnot only provides us with custom tags we can use to display our interface using JSPs, italso provides us with a component set and a standardized API for accessing andmanipulating them.Discussion of JSF components can be very complicated if we try to explain everything atthe same time. Instead, we will have to deal with the basics first, incorporating morecomplicated ideas as we go on. JSF-JSP IntegrationLets start with how to display JSF components to the user. The following is a listing for aJSP page containing JSF components which serves as the login page for our previousexamples:<%@taglib uri ="http://java.sun.com/jsf/core/" prefix="f" %><%@taglib uri ="http://java.sun.com/jsf/html" prefix="h" %><HTML><TITLE>Login Page</TITLE><BODY>Please login with your login name and password : <br/><br/><f:view><h:form id="simpleForm"><h:outputLabel for="loginName"><h:outputText value="Login Name:"/></h:outputLabel><h:inputText id="loginName" value="#{loginPage.loginName}"/><br/><h:outputLabel for="password"><h:outputText value="Password : "/></h:outputLabel><h:inputSecret id="password" value="#{loginPage.password}"/><br/><h:commandButton action="#{loginPage.performLogin}" value="Login"/></h:form></f:view></BODY></HTML>To make use of JSF components in our JSP pages, we need to include two tag libraries:core and html. The core tag library defines core functionality, such as how to managethe JSF components that they may be able to save state, etc. The html library definestags that tells the browser how to render our JSF components into their HTMLequivalents.Once we have included these two tag libraries, we make use of the custom tags thatthey define. Let us look at the tags we have used in the preceding example:
  • 12. • <f:view> - defined in the core library. All tags defining JSF components must be enlosed within this tag. This tag provides a place for JSF implementations to be able to save the state of our UI components. REMEMBER: no <f:view>, no saved state for our components. • <h:form> - defined in the html library. Renders a form in HTML. • <outputLabel> - defines a label component that is associated with another JSF component. The component it is associated with is indicated by the value in the for attribute while the value it displays as its label is the output of the <outputText> field enclosed within it. • <h:outputText> - simply renders the text within its value attribute into its HTML equivalent. • <h:inputText> - renders an HTML input element of type text. • <h:inputSecret> - renders an HTML input element of type password. • <h:commandButton> - renders an HTML button which defaults to SUBMIT.Below is a screenshot of the output resulting from the above JSP page. Figure 2: Login pageThe following is the HTML source of the output:
  • 13. <HTML> <TITLE>Login Page</TITLE> <BODY> Please login with your login name and password : <br/><br/> <form id="simpleForm" method="post" action="/JSFApplication/index.jsf" enctype="application/x-www-form-urlencoded"> <label for="simpleForm:loginName"> Login Name: </label> <input id="simpleForm:loginName" type="text" name="simpleForm:loginName" /><br/> <label for="simpleForm:password"> Password : </label> <input id="simpleForm:password" type="password" name="simpleForm:password" value="" /> <br/> <input type="submit" name="simpleForm:_id5" value="Login" /> <input type="hidden" name="simpleForm" value="simpleForm" /></form> </BODY></HTML> Figure 3: HTML source of the login page We can see from the above HTML listing how the JSF implementation renders our components as defined in the tags. The form element is defined to use the POST method of form submission, with the action pointing to the same page. Also, notice how the id values of the HTML elements are prefixed with the name of the form. This ensures that the name of the form elements are unique within the application, which is necessary for Faces operation. VALUE BINDING The UI components making up the view above require a backing model to be able to store the data that users would pass into them. The implementation of these backing models have been discussed previously. The only question now is how to link our components to the backing model. A snippet of the above JSP will be recreated here for easier recall. ... <h:inputText id="loginName" value="#{loginPage.loginName}"/><br/> <h:outputLabel for="password"> <h:outputText value="Password : "/> </h:outputLabel> <h:inputSecret id="password" value="#{loginPage.password}"/><br/> ...
  • 14. Take note of the text presented in bold font. The # notation that serves as the value forthe value attribute binds the properties in our LoginPageBean to our UI components,with our inputText component being bound to the loginName property and theinputSecret component being bound to the password property. In this case, loginPagerefers to an instance of a LoginPageBean that will store the data.The JSF page is able to associate the loginPage identifier to an instance of aLoginPageBean due to our entry in the faces-config.xml. The relevant entry is presentedbelow:<managed-bean><description>This bean serves as the backing model for our login form</description><managed-bean-name>loginPage</managed-bean-name><managed-bean-class>jedi.sample.LoginPageBean</managed-bean-class><managed-bean-scope>request</managed-bean-scope>...Since the LoginPageBean is declared to be a managed bean in the framework, aninstance of LoginPageBean will be created and placed in the configured scope (if onedoesnt already exist) when the JSF page is evaluated. On page submission, the valuesthat the user has entered would automatically be placed within the beans properties. REGISTERING ACTION HANDLERS TO VIEW COMPONENTSJSF introduces the concept of event-based programming into the web environment.Some of the UI components that JSF provides will, given the appropriate user action orinput, generate events that can be processed by action handlers.In our example above, we have a JSF component: the <h:commandButton> element.Whenever the user clicks on the button that this component represents, an event isgenerated within the framework which can be processed by registered handlers.This concept may be better understood if related to another event-based programmingmodel: Swing. In Swing, if we want to perform some processing whenever the usermakes a button click, we register with the button one or more ActionListeners thatimplement the required functionality. Same thing with JSF, if we want to perform somefunctionality on a button click, we register an action handler with the commandButtoncomponent.The way we do this "registering" of a handler for a commandButton component is shownbelow:...<h:commandButton action="#{loginPage.performLogin}" value="Login"/>...
  • 15. We find a # notation similar to that used in binding a bean property to a UI component.The intention here is similar as well: we are binding a method named performLoginfound in a bean referenced with the name loginPage to our button. This time, instead ofstoring the value for the component, the bound method acts as the action handler forthe button click. PAGE NAVIGATIONJSF determines the next screen that will be displayed to the user upon form submissionusing the return value of the method that serves as the action handler for the submitbutton. The String value is looked up against navigation rules defined within theconfiguration file.The relevant entries in the configuration file are reproduced below:<navigation-rule><from-view-id>/login.jsf</from-view-id><navigation-case><description>Any failure result should bring the user to an error page</description><from-outcome>failure</from-outcome><to-view-id>/error.jsp</to-view-id></navigation-case><navigation-case><description>Successful login should bring user to welcome page</description><from-outcome>success</from-outcome><to-view-id>/welcome.jsp</to-view-id></navigation-case></navigation-rule>So, coming in from our JSF page (login.jsf), if the performLogin method were to return avalue or outcome of "failure", the user will be redirected to error.jsp.As an alternative to using an action handler, it is also possible to statically provide thenavigation rule to be called:...<h:commandButton action="failure" value="Login"/>...Clicking on this button will redirect the user to error.jsp without having to perform anyprocessing. Other JSF Component tagsThere are a lot of other tags available within the JSF framework aside from the tags thatwe have used in our previous example and tags used to render HTML components. Here
  • 16. are a couple of samples:<h:messages> This tag acts in a way similar to that of the <html:errors/> tag in the Strutsframework. This tag exposes messages from the application into the output text. Forexample, if an input control was to report an internal problem, possibly due to avalidation error (validation is covered in the next chapter), it can be displayed using thistag.<h:dataTable> This tag displays an HTML <table> element. What makes this tag useful is that ittakes in an array (or collection of objects) and iterates over them, automatically creatingthe necessary <tr> and <td> elements. It defines a child tag named <h:column>.Content placed inside the body of a <h:column> tag form the template for the columndefinition for each row in the table.Take the following example:<h:dataTable id="myTable" value="#{personBean.personArray}" var="person"border="1" cellspacing="1" rowClasses="myTableRow"> <h:column> <h:outputText value="#{person.firstName}"/> </h:column> <h:column> <h:outputText value=#{person.lastName}"/> </h:column></h:dataTable>The generated HTML could possibly be something like this:<table border="1" cellspacing="1"> <tr class="myTableRow"> <td>Ewan</td> <td>Coba</td> </tr> <tr class="myTableRow"> <td>Devon</td> <td>Shire</td> </tr> <tr class="myTableRow"> <td>California</td> <td>San Diego</td> </tr></table>Some of the attributes of the <h:dataTable> tag include, but are not limited to: • value - defines the collection or array to be iterated over. This could either be a property inside a managed bean or a method in a bean that will return the necessary content. • var - defines the name of the variable which will expose the contents of the
  • 17. collection or array being iterated over. This variable is visible only within the <h:dataTable> tag. Once outside the tags body, this variable can no longer be accessed. • border, cellspacing - standard HTML table attributes. The values placed within these attributes will be carried over to the generated table tag. • rowClasses - a comma-delimited list of cascading style sheets(CSS) styles that will be alternately applied to each of the rows in the table.<f:verbatim> Container tags like <h:dataTable> only allow JSF tags within their body. This meansthat custom tags or even JSTL tags would not work inside of them. This can becircumvented with the use of the <f:verbatim> tag.EXERCISESAs an exercise in the use of the Java Server Faces framework, we will be creating a verysimple application. Unlike the previous Struts exercise, this is small enough that it canbe accomplished solo.Consider the following scenario:A small firm wants to be able to keep track of the comings and goings of its employees.To do this, it decides that it needs a web-based application that can record theiractivities. They want it to be very transparent as well, meaning that the records shouldbe visible to everyone.Eventually, they came up with the following page concept:Basically, the main page of the application consists of an input text field and submitbutton in the upper left field, with a table of records dominating the rest of the page.Sample Use Case Scenario 1:Employee A arrives at the office. He enters his employee number in the text field andclicks on the submit button. A new row is added to the top of the table, containing hisname, the keyword IN, as well as the timestamp of input submission.Sample Use Case Scenario 2:Employee B arrives at the office and tries to enter his employee number in the samemanner as Employee A. However, he became distracted and accidentally made amistake in his entry. The application takes him to another page informing him that theid he entered was not valid. It also presents a link so that he could return to the mainpage and try to correct his mistake.Sample Use Case Scenario 3:Employee A is leaving the office for lunch. He needs to record this as well, so he entershis ID number again. The application recognizes that his previous entry was an IN.When the app inserts a new row at the table, it again shows his name and thetimestamp of submission, but this time displays OUT.Create the application described by the use case scenario and page concept describedabove.