1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.el.unified.resolver;
20
21 import org.apache.myfaces.config.ManagedBeanBuilder;
22 import org.apache.myfaces.config.RuntimeConfig;
23 import org.apache.myfaces.config.element.ManagedBean;
24 import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
25
26 import javax.el.ELContext;
27 import javax.el.ELException;
28 import javax.el.ELResolver;
29 import javax.el.PropertyNotFoundException;
30 import javax.el.PropertyNotWritableException;
31 import javax.faces.FacesException;
32 import javax.faces.application.ProjectStage;
33 import javax.faces.component.UIViewRoot;
34 import javax.faces.context.ExternalContext;
35 import javax.faces.context.FacesContext;
36 import java.beans.FeatureDescriptor;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.logging.Level;
43 import java.util.logging.Logger;
44
45
46
47
48
49
50 public class ManagedBeanResolver extends ELResolver
51 {
52 private static final Logger log = Logger.getLogger(ManagedBeanResolver.class.getName());
53 private static final String BEANS_UNDER_CONSTRUCTION =
54 "org.apache.myfaces.el.unified.resolver.managedbean.beansUnderConstruction";
55 private static final String CUSTOM_SCOPE_CYCLIC_REFERENCE_DETECTION =
56 "org.apache.myfaces.el.unified.resolver.managedbean.customScopeCyclicReferenceDetection";
57
58
59 protected static final Map<String, Scope> s_standardScopes = new HashMap<String, Scope>(16);
60
61 static
62 {
63 s_standardScopes.put("request", new Scope()
64 {
65 public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
66 {
67 extContext.getRequestMap().put(name, obj);
68 }
69 });
70
71 s_standardScopes.put("session", new Scope()
72 {
73 public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
74 {
75 extContext.getSessionMap().put(name, obj);
76 }
77 });
78
79 s_standardScopes.put("application", new Scope()
80 {
81 public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
82 {
83 extContext.getApplicationMap().put(name, obj);
84 }
85 });
86
87 s_standardScopes.put("none", new Scope()
88 {
89 public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
90 {
91
92 }
93 });
94
95
96 s_standardScopes.put("view", new Scope()
97 {
98 public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
99 {
100 facesContext.getViewRoot().getViewMap().put(name, obj);
101 }
102 });
103 }
104
105
106
107
108
109
110
111
112
113
114
115
116
117 protected final Map<String, Scope> _scopes = new HashMap<String, Scope>(16);
118 {
119 _scopes.putAll(s_standardScopes);
120 }
121
122
123
124
125 private RuntimeConfig runtimeConfig;
126
127 private ManagedBeanBuilder beanBuilder = new ManagedBeanBuilder();
128
129
130 public ManagedBeanResolver()
131 {
132 }
133
134 @Override
135 public void setValue(final ELContext context, final Object base, final Object property, final Object value)
136 throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException
137 {
138
139 if ((base == null) && (property == null))
140 {
141 throw new PropertyNotFoundException();
142 }
143
144 }
145
146 @Override
147 public boolean isReadOnly(final ELContext context, final Object base, final Object property)
148 throws NullPointerException, PropertyNotFoundException, ELException
149 {
150
151 if ((base == null) && (property == null))
152 {
153 throw new PropertyNotFoundException();
154 }
155
156 return false;
157 }
158
159 @Override
160 @SuppressWarnings("unchecked")
161 public Object getValue(final ELContext context, final Object base, final Object property)
162 throws NullPointerException, PropertyNotFoundException, ELException
163 {
164
165 if (base != null)
166 {
167 return null;
168 }
169
170 if (property == null)
171 {
172 throw new PropertyNotFoundException();
173 }
174
175 final FacesContext facesContext = facesContext(context);
176 if (facesContext == null)
177 {
178 return null;
179 }
180 final ExternalContext extContext = facesContext.getExternalContext();
181 if (extContext == null)
182 {
183 return null;
184 }
185
186 final boolean startup = (extContext instanceof StartupServletExternalContextImpl);
187
188
189 if (!startup)
190 {
191 if (extContext.getRequestMap().containsKey(property))
192 {
193 return null;
194 }
195 }
196
197
198 UIViewRoot root = facesContext.getViewRoot();
199 if (root != null)
200 {
201 Map<String, Object> viewMap = root.getViewMap(false);
202 if (viewMap != null && viewMap.containsKey(property))
203 {
204 return null;
205 }
206 }
207
208
209 if (!startup)
210 {
211 if (extContext.getSessionMap().containsKey(property))
212 {
213 return null;
214 }
215 }
216
217
218 if (extContext.getApplicationMap().containsKey(property))
219 {
220 return null;
221 }
222
223
224
225 if (!(property instanceof String))
226 {
227 return null;
228 }
229 final String strProperty = (String) property;
230
231 final ManagedBean managedBean = runtimeConfig(context).getManagedBean(strProperty);
232 Object beanInstance = null;
233 if (managedBean != null)
234 {
235 context.setPropertyResolved(true);
236
237
238 if (managedBean.isManagedBeanScopeValueExpression())
239 {
240
241 boolean checkCyclicReferences = !facesContext.isProjectStage(ProjectStage.Production);
242 List<String> cyclicReferences = null;
243
244 if (checkCyclicReferences)
245 {
246 final Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
247 final String managedBeanName = managedBean.getManagedBeanName();
248
249 cyclicReferences = (List<String>) requestMap.get(CUSTOM_SCOPE_CYCLIC_REFERENCE_DETECTION);
250 if (cyclicReferences == null)
251 {
252 cyclicReferences = new ArrayList<String>();
253 requestMap.put(CUSTOM_SCOPE_CYCLIC_REFERENCE_DETECTION, cyclicReferences);
254 }
255 else if (cyclicReferences.contains(managedBeanName))
256 {
257 throw new ELException("Detected cyclic reference to managedBean " + managedBeanName);
258 }
259
260 cyclicReferences.add(managedBeanName);
261 }
262 try
263 {
264 Object customScope = managedBean.getManagedBeanScopeValueExpression(facesContext)
265 .getValue(facesContext.getELContext());
266 if (customScope instanceof Map)
267 {
268 beanInstance = ((Map) customScope).get(managedBean.getManagedBeanName());
269 }
270 else if (customScope != null)
271 {
272 throw new FacesException("The expression '" + managedBean.getManagedBeanScope() +
273 "' does not evaluate to java.util.Map. It evaluates to '" + customScope +
274 "' of type " + customScope.getClass().getName());
275 }
276 else
277 {
278 log.warning("Custom scope '" + managedBean.getManagedBeanScope() +
279 "' evaluated to null. Unable to determine if managed bean '" +
280 managedBean.getManagedBeanName() + "' exists.");
281 }
282 }
283 finally
284 {
285 if (checkCyclicReferences)
286 {
287 cyclicReferences.remove(managedBean.getManagedBeanName());
288 }
289 }
290 }
291
292
293 if (beanInstance == null)
294 {
295 beanInstance = createManagedBean(managedBean, facesContext);
296 }
297 }
298
299 return beanInstance;
300 }
301
302
303
304
305
306
307 @SuppressWarnings("unchecked")
308 private Object createManagedBean(final ManagedBean managedBean, final FacesContext facesContext) throws ELException
309 {
310
311 final ExternalContext extContext = facesContext.getExternalContext();
312 final Map<Object, Object> facesContextMap = facesContext.getAttributes();
313 final String managedBeanName = managedBean.getManagedBeanName();
314
315
316 List<String> beansUnderConstruction = (List<String>) facesContextMap.get(BEANS_UNDER_CONSTRUCTION);
317 if (beansUnderConstruction == null)
318 {
319 beansUnderConstruction = new ArrayList<String>();
320 facesContextMap.put(BEANS_UNDER_CONSTRUCTION, beansUnderConstruction);
321 }
322 else if (beansUnderConstruction.contains(managedBeanName))
323 {
324 throw new ELException("Detected cyclic reference to managedBean " + managedBeanName);
325 }
326
327 beansUnderConstruction.add(managedBeanName);
328
329 Object obj = null;
330 try
331 {
332 obj = beanBuilder.buildManagedBean(facesContext, managedBean);
333 }
334 finally
335 {
336 beansUnderConstruction.remove(managedBeanName);
337 }
338
339 putInScope(managedBean, facesContext, extContext, obj);
340
341 return obj;
342 }
343
344 @SuppressWarnings("unchecked")
345 private void putInScope(final ManagedBean managedBean, final FacesContext facesContext,
346 final ExternalContext extContext, final Object obj)
347 {
348
349 final String managedBeanName = managedBean.getManagedBeanName();
350
351 if (obj == null)
352 {
353 if (log.isLoggable(Level.FINE))
354 log.fine("Variable '" + managedBeanName + "' could not be resolved.");
355 }
356 else
357 {
358 final String scopeKey = managedBean.getManagedBeanScope();
359
360
361 final Scope scope = _scopes.get(scopeKey);
362 if (scope != null)
363 {
364 scope.put(facesContext, extContext, managedBeanName, obj);
365 }
366 else if (managedBean.isManagedBeanScopeValueExpression())
367 {
368
369
370
371 Object customScope = managedBean.getManagedBeanScopeValueExpression(facesContext)
372 .getValue(facesContext.getELContext());
373
374 if (customScope instanceof Map)
375 {
376 ((Map) customScope).put(managedBeanName, obj);
377 }
378 else if (customScope != null)
379 {
380 throw new FacesException("The expression '" + scopeKey + "' does not evaluate to " +
381 "java.util.Map. It evaluates to '" + customScope + "' of type " +
382 customScope.getClass().getName());
383 }
384 else
385 {
386 log.warning("Custom scope '" + scopeKey + "' evaluated to null. " +
387 "Cannot store managed bean '" + managedBeanName + "' in custom scope.");
388 }
389 }
390 else
391 {
392 log.severe("Managed bean '" + managedBeanName + "' has illegal scope: " + scopeKey);
393 }
394 }
395
396 }
397
398
399 private static FacesContext facesContext(final ELContext context)
400 {
401 return (FacesContext)context.getContext(FacesContext.class);
402 }
403
404 @Override
405 public Class<?> getType(final ELContext context, final Object base, final Object property)
406 throws NullPointerException, PropertyNotFoundException, ELException
407 {
408
409 if ((base == null) && (property == null))
410 {
411 throw new PropertyNotFoundException();
412 }
413
414 return null;
415 }
416
417 @Override
418 public Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext context, final Object base)
419 {
420
421 if (base != null)
422 return null;
423
424 final ArrayList<FeatureDescriptor> descriptors = new ArrayList<FeatureDescriptor>();
425
426 final Map<String, ManagedBean> managedBeans = runtimeConfig(context).getManagedBeans();
427 for (Map.Entry<String, ManagedBean> managedBean : managedBeans.entrySet())
428 {
429 descriptors.add(makeDescriptor(managedBean.getKey(), managedBean.getValue()));
430 }
431
432 return descriptors.iterator();
433 }
434
435 private static FeatureDescriptor makeDescriptor(final String beanName, final ManagedBean managedBean)
436 {
437 final FeatureDescriptor fd = new FeatureDescriptor();
438 fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE);
439 fd.setValue(ELResolver.TYPE, managedBean.getManagedBeanClass());
440 fd.setName(beanName);
441 fd.setDisplayName(beanName);
442 fd.setShortDescription(managedBean.getDescription());
443 fd.setExpert(false);
444 fd.setHidden(false);
445 fd.setPreferred(true);
446 return fd;
447 }
448
449 protected RuntimeConfig runtimeConfig(final ELContext context)
450 {
451 final FacesContext facesContext = facesContext(context);
452
453
454 if (this.runtimeConfig == null)
455 {
456 this.runtimeConfig = RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
457 }
458
459 return runtimeConfig;
460 }
461
462 @Override
463 public Class<?> getCommonPropertyType(final ELContext context, final Object base)
464 {
465 if (base == null)
466 {
467 return Object.class;
468 }
469
470 return null;
471 }
472
473 interface Scope
474 {
475 public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj);
476 }
477 }