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  package org.apache.myfaces.orchestra.lib.jsf;
20  
21  import java.lang.reflect.InvocationTargetException;
22  import java.lang.reflect.Method;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.ListIterator;
26  
27  import javax.el.ELContext;
28  import javax.faces.application.Application;
29  import javax.faces.application.FacesMessage;
30  import javax.faces.component.UIViewRoot;
31  import javax.faces.context.ExternalContext;
32  import javax.faces.context.FacesContext;
33  import javax.faces.context.ResponseStream;
34  import javax.faces.context.ResponseWriter;
35  import javax.faces.render.RenderKit;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.myfaces.orchestra.frameworkAdapter.FrameworkAdapter;
40  
41  /**
42   * Convenient class to wrap the current FacesContext in portlet environment.
43   * 
44   * @since 1.4
45   * 
46   * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
47   * @version $Revision: 798382 $ $Date: 2009-07-27 22:23:02 -0500 (Mon, 27 Jul 2009) $
48   */
49  public class _PortletFacesContextWrapper extends FacesContext
50  {
51      private final static String REQUEST_ADAPTER = "org.apache.myfaces.orchestra.REQUEST_ADAPTER";
52  
53      //~ Instance fields -------------------------------------------------------
54  
55      private final FacesContext _facesContext;
56      private Method methodGetELContext = null;
57      private final ExternalContext externalContextDelegate;
58      private final RequestHandler contextLockHandler;
59      private final List _handlers;
60      private final String _nextToken;
61  
62      private final Log log = LogFactory
63              .getLog(_PortletFacesContextWrapper.class);
64  
65      //~ Constructors ----------------------------------------------------------
66  
67      /**
68       * The install parameter controls whether this object will be configured as
69       * the object returned from calls to FacesContext.getCurrentInstance() or not.
70       * <p>
71       * When only overriding the release() method, then install=false is ok as that
72       * is called directly by the FacesServlet on the instance returned by the
73       * FacesContextFactory. However all other methods are invoked on the object
74       * that is returned from FacesContext.getCurrentInstance, so install=true is
75       * needed in order for any other method overrides to have any effect.
76       * <p>
77       * <b>IMPORTANT</b>: install=true should not be used until MYFACES-1820 is fixed.
78       */
79      public _PortletFacesContextWrapper(final FacesContext facesContext,
80              final boolean install, boolean finit, String fnextToken, List fhandlers,
81              final RequestHandler fcontextLockHandler )
82      {
83          log.debug("getFacesContext: running inner constructor");
84  
85          _facesContext = facesContext;
86  
87          if (install)
88          {
89              FacesContext.setCurrentInstance(this);
90          }
91  
92          externalContextDelegate = new PortletExternalContextWrapper(
93                  _facesContext.getExternalContext());
94  
95          _handlers = fhandlers;
96          _nextToken = fnextToken;
97          contextLockHandler = fcontextLockHandler;
98          if (finit)
99          {
100             ListIterator i = fhandlers.listIterator();
101             try
102             {
103                 contextLockHandler.init(facesContext);
104                 while (i.hasNext())
105                 {
106                     RequestHandler h = (RequestHandler) i.next();
107 
108                     if (log.isDebugEnabled())
109                     {
110                         log.debug("Running inithandler of type "
111                                 + h.getClass().getName());
112                     }
113 
114                     h.init(facesContext);
115                 }
116             }
117             catch (RuntimeException e)
118             {
119                 log.error("Problem initialising RequestHandler", e);
120                 _release(i);
121                 contextLockHandler.deinit();
122                 throw e;
123             }
124         }
125         else
126         {
127             try
128             {
129                 contextLockHandler.init(facesContext);
130             }
131             catch (RuntimeException e)
132             {
133                 contextLockHandler.deinit();
134             }
135 
136             RequestType type = ExternalContextUtils.getRequestType(facesContext
137                     .getExternalContext());
138 
139             if (RequestType.RENDER.equals(type))
140             {
141                 String handlersKey = (String) fnextToken;
142                 FrameworkAdapter adapter = (FrameworkAdapter) getExternalContext()
143                         .getApplicationMap().remove(
144                                 REQUEST_ADAPTER + handlersKey);
145                 if (FrameworkAdapter.getCurrentInstance() == null)
146                 {
147                     FrameworkAdapter.setCurrentInstance(adapter);
148                 }
149             }
150         }
151     }
152 
153     //~ Non-Final Methods -----------------------------------------------------
154 
155     public void release()
156     {
157         log.debug("Running release");
158         RequestType type = ExternalContextUtils
159                 .getRequestType(getExternalContext());
160         if (RequestType.RENDER.equals(type) || 
161             RequestType.EVENT.equals(type) || 
162             RequestType.RESOURCE.equals(type) || 
163             this.getResponseComplete())
164         {
165             ListIterator i = _handlers.listIterator();
166             while (i.hasNext())
167             {
168                 i.next();
169             }
170             _release(i);
171         }
172         if (RequestType.ACTION.equals(type))
173         {
174             if (this.getResponseComplete())
175             {
176                 // If response is complete by some reason, we need to
177                 // clean request handlers from application map. This is set
178                 // before an instance of this class is created.
179                 getExternalContext().getApplicationMap().remove(
180                         PortletOrchestraFacesContextFactory.REQUEST_HANDLERS+_nextToken);
181             }
182             else
183             {
184                 //Pass the current FrameworkAdapter through application map,
185                 //to remove it later when rendering 
186                 FrameworkAdapter adapter = FrameworkAdapter.getCurrentInstance();
187                 getExternalContext().getApplicationMap().put(
188                         REQUEST_ADAPTER + _nextToken, adapter);
189                 
190                 //Orchestra suppose the same thread handles the current request, but
191                 //in portlets this is not necessary true. One thread could handle action
192                 //requests and other render request. To keep code working we set it to
193                 //null here, so other request don't mix it.
194                 FrameworkAdapter.setCurrentInstance(null);
195             }
196         }
197 
198         try
199         {
200             //Since in portlets the same thread does not handler both action and
201             //render phase for the same request contextLockHandler needs to
202             //be cleared and lock again
203             contextLockHandler.deinit();
204         }
205         catch (Exception e)
206         {
207             log.error("Problem deinitialising RequestHandler", e);
208         }
209         log.debug("Release completed");
210         _facesContext.release();
211     }
212 
213     private void _release(ListIterator i)
214     {
215         while (i.hasPrevious())
216         {
217             try
218             {
219                 RequestHandler h = (RequestHandler) i.previous();
220                 if (log.isDebugEnabled())
221                 {
222                     log.debug("Running deinithandler of type "
223                             + h.getClass().getName());
224                 }
225                 h.deinit();
226             }
227             catch (Exception e)
228             {
229                 log.error("Problem deinitialising RequestHandler", e);
230             }
231         }
232     }
233 
234     //~ Final Methods ---------------------------------------------------------
235 
236     public final Application getApplication()
237     {
238         return _facesContext.getApplication();
239     }
240 
241     public final Iterator getClientIdsWithMessages()
242     {
243         return _facesContext.getClientIdsWithMessages();
244     }
245 
246     public ExternalContext getExternalContext()
247     {
248         return externalContextDelegate == null ? _facesContext
249                 .getExternalContext() : externalContextDelegate;
250     }
251 
252     public final FacesMessage.Severity getMaximumSeverity()
253     {
254         return _facesContext.getMaximumSeverity();
255     }
256 
257     public final Iterator getMessages()
258     {
259         return _facesContext.getMessages();
260     }
261 
262     public final Iterator getMessages(String clientId)
263     {
264         return _facesContext.getMessages(clientId);
265     }
266 
267     public final RenderKit getRenderKit()
268     {
269         return _facesContext.getRenderKit();
270     }
271 
272     public final boolean getRenderResponse()
273     {
274         return _facesContext.getRenderResponse();
275     }
276 
277     public final boolean getResponseComplete()
278     {
279         return _facesContext.getResponseComplete();
280     }
281 
282     public final void setResponseStream(ResponseStream responsestream)
283     {
284         _facesContext.setResponseStream(responsestream);
285     }
286 
287     public final ResponseStream getResponseStream()
288     {
289         return _facesContext.getResponseStream();
290     }
291 
292     public final void setResponseWriter(ResponseWriter responsewriter)
293     {
294         _facesContext.setResponseWriter(responsewriter);
295     }
296 
297     public final ResponseWriter getResponseWriter()
298     {
299         return _facesContext.getResponseWriter();
300     }
301 
302     public final void setViewRoot(UIViewRoot viewRoot)
303     {
304         _facesContext.setViewRoot(viewRoot);
305     }
306 
307     public final UIViewRoot getViewRoot()
308     {
309         return _facesContext.getViewRoot();
310     }
311 
312     public final void addMessage(String clientId, FacesMessage message)
313     {
314         _facesContext.addMessage(clientId, message);
315     }
316 
317     public final void renderResponse()
318     {
319         _facesContext.renderResponse();
320     }
321 
322     public final void responseComplete()
323     {
324         _facesContext.responseComplete();
325     }
326 
327     public final ELContext getELContext()
328     {
329         // Here, we cannot call getELContext on FacesContext as it does not
330         // exist for JSF1.1; the solution is to use reflection instead. This
331         // method will never be called unless we are in a JSF1.2 environment
332         // so the target method will always exist when this is called.
333         try
334         {
335             if (methodGetELContext == null)
336             {
337                 // Performance optimisation: find method, and cache it for later.
338                 methodGetELContext = FacesContext.class.getDeclaredMethod(
339                         "getELContext", (Class[]) null);
340             }
341             return (ELContext) methodGetELContext.invoke(_facesContext,
342                     (Object[]) null);
343         }
344         catch (NoSuchMethodException e)
345         {
346             // should never happen
347             Log log = LogFactory.getLog(this.getClass());
348             log.error("JSF1.2 method invoked in non-JSF-1.2 environment", e);
349             throw new IllegalStateException(
350                     "JSF1.2 method invoked in non-JSF-1.2 environment");
351         }
352         catch (InvocationTargetException e)
353         {
354             // should never happen
355             Log log = LogFactory.getLog(this.getClass());
356             log.error(
357                     "Method getELContext on wrapped instance threw exception",
358                     e);
359             throw new IllegalStateException(
360                     "Method getELContext on wrapped instance threw exception");
361         }
362         catch (IllegalAccessException e)
363         {
364             // should never happen
365             Log log = LogFactory.getLog(this.getClass());
366             log
367                     .error(
368                             "Method getElContext on wrapped instance is not accessable",
369                             e);
370             throw new IllegalStateException(
371                     "Method getElContext on wrapped instance is not accessable");
372         }
373     }
374 }