Introduction
JSF is a Web framework for developing Component oriented web applications in the User Interface layer. Amongst the various capabilities that JSF provides, one of the major strengths of JSF is that it is not tied to any specific target device. For example, currently most of the JSF applications are running in a web server and are accessible through a web browser. However, web browser is not the only target for a JSF application to be viewed; it can be even accessed through a hand-held device, for example through a mobile phone. In this example, we will see how to develop JSF applications targeted for mobile phones. This article assumes that the reader has a good understanding of JSF, its life-cycle and some understanding on JSF renderer kits.
also read:
Renderer kits
The responsibility of displaying a view in a target device is done through renderer kits. Renderer kits in JSF are nicely abstracted so it is possible to write custom implementation of renderer kits.
Sun’s implementation of JSF provides a reference implementation of a HTML renderer kit. The HTML renderer kit is responsible for displaying the view in a web browser. So while writing a renderer kit implementation amongst the various factors to be taken into consideration, the important things are the target device, the protocol, the markup language and the scripting language. For a HTML renderer kit implementation, these would be the Web browsers, HTTP, hyper text markup language and java script.
Similarly a render kit implementation would consider the mobile phone browser, Wireless application protocol, the Wireless markup language (WML) and WML Script for providing suitable support in the mobile or any WAP browser. Wireless application protocol is the standard defined for displaying contents on wireless devices such as mobile phones. Similar to HTML that targets Web browsers, WML is the markup language for mobile phones. Consider the sample WML script,
<?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml" > <wml> <card id="test" title="Test card"> <p>This is a test WML page. </card> </wml>
Usually WML document can be thought of as a collection of cards. Each user interaction will be modeled as a card and each card will be inter-dependant. The syntax will mostly look like HTML for displaying the UI elements and content in the WML browser.
WML script, similar to Java script, is the client side scripting language for WML. It is mainly used for dynamically validating user input and it generally will appear in a separate file. Consider the following example script,
extern function sayHello() { WMLBrowser.setVar("message", "Hello World."); WMLBrowser.refresh(); }
The above script will appear in a separate file, say ‘hello.wmls’ and the following wml page will provide a reference to the above wml script.
<?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml" > <wml> <card id="test" title="Test card"> <p><a href="hello.wmls#sayHello()">Run</a><br/> $(message) </card> </wml>
Mobile Faces
Mobile Faces for JSF provides a framework for simplifying the development of JSF applications targeted for wireless devices. The framework comes packaged with an implementation of renderer kits for HTML, XHTML-MP and WML. Also it supports various commonly used scripting languages such as Java Script, WML Script and ECMA Script. For testing JSF faces developed through Mobile Faces framework, we will be using OpenWave Browser for WAP. It serves as an emulator for testing WAP applications. In this article, we will be showing how to develop applications using the Mobile Faces toolkit.
Setting up the development environment
OpenWave is used for testing the JSF application in the WAP Browser. Mobile Faces distribution has to be downloaded, jar file has to be built from the distribution’s ant file and the same has to be made available in the application’s class path.
Hello World JSF-J2ME Application
In this example, we will develop a JSF application that will display the message ‘Hello World’ when it is invoked. Since this is the first application, we will keep the components to the minimal that we can. For example, we will not be using backing beans in this example.
Web Configuration file
Take the look at the web configuration file which is given below. Plenty of things need to be considered in the descriptor file. The first thing is that we have registered the Faces servlet for handling all the requests that matches the pattern “.JSF“. This is done by defining the faces servlet ‘javax.faces.webapp.FacesServlet’.
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param> <context-param> <param-name>javax.faces.CONFIG_FILES</param-name> <param-value>/WEB-INF/faces-config.xml</param-value> </context-param> <context-param> <param-name>ericsson.mobilefaces.CONFIG_FILE</param-name> <param-value>/WEB-INF/mfaces-config.xml</param-value> </context-param> <filter> <filter-name>MobileFaces Init Filter</filter-name> <filter-class>com.ericsson.sn.mobilefaces.MobileFacesSer vletFilter</filter-class> <init-param> <description>Set to "true" to turn on the debug </description> <param-name>Debug</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>MobileFaces Init Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet- class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> </web-app>
We have also defined a filter servlet called ‘MobileFacesServletFilter’ that will be invoked for all requests. This filter servlet is responsible for various things – for example, this servlet takes responsibility in finding out the device used for invoking the application and based on that it loads the media adapter and the script renderer implementations. For a JSF web application, ‘faces-config.xml’ is essential as it contains the managed beans and the navigation rules declaration. Similarly for mobile applications, the configuration file has to be specified through the parameter ‘ericsson.mobilefaces.CONFIG_FILE’. The details of this configuration file will be covered in the next section.
Mobile Faces Configuration file
The definition for mobile faces configuration file is given below. This configuration file is useful for configuring the factory implementation for defining the devices, scripting implementation and media adapters. For this simple example, the listing for the configuration file contains information for configuring the devices information.
<?xml version='1.0' encoding='UTF-8'?> <!-- MobileFaces System Configuration File. --> <mfaces-config> <configuration-file> <devices>conf/devices.xml</devices> </configuration-file> </mfaces-config>
Note that the configuration file refers to devices configuration file ‘devices.xml’ which is described in the next section.
Devices Configuration file
The listing for devices configuration file is given below. Here we define the mapping information for various devices with the list of supported configuration.
<?xml version="1.0" encoding="UTF-8"?> <device-list> <!-- Default Device. Use this one if no other device can be matched. --> <device> <DEVICE_NAME>DefaultDevice</DEVICE_NAME> <USER_AGENT>default</USER_AGENT> <SCREEN_LEVEL>9</SCREEN_LEVEL> <MARKUP>HTML_BASIC</MARKUP> <SCRIPT>javascript</SCRIPT> <IMAGE_SUPPORT>jpg;jpeg;gif;png;</IMAGE_SUPPORT> </device> <!-- Firefox. Web browser with HTML language. --> <device> <DEVICE_NAME>Firefox</DEVICE_NAME> <USER_AGENT>Firefox</USER_AGENT> <SCREEN_LEVEL>9</SCREEN_LEVEL> <MARKUP>HTML_BASIC</MARKUP> <SCRIPT>javascript</SCRIPT> <IMAGE_SUPPORT>jpg;jpeg;gif;png;</IMAGE_SUPPORT> </device> <!-- InternetExplorer. Web browser with HTML language. --> <device> <DEVICE_NAME>InternetExplorer</DEVICE_NAME> <USER_AGENT>MSIE</USER_AGENT> <SCREEN_LEVEL>9</SCREEN_LEVEL> <MARKUP>HTML_BASIC</MARKUP> <SCRIPT>javascript</SCRIPT> <IMAGE_SUPPORT>jpg;jpeg;bmp;gif;png;tiff;</IMAGE_SUPPORT > </device> <!-- OpenWave-WML. WAP1 browser with WML language. --> <device> <DEVICE_NAME>OpenWaveWML</DEVICE_NAME> <USER_AGENT>OPWV-SDK-WML</USER_AGENT> <SCREEN_LEVEL>5</SCREEN_LEVEL> <MARKUP>WML</MARKUP> <SCRIPT>wmlscript</SCRIPT> <IMAGE_SUPPORT>png;gif;wbmp;</IMAGE_SUPPORT> </device> <!-- OpenWave-XMP. WAP2 browser with XHTML-MP language. --> <device> <DEVICE_NAME>OpenWaveXMP</DEVICE_NAME> <USER_AGENT>OPWV-SDK-XMP</USER_AGENT> <SCREEN_LEVEL>5</SCREEN_LEVEL> <MARKUP>XHTML_MP</MARKUP> <SCRIPT></SCRIPT> <IMAGE_SUPPORT>png;gif;</IMAGE_SUPPORT> </device> <!-- NetFront Content Viewer. WAP2 browser with XHTML-MP language. --> <device> <DEVICE_NAME>NetFront</DEVICE_NAME> <USER_AGENT>NetFront</USER_AGENT> <SCREEN_LEVEL>5</SCREEN_LEVEL> <MARKUP>XHTML_MP</MARKUP> <SCRIPT>ecmascriptmp</SCRIPT> <IMAGE_SUPPORT>png;gif;jpg;jpeg;</IMAGE_SUPPORT> </device> </device-list>
For example, for the web browser ‘Firefox’, we have defined the markup language to be ‘HTML’ and the scripting language to be Javascript. Similarly for the device ‘OpenWave’, we have defined the markup language to be ‘WML’ and the scripting language as WML Script. So, after deploying this application in a server, when an application is accessing this application, the framework will determine the type of device by examining the ‘User-Agent’ field from the request parameter. It will then try to match the User-Agent information with the list of user agents that is defined in the ‘devices.xml’ configuration file. And appropriately the responses will be delivered to the target device. If the framework cannot find a suitable device, then it will lookup for the default device (mentioned below) in which case the markup language and the scripting language are HTML and Javascript respectively.
<!-- Default Device. Use this one if no other device can be matched. --> <device> <DEVICE_NAME>DefaultDevice</DEVICE_NAME> <USER_AGENT>default</USER_AGENT> <SCREEN_LEVEL>9</SCREEN_LEVEL> <MARKUP>HTML_BASIC</MARKUP> <SCRIPT>javascript</SCRIPT> <IMAGE_SUPPORT>jpg;jpeg;gif;png;</IMAGE_SUPPORT> </device>
Index Page
This page will be invoked during application’s startup. Note that this page doesn’t really do anything other than forwarding the request to the page ‘demo.jsf’.
<jsp:forward page="/hello.jsf" />
Hello Page
The complete listing for the hello page is given below. Note the tag library declaration at the top. We have used the core and the html tags along with the customized tags representing the mobile devices from the uri ‘http://www.ericsson.com/sn/mobilefaces’.
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <%@taglib prefix="m" uri="http://www.ericsson.com/sn/mobilefaces"%> <f:view> <m:doctype/> <m:html> <head> <m:title content="Hello JSF!"/> </head> <m:body> <h:form id="f"> <m:h3>Hello World</m:h3> <p> <h:messages/> <p> <h:outputText id="hello" value="Hello World"/> </h:form> </m:body> </m:html> </f:view>
Note that definition of the document type tag ‘m:doctype’. This is necessary for defining the Document type heading, whether the page has to be rendered as HTML or WML will be determined through the request parameter and the rendering will happen accordingly. Also we have defined the m:title which will render the text described in the ‘content’ attribute as a title text in the target device.
Faces Configuration file
The definition for faces configuration file is given below. Note that for this simple application, we haven’t declared any managed beans as well as the navigation rules.
<?xml version='1.0' encoding='UTF-8'?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xs d" version="1.2"> </faces-config>
Testing the application
As discussed already we will be making use of OpenWave for testing the application. Launch the application and type the url ‘http://localhost:8080/JSF-WML-Hello’. This assumes that the application is running on the port number ‘8080’ and the application’s context root is ‘JSF-WML-Hello’. Have a look at the screenshot.
Note that when this URL is accessed through the Open Wave Browser, the request will be a regular HTTP request including the protocol information. One more field of interest is the User Agent Field which will be ‘OPWV-SDK-WML’. This value for this field is very important as this value will be used for fetching the device information that is configured in the ‘devices.xml’ configuration file. Part of the request information is shown below.
... Host address: 127.0.0.1 URI: http://localhost:8080/JSF-WML-Hello/ GET /JSF-WML-Hello/ HTTP/1.1 Host: localhost:8080 User-Agent: OPWV-SDK-WML UP.Browser/7.0.2.3.119 (GUI) MMP/2.0 Push/PO ...
Once this request is accepted by the application, the response will be in Wireless markup language as that is the markup language that is configured for this user agent.
URI: http://localhost:8080/JSF-WML-Hello/ HTTP/1.1 200 OK <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" "http://www.wapforum.org/DTD/wml13.dtd"> <wml> <head> <meta name="title" content="Hello JSF!" /> </head> <card id="WMLCard" title="WML PAGE"><p><b>Hello World</b><br /> <p> <!--global message component for showing warning or error messages--> <p> Hello World <p /> </card> </wml>
Note that in the above response, the WML script is embedded in the response string.
Login Application
In this section, we will see how to implement the login support for an application when accessed through J2ME. In this example, we will see how to define managed beans for managing the state of the user inputs. Also we will see how to define the navigation rules when the application is accessed. Specifically we will see and analyze the navigation cases for a successful and a failure login.
Configuration files
The web application’s deployment descriptor won’t be getting covered in this section as the content of it will be the very same that we saw in the earlier section, same is the case for the mobile faces configuration file.
Login Bean Model
The model for the login bean is defined below. It essentially declares two things. The first thing is for collecting the user input from the UI, it defines the properties ‘username’ and ‘password’along with the getter and the setter methods. Also it provides a validation logic in the method ‘validateLogin()’ which validates the username and the password entered by the user.
package net.javabeat.articles.jsf.mobile.login; public class LoginBean { private String username; private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String validateLogin() { if (username != null && password != null) { if (username.equals("admin") && password.equals("admin")){ return "success"; } } return "failure"; } }
Note that for simplification, we didn’t validate the username and the password by hitting
the data layer. Instead the login credentials are hard-coded as ‘admin’ and ‘admin’ within the managed bean.
Index Page
The listing for the index page is shown below. As one can see it delegates the call to the login page. Note that this page will be handled by Faces Servlet as we have defined the corresponding mapping in the Web application’s deployment descriptor.
<jsp:forward page="/login.jsf" />
Login Page
The login page for the application that is used for collecting username and password information from the user is given below. Note that this is a basic form containing username/password textfields with the login button, the listing for the same is given below.
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <%@taglib prefix="m" uri="http://www.ericsson.com/sn/mobilefaces"%> <f:view> <m:doctype/> <m:html> <head> <m:title content="Login!"/> </head> <m:body> <h:form id="f"> <m:h3>Login</m:h3> <p> Username: <h:inputText id="username" value="#{loginBean.username}" required="true" /> <br/> Password: <h:inputText id="password" value="#{loginBean.password}" required="true" /> <br/> <h:commandButton id="login" type="submit" value="Login" action="#{loginBean.validateLogin}"/> </h:form> </m:body> </m:html> </f:view>
Note that when this application is accessed through a WML browser, the response that will be rendered will be WML script. Note that the developer doesn’t need to worry about the translation mechanism done for rendering as the framework takes complete care on it. The content of the WML script corresponding to the login form is given below.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" "http://www.wapforum.org/DTD/wml13.dtd"> <wml> <head> <meta name="title" content="Login!" /> </head> <card id="WMLCard" title="WML PAGE"><p><b>Login</b><br /> <p> Username: <input id="fausername" name="fausername" type="text" value="" /> <br/> Password: <input id="fapassword" name="fapassword" type="text" value="" /> <br/> <p> <do type="accept" label="Login" id="f:login" name="f:login"> <go method="post" href="/JSF-WML-Login/login.jsf;jsessionid=f5de0e83eded70 42ee6c2d295dec"> <postfield name="com.ericsson.sn.mfaces.FACES_VIEW_STATE" value="" /> <postfield name="f:login" value="submit" /> <postfield name="f:password" value="$(fapassword)" /> <postfield name="f" value="f" /> <postfield name="f:username" value="$(fausername)" /> </go></do> </card> </wml>
The screenshot for the above page is given below.
Faces Configuration file
We use the faces configuration file for defining the managed bean and the list of navigation rules in this example. Have a look at the listing of the configuration file.
<?xml version='1.0' encoding='UTF-8'?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" version="1.2"> <navigation-rule> <from-view-id>/login.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/success.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>failure</from-outcome> <to-view-id>/failure.jsp</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <description>Login Bean</description> <managed-bean-name>loginBean</managed-bean-name> <managed-bean-class> net.javabeat.articles.jsf.mobile.login.LoginBean </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>
Note that the navigation rule for this application is defined through the element’navigation-rule’. Here we have defined if the outcome from the view ‘login.jsp’ is success, then the view definition file that has to be rendered is “success.jsp”. Similarly for the outcome “failure”, the view “failure.jsp” has to be mapped and displayed. Have a look at the declaration of the login managed bean which is done within the elements ‘managed-bean’.
Success Page
When the user enters the username and the password details, the method ‘validateLogin()’ will be invoked on the Login Bean object. This method will validate for the correctness of the username and the password and if they are correct will return the string “success”. It is mentioned that for the outcome “success”, the view definition file that is mapped is “success.jsf” and the content of the same is given below.
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <%@taglib prefix="m" uri="http://www.ericsson.com/sn/mobilefaces"%> <f:view> <m:doctype/> <m:html> <head> <m:title content="Login Success"/> </head> <m:body> <m:h2>Congratulation! You login is successful</m:h2> <p><a href="login.jsf"><b>Login</b></a> </m:body> </m:html> </f:view>
Note that the content that will be returned to the WAP browser is shown below which will decode and display the view as shown in the screenshot to the user.
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" "http://www.wapforum.org/DTD/wml13.dtd"> <wml> <head> <meta name="title" content="Login Success" /> </head> <card id="WMLCard" title="WML PAGE"><p><strong>Congratulation! You login is successful</strong><br /> <p><a href="login.jsf"><b>Login</b></a> </card> </wml>
Failure page
When the user entered username/password seems to be invalid – i.e. in which case the method validateLogin() returns the string “failure”, then the failure view will be displayed to the user. The content of this view file is shown below.
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <%@taglib prefix="m" uri="http://www.ericsson.com/sn/mobilefaces"%> <f:view> <m:doctype/> <m:html> <head> <m:title content="Login Failure"/> </head> <m:body> <m:h2>Sorry! Login credentials are invalid.</m:h2> <p><a href="login.jsf"><b>Try again</b></a> </m:body> </m:html> </f:view>
The corresponding WML document that will be parsed and displayed in the target device is also shown here along with the screenshot.
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" "http://www.wapforum.org/DTD/wml13.dtd"> <wml> <head> <meta name="title" content="Login Failure" /> </head> <card id="WMLCard" title="WML PAGE"><p><strong>Sorry! Login credentials are invalid.</strong><br /> <p><a href="login.jsf"><b>Try again</b></a> </card> </wml>
Conclusion
This article started with the concepts of Renderer kits through which rendering JSF applications on multiple types of devices having different views is possible. It then went on explaining Mobile Faces – a distribution that contains an implementation for WAP support. For a basic demonstration, an illustration was given for displaying a text hello in a WAP browser thereby familiarizing with Mobile JSF and OpenWave. Finally the article concluded with Login application that explained the usage of Managed beans and Navigation rules.