Saturday, July 14, 2012


An Alternative JSF Navigation Handler

Posted by Roger Keays7 September 2008, 8:50 PM

Two of the things that frustrate me about the stock JSF navigation handler are 1) I find it cumbersome to have navigation rules externalised in faces-config.xml; and 2) there is little or no possibility for reuse in XML. The CRUD pattern we use was spawning lines and lines of almost identical configuration for navigation.
Naturally the only solution to these problems is to swear a lot, post angry messages online and denounce the JCP as a disturbed, malevolent oligarchy led by individuals with as much grip on reality as a gecko has on teflon. But... I refrained .
Instead, I implemented this little NavigationHandler which allows you to shortcut the navigation rules by specifying a view id directly as an outcome:

The action can still be a method expression which returns the view id.
Here is the implementation, which you can also find in Furnace Webcore 1.4:
/**
 * An extension to the default navigation handler which allows us to
 * specify viewIds directly as the outcome. There is no support for 
 * redirection, however if you need this you can specify a viewId 
 * which simply contains a web:redirect tag.
 */
public class WebcoreNavigationHandler extends NavigationHandlerImpl {
    private Logger log = Logger.getLogger(getClass().getName());
    
    /** 
     * Default constructor.
     */
    public WebcoreNavigationHandler() {
        super();
    }
    
    
    /**
     * Override the default navigation handler to check for viewIds in
     * the outcome string. This simply looks for the .xhtml extension.
     */
    @Override
    public void handleNavigation(FacesContext context, String fromAction,
                                 String outcome) {
        if (outcome != null && outcome.endsWith(".xhtml")) {
            
            // canonicalize path relative to current view
            String dir = "/";
            if (!outcome.startsWith("/")) {
                dir = context.getViewRoot().getViewId();
                dir = dir.substring(0, dir.lastIndexOf("/"));
            }
            try {
                File file = new File(dir, outcome);
                outcome = file.getCanonicalPath();
            } catch (IOException ioe) {
                log.severe("Error canonicalizing " + outcome);
                return;
            }
            
            // set the specified view
            ViewHandler views = context.getApplication().getViewHandler();
            UIViewRoot view = views.createView(context, outcome);
            context.setViewRoot(view);
        } else {
            super.handleNavigation(context, fromAction, outcome);
        }
    }
}
You need to configure the WebcoreNavigationHandler in your faces-config.xml (this is already done for you in the Furnace jar):

  au.com.ninthavenue.webcore.application.WebcoreNavigationHandler
Hope you find it useful :)

No comments: