1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.shared.renderkit;
20
21 import java.lang.reflect.Array;
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.Queue;
30 import java.util.Set;
31 import java.util.SortedSet;
32 import java.util.TreeSet;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35
36 import javax.el.ValueExpression;
37 import javax.faces.FacesException;
38 import javax.faces.component.UIOutput;
39 import javax.faces.component.UISelectMany;
40 import javax.faces.context.FacesContext;
41 import javax.faces.convert.Converter;
42 import javax.faces.convert.ConverterException;
43 import javax.faces.model.SelectItem;
44 import javax.faces.model.SelectItemGroup;
45
46 import org.apache.myfaces.shared.util.SelectItemsIterator;
47
48
49
50
51
52
53 class _SharedRendererUtils
54 {
55 static final String COLLECTION_TYPE_KEY = "collectionType";
56 static final String VALUE_TYPE_KEY = "valueType";
57
58 static Converter findUIOutputConverter(FacesContext facesContext,
59 UIOutput component)
60 {
61
62
63
64
65 Converter converter = component.getConverter();
66 if (converter != null)
67 {
68 return converter;
69 }
70
71
72 ValueExpression expression = component.getValueExpression("value");
73 if (expression == null)
74 {
75 return null;
76 }
77
78 Class<?> valueType = expression.getType(facesContext.getELContext());
79 if (valueType == null)
80 {
81 return null;
82 }
83
84 if (Object.class.equals(valueType))
85 {
86 return null;
87 }
88
89 try
90 {
91 return facesContext.getApplication().createConverter(valueType);
92 }
93 catch (FacesException e)
94 {
95 log(facesContext, "No Converter for type " + valueType.getName()
96 + " found", e);
97 return null;
98 }
99 }
100
101 static Object getConvertedUISelectManyValue(FacesContext facesContext, UISelectMany component,
102 String[] submittedValue) throws ConverterException
103 {
104 return getConvertedUISelectManyValue(facesContext, component,
105 submittedValue, false);
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120 static Object getConvertedUISelectManyValue(FacesContext facesContext, UISelectMany component,
121 String[] submittedValue, boolean considerValueType) throws ConverterException
122 {
123
124
125
126
127 if (submittedValue == null)
128 {
129 throw new NullPointerException("submittedValue");
130 }
131
132 ValueExpression expression = component.getValueExpression("value");
133 Object targetForConvertedValues = null;
134
135
136 Converter converter = component.getConverter();
137 if (converter == null && considerValueType)
138 {
139
140 converter = getValueTypeConverter(facesContext, component);
141 }
142
143 if (expression != null)
144 {
145 Class<?> modelType = expression
146 .getType(facesContext.getELContext());
147 if (modelType == null)
148 {
149
150 return submittedValue;
151 }
152 else if (modelType.isArray())
153 {
154
155 Class<?> componentType = modelType.getComponentType();
156
157
158 if (String.class.equals(componentType))
159 {
160 return submittedValue;
161 }
162 if (converter == null)
163 {
164
165
166 converter = facesContext.getApplication().createConverter(
167 componentType);
168
169 if (converter == null)
170 {
171
172
173 if (!Object.class.equals(componentType))
174 {
175
176
177
178 throw new ConverterException(
179 "Could not obtain a Converter for "
180 + componentType.getName());
181 }
182 }
183 }
184
185 targetForConvertedValues = Array.newInstance(componentType,
186 submittedValue.length);
187 }
188 else if (Collection.class.isAssignableFrom(modelType) || Object.class.equals(modelType))
189 {
190 if (converter == null)
191 {
192
193 SelectItemsIterator iterator = new SelectItemsIterator(component, facesContext);
194 converter = getSelectItemsValueConverter(iterator, facesContext);
195 }
196
197 Object collectionTypeAttr = component.getAttributes().get(
198 COLLECTION_TYPE_KEY);
199 if (collectionTypeAttr != null)
200 {
201 Class<?> collectionType = getClassFromAttribute(facesContext, collectionTypeAttr);
202 if (collectionType == null)
203 {
204 throw new FacesException(
205 "The attribute "
206 + COLLECTION_TYPE_KEY
207 + " of component "
208 + component.getClientId(facesContext)
209 + " does not evaluate to a "
210 + "String, a Class object or a ValueExpression pointing "
211 + "to a String or a Class object.");
212 }
213
214 if (!Collection.class.isAssignableFrom(collectionType))
215 {
216 throw new FacesException("The attribute "
217 + COLLECTION_TYPE_KEY + " of component "
218 + component.getClientId(facesContext)
219 + " does not point to a valid type of Collection.");
220 }
221
222 try
223 {
224 targetForConvertedValues = collectionType.newInstance();
225 }
226 catch (Exception e)
227 {
228 throw new FacesException("The Collection "
229 + collectionType.getName()
230 + "can not be instantiated.", e);
231 }
232 }
233 else if (Collection.class.isAssignableFrom(modelType))
234 {
235
236 Collection<?> componentValue = (Collection<?>) component
237 .getValue();
238
239 if (componentValue instanceof Cloneable)
240 {
241
242 try
243 {
244 Method cloneMethod = componentValue.getClass()
245 .getMethod("clone");
246 Collection<?> clone = (Collection<?>) cloneMethod
247 .invoke(componentValue);
248 clone.clear();
249 targetForConvertedValues = clone;
250 }
251 catch (Exception e)
252 {
253 log(facesContext, "Could not clone "
254 + componentValue.getClass().getName(), e);
255 }
256 }
257
258
259 if (targetForConvertedValues == null)
260 {
261
262
263 try
264 {
265 targetForConvertedValues = (componentValue != null
266 ? componentValue.getClass()
267 : modelType).newInstance();
268 }
269 catch (Exception e)
270 {
271
272
273 if (SortedSet.class.isAssignableFrom(modelType))
274 {
275 targetForConvertedValues = new TreeSet();
276 }
277 else if (Queue.class.isAssignableFrom(modelType))
278 {
279 targetForConvertedValues = new LinkedList();
280 }
281 else if (Set.class.isAssignableFrom(modelType))
282 {
283 targetForConvertedValues = new HashSet(
284 submittedValue.length);
285 }
286 else
287 {
288 targetForConvertedValues = new ArrayList(
289 submittedValue.length);
290 }
291 }
292 }
293 }
294 else
295 {
296
297
298
299
300 if (converter == null)
301 {
302 return submittedValue;
303 }
304
305 targetForConvertedValues = new Object[submittedValue.length];
306 }
307 }
308 else
309 {
310
311 throw new ConverterException(
312 "ValueExpression for UISelectMany must be of type Collection or Array.");
313 }
314 }
315 else
316 {
317 targetForConvertedValues = new Object[submittedValue.length];
318 }
319
320
321
322 boolean isArray = (targetForConvertedValues.getClass().isArray());
323 for (int i = 0; i < submittedValue.length; i++)
324 {
325
326 Object value;
327 if (converter != null)
328 {
329 value = converter.getAsObject(facesContext, component,
330 submittedValue[i]);
331 }
332 else
333 {
334 value = submittedValue[i];
335 }
336
337 if (isArray)
338 {
339 Array.set(targetForConvertedValues, i, value);
340 }
341 else
342 {
343 ((Collection) targetForConvertedValues).add(value);
344 }
345 }
346
347 return targetForConvertedValues;
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361 static Class<?> getClassFromAttribute(FacesContext facesContext,
362 Object attribute) throws FacesException
363 {
364
365
366
367
368 Class<?> type = null;
369
370
371
372 if (attribute instanceof ValueExpression)
373 {
374
375 attribute = ((ValueExpression) attribute)
376 .getValue(facesContext.getELContext());
377 }
378
379 if (attribute instanceof String)
380 {
381 try
382 {
383 type = Class.forName((String) attribute);
384 }
385 catch (ClassNotFoundException cnfe)
386 {
387 throw new FacesException(
388 "Unable to find class "
389 + attribute
390 + " on the classpath.", cnfe);
391 }
392
393 }
394
395 else if (attribute instanceof Class)
396 {
397 type = (Class<?>) attribute;
398 }
399
400 return type;
401 }
402
403
404
405
406
407
408
409
410
411 static Converter getValueTypeConverter(FacesContext facesContext, UISelectMany component)
412 {
413 Converter converter = null;
414
415 Object valueTypeAttr = component.getAttributes().get(VALUE_TYPE_KEY);
416 if (valueTypeAttr != null)
417 {
418
419 Class<?> valueType = getClassFromAttribute(facesContext, valueTypeAttr);
420 if (valueType == null)
421 {
422 throw new FacesException(
423 "The attribute "
424 + VALUE_TYPE_KEY
425 + " of component "
426 + component.getClientId(facesContext)
427 + " does not evaluate to a "
428 + "String, a Class object or a ValueExpression pointing "
429 + "to a String or a Class object.");
430 }
431
432
433 converter = facesContext.getApplication().createConverter(valueType);
434
435 if (converter == null)
436 {
437 log.log(Level.WARNING, "Found attribute valueType on component " +
438 RendererUtils.getPathToComponent(component) +
439 ", but could not get a by-type converter for type " +
440 valueType.getName());
441 }
442 }
443
444 return converter;
445 }
446
447
448
449
450
451
452
453
454 static Converter getSelectItemsValueConverter(Iterator<SelectItem> iterator, FacesContext facesContext)
455 {
456
457
458
459
460 Converter converter = null;
461 while (converter == null && iterator.hasNext())
462 {
463 SelectItem item = iterator.next();
464 if (item instanceof SelectItemGroup)
465 {
466 Iterator<SelectItem> groupIterator = Arrays.asList(
467 ((SelectItemGroup) item).getSelectItems()).iterator();
468 converter = getSelectItemsValueConverter(groupIterator, facesContext);
469 }
470 else
471 {
472 Class<?> selectItemsType = item.getValue().getClass();
473
474
475 if (String.class.equals(selectItemsType))
476 {
477 return null;
478 }
479
480 try
481 {
482 converter = facesContext.getApplication().createConverter(selectItemsType);
483 }
484 catch (FacesException e)
485 {
486
487 }
488 }
489 }
490 return converter;
491 }
492
493
494 private static final Logger log = Logger.getLogger(_SharedRendererUtils.class.getName());
495
496
497
498
499 private static void log(FacesContext context, String msg, Exception e)
500 {
501 log.log(Level.SEVERE, msg, e);
502 }
503 }