1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.application;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.faces.FacesException;
32 import javax.faces.application.NavigationHandler;
33 import javax.faces.application.ViewHandler;
34 import javax.faces.component.UIViewRoot;
35 import javax.faces.context.ExternalContext;
36 import javax.faces.context.FacesContext;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.myfaces.config.RuntimeConfig;
41 import org.apache.myfaces.config.element.NavigationCase;
42 import org.apache.myfaces.config.element.NavigationRule;
43 import org.apache.myfaces.portlet.PortletUtil;
44 import org.apache.myfaces.shared_impl.util.HashMapUtils;
45
46
47
48
49
50
51 public class NavigationHandlerImpl
52 extends NavigationHandler
53 {
54 private static final Log log = LogFactory.getLog(NavigationHandlerImpl.class);
55 private static final String PARTIAL_STATE_SAVING_METHOD_PARAM_NAME = "javax.faces.PARTIAL_STATE_SAVING_METHOD";
56 private static final String PARTIAL_STATE_SAVING_METHOD_ON = "true";
57 private static final String PARTIAL_STATE_SAVING_METHOD_OFF = "false";
58
59 private static final String ASTERISK = "*";
60 private Boolean _partialStateSaving = null;
61
62 private boolean isPartialStateSavingOn(javax.faces.context.FacesContext context)
63 {
64 if(context == null) throw new NullPointerException("context");
65 if (_partialStateSaving != null) return _partialStateSaving.booleanValue();
66 String stateSavingMethod = context.getExternalContext().getInitParameter(PARTIAL_STATE_SAVING_METHOD_PARAM_NAME);
67 if (stateSavingMethod == null)
68 {
69 _partialStateSaving = Boolean.FALSE;
70 context.getExternalContext().log("No context init parameter '"+PARTIAL_STATE_SAVING_METHOD_PARAM_NAME+"' found; no partial state saving method defined, assuming default partial state saving method off.");
71 }
72 else if (stateSavingMethod.equals(PARTIAL_STATE_SAVING_METHOD_ON))
73 {
74 _partialStateSaving = Boolean.TRUE;
75 }
76 else if (stateSavingMethod.equals(PARTIAL_STATE_SAVING_METHOD_OFF))
77 {
78 _partialStateSaving = Boolean.FALSE;
79 }
80 else
81 {
82 _partialStateSaving = Boolean.FALSE;
83 context.getExternalContext().log("Illegal partial state saving method '" + stateSavingMethod + "', default partial state saving will be used (partial state saving off).");
84 }
85 return _partialStateSaving.booleanValue();
86 }
87
88
89 private Map _navigationCases = null;
90 private List _wildcardKeys = new ArrayList();
91
92 public NavigationHandlerImpl()
93 {
94 if (log.isTraceEnabled()) log.trace("New NavigationHandler instance created");
95 }
96
97 public void handleNavigation(FacesContext facesContext, String fromAction, String outcome)
98 {
99 if (outcome == null)
100 {
101
102 return;
103 }
104
105 NavigationCase navigationCase = getNavigationCase(facesContext, fromAction, outcome);
106
107 if (navigationCase != null)
108 {
109 if (log.isTraceEnabled())
110 {
111 log.trace("handleNavigation fromAction=" + fromAction + " outcome=" + outcome +
112 " toViewId =" + navigationCase.getToViewId() +
113 " redirect=" + navigationCase.isRedirect());
114 }
115 if (navigationCase.isRedirect() &&
116 (!PortletUtil.isPortletRequest(facesContext)))
117 {
118 ExternalContext externalContext = facesContext.getExternalContext();
119 ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
120 String redirectPath = viewHandler.getActionURL(facesContext, navigationCase.getToViewId());
121
122 try
123 {
124 externalContext.redirect(externalContext.encodeActionURL(redirectPath));
125 }
126 catch (IOException e)
127 {
128 throw new FacesException(e.getMessage(), e);
129 }
130 }
131 else
132 {
133 ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
134
135 String newViewId = navigationCase.getToViewId();
136 UIViewRoot viewRoot = null;
137 if (isPartialStateSavingOn(facesContext)) {
138 viewRoot = viewHandler.restoreView(facesContext,newViewId);
139 } else {
140 viewRoot = viewHandler.createView(facesContext, newViewId);
141 }
142 facesContext.setViewRoot(viewRoot);
143 facesContext.renderResponse();
144 }
145 }
146 else
147 {
148
149 if (log.isTraceEnabled())
150 {
151 log.trace("handleNavigation fromAction=" + fromAction + " outcome=" + outcome +
152 " no matching navigation-case found, staying on current ViewRoot");
153 }
154 }
155 }
156
157
158
159
160 public NavigationCase getNavigationCase(FacesContext facesContext, String fromAction, String outcome)
161 {
162 String viewId = facesContext.getViewRoot().getViewId();
163 Map casesMap = getNavigationCases(facesContext);
164 NavigationCase navigationCase = null;
165
166 List casesList = (List)casesMap.get(viewId);
167 if (casesList != null)
168 {
169
170 navigationCase = calcMatchingNavigationCase(casesList, fromAction, outcome);
171 }
172
173 if (navigationCase == null)
174 {
175
176 List keys = getSortedWildcardKeys();
177 for (int i = 0, size = keys.size(); i < size; i++)
178 {
179 String fromViewId = (String)keys.get(i);
180 if (fromViewId.length() > 2)
181 {
182 String prefix = fromViewId.substring(0, fromViewId.length() - 1);
183 if (viewId != null && viewId.startsWith(prefix))
184 {
185 casesList = (List)casesMap.get(fromViewId);
186 if (casesList != null)
187 {
188 navigationCase = calcMatchingNavigationCase(casesList, fromAction, outcome);
189 if (navigationCase != null) break;
190 }
191 }
192 }
193 else
194 {
195 casesList = (List)casesMap.get(fromViewId);
196 if (casesList != null)
197 {
198 navigationCase = calcMatchingNavigationCase(casesList, fromAction, outcome);
199 if (navigationCase != null) break;
200 }
201 }
202 }
203 }
204 return navigationCase;
205 }
206
207
208
209
210 public String getViewId(FacesContext context, String fromAction, String outcome)
211 {
212 return this.getNavigationCase(context, fromAction, outcome).getToViewId();
213 }
214
215
216
217
218
219
220
221
222
223
224
225 public String beforeNavigation(String viewId)
226 {
227 return null;
228 }
229
230 private NavigationCase calcMatchingNavigationCase(List casesList, String actionRef, String outcome)
231 {
232 for (int i = 0, size = casesList.size(); i < size; i++)
233 {
234 NavigationCase caze = (NavigationCase)casesList.get(i);
235 String cazeOutcome = caze.getFromOutcome();
236 String cazeActionRef = caze.getFromAction();
237 if ((cazeOutcome == null || cazeOutcome.equals(outcome)) &&
238 (cazeActionRef == null || cazeActionRef.equals(actionRef)))
239 {
240 return caze;
241 }
242 }
243 return null;
244 }
245
246 private List getSortedWildcardKeys()
247 {
248 return _wildcardKeys;
249 }
250
251 private Map getNavigationCases(FacesContext facesContext)
252 {
253 ExternalContext externalContext = facesContext.getExternalContext();
254 RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
255
256 if (_navigationCases == null || runtimeConfig.isNavigationRulesChanged())
257 {
258 synchronized(this)
259 {
260 if (_navigationCases == null || runtimeConfig.isNavigationRulesChanged())
261 {
262 Collection rules = runtimeConfig.getNavigationRules();
263 int rulesSize = rules.size();
264 Map cases = new HashMap(HashMapUtils.calcCapacity(rulesSize));
265 List wildcardKeys = new ArrayList();
266
267 for (Iterator iterator = rules.iterator(); iterator.hasNext();)
268 {
269 NavigationRule rule = (NavigationRule) iterator.next();
270 String fromViewId = rule.getFromViewId();
271
272
273 if (fromViewId == null)
274 {
275 fromViewId = ASTERISK;
276 }
277 else
278 {
279 fromViewId = fromViewId.trim();
280 }
281
282 List list = (List) cases.get(fromViewId);
283 if (list == null)
284 {
285 list = new ArrayList(rule.getNavigationCases());
286 cases.put(fromViewId, list);
287 if (fromViewId.endsWith(ASTERISK))
288 {
289 wildcardKeys.add(fromViewId);
290 }
291 } else {
292 list.addAll(rule.getNavigationCases());
293 }
294
295 }
296 Collections.sort(wildcardKeys, new KeyComparator());
297
298 synchronized (cases)
299 {
300
301
302
303
304 _navigationCases = cases;
305 _wildcardKeys = wildcardKeys;
306
307 runtimeConfig.setNavigationRulesChanged(false);
308 }
309 }
310 }
311 }
312 return _navigationCases;
313 }
314
315 private static final class KeyComparator
316 implements Comparator
317 {
318 public int compare(Object o1, Object o2)
319 {
320 return -(((String)o1).compareTo((String)o2));
321 }
322 }
323 }