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.tobago.internal.lifecycle;
21  
22  import org.apache.myfaces.tobago.util.DebugUtils;
23  import org.apache.myfaces.tobago.util.RequestUtils;
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  import javax.faces.FacesException;
28  import javax.faces.context.FacesContext;
29  import javax.faces.event.PhaseId;
30  import javax.faces.event.PhaseListener;
31  import javax.faces.lifecycle.Lifecycle;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  /**
36   * Implements the lifecycle as described in Spec. 1.0 PFD Chapter 2
37   *
38   * Not longer needed.
39   *
40   * @deprecated since Tobago 2.0.0
41   */
42  @Deprecated
43  public class TobagoLifecycle extends Lifecycle {
44  
45    private static final Logger LOG = LoggerFactory.getLogger(TobagoLifecycle.class);
46  
47    public static final String VIEW_ROOT_KEY = TobagoLifecycle.class.getName() + ".VIEW_ROOT_KEY";
48    public static final String FACES_MESSAGES_KEY = TobagoLifecycle.class.getName() + ".FACES_MESSAGES_KEY";
49  
50    private PhaseExecutor[] lifecycleExecutors;
51    private PhaseExecutor renderExecutor;
52  
53    private final List<PhaseListener> phaseListenerList = new ArrayList<PhaseListener>();
54  
55    /**
56     * Lazy cache for returning phaseListenerList as an Array.
57     */
58    private PhaseListener[] phaseListenerArray = null;
59  
60    public TobagoLifecycle() {
61      // hide from public access
62      lifecycleExecutors = new PhaseExecutor[]{
63          new RestoreViewExecutor(),
64          new ApplyRequestValuesExecutor(),
65          new ProcessValidationsExecutor(),
66          new UpdateModelValuesExecutor(),
67          new InvokeApplicationExecutor()
68      };
69  
70      renderExecutor = new RenderResponseExecutor();
71    }
72  
73    public void execute(FacesContext context) throws FacesException {
74  
75      PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, context, getPhaseListeners());
76  
77      // At very first ensure the requestEncoding, this MUST done before
78      // accessing request parameters, which can occur in custom phaseListeners.
79      RequestUtils.ensureEncoding(context);
80  
81      for (PhaseExecutor executor : lifecycleExecutors) {
82        if (executePhase(context, executor, phaseListenerMgr)) {
83          return;
84        }
85      }
86    }
87  
88    private boolean executePhase(FacesContext facesContext, PhaseExecutor executor, PhaseListenerManager phaseListenerMgr)
89        throws FacesException {
90  
91      boolean skipFurtherProcessing = false;
92      if (LOG.isTraceEnabled()) {
93        LOG.trace("entering " + executor.getPhase() + " in " + TobagoLifecycle.class.getName());
94      }
95  
96      try {
97        phaseListenerMgr.informPhaseListenersBefore(executor.getPhase());
98  
99        if (isResponseComplete(facesContext, executor.getPhase(), true)) {
100         // have to return right away
101         return true;
102       }
103       if (shouldRenderResponse(facesContext, executor.getPhase(), true)) {
104         skipFurtherProcessing = true;
105       }
106 
107       if (executor.execute(facesContext)) {
108         return true;
109       }
110     } finally {
111       phaseListenerMgr.informPhaseListenersAfter(executor.getPhase());
112     }
113 
114 
115     if (isResponseComplete(facesContext, executor.getPhase(), false)
116         || shouldRenderResponse(facesContext, executor.getPhase(), false)) {
117       // since this phase is completed we don't need to return right away even if the response is completed
118       skipFurtherProcessing = true;
119     }
120 
121     if (!skipFurtherProcessing && LOG.isTraceEnabled()) {
122       LOG.trace("exiting " + executor.getPhase() + " in " + TobagoLifecycle.class.getName());
123     }
124 
125     return skipFurtherProcessing;
126   }
127 
128   public void render(FacesContext facesContext) throws FacesException {
129     // if the response is complete we should not be invoking the phase listeners
130     if (isResponseComplete(facesContext, renderExecutor.getPhase(), true)) {
131       return;
132     }
133     if (LOG.isTraceEnabled()) {
134       LOG.trace("entering " + renderExecutor.getPhase() + " in " + TobagoLifecycle.class.getName());
135     }
136 
137     PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, facesContext, getPhaseListeners());
138 
139     try {
140       phaseListenerMgr.informPhaseListenersBefore(renderExecutor.getPhase());
141       // also possible that one of the listeners completed the response
142       if (isResponseComplete(facesContext, renderExecutor.getPhase(), true)) {
143         return;
144       }
145       renderExecutor.execute(facesContext);
146     } finally {
147       phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
148     }
149 
150     if (LOG.isTraceEnabled()) {
151       LOG.trace(DebugUtils.toString(facesContext.getViewRoot(), 0));
152       LOG.trace("exiting " + renderExecutor.getPhase() + " in " + TobagoLifecycle.class.getName());
153     }
154 
155   }
156 
157   private boolean isResponseComplete(FacesContext facesContext, PhaseId phase, boolean before) {
158     boolean flag = false;
159     if (facesContext.getResponseComplete()) {
160       if (LOG.isDebugEnabled()) {
161         LOG.debug("exiting from lifecycle.execute in " + phase
162             + " because getResponseComplete is true from one of the "
163             + (before ? "before" : "after") + " listeners");
164       }
165       flag = true;
166     }
167     return flag;
168   }
169 
170   private boolean shouldRenderResponse(FacesContext facesContext, PhaseId phase, boolean before) {
171     boolean flag = false;
172     if (facesContext.getRenderResponse()) {
173       if (LOG.isDebugEnabled()) {
174         LOG.debug("exiting from lifecycle.execute in " + phase
175             + " because getRenderResponse is true from one of the "
176             + (before ? "before" : "after") + " listeners");
177       }
178       flag = true;
179     }
180     return flag;
181   }
182 
183   public void addPhaseListener(PhaseListener phaseListener) {
184     if (phaseListener == null) {
185       throw new NullPointerException("PhaseListener must not be null.");
186     }
187     synchronized (phaseListenerList) {
188       phaseListenerList.add(phaseListener);
189       phaseListenerArray = null; // reset lazy cache array
190     }
191   }
192 
193   public void removePhaseListener(PhaseListener phaseListener) {
194     if (phaseListener == null) {
195       throw new NullPointerException("PhaseListener must not be null.");
196     }
197     synchronized (phaseListenerList) {
198       phaseListenerList.remove(phaseListener);
199       phaseListenerArray = null; // reset lazy cache array
200     }
201   }
202 
203   public PhaseListener[] getPhaseListeners() {
204     synchronized (phaseListenerList) {
205       // (re)build lazy cache array if necessary
206       if (phaseListenerArray == null) {
207         phaseListenerArray = phaseListenerList.toArray(new PhaseListener[phaseListenerList.size()]);
208       }
209       return phaseListenerArray;
210     }
211   }
212 }