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 }