XML-less JSF Navigations

JSF’s declarative navigation management requires you to specify a navigation rule with navigation cases in faces-config.xml. If your application gets bigger, your faces-config.xml would get bigger as a result. Following the convention over configuration design paradigm, it is possible to avoid navigation rules in xml.

As usual we need to extend JSF and the idea is to plug-in a custom navigation handler. This navigation handler assumes the outcome is the name of the target view of the navigation.


public class LetsGetRidofXMLStuffNavigationHandler extends NavigationHandler{

    public final static String REDIRECT_PREFIX = "redirect";

    @Override
    public void handleNavigation(FacesContext facesContext, String fromAction, String outcome) {
        if(outcome == null)
            return;            //no navigation

        ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
        String targetViewId = getTargetViewId(facesContext, outcome);

        if(isRedirect(outcome))
        {
             ExternalContext externalContext = facesContext.getExternalContext();
             String redirectPath = viewHandler.getActionURL(facesContext, targetViewId);

             try
             {
                 externalContext.redirect(externalContext.encodeActionURL(redirectPath));
             }
             catch (IOException e)
             {
                 throw new FacesException(e.getMessage(), e);
             }
        }
        else
        {
            UIViewRoot viewRoot = viewHandler.createView(facesContext, targetViewId);
            facesContext.setViewRoot(viewRoot);
            facesContext.renderResponse();
        }
    }

    private boolean isRedirect(String outcome) {
        return outcome.startsWith(REDIRECT_PREFIX);
    }

    private String getTargetViewId(FacesContext facesContext, String outcome) {
        String targetViewId;
        String viewSuffix = getDefaultViewSuffix(facesContext);

        if(isRedirect(outcome)) {
            targetViewId = "/" + outcome.split(":")[1] + viewSuffix;
        } else {
            targetViewId = "/" + outcome + viewSuffix;
        }

        return targetViewId;
    }

    private String getDefaultViewSuffix(FacesContext facesContext) {
        String suffix = facesContext.getExternalContext().getInitParameter("javax.faces.DEFAULT_SUFFIX");

        return suffix!=null ? suffix : ".jsp";
    }

}

After implementing this navigation handler, we need to plug it in so that it can take over navigation management. In faces-config;


<?xml version="1.0" encoding="utf-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xi="http://www.w3.org/2001/XInclude"
 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">

 <application>
  <navigation-handler>com.mycompany.myproject.stuff.LetsGetRidofXMLStuffNavigationHandler</navigation-handler>
 </application>

Now without defining an navigation rule in xml, in action binding methods just return the name of the page. For example, to navigate from a paged called login.jsf to mainpage.jsf, return “mainpage”.


public String login() {

//do some stuff

return "mainpage";

}

When the “mainpage” outcome reaches our navigation management, it finds the view id as /target.jsp or /target.xhtml(depending on what view technology you use) and then do a forward. For redirects add the redirect prefix so the string to be returned should be “redirect:mainpage”.

After all there is no need to define any navigation-rule in faces-config so we can get rid of this;

<navigation-rule>
    <from-view-id>/login.jsp</from-view-id>
    <navigation-case>
      <from-outcome>mainpage</from-outcome>
      <to-view-id>/mainpage.jsp</to-view-id>
    </navigation-case>
</navigation-rule>
About these ads

5 Responses to XML-less JSF Navigations

  1. Isn’t there something like this already in Myfaces (or was it tomahawk)?

  2. cagataycivici says:

    Don’t know, never seen one.

  3. Matt Raible says:

    Good stuff – is something like this going to be a part of JSF 2.0? If not, I’d love to see it added to another library (i.e. Spring or MyFaces).

  4. cagataycivici says:

    I’ve pinged Ed Burns about this today after writing the example, I hope this goes in 2.0 somehow. At least, I may commit it to myfaces.

  5. Pingback: XML-less JSF Navigation | Maxa Blog

Follow

Get every new post delivered to your Inbox.

Join 107 other followers

%d bloggers like this: