Every wanted to access a JSF view by directly entering the view onto URL? This is a common request. In my case, I needed to link to specific places in my JSF app from a legacy non-JSF application. This is the type of thing you'd think would be straightforward, but JSF falls flat.
I scoured the web for solutions to this, and this is the simplest: implement a phase listener. In the interest of getting right to it, here it is:
public class RedirectPhaseListener implements PhaseListener {
public RedirectPhaseListener() {
}
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
public void afterPhase(PhaseEvent phaseEvent) {
}
public void beforePhase(PhaseEvent phaseEvent) {
FacesContext ctx = phaseEvent.getFacesContext();
HttpServletRequest request =
(HttpServletRequest) ctx.getExternalContext().getRequest();
String viewId = request.getParameter("viewId");
if (viewId != null) {
UIViewRoot page = ctx.getApplication().getViewHandler().createView(ctx, viewId);
ctx.setViewRoot(page);
ctx.renderResponse();
}
}
}
The phase listener gets the request, and checks for a parameter. The parameter is the path to the view ID you want to visit. For example: /faces/someview.xhtml. With Facelets, these goto URLs end up looking funny, because the real view ID is in the URL also,
/faces/home.xhtml?viewId=/faces/other.xhtml
Not nice, but it works. Other solutions I've seen try to get fancy by keeping a mapping a view+action result=new view. That's cleaner, and it's easy to do once you understand what's going on above.

Or you could use seam if your project allows it. Much easier and much more expressive.
Posted by Fadzlan on May 06, 2009 at 08:08 AM PDT #
You can also check primefaces. it has xml-less navigation
http://www.rehberharitam.com/prime-showcase/optimus/source.jsf
Yigit.
Posted by yigit darcin on May 07, 2009 at 02:23 AM PDT #
Cool solution. It shows how relatively cleanly URL-based navigation can be added to JSF. What you are talking about here is addessability which is a fundamental aspect of HTTP's original design. It's not just legacy applications that benefit, but human users too. If done right this approach enables bookmarking and back/forward buttons to work as expected. The big limitation here is that many views in a non-trivial JSF application rely on session state from previous requests in the expected click path to that view. I do like this solution and I hope it encourages JSF developers to rely a lot less on session state.
Posted by Alain O'Des on May 07, 2009 at 03:44 AM PDT #
JSF also lets you create your own NavigationHandler and plug it in through faces-config.xml. This way, you could make your action methods return a string that is prefixed with url: ("url:MyPage.jsf") and have it navigate to the url. If there is no "url:" prefix, just delegate to the base navigation handler which will look up the navigation rule.
Posted by Geoffrey Longo on May 07, 2009 at 04:57 AM PDT #
Ignore my previous comment, I missed the part about coming from a non-JSF application.
Posted by Geoffrey Longo on May 07, 2009 at 05:04 AM PDT #
Perhaps I'm missing something, but I don't see what this accomplishes. Can you provide an example of the use case?
Posted by Kito D. Mann on May 13, 2009 at 03:15 PM PDT #
kito,
in JSF, the view ID is not determined by the URL. you can't hit http://foo.bar/../a.xhtml and go to view a.xhtml. it will go to whatever view JSF has internally set to be the current view.
it is common however to have a non-JSF app that needs to link to view a.xhtml directly. that's where this type of solution comes in. i understand there are JSF extension and JSF-like frameworks that allow this, but pure JSF does not.
Posted by jeff on May 13, 2009 at 03:22 PM PDT #