Saturday, July 14, 2012


I am trying to extend the NavigationHandler in JSF 1.2, and to keep a stack of the visited pages (more precisely, the view-ids, along with the action and the output).
I try to implement a custom action, such as "go_back", that will take me back to the previous page.
My current NavigationHandler:
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import java.util.Stack;
public class NavigationManager extends NavigationHandler {

    NavigationHandler _base;
    private Stack trailPointStack;

    public NavigationManager(NavigationHandler base) {
        super();
        _base = base;
        trailPointStack = new Stack();
    }

    @Override
    public void handleNavigation(FacesContext fc, String actionMethod, String actionName) {
        NavigationPoint point;
        String currentAction = actionName;
        String currentMethod = actionMethod;

        if (actionName.equals("go_back") && (trailPointStack.size() > 0)) {
            point = (NavigationPoint) trailPointStack.pop();//better check if there is something in there
            //currentAction = null;
            //currentMethod = null;
            currentAction = point.getAction();
            currentMethod = point.getActionMethod();
            fc.getViewRoot().setViewId(point.getViewId());
        } else {
            point = new NavigationPoint(actionName, actionMethod, fc.getViewRoot().getViewId());
            trailPointStack.push(point);
        }

        //check stack size to be less than 6 items
        while (trailPointStack.size() > 5) {
            trailPointStack.removeElementAt(0);
        }

        _base.handleNavigation(fc, currentMethod, currentAction);
    }
}
The NavigationPoint is just a simple class with 3 Strings, for the actionName, actionMethod and ViewId.
My navigation rules, in faces-config.xml:

 Index to subpages
 /index.jsp
     
        i_to_1
        /page_a1.jsp
         />
     
     
        to_page_a2
        /page_a2.jsp
         />
     
 

 
 From page a1
 /page_a1.jsp
     
        to_page_a2
        /page_a2.jsp
         />
     
 

 
 From page a2
 /page_a2.jsp
     
        to_page_a1
        /page_a1.jsp
         />
     

     
        to_index
        /index.jsp
         />
     
 
I only have 3 pages, index.jsp, page_a1.jsp and page_a2.jsp.
You can see in the navigation cases, the connections between them. What I want is to be able to "go_back" from page_a2.jsp, to either page_a1.jsp, or to index.jsp.
The normal navigation works fine: Index -> P1 -> P2 -> P1 -> P2 -> Index; no problem.
If I do: Index -> P1 -> P2
I will have on the stack:
bottom
1:index.jsp/i_to_1 -> page_a1.jsp
2:page_a1.jsp/to_page_a2 -> page_a2.jsp
top
When I try "go_back" from P2, I expect it to go back to page 1. It doesn't (the page is just reloaded). If I try it a second time, it works.
I think it's because on the first try, I pop from the stack, and it tries with the action "to_page_a2" - fails. The second time, it pops again from the stack, but now it tries with "i_to_1", and this.. somehow, works.
Can anyone help me with this? I hope my explanations were clear enough - if not, please ask.
Any similar idea is also welcome. I should mention that it was 2 days ago that I started using JSF, and it's not very clear to me all that happens there.
Thank you, Alex
link|improve this question

67% accept rate
Was this post useful to you?     
Ok, I have found a solution (or, better said, a patch, because I am not sure it works too well).
I am popping 2 items, instead of one, before I do the "go_back".
Ex: Index -> P1 -> P2 - go_back; I am supposed to go to P1 (P2 -> P1)
To be able to reach P1, I actually have to go the the "Index" point, and then try to go to P1. (I have to go with one step before the page I want to go back to):
The stack:
1: pop P1 (I want to get to it, so I can't use it; I just remove it from the stack)
2: pop Index - use the Index point to go to P1 (even if am actually in P2)
The updated code:
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import java.util.Stack;
public class NavigationManager extends NavigationHandler {

    NavigationHandler _base;
    private Stack trailPointStack;

    public NavigationManager(NavigationHandler base) {
        super();
        _base = base;
        trailPointStack = new Stack();
    }

    @Override
    public void handleNavigation(FacesContext fc, String actionMethod, String actionName) {
        NavigationPoint point;
        String currentAction = actionName;
        String currentMethod = actionMethod;

        if (actionName.equals("go_back") && (trailPointStack.size() > 0)) {//"go_back" is the action that triggers the back move

            if (trailPointStack.size() == 1) {
                //It is the first page we visit (the second page in stack)
                point = (NavigationPoint) trailPointStack.pop();
                currentAction = null;
                currentMethod = point.getActionMethod();
            } else {
                trailPointStack.pop();//we get rid of the prev, and we go from prev-prev to prev :D
                point = (NavigationPoint) trailPointStack.pop();//actually the second one in the stack
                currentAction = point.getAction();
                currentMethod = point.getActionMethod();
            }

            fc.getViewRoot().setViewId(point.getViewId());
        } else {
            point = new NavigationPoint(actionName, actionMethod, fc.getViewRoot().getViewId());
            trailPointStack.push(point);
        }

        //check stack size to be max 10 items
        while (trailPointStack.size() > 10) {
            trailPointStack.removeElementAt(0);
        }

        _base.handleNavigation(fc, currentMethod, currentAction);
    }
}
I hope this helps someone!
Also, I am sure this may not be working very well, I haven't tested too much yet.
Any other ideas are welcome.
Thanks
Alex

No comments: