001: /*
002: * Copyright 2006 The Apache Software Foundation.
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: * http://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:
017: package org.apache.myfaces.el.unified.resolver;
018:
019: import java.beans.FeatureDescriptor;
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import javax.el.ELContext;
026: import javax.el.ELException;
027: import javax.el.ELResolver;
028: import javax.el.PropertyNotFoundException;
029: import javax.el.PropertyNotWritableException;
030: import javax.faces.context.ExternalContext;
031: import javax.faces.context.FacesContext;
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.apache.myfaces.config.ManagedBeanBuilder;
035: import org.apache.myfaces.config.RuntimeConfig;
036: import org.apache.myfaces.config.element.ManagedBean;
037:
038: /**
039: * See JSF 1.2 spec section 5.6.1.2
040: *
041: * @author Stan Silvert
042: */
043: public class ManagedBeanResolver extends ELResolver {
044: private static final Log log = LogFactory
045: .getLog(ManagedBeanResolver.class);
046: private static final String BEANS_UNDER_CONSTRUCTION = "org.apache.myfaces.el.unified.resolver.managedbean.beansUnderConstruction";
047:
048: // adapted from Manfred's JSF 1.1 VariableResolverImpl
049: protected static final Map s_standardScopes = new HashMap(16);
050: static {
051: s_standardScopes.put("request", new Scope() {
052: public void put(ExternalContext extContext, String name,
053: Object obj) {
054: extContext.getRequestMap().put(name, obj);
055: }
056: });
057: s_standardScopes.put("session", new Scope() {
058: public void put(ExternalContext extContext, String name,
059: Object obj) {
060: extContext.getSessionMap().put(name, obj);
061: }
062: });
063: s_standardScopes.put("application", new Scope() {
064: public void put(ExternalContext extContext, String name,
065: Object obj) {
066: extContext.getApplicationMap().put(name, obj);
067: }
068: });
069: s_standardScopes.put("none", new Scope() {
070: public void put(ExternalContext extContext, String name,
071: Object obj) {
072: // do nothing
073: }
074: });
075: }
076:
077: /**
078: * Stores all scopes defined for this instance of <code>VariableResolver</code>
079: * <p>
080: * Can store instances of <code>Scope</code> which have the ability to
081: * dynamically resolve against ExternalContext for put operations.
082: * </p>
083: * <p>
084: * WARNING: this implementation is not serialized as it is thread safe because
085: * it does not update/add to _scopes after object initialization.
086: * If you need to add your own scopes, either extend and add more
087: * in an initialization block, or add proper sychronization
088: * </p>
089: */
090: protected final Map _scopes = new HashMap(16);
091: {
092: _scopes.putAll(s_standardScopes);
093: }
094:
095: /**
096: * RuntimeConfig is instantiated once per servlet and never changes--we can
097: * safely cache it
098: */
099: private RuntimeConfig runtimeConfig;
100:
101: private ManagedBeanBuilder beanBuilder = new ManagedBeanBuilder();
102:
103: /** Creates a new instance of ManagedBeanResolver */
104: public ManagedBeanResolver() {
105: }
106:
107: public void setValue(ELContext context, Object base,
108: Object property, Object value) throws NullPointerException,
109: PropertyNotFoundException, PropertyNotWritableException,
110: ELException {
111:
112: if ((base == null) && (property == null)) {
113: throw new PropertyNotFoundException();
114: }
115:
116: }
117:
118: public boolean isReadOnly(ELContext context, Object base,
119: Object property) throws NullPointerException,
120: PropertyNotFoundException, ELException {
121:
122: if ((base == null) && (property == null)) {
123: throw new PropertyNotFoundException();
124: }
125:
126: return false;
127: }
128:
129: public Object getValue(ELContext context, Object base,
130: Object property) throws NullPointerException,
131: PropertyNotFoundException, ELException {
132:
133: if (base != null)
134: return null;
135:
136: if (property == null) {
137: throw new PropertyNotFoundException();
138: }
139:
140: ExternalContext extContext = externalContext(context);
141:
142: if (extContext == null)
143: return null;
144: if (extContext.getRequestMap().containsKey(property))
145: return null;
146: if (extContext.getSessionMap().containsKey(property))
147: return null;
148: if (extContext.getApplicationMap().containsKey(property))
149: return null;
150:
151: if (!(property instanceof String))
152: return null;
153:
154: String strProperty = (String) property;
155:
156: ManagedBean managedBean = runtimeConfig(context)
157: .getManagedBean(strProperty);
158: Object beanInstance = null;
159: if (managedBean != null) {
160: FacesContext facesContext = facesContext(context);
161: context.setPropertyResolved(true);
162: beanInstance = createManagedBean(managedBean, facesContext);
163: }
164:
165: return beanInstance;
166: }
167:
168: // Create a managed bean. If the scope of the bean is "none" then
169: // return it right away. Otherwise store the bean in the appropriate
170: // scope and return null.
171: //
172: // adapted from Manfred's JSF 1.1 VariableResolverImpl
173: private Object createManagedBean(ManagedBean managedBean,
174: FacesContext facesContext) throws ELException {
175:
176: ExternalContext extContext = facesContext.getExternalContext();
177: Map requestMap = extContext.getRequestMap();
178:
179: // check for cyclic references
180: List beansUnderConstruction = (List) requestMap
181: .get(BEANS_UNDER_CONSTRUCTION);
182: if (beansUnderConstruction == null) {
183: beansUnderConstruction = new ArrayList();
184: requestMap.put(BEANS_UNDER_CONSTRUCTION,
185: beansUnderConstruction);
186: }
187:
188: String managedBeanName = managedBean.getManagedBeanName();
189: if (beansUnderConstruction.contains(managedBeanName)) {
190: throw new ELException(
191: "Detected cyclic reference to managedBean "
192: + managedBeanName);
193: }
194:
195: beansUnderConstruction.add(managedBeanName);
196:
197: Object obj = null;
198: try {
199: obj = beanBuilder.buildManagedBean(facesContext,
200: managedBean);
201: } finally {
202: beansUnderConstruction.remove(managedBeanName);
203: }
204:
205: putInScope(managedBean, extContext, obj);
206:
207: return obj;
208: }
209:
210: private void putInScope(ManagedBean managedBean,
211: ExternalContext extContext, Object obj) {
212:
213: final String managedBeanName = managedBean.getManagedBeanName();
214:
215: if (obj == null) {
216: if (log.isDebugEnabled())
217: log.debug("Variable '" + managedBeanName
218: + "' could not be resolved.");
219: } else {
220:
221: String scopeKey = managedBean.getManagedBeanScope();
222:
223: // find the scope handler object
224: Scope scope = (Scope) _scopes.get(scopeKey);
225: if (scope == null) {
226: log.error("Managed bean '" + managedBeanName
227: + "' has illegal scope: " + scopeKey);
228: } else {
229: scope.put(extContext, managedBeanName, obj);
230: }
231: }
232:
233: }
234:
235: // get the FacesContext from the ELContext
236: private FacesContext facesContext(ELContext context) {
237: return (FacesContext) context.getContext(FacesContext.class);
238: }
239:
240: private ExternalContext externalContext(ELContext context) {
241: FacesContext facesContext = facesContext(context);
242:
243: return facesContext != null ? facesContext.getExternalContext()
244: : null;
245: }
246:
247: public Class<?> getType(ELContext context, Object base,
248: Object property) throws NullPointerException,
249: PropertyNotFoundException, ELException {
250:
251: if ((base == null) && (property == null)) {
252: throw new PropertyNotFoundException();
253: }
254:
255: return null;
256: }
257:
258: public Iterator getFeatureDescriptors(ELContext context, Object base) {
259:
260: if (base != null)
261: return null;
262:
263: ArrayList<FeatureDescriptor> descriptors = new ArrayList<FeatureDescriptor>();
264:
265: Map<String, ManagedBean> managedBeans = runtimeConfig(context)
266: .getManagedBeans();
267: for (String beanName : managedBeans.keySet()) {
268: descriptors.add(makeDescriptor(beanName, managedBeans
269: .get(beanName)));
270: }
271:
272: return descriptors.iterator();
273: }
274:
275: private FeatureDescriptor makeDescriptor(String beanName,
276: ManagedBean managedBean) {
277: FeatureDescriptor fd = new FeatureDescriptor();
278: fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE);
279: fd.setValue(ELResolver.TYPE, managedBean.getManagedBeanClass());
280: fd.setName(beanName);
281: fd.setDisplayName(beanName);
282: fd.setShortDescription(managedBean.getDescription());
283: fd.setExpert(false);
284: fd.setHidden(false);
285: fd.setPreferred(true);
286: return fd;
287: }
288:
289: protected RuntimeConfig runtimeConfig(ELContext context) {
290: FacesContext facesContext = facesContext(context);
291:
292: // application-level singleton - we can safely cache this
293: if (this .runtimeConfig == null) {
294: this .runtimeConfig = RuntimeConfig
295: .getCurrentInstance(facesContext
296: .getExternalContext());
297: }
298:
299: return runtimeConfig;
300: }
301:
302: public Class<?> getCommonPropertyType(ELContext context, Object base) {
303:
304: if (base != null)
305: return null;
306:
307: return Object.class;
308: }
309:
310: interface Scope {
311: public void put(ExternalContext extContext, String name,
312: Object obj);
313: }
314:
315: }
|