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: bommel $)
47   * @version $Revision: 922201 $ $Date: 2010-03-12 05:36:39 -0500 (Fri, 12 Mar 2010) $
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          if (log.isDebugEnabled())
84          {
85              log.debug("getFacesContext: running inner constructor");
86          }
87  
88          _facesContext = facesContext;
89  
90          if (install)
91          {
92              FacesContext.setCurrentInstance(this);
93          }
94  
95          externalContextDelegate = new PortletExternalContextWrapper(
96                  _facesContext.getExternalContext());
97  
98          _handlers = fhandlers;
99          _nextToken = fnextToken;
100         contextLockHandler = fcontextLockHandler;
101         if (finit)
102         {
103             ListIterator i = fhandlers.listIterator();
104             try
105             {
106                 contextLockHandler.init(facesContext);
107                 while (i.hasNext())
108                 {
109                     RequestHandler h = (RequestHandler) i.next();
110 
111                     if (log.isDebugEnabled())
112                     {
113                         log.debug("Running inithandler of type "
114                                 + h.getClass().getName());
115                     }
116 
117                     h.init(facesContext);
118                 }
119             }
120             catch (RuntimeException e)
121             {
122                 log.error("Problem initialising RequestHandler", e);
123                 _release(i);
124                 contextLockHandler.deinit();
125                 throw e;
126             }
127         }
128         else
129         {
130             try
131             {
132                 contextLockHandler.init(facesContext);
133             }
134             catch (RuntimeException e)
135             {
136                 contextLockHandler.deinit();
137             }
138 
139             RequestType type = ExternalContextUtils.getRequestType(facesContext
140                     .getExternalContext());
141 
142             if (RequestType.RENDER.equals(type))
143             {
144                 String handlersKey = (String) fnextToken;
145                 FrameworkAdapter adapter = (FrameworkAdapter) getExternalContext()
146                         .getApplicationMap().remove(
147                                 REQUEST_ADAPTER + handlersKey);
148                 if (FrameworkAdapter.getCurrentInstance() == null)
149                 {
150                     FrameworkAdapter.setCurrentInstance(adapter);
151                 }
152             }
153         }
154     }
155 
156     //~ Non-Final Methods -----------------------------------------------------
157 
158     public void release()
159     {
160         if (log.isDebugEnabled())
161         {
162             log.debug("Running release");
163         }
164         RequestType type = ExternalContextUtils
165                 .getRequestType(getExternalContext());
166         if (RequestType.RENDER.equals(type) || 
167             RequestType.EVENT.equals(type) || 
168             RequestType.RESOURCE.equals(type) || 
169             this.getResponseComplete())
170         {
171             ListIterator i = _handlers.listIterator();
172             while (i.hasNext())
173             {
174                 i.next();
175             }
176             _release(i);
177         }
178         if (RequestType.ACTION.equals(type))
179         {
180             if (this.getResponseComplete())
181             {
182                 // If response is complete by some reason, we need to
183                 // clean request handlers from application map. This is set
184                 // before an instance of this class is created.
185                 getExternalContext().getApplicationMap().remove(
186                         PortletOrchestraFacesContextFactory.REQUEST_HANDLERS+_nextToken);
187             }
188             else
189             {
190                 //Pass the current FrameworkAdapter through application map,
191                 //to remove it later when rendering 
192                 FrameworkAdapter adapter = FrameworkAdapter.getCurrentInstance();
193                 getExternalContext().getApplicationMap().put(
194                         REQUEST_ADAPTER + _nextToken, adapter);
195                 
196                 //Orchestra suppose the same thread handles the current request, but
197                 //in portlets this is not necessary true. One thread could handle action
198                 //requests and other render request. To keep code working we set it to
199                 //null here, so other request don't mix it.
200                 FrameworkAdapter.setCurrentInstance(null);
201             }
202         }
203 
204         try
205         {
206             //Since in portlets the same thread does not handler both action and
207             //render phase for the same request contextLockHandler needs to
208             //be cleared and lock again
209             contextLockHandler.deinit();
210         }
211         catch (Exception e)
212         {
213             log.error("Problem deinitialising RequestHandler", e);
214         }
215         if (log.isDebugEnabled())
216         {
217             log.debug("Release completed");
218         }
219         _facesContext.release();
220     }
221 
222     private void _release(ListIterator i)
223     {
224         while (i.hasPrevious())
225         {
226             try
227             {
228                 RequestHandler h = (RequestHandler) i.previous();
229                 if (log.isDebugEnabled())
230                 {
231                     log.debug("Running deinithandler of type "
232                             + h.getClass().getName());
233                 }
234                 h.deinit();
235             }
236             catch (Exception e)
237             {
238                 log.error("Problem deinitialising RequestHandler", e);
239             }
240         }
241     }
242 
243     //~ Final Methods ---------------------------------------------------------
244 
245     public final Application getApplication()
246     {
247         return _facesContext.getApplication();
248     }
249 
250     public final Iterator getClientIdsWithMessages()
251     {
252         return _facesContext.getClientIdsWithMessages();
253     }
254 
255     public ExternalContext getExternalContext()
256     {
257         return externalContextDelegate == null ? _facesContext
258                 .getExternalContext() : externalContextDelegate;
259     }
260 
261     public final FacesMessage.Severity getMaximumSeverity()
262     {
263         return _facesContext.getMaximumSeverity();
264     }
265 
266     public final Iterator getMessages()
267     {
268         return _facesContext.getMessages();
269     }
270 
271     public final Iterator getMessages(String clientId)
272     {
273         return _facesContext.getMessages(clientId);
274     }
275 
276     public final RenderKit getRenderKit()
277     {
278         return _facesContext.getRenderKit();
279     }
280 
281     public final boolean getRenderResponse()
282     {
283         return _facesContext.getRenderResponse();
284     }
285 
286     public final boolean getResponseComplete()
287     {
288         return _facesContext.getResponseComplete();
289     }
290 
291     public final void setResponseStream(ResponseStream responsestream)
292     {
293         _facesContext.setResponseStream(responsestream);
294     }
295 
296     public final ResponseStream getResponseStream()
297     {
298         return _facesContext.getResponseStream();
299     }
300 
301     public final void setResponseWriter(ResponseWriter responsewriter)
302     {
303         _facesContext.setResponseWriter(responsewriter);
304     }
305 
306     public final ResponseWriter getResponseWriter()
307     {
308         return _facesContext.getResponseWriter();
309     }
310 
311     public final void setViewRoot(UIViewRoot viewRoot)
312     {
313         _facesContext.setViewRoot(viewRoot);
314     }
315 
316     public final UIViewRoot getViewRoot()
317     {
318         return _facesContext.getViewRoot();
319     }
320 
321     public final void addMessage(String clientId, FacesMessage message)
322     {
323         _facesContext.addMessage(clientId, message);
324     }
325 
326     public final void renderResponse()
327     {
328         _facesContext.renderResponse();
329     }
330 
331     public final void responseComplete()
332     {
333         _facesContext.responseComplete();
334     }
335 
336     public final ELContext getELContext()
337     {
338         // Here, we cannot call getELContext on FacesContext as it does not
339         // exist for JSF1.1; the solution is to use reflection instead. This
340         // method will never be called unless we are in a JSF1.2 environment
341         // so the target method will always exist when this is called.
342         try
343         {
344             if (methodGetELContext == null)
345             {
346                 // Performance optimisation: find method, and cache it for later.
347                 methodGetELContext = FacesContext.class.getDeclaredMethod(
348                         "getELContext", (Class[]) null);
349             }
350             return (ELContext) methodGetELContext.invoke(_facesContext,
351                     (Object[]) null);
352         }
353         catch (NoSuchMethodException e)
354         {
355             // should never happen
356             Log log = LogFactory.getLog(this.getClass());
357             log.error("JSF1.2 method invoked in non-JSF-1.2 environment", e);
358             throw new IllegalStateException(
359                     "JSF1.2 method invoked in non-JSF-1.2 environment");
360         }
361         catch (InvocationTargetException e)
362         {
363             // should never happen
364             Log log = LogFactory.getLog(this.getClass());
365             log.error(
366                     "Method getELContext on wrapped instance threw exception",
367                     e);
368             throw new IllegalStateException(
369                     "Method getELContext on wrapped instance threw exception");
370         }
371         catch (IllegalAccessException e)
372         {
373             // should never happen
374             Log log = LogFactory.getLog(this.getClass());
375             log
376                     .error(
377                             "Method getElContext on wrapped instance is not accessable",
378                             e);
379             throw new IllegalStateException(
380                     "Method getElContext on wrapped instance is not accessable");
381         }
382     }
383 }