JSF and Mobile Web Applications — Part 2: The ServletFilter approach

The challenges to develop a mobile web application are two-folds:

  1. The application needs to generate different page layout and markups for different devices. This is not just about using wider layout for wider screens — it also includes using table / CSS / JavaScript for devices that support those features.
  2. The content (e.g., image, media, and text) also need to be customized and transformed for each device.

The web server can tell the client device type from the user agent header in the incoming HTTP request. The question now is how we integrate the user agent header information into the web framework and generate the right web page. The JSF renderkit approach we discussed earlier is not practical since we are not going to go through the trouble to write our own JSF renderkit.

One potential choice is to use the WURFL WALL JSP tag library, which can generate WML / CHTML / XHTML MP markups from the same JSP page based on the user agent. But the WALL tag library is difficult to integrate with modern web frameworks: it requires you to construct your page in WALL tags completely, while frameworks like JSF requires you to use its own component tags on the page. The WALL tag library also only deal with markup transformation. It does not provide different page layouts for different devices / screen sizes (except for the most basic customization hardcoded into the tag library), and does not deal with content transformation / management. We need a more flexible solution.

Don Kittle and Frank Carver mentioned in the comments to my previous blog entry that they use a JSTL servlet filter to transform the rendered XHTML content into WML / XHTML MP, and use special markups on the view template to progressively select content fragments for the target device. Those solutions are very good but they generally break the JSF component model, and to me, they are not generic enough.

So, here is what I think we could do (please let me know if I am missing something!): We can use a URL re-writing servlet filter to check the user agent of the incoming request, figure out the device attributes (e.g., screen sizes, whether CSS is supported etc.), and dispatch the request to the correct template for rendering based on the device attributes. For instance, a request from Nokia 6600 will be dispatched to the 176×208 XHTML MP with CSS template. For most current mobile device, I think the following 10 templates (in 5 groups) will suffice:

* Basic XHTML MP without CSS or table for small screens (width <= 128)
* Basic XHTML MP without CSS or table for medium screens (128 < width <= 176)

* Basic XHTML with table support for small screens (width < 128)
* Basic XHTML with table support for medium screens (128 < width <= 176)

* XHTML MP with CSS for small screens (width <= 128)
* XHTML MP with CSS for medium screens (128 < width <= 176)
* XHTML MP with CSS for large screens (176 < width <= 320, i.e., iphone-like)

* XHTML MP with CSS and JavaScript for medium screens (128 < width <= 176)
* XHTML MP with CSS and JavaScript for large screens (176 < width <= 320, i.e., iphone-like)

* Regular full blown XHTML with JavaScript for PC screens

The filter also saves the device attribute in the HttpSession object. When backing beans render content for the page, they can use the device attributes from the session to retrieve the right content for the device. For instance, the backing bean would retrieve a 176×10 banner image for the Nokia 6600, and limit the dynamic text to less than 250 chars (more or less one screen).

In the context of JBoss Seam, it would be great if we can make the filter a Seam component so that the user can configure it (e.g., URL rewriting rules for template locations) in components.xml. We can also make the device attribute object available as a Seam component so that all JSF beans can inject it as needed. Maybe this will be my next contribution to Seam. :)

Now, there are some potential issues with this approach. Let me explain why they do not matter in most cases …

  • There are some repetition to write different templates for the same content. But it improves the usability of both the mobile and PC web pages, and that is all that matters. Also, the clarity of XHTML MP/HTML/WML-based design is far better than the opaque JSF tag-based design.
  • The standard JSF renderer cannot generate WML markup for JSF input/form tags. That needs to be corrected by developing a set of WML-specific JSF form tags. That is much simpler than meddling with the renderkit. And frankly, there are not many WML devices out there! The vast majority of mobile phones today are XHTML MP-compliant and works perfectly with standard JSF tags.
  • Some JSF implementations (e.g., MyFaces) use JavaScript to trigger button click actions. That will not work on some lower end devices. Fortunately, JavaScript-free high-quality JSF implementations (e.g., the RI) are readily available.

All in all, I believe the servlet filter approach is the right way to go for most mobile web applications. It allows web pages to be optimized for a variety of devices from the PC to iphone to PDAs to small mobile phones. And it can be used in any web framework since there is really nothing specific to JSF here!

In the next post, I will discuss how to map user agent strings to device capabilities (e.g., supported markups and screen sizes) in the filter, as well as exactly how many different view templates you will need in a typical mobile web application.

6 Responses to “JSF and Mobile Web Applications — Part 2: The ServletFilter approach”

  1. Marcus Says:

    This is great. I was working on this very issue in the past couple weeks (in Seam, no less) and I feel that this is very very close to the solution.

    I feel though that there may be some big weaknesses to the filter + template approach. I think you even touched upon the very issues I’m concerned about in your previous post on the topic: The differently sized devices, even in a highly planned and structured web application, have different strategic goals in the planning of their site maps. So I see the site map as changing substantially when we’re talking about (a) extremely small screens, (b) small and medium, and (c) PC.

    So the separate template are likely a necessity for different device size types, as you have stated, but there are also separate site maps for some or all of the device sizes in many or all cases.

    What do you think? Does this mesh with your approach much or at all?

    BTW, alongside iPhones for the medium sized devices, I’m thinking perhaps we could put set-top boxes, perhaps in two categories: HD and regular TV, depending on how important those markets are for a given application. But I haven’t explored that very far yet. Depending on how important those devices are for a given application, this may bring in color correction considerations, and alternative input device considerations, but really shouldn’t be too hard overall.

    Also, regarding URL rewriting for templates, I don’t think it has to be all the way out there in the URL rewriter. The way I’ve implemented is just in simple manager components and components that implement Map with the template choice within the get(). It seems to me that the URL rewriter is really for external request translation, rather than internal. Does that make sense?

  2. Michael Yuan Says:

    Hi Marcus,

    Thanks for sharing your thoughts! Yes, I think my approach should be able to handle different sitemaps for different screen size templates. For instance, the small screen version of the “product description page” might be broken into multiple parts with “next page” links on each page. All I need is to put the “next page” link on the template for this screen size. The other large screen pages will simply not render that link and the user will not be prompted to go to the next page, right? So, I guess it should work as long as we keep each set of templates internally consistent. They are accessed by common URLs (e.g., /app/product.seam?id=123 always gets product 123 customized for the request device), but some URL (e.g., /app/product.seam?id=123&page=2) only works for certain screen sizes.

    As for the manager component to replace my URL rewriting component, can you provide more details (a code snippet? :))? Do you use get() to get JSF rendered content? How do you do that exactly? Thanks!

    cheers
    Michael

  3. Marcus Says:


    @Name("template")
    public class Template
    extends AbstractMap
    implements Serializable {

    @In Theme contextTheme;

    @Override public String get(Object key) {
    // do whatever you need to select the right
    // template based on the key, device, config, etc.
    //
    // I also allow an override from a request param.
    //
    // Note that this doesn't remove the need for a
    // separate theme component (also a map). The one
    // that comes with Seam can work but is generally
    // too simplistic.
    return contextTheme.get(templateKey);
    }

    @Override
    public Set> entrySet() {
    // this return doesn't matter too much
    return contextTheme.entrySet();
    }
    }

    ContextTheme is a simple manager component with one method that selects and returns the right Theme component depending on the context.

    It’s not really groundbreaking but works nicely for me.

  4. Marcus Says:

    I do put some config for both template, and themes into components.xml, left it out for brevity.

  5. Austin Huang Says:

    Hi,

    I tried JSF 1.2 RI (with Seam 2.0.1.CR1) embeeded in Jboss 4.2.2.GA. Seems that JSF 1.2 RI is not completely javascript-free implementation. Hereunder is the code

    And I got

    //

    I am wondering is there any other JSF implementation for rendering XHTML MP ?

  6. James F Says:

    Have you heard about the book, Pro JSF and Ajax? There’s a chapter on ‘Dynamically changing the renderkit’, which sounds interesting on the face of it. That may allow you to reduce the number of permutations of templates that you need to create for each markup language, and perhaps use multiple templates to optimize for screen-size.

    http://www.springerlink.com/content/v123xm51gj7j27n3/

Leave a Reply