View Javadoc

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  
20  package org.apache.myfaces.orchestra.viewController.jsf;
21  
22  import java.util.Set;
23  import java.util.TreeSet;
24  
25  import javax.faces.component.UIViewRoot;
26  import javax.faces.context.FacesContext;
27  import javax.faces.event.PhaseEvent;
28  import javax.faces.event.PhaseId;
29  import javax.faces.event.PhaseListener;
30  
31  import org.apache.myfaces.orchestra.viewController.ViewControllerManager;
32  
33  /**
34   * Causes lifecycle methods to be invoked on backing beans that are associated with
35   * the current view.
36   * <p>
37   * Method executeInitView is invoked on the configured ViewControllerManager when ...
38   * <p>
39   * 
40   * <p>
41   * See the javadoc for class ViewControllerManager on how to configure this.
42   * <p>
43   * Note that at the moment this does not supprt a ViewController bean for subviews
44   * (ie f:subView tags), which the Shale ViewController framework does provide.
45   * <p>
46   * It also might not invoke all the callbacks if exceptions are thrown by actionlisteners,
47   * etc (which again Shale guarantees). This is particularly important for an "endView"
48   * callback, where resources allocated on initView (such as database connections) might
49   * be released.
50   */
51  public class ViewControllerPhaseListener implements PhaseListener
52  {
53      private static final long serialVersionUID = -3975277433747722402L;
54  
55      /**
56       * @since 1.1
57       */
58      public static class ViewControllerPhaseListenerState
59      {
60          private Set initedViews = new TreeSet();
61  
62          protected ViewControllerPhaseListenerState()
63          {
64          }
65      }
66  
67      public void beforePhase(PhaseEvent event)
68      {
69          if (PhaseId.RESTORE_VIEW.equals(event.getPhaseId()) ||
70              PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()))
71          {
72              assertConversationState(event.getFacesContext());
73              if (event.getFacesContext().getResponseComplete())
74              {
75                  // we have a redirect ... stop now
76                  return;
77              }
78          }
79  
80          // Try to init the view in every phase, just so we are sure to never miss it.
81          // This skips the actual call if init has already happened.
82          executeInitView(event.getFacesContext());
83          
84          if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()))
85          {
86              preRenderResponse(event.getFacesContext());
87          }
88  
89          if (PhaseId.INVOKE_APPLICATION.equals(event.getPhaseId()))
90          {
91              preInvokeApplication(event.getFacesContext());
92          }
93      }
94  
95      public void afterPhase(PhaseEvent event)
96      {
97          if (PhaseId.RESTORE_VIEW.equals(event.getPhaseId()))
98          {
99              assertConversationState(event.getFacesContext());
100             if (event.getFacesContext().getResponseComplete())
101             {
102                 // we have a redirect ... stop now
103                 return;
104             }
105         }
106 
107         executeInitView(event.getFacesContext());
108     }
109 
110     public PhaseId getPhaseId()
111     {
112         return PhaseId.ANY_PHASE;
113     }
114 
115     protected String getViewId(FacesContext facesContext)
116     {
117         UIViewRoot viewRoot = facesContext.getViewRoot();
118         if (viewRoot == null)
119         {
120             return null;
121         }
122         return viewRoot.getViewId();
123     }
124 
125     /**
126      * invoked multiple times during the lifecycle to ensure the conversation(s)
127      * to the associated viewController are running.
128      *
129      * @param facesContext
130      */
131     protected void assertConversationState(FacesContext facesContext)
132     {
133         ViewControllerManager manager = ViewControllerVariableResolver.getViewControllerManager(facesContext);
134         if (manager == null)
135         {
136             return;
137         }
138 
139         String viewId = getViewId(facesContext);
140         if (viewId == null)
141         {
142             return;
143         }
144 
145         manager.assertConversationState(viewId);
146     }
147 
148     /**
149      * invokes the preRenderView method on your view controller
150      */
151     protected void preRenderResponse(FacesContext facesContext)
152     {
153         ViewControllerManager manager = ViewControllerVariableResolver.getViewControllerManager(facesContext);
154         if (manager == null)
155         {
156             return;
157         }
158 
159         String viewId = getViewId(facesContext);
160         if (viewId == null)
161         {
162             return;
163         }
164 
165         manager.executePreRenderView(viewId);
166     }
167 
168     /**
169      * invokes the initView method on your view controller
170      * @since 1.1
171      */
172     protected void executeInitView(FacesContext facesContext)
173     {
174         postRestoreView(facesContext);
175     }
176 
177     /**
178      * @deprecated overload/use {@link #executeInitView(javax.faces.context.FacesContext)} instead
179      */
180     protected void postRestoreView(FacesContext facesContext)
181     {
182         ViewControllerManager manager = ViewControllerVariableResolver.getViewControllerManager(facesContext);
183         if (manager == null)
184         {
185             return;
186         }
187 
188         String viewId = getViewId(facesContext);
189         if (viewId == null)
190         {
191             return;
192         }
193 
194         ViewControllerPhaseListenerState state = getState(facesContext);
195 
196         if (state.initedViews.contains(viewId))
197         {
198             // already inited
199             return;
200         }
201         state.initedViews.add(viewId);
202 
203         manager.executeInitView(viewId);
204     }
205 
206     protected ViewControllerPhaseListenerState getState(FacesContext facesContext)
207     {
208         ViewControllerPhaseListenerState state = (ViewControllerPhaseListenerState)
209             facesContext.getExternalContext().getRequestMap()
210                 .get(ViewControllerPhaseListenerState.class.getName());
211         if (state == null)
212         {
213             state = new ViewControllerPhaseListenerState();
214             facesContext.getExternalContext().getRequestMap().put(
215                 ViewControllerPhaseListenerState.class.getName(), state);
216         }
217         return state;
218     }
219 
220     /**
221      * invokes the preProcess method on your view controller
222      */
223     protected void preInvokeApplication(FacesContext facesContext)
224     {
225         ViewControllerManager manager = ViewControllerVariableResolver.getViewControllerManager(facesContext);
226         if (manager == null)
227         {
228             return;
229         }
230 
231         String viewId = getViewId(facesContext);
232         if (viewId == null)
233         {
234             return;
235         }
236 
237         manager.executePreProcess(viewId);
238     }
239 }