1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.config;
20
21 import org.apache.commons.beanutils.PropertyUtils;
22 import org.apache.myfaces.config.annotation.LifecycleProvider;
23 import org.apache.myfaces.config.annotation.LifecycleProvider2;
24 import org.apache.myfaces.config.annotation.LifecycleProviderFactory;
25 import org.apache.myfaces.config.element.ListEntries;
26 import org.apache.myfaces.config.element.ListEntry;
27 import org.apache.myfaces.config.element.ManagedBean;
28 import org.apache.myfaces.config.element.ManagedProperty;
29 import org.apache.myfaces.config.element.MapEntries;
30 import org.apache.myfaces.config.element.MapEntry;
31 import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
32 import org.apache.myfaces.shared.util.ClassUtils;
33 import org.apache.myfaces.util.ContainerUtils;
34
35 import javax.el.ELContext;
36 import javax.el.ELException;
37 import javax.el.ELResolver;
38 import javax.el.ExpressionFactory;
39 import javax.el.ValueExpression;
40 import javax.faces.FacesException;
41 import javax.faces.application.Application;
42 import javax.faces.application.ProjectStage;
43 import javax.faces.context.ExternalContext;
44 import javax.faces.context.FacesContext;
45 import javax.naming.NamingException;
46 import java.lang.reflect.Array;
47 import java.lang.reflect.InvocationTargetException;
48 import java.util.ArrayList;
49 import java.util.Comparator;
50 import java.util.HashMap;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.logging.Level;
55 import java.util.logging.Logger;
56
57
58
59
60
61
62
63
64 public class ManagedBeanBuilder
65 {
66
67 private static Logger log = Logger.getLogger(ManagedBeanBuilder.class.getName());
68 private RuntimeConfig _runtimeConfig;
69 public final static String REQUEST = "request";
70 public final static String VIEW = "view";
71 public final static String APPLICATION = "application";
72 public final static String SESSION = "session";
73 public final static String NONE = "none";
74
75
76
77
78
79
80 private final static Comparator<String> SCOPE_COMPARATOR
81 = new Comparator<String>()
82 {
83
84 public int compare(String o1, String o2)
85 {
86 if (o1.equalsIgnoreCase(o2))
87 {
88
89 return 0;
90 }
91 if (o1.equalsIgnoreCase(NONE))
92 {
93
94 return 1;
95 }
96 if (o1.equalsIgnoreCase(APPLICATION))
97 {
98 if (o2.equalsIgnoreCase(NONE))
99 {
100
101 return -1;
102 }
103 else
104 {
105
106 return 1;
107 }
108 }
109 if (o1.equalsIgnoreCase(SESSION))
110 {
111 if (o2.equalsIgnoreCase(REQUEST) || o2.equalsIgnoreCase(VIEW))
112 {
113
114 return 1;
115 }
116 else
117 {
118
119 return -1;
120 }
121 }
122 if (o1.equalsIgnoreCase(VIEW))
123 {
124 if (o2.equalsIgnoreCase(REQUEST))
125 {
126
127 return 1;
128 }
129 else
130 {
131
132 return -1;
133 }
134 }
135 if (o1.equalsIgnoreCase(REQUEST))
136 {
137
138 return -1;
139 }
140
141
142 throw new IllegalArgumentException(o1 + " is not a valid scope");
143 }
144
145 };
146
147 @SuppressWarnings("unchecked")
148 public Object buildManagedBean(FacesContext facesContext, ManagedBean beanConfiguration) throws FacesException
149 {
150 try
151 {
152 ExternalContext externalContext = facesContext.getExternalContext();
153 LifecycleProvider lifecycleProvider = LifecycleProviderFactory
154 .getLifecycleProviderFactory( externalContext).getLifecycleProvider(externalContext);
155
156 final Object bean = lifecycleProvider.newInstance(beanConfiguration.getManagedBeanClassName());
157
158 switch (beanConfiguration.getInitMode())
159 {
160 case ManagedBean.INIT_MODE_PROPERTIES:
161 try
162 {
163 initializeProperties(facesContext, beanConfiguration, bean);
164 }
165 catch (IllegalArgumentException e)
166 {
167 throw new IllegalArgumentException(
168 e.getMessage()
169 + " for bean '"
170 + beanConfiguration.getManagedBeanName()
171 + "' check the configuration to make sure all properties "
172 + "correspond with get/set methods", e);
173 }
174 break;
175
176 case ManagedBean.INIT_MODE_MAP:
177 if (!(bean instanceof Map))
178 {
179 throw new IllegalArgumentException("Class " + bean.getClass().getName()
180 + " of managed bean "
181 + beanConfiguration.getManagedBeanName()
182 + " is not a Map.");
183 }
184 initializeMap(facesContext, beanConfiguration.getMapEntries(), (Map<Object, Object>) bean);
185 break;
186
187 case ManagedBean.INIT_MODE_LIST:
188 if (!(bean instanceof List))
189 {
190 throw new IllegalArgumentException("Class " + bean.getClass().getName()
191 + " of managed bean "
192 + beanConfiguration.getManagedBeanName()
193 + " is not a List.");
194 }
195 initializeList(facesContext, beanConfiguration.getListEntries(), (List<Object>) bean);
196 break;
197
198 case ManagedBean.INIT_MODE_NO_INIT:
199
200 break;
201
202 default:
203 throw new IllegalStateException("Unknown managed bean type "
204 + bean.getClass().getName() + " for managed bean "
205 + beanConfiguration.getManagedBeanName() + '.');
206 }
207
208
209
210
211 if (lifecycleProvider instanceof LifecycleProvider2)
212 {
213 ((LifecycleProvider2)lifecycleProvider).postConstruct(bean);
214 }
215 return bean;
216 }
217 catch (IllegalAccessException e)
218 {
219 throw new FacesException(e);
220 }
221 catch (InvocationTargetException e)
222 {
223 throw new FacesException(e);
224 }
225 catch (NamingException e)
226 {
227 throw new FacesException(e);
228 }
229 catch (ClassNotFoundException e)
230 {
231 throw new FacesException(e);
232 }
233 catch (InstantiationException e)
234 {
235 throw new FacesException(e);
236 }
237
238 }
239
240
241 @SuppressWarnings("unchecked")
242 private void initializeProperties(FacesContext facesContext,
243 ManagedBean beanConfiguration, Object bean)
244 {
245 ELResolver elResolver = facesContext.getApplication().getELResolver();
246 ELContext elContext = facesContext.getELContext();
247
248 for (ManagedProperty property : beanConfiguration.getManagedProperties())
249 {
250 Object value = null;
251
252 switch (property.getType())
253 {
254 case ManagedProperty.TYPE_LIST:
255
256
257
258
259
260 if (PropertyUtils.isReadable(bean, property.getPropertyName()))
261 {
262 value = elResolver.getValue(elContext, bean, property.getPropertyName());
263 }
264
265 value = value == null ? new ArrayList<Object>() : value;
266
267 if (value instanceof List)
268 {
269 initializeList(facesContext, property.getListEntries(), (List<Object>)value);
270
271 }
272 else if (value != null && value.getClass().isArray())
273 {
274 int length = Array.getLength(value);
275 ArrayList<Object> temp = new ArrayList<Object>(length);
276 for (int i = 0; i < length; i++)
277 {
278 temp.add(Array.get(value, i));
279 }
280 initializeList(facesContext, property.getListEntries(), temp);
281 value = Array.newInstance(value.getClass().getComponentType(), temp.size());
282 length = temp.size();
283
284 for (int i = 0; i < length; i++)
285 {
286 Array.set(value, i, temp.get(i));
287 }
288 }
289 else
290 {
291 value = new ArrayList<Object>();
292 initializeList(facesContext, property.getListEntries(), (List<Object>) value);
293 }
294
295 break;
296 case ManagedProperty.TYPE_MAP:
297
298
299
300
301
302 if (PropertyUtils.isReadable(bean, property.getPropertyName()))
303 {
304 value = elResolver.getValue(elContext, bean, property.getPropertyName());
305 }
306 value = value == null ? new HashMap<Object, Object>() : value;
307
308 if (!(value instanceof Map))
309 {
310 value = new HashMap<Object, Object>();
311 }
312
313 initializeMap(facesContext, property.getMapEntries(), (Map<Object, Object>) value);
314 break;
315 case ManagedProperty.TYPE_NULL:
316 break;
317 case ManagedProperty.TYPE_VALUE:
318
319 if (!isInValidScope(facesContext, property, beanConfiguration))
320 {
321 throw new FacesException("Property " + property.getPropertyName() +
322 " references object in a scope with shorter lifetime than the target scope " +
323 beanConfiguration.getManagedBeanScope());
324 }
325 value = property.getRuntimeValue(facesContext);
326 break;
327 default:
328 throw new FacesException("unknown ManagedProperty type: "+ property.getType());
329 }
330
331 Class<?> propertyClass = null;
332
333 if (property.getPropertyClass() == null)
334 {
335 propertyClass = elResolver.getType(elContext, bean, property.getPropertyName());
336 }
337 else
338 {
339 propertyClass = ClassUtils.simpleJavaTypeToClass(property.getPropertyClass());
340 }
341
342 if (null == propertyClass)
343 {
344 throw new IllegalArgumentException("unable to find the type of property " + property.getPropertyName());
345 }
346
347 Object coercedValue = coerceToType(facesContext, value, propertyClass);
348 elResolver.setValue(elContext, bean, property.getPropertyName(), coercedValue);
349 }
350 }
351
352
353
354 @SuppressWarnings("unchecked")
355 public static <T> T coerceToType(FacesContext facesContext, Object value, Class<? extends T> desiredClass)
356 {
357 if (value == null)
358 {
359 return null;
360 }
361
362 try
363 {
364 ExpressionFactory expFactory = facesContext.getApplication().getExpressionFactory();
365
366
367 return (T)expFactory.coerceToType(value, desiredClass);
368 }
369 catch (ELException e)
370 {
371 String message = "Cannot coerce " + value.getClass().getName()
372 + " to " + desiredClass.getName();
373 log.log(Level.SEVERE, message , e);
374 throw new FacesException(message, e);
375 }
376 }
377
378
379
380
381
382
383
384
385
386
387 private boolean isInValidScope(FacesContext facesContext, ManagedProperty property, ManagedBean beanConfiguration)
388 {
389 if (!property.isValueReference())
390 {
391
392 return true;
393 }
394
395
396 String targetScope = null;
397 if (beanConfiguration.isManagedBeanScopeValueExpression())
398 {
399
400
401
402
403 if (facesContext.isProjectStage(ProjectStage.Production))
404 {
405 return true;
406 }
407 else
408 {
409 targetScope = getNarrowestScope(facesContext,
410 beanConfiguration
411 .getManagedBeanScopeValueExpression(facesContext)
412 .getExpressionString());
413
414 if (targetScope == null)
415 {
416 return true;
417 }
418 }
419 }
420 else
421 {
422 targetScope = beanConfiguration.getManagedBeanScope();
423 if (targetScope == null)
424 {
425 targetScope = NONE;
426 }
427 }
428
429
430 if (targetScope.equalsIgnoreCase(REQUEST))
431 {
432 return true;
433 }
434
435 String valueScope = getNarrowestScope(facesContext,
436 property.getValueBinding(facesContext)
437 .getExpressionString());
438
439
440 if (valueScope == null)
441 {
442 return true;
443 }
444
445
446 return (SCOPE_COMPARATOR.compare(targetScope, valueScope) <= 0);
447 }
448
449
450
451
452
453
454
455 private String getNarrowestScope(FacesContext facesContext, String valueExpression)
456 {
457 List<String> expressions = extractExpressions(valueExpression);
458
459 String narrowestScope = expressions.size() == 1 ? NONE : APPLICATION;
460 boolean scopeFound = false;
461
462 for (String expression : expressions)
463 {
464 String valueScope = getScope(facesContext, expression);
465 if (valueScope == null)
466 {
467 continue;
468 }
469
470 scopeFound = true;
471 if (SCOPE_COMPARATOR.compare(valueScope, narrowestScope) < 0)
472 {
473 narrowestScope = valueScope;
474 }
475 }
476
477 return scopeFound ? narrowestScope : null;
478 }
479
480 private String getScope(FacesContext facesContext, String expression)
481 {
482 String beanName = getFirstSegment(expression);
483 ExternalContext externalContext = facesContext.getExternalContext();
484
485
486 if (beanName.equalsIgnoreCase("requestScope"))
487 {
488 return REQUEST;
489 }
490 if (beanName.equalsIgnoreCase("sessionScope"))
491 {
492 return SESSION;
493 }
494 if (beanName.equalsIgnoreCase("applicationScope"))
495 {
496 return APPLICATION;
497 }
498
499
500 if (beanName.equalsIgnoreCase("cookie"))
501 {
502 return REQUEST;
503 }
504 if (beanName.equalsIgnoreCase("facesContext"))
505 {
506 return REQUEST;
507 }
508 if (beanName.equalsIgnoreCase("header"))
509 {
510 return REQUEST;
511 }
512 if (beanName.equalsIgnoreCase("headerValues"))
513 {
514 return REQUEST;
515 }
516 if (beanName.equalsIgnoreCase("param"))
517 {
518 return REQUEST;
519 }
520 if (beanName.equalsIgnoreCase("paramValues"))
521 {
522 return REQUEST;
523 }
524 if (beanName.equalsIgnoreCase("request"))
525 {
526 return REQUEST;
527 }
528 if (beanName.equalsIgnoreCase("view"))
529 {
530 return REQUEST;
531 }
532 if (beanName.equalsIgnoreCase("application"))
533 {
534 return APPLICATION;
535 }
536 if (beanName.equalsIgnoreCase("initParam"))
537 {
538 return APPLICATION;
539 }
540
541
542 final boolean startup = (externalContext instanceof StartupServletExternalContextImpl);
543 if (!startup)
544 {
545
546
547 if (externalContext.getRequestMap().get(beanName) != null)
548 {
549 return REQUEST;
550 }
551 if (externalContext.getSessionMap().get(beanName) != null)
552 {
553 return SESSION;
554 }
555 }
556 if (externalContext.getApplicationMap().get(beanName) != null)
557 {
558 return APPLICATION;
559 }
560 if (facesContext.getViewRoot() != null)
561 {
562
563 Map<String, Object> viewMap = facesContext.getViewRoot().getViewMap(!startup);
564 if (viewMap!= null && viewMap.get(beanName) != null)
565 {
566 return VIEW;
567 }
568 }
569
570
571 ManagedBean mbc = getRuntimeConfig(facesContext).getManagedBean(beanName);
572 if (mbc != null)
573 {
574
575 if (mbc.isManagedBeanScopeValueExpression())
576 {
577
578
579
580
581 if (facesContext.isProjectStage(ProjectStage.Production))
582 {
583 return null;
584 }
585 else
586 {
587 String scopeExpression = mbc.getManagedBeanScopeValueExpression(facesContext).getExpressionString();
588 return getNarrowestScope(facesContext, scopeExpression);
589 }
590 }
591 else
592 {
593 return mbc.getManagedBeanScope();
594 }
595 }
596
597 return null;
598 }
599
600
601
602
603
604
605
606 private String getFirstSegment(String expression)
607 {
608 int indexDot = expression.indexOf('.');
609 int indexBracket = expression.indexOf('[');
610
611 if (indexBracket < 0)
612 {
613
614 return indexDot < 0 ? expression : expression.substring(0, indexDot);
615
616 }
617
618 if (indexDot < 0)
619 {
620 return expression.substring(0, indexBracket);
621 }
622
623 return expression.substring(0, Math.min(indexDot, indexBracket));
624
625 }
626
627 private List<String> extractExpressions(String expressionString)
628 {
629 List<String> expressions = new ArrayList<String>();
630 for (String expression : expressionString.split("\\#\\{"))
631 {
632 int index = expression.indexOf('}');
633 if (index >= 0)
634 {
635 expressions.add(expression.substring(0, index));
636 }
637 }
638 return expressions;
639 }
640
641
642 private void initializeMap(FacesContext facesContext, MapEntries mapEntries,
643 Map<? super Object, ? super Object> map)
644 {
645 Application application = facesContext.getApplication();
646
647 Class<?> keyClass = (mapEntries.getKeyClass() == null)
648 ? String.class : ClassUtils.simpleJavaTypeToClass(mapEntries.getKeyClass());
649
650 Class<?> valueClass = (mapEntries.getValueClass() == null)
651 ? String.class : ClassUtils.simpleJavaTypeToClass(mapEntries.getValueClass());
652
653 ValueExpression valueExpression;
654 ExpressionFactory expFactory = application.getExpressionFactory();
655 ELContext elContext = facesContext.getELContext();
656
657 for (Iterator<? extends MapEntry> iterator = mapEntries.getMapEntries(); iterator.hasNext();)
658 {
659 MapEntry entry = iterator.next();
660 Object key = entry.getKey();
661
662 if (ContainerUtils.isValueReference((String) key))
663 {
664 valueExpression = expFactory.createValueExpression(elContext, (String) key, Object.class);
665 key = valueExpression.getValue(elContext);
666 }
667
668 if (entry.isNullValue())
669 {
670 map.put(coerceToType(facesContext, key, keyClass), null);
671 }
672 else
673 {
674 Object value = entry.getValue();
675 if (ContainerUtils.isValueReference((String) value))
676 {
677 valueExpression = expFactory.createValueExpression(elContext, (String) value, Object.class);
678 value = valueExpression.getValue(elContext);
679 }
680
681 map.put(coerceToType(facesContext, key, keyClass), coerceToType(facesContext, value, valueClass));
682 }
683 }
684 }
685
686
687 private void initializeList(FacesContext facesContext, ListEntries listEntries, List<? super Object> list)
688 {
689 Application application = facesContext.getApplication();
690
691 Class<?> valueClass = (listEntries.getValueClass() == null)
692 ? String.class : ClassUtils.simpleJavaTypeToClass(listEntries.getValueClass());
693
694 ExpressionFactory expFactory = application.getExpressionFactory();
695 ELContext elContext = facesContext.getELContext();
696
697 for (Iterator<? extends ListEntry> iterator = listEntries.getListEntries(); iterator.hasNext();)
698 {
699 ListEntry entry = iterator.next();
700 if (entry.isNullValue())
701 {
702 list.add(null);
703 }
704 else
705 {
706 Object value = entry.getValue();
707 if (ContainerUtils.isValueReference((String) value))
708 {
709 ValueExpression valueExpression = expFactory.createValueExpression(elContext, (String) value,
710 Object.class);
711 value = valueExpression.getValue(elContext);
712 }
713
714 list.add(coerceToType(facesContext, value, valueClass));
715 }
716 }
717 }
718
719 private RuntimeConfig getRuntimeConfig(FacesContext facesContext)
720 {
721 if (_runtimeConfig == null)
722 {
723 _runtimeConfig = RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
724 }
725
726 return _runtimeConfig;
727 }
728 }