JSF 1.2 NavigationHandler custom navigation
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 pr开发者_Python百科evious 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 topWhen 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
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
I've implemented something similar; I've also intercepted the "backspace" key in javascript in order to click an hidden commandLink which triggers the navigation to the previous view in the stack (or any combination/logic that you need).
In my use case I've flattened the logic of the navigation cases in order to navigate more easily from point to point within the code:
public static void navigate(String action, String outcome) {
FacesContext fc = FacesContext.getCurrentInstance();
NavigationHandler nh = fc.getApplication().getNavigationHandler();
nh.handleNavigation(fc, action, outcome);
}
精彩评论