logo
Home Article

How to do Smart Navigation Handler in JavaserverTM Faces


Author:Vladimir Perlov
Contact E-Mail:

Now itís really time to make smart navigation system. Just see some of recently posted threads on the SUN's Javaserver Faces forum:


http://forum.java.sun.com/thread.jspa?threadID=590811:

>I am trying to do the following.

>From 2 different "home" pages I navigate to another page

>home1->apage
>home2->apage

>How do I navigate back to the calling home page from "apage".
>It has a single button on >it with value "home". What is the action?
http://forum.java.sun.com/thread.jspa?threadID=588326:

>RestoreView method of ma custom ViewHander is always called
>from a refresh page AND from a click buttton in the view.
>How to distinct with the context object ( this is the only parameter I have )
>if I came from a refresh of the page or from a click on a button on the page ?
http://forum.java.sun.com/thread.jspa?threadID=589233:

>I need to get the current URL and I used FacesContext.getViewRoot().getViewId() 
>but it always return the previous URL.

>Like when I click on the login link from main.jsf,the getViewId() always
>return main.jsf instead of login.jsf. Pls help, Thanks !
http://forum.java.sun.com/thread.jspa?threadID=588984:

>I have a JSF page(navigator.jsp) embedded in a main JSF page(main.jsp)
>navigator.jsp contains the commandLinks for navigation across the application to 
>various other JSP pages like about.jsp,help.jsp. When i define the navigation
>rule in the faces-config file, should navigator.jsp be given in <from-view-id>
>or the pages about.jsp,help.jsp,etc 
>Kindly help me with the code
http://forum.java.sun.com/thread.jspa?threadID=542919:

>ok when I clicked on a link in selectcountry.jsp for the first time,
>it will route to main.jsp. But when I go back to selectcountry.jsp from main.jsp
>by clicking the "Back" button of IE6, and then click on a link again,
>I was being route to front.jsp. Is this a bug in JSF?

>Appreciate some comment here ! Thanks !

There are two questions need to be answered.
First question is why we need navigation handler decorator.
Second question is how to implement all necessary functionality related to smart navigation system.

Reasons to make navigation handler decorator:

  1. Handling all universal navigation related actions
  2. Authorization navigation
  3. Bookmark handling
  4. Track current URL
  5. Navigation by URL
  6. Using action based navigation rules
  7. Customize navigation logic

Here is some code to illustrate some ideas in this area.

import javax.faces.context.FacesContext;
import javax.faces.application.NavigationHandler;
 
public class SemanticNavigationHandler extends NavigationHandler {
 
  private NavigationHandler handler;
  enum Action {refresh, reTurn, forward, backward, login, exitSession,
    success, accessDeny, nothing} 
  private String currentAction;
  
  public SemanticNavigationHandler (NavigationHandler handler) {
    super();
    this.handler = handler; 
  } 
  
  public void handleNavigation(FacesContext fc, String actionMethod, String actionName) {
    Action action;
    NavigationPoint point;
    currentAction = actionName;
    SessionHandler sessionHandler = 
      (SessionHandler)AppHandler.getObjectById("sessionHandler");
    action = defineNavigationAction(sessionHandler);
    switch (action) {
    case login: 
      point = new NavigationPoint(actionName, actionMethod, fc.getViewRoot().getViewId()); 
      sessionHandler.pushReturnPoint(point);
      break;
    case reTurn:
      point = sessionHandler.popReturnPoint();
      currentAction = point.getAction();
      actionMethod = point.getActionMethod();
      fc.getViewRoot().setViewId(point.getViewId());
      break;      
    case exitSession:
      AppHandler.endSession();
      break;
    case refresh:
      currentAction = null;
      break;
    case forward:
      point = new NavigationPoint(actionName, actionMethod, fc.getViewRoot().getViewId()); 
      sessionHandler.pushTrailPoint(point);
      break;
    case backward: 
      point = sessionHandler.popTrailPoint();
      currentAction = point.getAction();
      actionMethod = point.getActionMethod();
      fc.getViewRoot().setViewId(point.getViewId());
      break;
    }
    handler.handleNavigation(fc, actionMethod, currentAction);
  }
 
  public Action defineNavigationAction(SessionHandler sessionHandler) {
    if (currentAction != null) {
      if (!sessionHandler.isReturnPointStackEmpty() && 
          currentAction.equals(Action.success.name())) {
        return Action.reTurn;
      }
      if (currentAction.indexOf("access@") > -1) {
        if (sessionHandler.isLogin()) {
          int atPosition = currentAction.indexOf("@");
          String action = currentAction.substring(0, atPosition);
          String entity = currentAction.substring(atPosition+1);
          if (!sessionHandler.isActionPermitted(entity, action)) {
            currentAction = Action.accessDeny.name();
          }
          return Action.nothing;
        }
        else 
          currentAction = Action.login.name();
      }
      try {
        return Action.valueOf(currentAction);
      } 
      catch (Exception ex) {        
      }
    }
    return Action.nothing;
  }
}

SessionHandler.java:

import java.util.Date;
import java.util.Stack;
import javax.faces.FacesException;
import com.semanticprogrammer.framework.data.DataHandler;
import com.semanticprogrammer.framework.accesscontrol.Authentication;
import com.semanticprogrammer.framework.accesscontrol.Authorization;
import com.semanticprogrammer.framework.web.AppHandler;
import static com.semanticprogrammer.framework.web.AppAction.*;
import com.semanticprogrammer.domain.biz.accesscontrol.User;
import com.semanticprogrammer.domain.biz.accesscontrol.Login;
 
public class SessionHandler {
  private Authentication authentication;
  private Authorization authorization;
  private DataHandler dataHandler;
  private String moduleId;
  private String title;
  private User user = null;
 
  private Stack returnPointStack;
  private Stack trailPointStack;
  
  public SessionHandler() {
    returnPointStack = new Stack();
    trailPointStack = new Stack();    
  }
 
  public void setAuthentication(Authentication authentication) {
    this.authentication = authentication;
  }
 
  public synchronized void setAuthorization(Authorization authorization) {
    this.authorization = authorization;
  }
  
  public void setDataHandler(DataHandler dataHandler) {
    this.dataHandler = dataHandler;
  }
 
  public void setModuleId(String moduleId) {
    this.moduleId = moduleId;
  }
 
  public String getModuleId() {
    return moduleId;
  }
 
  public void setTitle(String title) {
    this.title = title;
  }
 
  public String getTitle() {
    return title;
  }
 
  public synchronized Date getCurrentDate() {
    return new Date();
  }
  
  public void setUser(User user) {
    this.user = user;
  }
 
  public User getUser() {
    return user;
  }
 
  public boolean isLogin() {
    return user != null;
  } 
 
  public void pushReturnPoint(NavigationPoint point) {
    returnPointStack.push(point);
  }
 
  public NavigationPoint popReturnPoint() {
    return returnPointStack.pop();
  }
 
  public boolean isReturnPointStackEmpty() {
    return returnPointStack.empty();
  }
 
  public void pushTrailPoint(NavigationPoint point) {
    trailPointStack.push(point);
  }
 
  public NavigationPoint popTrailPoint() {
    return trailPointStack.pop();
  }
 
  public boolean isTrailPointStackEmpty() {
    return trailPointStack.empty();
  }
  
  public String selectModule() {
    setModuleId((String)AppHandler.getParameterByKey("moduleId"));
    setTitle(AppHandler.messages.getString(getModuleId()));
    return Action.access.name() + '@' + moduleId;
  }
 
  public String doorAction() {
    return isLogin() ? "exitSession" : "access@main"; 
  }
  
  public String login() {
    String result = Action.failure.name();
    try {
      Login login = (Login)AppHandler.getObjectById("login");
      if (login != null) {
        User user = authentication.ByLogin(login);
        if (user != null) {
          setUser(user);
          result = Action.success.name();
        }
      }
    }
    catch ( Exception e) {
        throw new FacesException(e);
    }
    return result;
  }
 
  public String end() {
    AppHandler.endSession();
    return Action.success.name();
  }  
 
  public int getUserId() {
    return user.getId();
  }
  
  public boolean isActionPermitted(String entityName, String actionName) {
    return authorization.isActionPermitted(user, entityName, actionName);
  }
 
  public boolean isInvoiceCreatePermitted() {
    return isActionPermitted("invoice", "create");
  }
 
  public boolean isUserCreatePermitted() {
    return isActionPermitted("user", "create");
  }
 
  public boolean isUserEditPermitted() {
    return isActionPermitted("user", "edit");
  }
 
  public boolean isUserDeletePermitted() {
    return isActionPermitted("user", "delete");
  }
}

NavigationPoint.java:

public class NavigationPoint {
  private String action;
  private String actionMethod;
  private String viewId;  
 
  public NavigationPoint(String action, String actionMethod, String viewId) {
    this.action = action;
    this.actionMethod = actionMethod;
    this.viewId = viewId;
  }
 
  public String getAction() {
    return action;
  }
 
  public void setAction(String action) {
    this.action = action;
  }
 
  public String getActionMethod() {
    return actionMethod;
  }
 
  public void setActionMethod(String actionMethod) {
    this.actionMethod = actionMethod;
  }
 
  public String getViewId() {
    return viewId;
  }
 
  public void setViewId(String viewId) {
    this.viewId = viewId;
  }
}
See Also:

JSF Navigation by Examples


Overview the standard navigation mechanism in JavaServer Faces

JSF Navigation Handler Decorator


Extending the standard navigation mechanism used in the JSF