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