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 }