1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.orchestra.flow;
20
21 import javax.faces.application.ViewHandler;
22 import javax.faces.application.ViewHandlerWrapper;
23 import javax.faces.component.UIViewRoot;
24 import javax.faces.context.FacesContext;
25
26 /**
27 * Custom ViewHandler that executes the necessary logic to handle entering and exiting a Flow.
28 * <p>
29 * Combining this class with other ViewHandlers can cause unexpected results, particularly when
30 * libararies in the classpath include faces-config.xml files that automatically register custom
31 * ViewHandler classes as in that case the order of ViewHandler nesting is hard to control. The most
32 * significant library that registers a custom ViewHandler is Facelets, but that is not a problem: this
33 * class only actually cares about the createView method, and Facelets does not do anything significant
34 * in its createView implementation.
35 */
36 public class FlowViewHandler extends ViewHandlerWrapper
37 {
38 private ViewHandler delegate;
39
40 /**
41 * Constructor.
42 */
43 public FlowViewHandler(ViewHandler delegate)
44 {
45 this.delegate = delegate;
46 }
47
48 @Override
49 protected ViewHandler getWrapped()
50 {
51 return delegate;
52 }
53
54 /**
55 * Special createView handling for Orchestra Flows.
56 * <p>
57 * When this request was a postback that started a flowcall:
58 * <ul>
59 * <li>validate that this new view is a suitable flow entry point
60 * <li>import passed parameters into child context
61 * <li>for non-modal call: send a redirect to this view
62 * <li>for modal call: rerender the *old* view, which should then
63 * trigger a GET to the new view in a new window or frame.
64 * </ul>
65 * <p>
66 * When this request was a postback that started a flowreturn:
67 * <ul>
68 * <li>Normally the view to return to is known so this code is not executed.
69 * <li>When the view to return to has a "return handler" that provides
70 * a nav-outcome then this code is executed; just redirect to the desired view.
71 * </ul>
72 * <p>
73 * Throws OrchestraException if there is a flow error, eg if the view
74 * specified is the entry point for a flow but the previous view did
75 * not do a FlowCall.
76 */
77 public UIViewRoot createView(FacesContext facesContext, String newViewId)
78 {
79 UIViewRoot viewRoot = FlowHandler.processPreCreateView(facesContext, delegate, newViewId);
80 if (viewRoot == null)
81 {
82 if (facesContext.getResponseComplete())
83 {
84 // We will never use the viewRoot returned from this method because the response
85 // is already complete. However this method is not allowed to return null, so
86 // here we return a dummy root object.
87 viewRoot = new UIViewRoot();
88 }
89 else
90 {
91 viewRoot = delegate.createView(facesContext, newViewId);
92 }
93 }
94 return viewRoot;
95 }
96 }