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