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 }