views:

627

answers:

1

Hello.

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:

<navigation-rule>
 <description>Index to subpages</description>
 <from-view-id>/index.jsp</from-view-id>
     <navigation-case>
        <from-outcome>i_to_1</from-outcome>
        <to-view-id>/page_a1.jsp</to-view-id>
        <redirect />
     </navigation-case>
     <navigation-case>
        <from-outcome>to_page_a2</from-outcome>
        <to-view-id>/page_a2.jsp</to-view-id>
        <redirect />
     </navigation-case>
 </navigation-rule>

 <navigation-rule>
 <description>From page a1</description>
 <from-view-id>/page_a1.jsp</from-view-id>
     <navigation-case>
        <from-outcome>to_page_a2</from-outcome>
        <to-view-id>/page_a2.jsp</to-view-id>
        <redirect />
     </navigation-case>
 </navigation-rule>

 <navigation-rule>
 <description>From page a2</description>
 <from-view-id>/page_a2.jsp</from-view-id>
     <navigation-case>
        <from-outcome>to_page_a1</from-outcome>
        <to-view-id>/page_a1.jsp</to-view-id>
        <redirect />
     </navigation-case>

     <navigation-case>
        <from-outcome>to_index</from-outcome>
        <to-view-id>/index.jsp</to-view-id>
        <redirect />
     </navigation-case>
 </navigation-rule>

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

A: 

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

Alex