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
    25  import javax.el.ELContext;
    26  import javax.faces.application.Application;
    27  import javax.faces.application.FacesMessage;
    28  import javax.faces.component.UIViewRoot;
    29  import javax.faces.context.ExternalContext;
    30  import javax.faces.context.FacesContext;
    31  import javax.faces.context.ResponseStream;
    32  import javax.faces.context.ResponseWriter;
    33  import javax.faces.render.RenderKit;
    34
    35  import org.apache.commons.logging.Log;
    36  import org.apache.commons.logging.LogFactory;
    37
    38
    39  /**
    40   * Convenient class to wrap the current FacesContext.
    41   * <p>
    42   * A class of this name is provided in JSF1.2, but not in JSF1.1.
    43   * <p>
    44   * Any methods that do not actually need to be overridden are declared final
    45   * in order to improve performance (helps the JVM to optimise away the call).
    46   * <p>
    47   * Note that whether a newly-created instance immediately becomes the
    48   * object that is returned by FacesContext.getCurrentInstance() depends
    49   * upon the value of the "install" parameter for the constructor method.
    50   * <p>
    51   * This class is copied from the code in MyFaces Core Impl 1.2.x, but
    52   * modified to be compatible with JSF1.1.
    53   * <p>
    54   * Note that this class must be public in order to support custom
    55   * FacesContextFactory classes in other libraries that also wrap this
    56   * instance, then use reflection to invoke methods on this object. In
    57   * this case, an IllegalAccessException would occur if this class was
    58   * package-scoped. However this class is NOT intended to be part of the
    59   * public Orchestra API, and may change at any time.
    60   *
    61   * @since 1.1
    62   *
    63   * @author Manfred Geiler (latest modification by $Author: skitching $)
    64   * @author Anton Koinov
    65   * @version $Revision: 672906 $ $Date: 2008-06-30 15:45:16 -0500 (Mon, 30 Jun 2008) $
    66   */
    67  public class _FacesContextWrapper extends FacesContext
    68  {
    69      //~ Instance fields -------------------------------------------------------
    70
    71      private final FacesContext _facesContext;
    72      private Method methodGetELContext = null;
    73
    74      //~ Constructors ----------------------------------------------------------
    75
    76      /**
    77       * The install parameter controls whether this object will be configured as
    78       * the object returned from calls to FacesContext.getCurrentInstance() or not.
    79       * <p>
    80       * When only overriding the release() method, then install=false is ok as that
    81       * is called directly by the FacesServlet on the instance returned by the
    82       * FacesContextFactory. However all other methods are invoked on the object
    83       * that is returned from FacesContext.getCurrentInstance, so install=true is
    84       * needed in order for any other method overrides to have any effect.
    85       * <p>
    86       * <b>IMPORTANT</b>: install=true should not be used until MYFACES-1820 is fixed.
    87       */
    88      public _FacesContextWrapper(FacesContext facesContext, boolean install)
    89      {
    90          _facesContext = facesContext;
    91
    92          if (install)
    93          {
    94              FacesContext.setCurrentInstance(this);
    95          }
    96      }
    97
    98      //~ Non-Final Methods -----------------------------------------------------
    99
    100     public void release()
    101     {
    102         _facesContext.release();
    103     }
    104
    105     //~ Final Methods ---------------------------------------------------------
    106
    107     public final Application getApplication()
    108     {
    109         return _facesContext.getApplication();
    110     }
    111
    112     public final Iterator getClientIdsWithMessages()
    113     {
    114         return _facesContext.getClientIdsWithMessages();
    115     }
    116
    117     public final ExternalContext getExternalContext()
    118     {
    119         return _facesContext.getExternalContext();
    120     }
    121
    122     public final FacesMessage.Severity getMaximumSeverity()
    123     {
    124         return _facesContext.getMaximumSeverity();
    125     }
    126
    127     public final Iterator getMessages()
    128     {
    129         return _facesContext.getMessages();
    130     }
    131
    132     public final Iterator getMessages(String clientId)
    133     {
    134         return _facesContext.getMessages(clientId);
    135     }
    136
    137     public final RenderKit getRenderKit()
    138     {
    139         return _facesContext.getRenderKit();
    140     }
    141
    142     public final boolean getRenderResponse()
    143     {
    144         return _facesContext.getRenderResponse();
    145     }
    146
    147     public final boolean getResponseComplete()
    148     {
    149         return _facesContext.getResponseComplete();
    150     }
    151
    152     public final void setResponseStream(ResponseStream responsestream)
    153     {
    154         _facesContext.setResponseStream(responsestream);
    155     }
    156
    157     public final ResponseStream getResponseStream()
    158     {
    159         return _facesContext.getResponseStream();
    160     }
    161
    162     public final void setResponseWriter(ResponseWriter responsewriter)
    163     {
    164         _facesContext.setResponseWriter(responsewriter);
    165     }
    166
    167     public final ResponseWriter getResponseWriter()
    168     {
    169         return _facesContext.getResponseWriter();
    170     }
    171
    172     public final void setViewRoot(UIViewRoot viewRoot)
    173     {
    174         _facesContext.setViewRoot(viewRoot);
    175     }
    176
    177     public final UIViewRoot getViewRoot()
    178     {
    179         return _facesContext.getViewRoot();
    180     }
    181
    182     public final void addMessage(String clientId, FacesMessage message)
    183     {
    184         _facesContext.addMessage(clientId, message);
    185     }
    186
    187     public final void renderResponse()
    188     {
    189         _facesContext.renderResponse();
    190     }
    191
    192     public final void responseComplete()
    193     {
    194         _facesContext.responseComplete();
    195     }
    196
    197     /**
    198      * Implement getELContext by delegating call to another instance.
    199      * <p>
    200      * Note that this method was added in JSF1.2. In order for a JSF1.2
    201      * implementation to be backwards-compatible with JSF1.1, the base
    202      * class FacesContext therefore has to automatically do the delegation.
    203      * Without automatic delegation, any JSF1.1 class that applies the decorator
    204      * pattern to a FacesContext will just break in JSF1.2; the getELContext
    205      * method is there (inherited from the base class) but does not correctly
    206      * delegate.
    207      * <p>
    208      * Unfortunately, due to a design flaw in JSF1.2 it is simply not possible
    209      * for the base class to delegate; the object to delegate to is not known
    210      * to the base class! A partial solution that works in most cases is for
    211      * the base class to delegate to the "core" instance of FacesContext for
    212      * methods that are not overridden; Sun's RI does this correctly but
    213      * unfortunately MyFaces 1.2.0-1.2.2 do not. See MYFACES-1820 for details.
    214      * <p>
    215      * The solution *here* is to require that a javax.el implementation is in
    216      * the classpath even when running JSF1.1. It is then possible for this
    217      * wrapper to override the method defined in JSF1.2 even when being
    218      * compiled against the JSF1.1 implementation. It is mildly annoying to
    219      * have to include javax.el in a JSF environment (ie when it will never
    220      * be used) but better than the alternatives. Actually, for at least some
    221      * JVMs, classes needed by a method are not loaded unless that method is
    222      * actually referenced, so in some cases (including Sun Java 1.4-1.6) the
    223      * el library *can* be omitted from the classpath with JSF1.1.
    224      */
    225     public final ELContext getELContext()
    226     {
    227         // Here, we cannot call getELContext on FacesContext as it does not
    228         // exist for JSF1.1; the solution is to use reflection instead. This
    229         // method will never be called unless we are in a JSF1.2 environment
    230         // so the target method will always exist when this is called.
    231         try
    232         {
    233             if (methodGetELContext == null)
    234             {
    235                 // Performance optimisation: find method, and cache it for later.
    236                 methodGetELContext = FacesContext.class.getDeclaredMethod("getELContext", (Class[]) null);
    237             }
    238             return (ELContext) methodGetELContext.invoke(_facesContext, (Object[]) null);
    239         }
    240         catch(NoSuchMethodException e)
    241         {
    242             // should never happen
    243             Log log = LogFactory.getLog(this.getClass());
    244             log.error("JSF1.2 method invoked in non-JSF-1.2 environment", e);
    245             throw new IllegalStateException("JSF1.2 method invoked in non-JSF-1.2 environment");
    246         }
    247         catch(InvocationTargetException e)
    248         {
    249             // should never happen
    250             Log log = LogFactory.getLog(this.getClass());
    251             log.error("Method getELContext on wrapped instance threw exception", e);
    252             throw new IllegalStateException("Method getELContext on wrapped instance threw exception");
    253         }
    254         catch(IllegalAccessException e)
    255         {
    256             // should never happen
    257             Log log = LogFactory.getLog(this.getClass());
    258             log.error("Method getElContext on wrapped instance is not accessable", e);
    259             throw new IllegalStateException("Method getElContext on wrapped instance is not accessable");
    260         }
    261     }
    262 }