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 }