001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.jsf.el; 018 019import java.beans.FeatureDescriptor; 020import java.util.Iterator; 021import javax.el.ELContext; 022import javax.el.ELException; 023import javax.el.ELResolver; 024import javax.faces.context.FacesContext; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028 029import org.springframework.beans.BeansException; 030import org.springframework.web.context.WebApplicationContext; 031import org.springframework.web.jsf.FacesContextUtils; 032 033/** 034 * Special JSF {@code ELResolver} that exposes the Spring {@code WebApplicationContext} 035 * instance under a variable named "webApplicationContext". 036 * 037 * <p>In contrast to {@link SpringBeanFacesELResolver}, this ELResolver variant 038 * does <i>not</i> resolve JSF variable names as Spring bean names. It rather 039 * exposes Spring's root WebApplicationContext <i>itself</i> under a special name, 040 * and is able to resolve "webApplicationContext.mySpringManagedBusinessObject" 041 * dereferences to Spring-defined beans in that application context. 042 * 043 * <p>Configure this resolver in your {@code faces-config.xml} file as follows: 044 * 045 * <pre class="code"> 046 * <application> 047 * ... 048 * <el-resolver>org.springframework.web.jsf.el.WebApplicationContextFacesELResolver</el-resolver> 049 * </application></pre> 050 * 051 * @author Juergen Hoeller 052 * @since 2.5 053 * @see SpringBeanFacesELResolver 054 * @see org.springframework.web.jsf.FacesContextUtils#getWebApplicationContext 055 */ 056public class WebApplicationContextFacesELResolver extends ELResolver { 057 058 /** 059 * Name of the exposed WebApplicationContext variable: "webApplicationContext". 060 */ 061 public static final String WEB_APPLICATION_CONTEXT_VARIABLE_NAME = "webApplicationContext"; 062 063 064 /** Logger available to subclasses */ 065 protected final Log logger = LogFactory.getLog(getClass()); 066 067 068 @Override 069 public Object getValue(ELContext elContext, Object base, Object property) throws ELException { 070 if (base != null) { 071 if (base instanceof WebApplicationContext) { 072 WebApplicationContext wac = (WebApplicationContext) base; 073 String beanName = property.toString(); 074 if (logger.isTraceEnabled()) { 075 logger.trace("Attempting to resolve property '" + beanName + "' in root WebApplicationContext"); 076 } 077 if (wac.containsBean(beanName)) { 078 if (logger.isDebugEnabled()) { 079 logger.debug("Successfully resolved property '" + beanName + "' in root WebApplicationContext"); 080 } 081 elContext.setPropertyResolved(true); 082 try { 083 return wac.getBean(beanName); 084 } 085 catch (BeansException ex) { 086 throw new ELException(ex); 087 } 088 } 089 else { 090 // Mimic standard JSF/JSP behavior when base is a Map by returning null. 091 return null; 092 } 093 } 094 } 095 else { 096 if (WEB_APPLICATION_CONTEXT_VARIABLE_NAME.equals(property)) { 097 elContext.setPropertyResolved(true); 098 return getWebApplicationContext(elContext); 099 } 100 } 101 102 return null; 103 } 104 105 @Override 106 public Class<?> getType(ELContext elContext, Object base, Object property) throws ELException { 107 if (base != null) { 108 if (base instanceof WebApplicationContext) { 109 WebApplicationContext wac = (WebApplicationContext) base; 110 String beanName = property.toString(); 111 if (logger.isDebugEnabled()) { 112 logger.debug("Attempting to resolve property '" + beanName + "' in root WebApplicationContext"); 113 } 114 if (wac.containsBean(beanName)) { 115 if (logger.isDebugEnabled()) { 116 logger.debug("Successfully resolved property '" + beanName + "' in root WebApplicationContext"); 117 } 118 elContext.setPropertyResolved(true); 119 try { 120 return wac.getType(beanName); 121 } 122 catch (BeansException ex) { 123 throw new ELException(ex); 124 } 125 } 126 else { 127 // Mimic standard JSF/JSP behavior when base is a Map by returning null. 128 return null; 129 } 130 } 131 } 132 else { 133 if (WEB_APPLICATION_CONTEXT_VARIABLE_NAME.equals(property)) { 134 elContext.setPropertyResolved(true); 135 return WebApplicationContext.class; 136 } 137 } 138 139 return null; 140 } 141 142 @Override 143 public void setValue(ELContext elContext, Object base, Object property, Object value) throws ELException { 144 } 145 146 @Override 147 public boolean isReadOnly(ELContext elContext, Object base, Object property) throws ELException { 148 if (base instanceof WebApplicationContext) { 149 elContext.setPropertyResolved(true); 150 return true; 151 } 152 return false; 153 } 154 155 @Override 156 public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext elContext, Object base) { 157 return null; 158 } 159 160 @Override 161 public Class<?> getCommonPropertyType(ELContext elContext, Object base) { 162 return Object.class; 163 } 164 165 166 /** 167 * Retrieve the {@link WebApplicationContext} reference to expose. 168 * <p>The default implementation delegates to {@link FacesContextUtils}, 169 * returning {@code null} if no {@code WebApplicationContext} found. 170 * @param elContext the current JSF ELContext 171 * @return the Spring web application context 172 * @see org.springframework.web.jsf.FacesContextUtils#getWebApplicationContext 173 */ 174 protected WebApplicationContext getWebApplicationContext(ELContext elContext) { 175 FacesContext facesContext = FacesContext.getCurrentInstance(); 176 return FacesContextUtils.getRequiredWebApplicationContext(facesContext); 177 } 178 179}