So I've been working out how to swap the target for multiple devices in Struts and I think I've got the idea now. I was getting a bit psycho with all the names of the targets before I finally took a step back and decided on a naming convention that both let me keep track of all the pages on the site, but also allowed me to dynamically change the path of the request based on the type of device hitting the website. (Excuse me if I'm repeating common knowledge here, but I'm making this stuff up as I go along).
I've got Struts set up so that each request for *.html, *xhmtl, *.wml or *.xml files first go through a custom servlet to an Action called URLProcessorAction which takes a look at the query path and decides which Action should process the request, it then uses a mapping.findForward() method to pass the request to the global-forward name of the Action which will process the page. It may seem complicated, but that's sorta how Struts works sometimes.
This is the part that can get nuts if you don't have some sort of naming convention. There are two types of global-forwards in the struts.config file, ones that go to the jsp page, and others which call another Action. Unlike many of the samples out there, I've got Struts set up so that each jsp page and Action has its own global-foward name so that everything is centrally located, I don't put forward attributes in the actions below because I find that even more confusing.
So my naming convention is quite simple, Actions always end in "Action" and the actual jsp pages end in the name of the device that they're targeting. The Actions are divided up by function into called "EditAction", "SaveAction", "DelAction", "QueryAction". Edit Actions return forms, Save and Delete modify data, and Query is for something like Searches. The pages have endings like "Web", "WAP", or even something specific like "NokiaXHTML", etc.
So... here's what the forwards section looks like:
<forward name="indexAction" path="/do/index"/> <forward name="indexWeb" path="/index.jsp"/> <forward name="indexWAP" path="/wap/index.jsp"/> <forward name="pageAction" path="/do/page"/> <forward name="pageEditAction" path="/do/page?method=edit"/> <forward name="pageSaveAction" path="/do/page?method=save"/> <forward name="pageDelAction" path="/do/page?metho=del"/> <forward name="pageWeb" path="/page.jsp"/> <forward name="pageWAP" path="/wap/page.jsp"/> <forward name="archiveAction" path="/do/archive"/> <forward name="archiveWeb" path="/archive.jsp"/> <forward name="archiveWAP" path="/wap/archive.jsp"/> <forward name="searchAction" path="/do/search"/> <forward name="searchQueryAction" path="/do/search?method=query"/> <forward name="searchWeb" path="/search.jsp"/> <forward name="searchWAP" path="/wap/search.jsp"/> <forward name="favoritesAction" path="/do/favorites"/> <forward name="favoritesWeb" path="/favorites.jsp"/> <forward name="favoritesWAP" path="/wap/favorites.jsp"/> <forward name="aboutAction" path="/about"/> <forward name="aboutWeb" path="/about.jsp"/> <forward name="aboutWAP" path="/wap/about.jsp"/>
To apply the ending to the jsp page names, I simply analyze the request in the URLProcessorAction and pop the name of the device that corresponds into the request object like you would normally pass a variable request.setAttribute("deviceType", deviceType) and append that to the name of the page type in the Action like this: mapping.findForward("index" + deviceType).
Right now I'm just matching User-Agents sorta dumbly, but I'm looking at ripping off some DELI code from the Cocoon project which should work quite well for this. DELI is an HP project that provides a set of RDF documents for various mobile devices noting all their capabilities and the Cocoon guys have written some nice code that wraps that all up and returns a HashMap of attributes (thanks guys!). I'm also thinking about tagging the DELI stuff up so that it can be used in a transform process later on directly on the pages. For lots of minor differences (one browser supports color another doesn't) this sort of late-transform would be perfect (remember, the only data my pages receive is XML data because of my XAOs), but for most big options you need that device info a lot earlier on.
Okay, that's all for now. Comments welcome. Please tell me if I'm on crack.