Sunday, March 13, 2011

JSF 2 Internals - Efficient way of Redirecting to a Page

There are certain cases where you are needed to redirect  to a different page than requested by user e.g. if user has requested a secure page for which he/she is not authorized, your application will have to redirect to login page or some other page. I have created a utility method to redirect to a page. You can call anywhere but for example given above, you can call it a beforePhase method of RestoreViewPhaseListener. Here is the method code:

public static void redirect(String viewId) {

execute(FacesContext.getCurrentInstance(), viewId);
}


private static void execute(FacesContext facesContext, String viewId)
throws FacesException {

UIViewRoot viewRoot = null;
ViewDeclarationLanguage vdl = facesContext.getApplication()
.getViewHandler()
.getViewDeclarationLanguage(facesContext, viewId);

if (vdl != null) {
// If we have one, get the ViewMetadata...
ViewMetadata metadata = vdl.getViewMetadata(facesContext,
viewId);

if (metadata != null) { // perhaps it's not supported
// and use it to create the ViewRoot. This will have, at
// most
// the UIViewRoot and its metadata facet.
viewRoot = metadata.createMetadataView(facesContext);

}
}

facesContext.setViewRoot(viewRoot);
facesContext.renderResponse();
assert (null != viewRoot);

}

viewId is the name of page to which it should redirect e.g. "/redirect.xml" (assuming page is at root level). Inside execute method, you get the ViewDeclarationLanguage which is page type specific e.g. if page is in facelet markup, you get DefaultFaceletViewDeclarationLanguage and if page is in JSP markup, then you will get corresponding ViewDeclarationLanguage. After this, page root tree is constructed by calling createMetadataView if it is not already constructed. Finally set the new ViewRoot and call renderResponse method, which will bypass all phases and will jump directly to render phase.

3 comments:

vortex said...

hey, thanks for the post, being a newby i have a hard time understand what to do with the code you provided, i'm learning jsf, and i need a redirect when a user is accessing a page that he shouldn't, can you help me with that (using the boolean property isConnected in a managed bean UserBean ) where do i have to copy your code and how can i use it ? i need to provide a tag with this logic , right ? thanks and sorry for bothering you

amer sohail said...

First of all copied my code in some of ur utility class. If you don't have it then create a class and copied that code to it.

Then you will have to register PhaseListener for "RestoreView" phase and inside beforePhase method, you can write code something like this,

FacesContext context = event.getFacesContext(); String requestPath = context.getExternalContext().getRequestPathInfo();
if (requestPath != null && requestPath.equals("/your_page.xhtml")){
FacesUtil.redirect("/redirected_page.xhtml");

In the code "your_page" is the page against which you want to redirect. "redirected_page" is the page to which you want to redirect. "FacesUtil" is my utility class which contains my code given in this blog.

Steve Smith said...

Great and Useful Article.

JSF Online Training

JSF Training

JSF Interview Questions

JSF Tutorials

Java Training Institutes in Chennai

Java Training in Chennai