Source code: org/apache/myfaces/config/ManagedBeanBuilder.java
1 /*
2 * Copyright 2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.myfaces.config;
17
18 import org.apache.myfaces.config.element.*;
19 import org.apache.myfaces.util.ClassUtils;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22
23 import javax.faces.FacesException;
24 import javax.faces.application.Application;
25 import javax.faces.context.FacesContext;
26 import javax.faces.context.ExternalContext;
27 import javax.faces.el.PropertyResolver;
28 import javax.faces.el.ValueBinding;
29 import javax.faces.el.EvaluationException;
30 import javax.faces.webapp.UIComponentTag;
31 import java.util.*;
32 import java.lang.reflect.Array;
33
34
35 /**
36 * Create and initialize managed beans
37 *
38 * @author <a href="mailto:oliver@rossmueller.com">Oliver Rossmueller</a> (latest modification by $Author: oros $)
39 * @author Anton Koinov
40 */
41 public class ManagedBeanBuilder
42 {
43 private static Log log = LogFactory.getLog(ManagedBeanBuilder.class);
44 private RuntimeConfig _runtimeConfig;
45
46
47 public Object buildManagedBean(FacesContext facesContext, ManagedBean beanConfiguration) throws FacesException
48 {
49 Object bean = ClassUtils.newInstance(beanConfiguration.getManagedBeanClassName());
50
51 switch (beanConfiguration.getInitMode())
52 {
53 case ManagedBean.INIT_MODE_PROPERTIES:
54 try {
55 initializeProperties(facesContext, beanConfiguration.getManagedProperties(),
56 beanConfiguration.getManagedBeanScope(), bean);
57 } catch (IllegalArgumentException e) {
58 throw new IllegalArgumentException(
59 e.getMessage()
60 + " for bean '"
61 + beanConfiguration.getManagedBeanName()
62 + "' check the configuration to make sure all properties correspond with get/set methods");
63 }
64 break;
65
66 case ManagedBean.INIT_MODE_MAP:
67 if (!(bean instanceof Map))
68 {
69 throw new IllegalArgumentException("Class " + bean.getClass().getName()
70 + " of managed bean "
71 + beanConfiguration.getManagedBeanName()
72 + " is not a Map.");
73 }
74 initializeMap(facesContext, beanConfiguration.getMapEntries(), (Map) bean);
75 break;
76
77 case ManagedBean.INIT_MODE_LIST:
78 if (!(bean instanceof List))
79 {
80 throw new IllegalArgumentException("Class " + bean.getClass().getName()
81 + " of managed bean "
82 + beanConfiguration.getManagedBeanName()
83 + " is not a List.");
84 }
85 initializeList(facesContext, beanConfiguration.getListEntries(), (List) bean);
86 break;
87
88 case ManagedBean.INIT_MODE_NO_INIT:
89 // no init values
90 break;
91
92 default:
93 throw new IllegalStateException("Unknown managed bean type "
94 + bean.getClass().getName() + " for managed bean "
95 + beanConfiguration.getManagedBeanName() + '.');
96 }
97 return bean;
98 }
99
100
101 private void initializeProperties(FacesContext facesContext, Iterator managedProperties, String targetScope, Object bean)
102 {
103 PropertyResolver propertyResolver =
104 facesContext.getApplication().getPropertyResolver();
105
106 while (managedProperties.hasNext())
107 {
108 ManagedProperty property = (ManagedProperty) managedProperties.next();
109 Object value = null;
110
111 switch (property.getType())
112 {
113 case ManagedProperty.TYPE_LIST:
114 value = propertyResolver.getValue(bean, property.getPropertyName());
115
116 if (value instanceof List) {
117 initializeList(facesContext, property.getListEntries(), (List) value);
118
119 } else if (value != null && value.getClass().isArray()) {
120 int length = Array.getLength(value);
121 ArrayList temp = new ArrayList(length);
122 for (int i = 0; i < length; i++) {
123 temp.add(Array.get(value, i));
124 }
125 initializeList(facesContext, property.getListEntries(), temp);
126 value = Array.newInstance(value.getClass().getComponentType(), temp.size());
127 length = temp.size();
128
129 for (int i = 0; i < length; i++) {
130 Array.set(value, i, temp.get(i));
131 }
132 } else {
133 value = new ArrayList();
134 initializeList(facesContext, property.getListEntries(), (List) value);
135 }
136
137 break;
138 case ManagedProperty.TYPE_MAP:
139
140 value = propertyResolver.getValue(bean, property.getPropertyName());
141
142 if (! (value instanceof Map)) {
143 value = new HashMap();
144 }
145
146 initializeMap(facesContext, property.getMapEntries(), (Map) value);
147 break;
148 case ManagedProperty.TYPE_NULL:
149 value = null;
150 break;
151 case ManagedProperty.TYPE_VALUE:
152 // check for correct scope of a referenced bean
153 if (! isInValidScope(facesContext, property, targetScope)) {
154 throw new FacesException("Property " + property.getPropertyName() +
155 " references object in a scope with shorter lifetime than the target scope " + targetScope);
156 }
157 value = property.getRuntimeValue(facesContext);
158 break;
159 }
160 Class propertyClass = null;
161
162 if (property.getPropertyClass() == null)
163 {
164 propertyClass = propertyResolver
165 .getType(bean, property.getPropertyName());
166 }
167 else
168 {
169 propertyClass = ClassUtils
170 .simpleJavaTypeToClass(property.getPropertyClass());
171 }
172 if(null == propertyClass) {
173 throw new IllegalArgumentException("unable to find the type of property " + property.getPropertyName());
174 }
175 Object coercedValue = ClassUtils.convertToType(value, propertyClass);
176 propertyResolver.setValue(
177 bean, property.getPropertyName(), coercedValue);
178 }
179 }
180
181
182 /**
183 * Check if the scope of the property value is valid for a bean to be stored in targetScope.
184 * @param facesContext
185 * @param property the property to be checked
186 * @param targetScope name of the target scope of the bean under construction
187 */
188 private boolean isInValidScope(FacesContext facesContext, ManagedProperty property, String targetScope)
189 {
190 if (! property.isValueReference()) {
191 // no value reference but a literal value -> nothing to check
192 return true;
193 }
194 String[] expressions = extractExpressions(property.getValueBinding(facesContext).getExpressionString());
195
196 for (int i = 0; i < expressions.length; i++) {
197 String expression = expressions[i];
198 if (expression == null) {
199 continue;
200 }
201
202 String valueScope = getScope(facesContext, expression);
203
204 // if the target scope is 'none' value scope has to be 'none', too
205 if (targetScope == null || targetScope.equalsIgnoreCase("none")) {
206 if (valueScope != null && !(valueScope.equalsIgnoreCase("none"))) {
207 return false;
208 }
209 return true;
210 }
211
212 // 'application' scope can reference 'application' and 'none'
213 if (targetScope.equalsIgnoreCase("application")) {
214 if (valueScope != null) {
215 if (valueScope.equalsIgnoreCase("request") ||
216 valueScope.equalsIgnoreCase("session")) {
217 return false;
218 }
219 }
220 return true;
221 }
222
223 // 'session' scope can reference 'session', 'application', and 'none' but not 'request'
224 if (targetScope.equalsIgnoreCase("session")) {
225 if (valueScope != null) {
226 if (valueScope.equalsIgnoreCase("request")) {
227 return false;
228 }
229 }
230 return true;
231 }
232
233 // 'request' scope can reference any value scope
234 if (targetScope.equalsIgnoreCase("request")) {
235 return true;
236 }
237 }
238 return false;
239 }
240
241
242 private String getScope(FacesContext facesContext, String expression)
243 {
244 String beanName = getFirstSegment(expression);
245 ExternalContext externalContext = facesContext.getExternalContext();
246
247 // check scope objects
248 if (beanName.equalsIgnoreCase("requestScope")) {
249 return "request";
250 }
251 if (beanName.equalsIgnoreCase("sessionScope")) {
252 return "session";
253 }
254 if (beanName.equalsIgnoreCase("applicationScope")) {
255 return "application";
256 }
257
258 // check implicit objects
259 if (beanName.equalsIgnoreCase("cookie")) {
260 return "request";
261 }
262 if (beanName.equalsIgnoreCase("facesContext")) {
263 return "request";
264 }
265
266 if (beanName.equalsIgnoreCase("header")) {
267 return "request";
268 }
269 if (beanName.equalsIgnoreCase("headerValues")) {
270 return "request";
271 }
272
273 if (beanName.equalsIgnoreCase("initParam")) {
274 return "application";
275 }
276 if (beanName.equalsIgnoreCase("param")) {
277 return "request";
278 }
279 if (beanName.equalsIgnoreCase("paramValues")) {
280 return "request";
281 }
282 if (beanName.equalsIgnoreCase("view")) {
283 return "request";
284 }
285
286
287 // not found so far - check all scopes
288 if (externalContext.getRequestMap().get(beanName) != null) {
289 return "request";
290 }
291 if (externalContext.getSessionMap().get(beanName) != null) {
292 return "session";
293 }
294 if (externalContext.getApplicationMap().get(beanName) != null) {
295 return "application";
296 }
297
298 //not found - check mangaged bean config
299
300
301 ManagedBean mbc = getRuntimeConfig(facesContext).getManagedBean(beanName);
302
303 if (mbc != null) {
304 return mbc.getManagedBeanScope();
305 }
306
307 return null;
308 }
309
310
311
312
313 /**
314 * Extract the first expression segment, that is the substring up to the first '.' or '['
315 * @param expression
316 * @return first segment of the expression
317 */
318 private String getFirstSegment(String expression)
319 {
320 int indexDot = expression.indexOf('.');
321 int indexBracket = expression.indexOf('[');
322
323 if (indexBracket < 0) {
324 if (indexDot < 0) {
325 return expression;
326 } else {
327 return expression.substring(0, indexDot);
328 }
329 } else {
330 if (indexDot < 0) {
331 return expression.substring(0, indexBracket);
332 } else {
333 return expression.substring(0, Math.min(indexDot, indexBracket));
334 }
335 }
336 }
337
338 private String getSecondSegment(String expression, String firstSegment)
339 {
340 String tmp = expression.substring(firstSegment.length());
341
342 if (tmp.length() == 0) {
343 return null;
344 }
345 if (tmp.charAt(0) == '.') {
346 return getFirstSegment(tmp.substring(1));
347 }
348 // starts with [
349 tmp = tmp.substring(1).trim();
350 int index;
351
352 if (tmp.charAt(0) == '"') {
353 index = tmp.indexOf('"', 1);
354
355 if (index < 0) {
356 throw new EvaluationException(tmp);
357 }
358 return tmp.substring(1, index);
359 }
360 if (tmp.charAt(0) == '\'') {
361 index = tmp.indexOf('\'', 1);
362
363 if (index < 0) {
364 throw new EvaluationException(tmp);
365 }
366 return tmp.substring(1, index);
367 }
368
369 index = tmp.indexOf(']');
370
371 if (index < 0) {
372 throw new EvaluationException(tmp);
373 }
374
375 return tmp.substring(1, index);
376 }
377
378
379 private String[] extractExpressions(String expressionString)
380 {
381 String[] expressions = expressionString.split("\\#\\{");
382 for (int i = 0; i < expressions.length; i++) {
383 String expression = expressions[i];
384 if (expression.trim().length() == 0) {
385 expressions[i] = null;
386 } else {
387 int index = expression.indexOf('}');
388 expressions[i] = expression.substring(0, index);
389 }
390 }
391 return expressions;
392 }
393
394
395 private void initializeMap(FacesContext facesContext, MapEntries mapEntries, Map map)
396 {
397 Application application = facesContext.getApplication();
398 Class keyClass = (mapEntries.getKeyClass() == null)
399 ? String.class : ClassUtils.simpleJavaTypeToClass(mapEntries.getKeyClass());
400 Class valueClass = (mapEntries.getValueClass() == null)
401 ? String.class : ClassUtils.simpleJavaTypeToClass(mapEntries.getValueClass());
402 ValueBinding valueBinding;
403
404 for (Iterator iterator = mapEntries.getMapEntries(); iterator.hasNext();)
405 {
406 MapEntry entry = (MapEntry) iterator.next();
407 Object key = entry.getKey();
408
409 if (UIComponentTag.isValueReference((String) key))
410 {
411 valueBinding = application.createValueBinding((String) key);
412 key = valueBinding.getValue(facesContext);
413 }
414
415 if (entry.isNullValue())
416 {
417 map.put(ClassUtils.convertToType(key, keyClass), null);
418 }
419 else
420 {
421 Object value = entry.getValue();
422 if (UIComponentTag.isValueReference((String) value))
423 {
424 valueBinding = application.createValueBinding((String) value);
425 value = valueBinding.getValue(facesContext);
426 }
427 map.put(ClassUtils.convertToType(key, keyClass), ClassUtils.convertToType(value, valueClass));
428 }
429 }
430 }
431
432
433 private void initializeList(FacesContext facesContext, ListEntries listEntries, List list)
434 {
435 Application application = facesContext.getApplication();
436 Class valueClass = listEntries.getValueClass() == null ? String.class : ClassUtils.simpleJavaTypeToClass(listEntries.getValueClass());
437 ValueBinding valueBinding;
438
439 for (Iterator iterator = listEntries.getListEntries(); iterator.hasNext();)
440 {
441 ListEntry entry = (ListEntry) iterator.next();
442 if (entry.isNullValue())
443 {
444 list.add(null);
445 }
446 else
447 {
448 Object value = entry.getValue();
449 if (UIComponentTag.isValueReference((String) value))
450 {
451 valueBinding = application.createValueBinding((String) value);
452 value = valueBinding.getValue(facesContext);
453 }
454 list.add(ClassUtils.convertToType(value, valueClass));
455 }
456 }
457 }
458
459 private RuntimeConfig getRuntimeConfig(FacesContext facesContext)
460 {
461 if (_runtimeConfig == null)
462 {
463 _runtimeConfig = RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
464 }
465 return _runtimeConfig;
466 }
467 }