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 }