Source code: javax/faces/component/UISelectMany.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 javax.faces.component;
17
18 import java.lang.reflect.Array;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.List;
23
24 import javax.faces.application.FacesMessage;
25 import javax.faces.component._SelectItemsUtil._ValueConverter;
26 import javax.faces.context.FacesContext;
27 import javax.faces.convert.ConverterException;
28 import javax.faces.el.ValueBinding;
29 import javax.faces.render.Renderer;
30
31 /**
32 * see Javadoc of JSF Specification
33 *
34 * @author Manfred Geiler (latest modification by $Author: svieujot $)
35 * @version $Revision: 280406 $ $Date: 2005-09-12 16:08:06 -0400 (Mon, 12 Sep 2005) $
36 */
37 public class UISelectMany extends UIInput
38 {
39 public static final String INVALID_MESSAGE_ID = "javax.faces.component.UISelectMany.INVALID";
40
41 public Object[] getSelectedValues()
42 {
43 return (Object[]) getValue();
44 }
45
46 public void setSelectedValues(Object[] selectedValues)
47 {
48 setValue(selectedValues);
49 }
50
51 public ValueBinding getValueBinding(String name)
52 {
53 if (name == null)
54 throw new NullPointerException("name");
55 if (name.equals("selectedValues"))
56 {
57 return super.getValueBinding("value");
58 }
59 else
60 {
61 return super.getValueBinding(name);
62 }
63 }
64
65 public void setValueBinding(String name, ValueBinding binding)
66 {
67 if (name == null)
68 throw new NullPointerException("name");
69 if (name.equals("selectedValues"))
70 {
71 super.setValueBinding("value", binding);
72 }
73 else
74 {
75 super.setValueBinding(name, binding);
76 }
77 }
78
79 /**
80 * @return true if Objects are different (!)
81 */
82 protected boolean compareValues(Object previous, Object value)
83 {
84 if (previous == null)
85 {
86 // one is null, the other not
87 return value != null;
88 }
89 else if (value == null)
90 {
91 // one is null, the other not
92 return previous != null;
93 }
94 else
95 {
96 if (previous instanceof Object[] && value instanceof Object[])
97 {
98 return compareObjectArrays((Object[]) previous,
99 (Object[]) value);
100 }
101 else if (previous instanceof List && value instanceof List)
102 {
103 return compareLists((List) previous, (List) value);
104 }
105 else if (previous.getClass().isArray()
106 && value.getClass().isArray())
107 {
108 return comparePrimitiveArrays(previous, value);
109 }
110 else
111 {
112 //Objects have different classes
113 return true;
114 }
115 }
116 }
117
118 private boolean compareObjectArrays(Object[] previous, Object[] value)
119 {
120 int length = value.length;
121 if (previous.length != length)
122 {
123 //different length
124 return true;
125 }
126
127 boolean[] scoreBoard = new boolean[length];
128 for (int i = 0; i < length; i++)
129 {
130 Object p = previous[i];
131 boolean found = false;
132 for (int j = 0; j < length; j++)
133 {
134 if (scoreBoard[j] == false)
135 {
136 Object v = value[j];
137 if ((p == null && v == null)
138 || (p != null && v != null && p.equals(v)))
139 {
140 scoreBoard[j] = true;
141 found = true;
142 break;
143 }
144 }
145 }
146 if (!found)
147 {
148 return true; //current element of previous array not found in new array
149 }
150 }
151
152 return false; // arrays are identical
153 }
154
155 private boolean compareLists(List previous, List value)
156 {
157 int length = value.size();
158 if (previous.size() != length)
159 {
160 //different length
161 return true;
162 }
163
164 boolean[] scoreBoard = new boolean[length];
165 for (int i = 0; i < length; i++)
166 {
167 Object p = previous.get(i);
168 boolean found = false;
169 for (int j = 0; j < length; j++)
170 {
171 if (scoreBoard[j] == false)
172 {
173 Object v = value.get(j);
174 if ((p == null && v == null)
175 || (p != null && v != null && p.equals(v)))
176 {
177 scoreBoard[j] = true;
178 found = true;
179 break;
180 }
181 }
182 }
183 if (!found)
184 {
185 return true; //current element of previous List not found in new List
186 }
187 }
188
189 return false; // Lists are identical
190 }
191
192 private boolean comparePrimitiveArrays(Object previous, Object value)
193 {
194 int length = Array.getLength(value);
195 if (Array.getLength(previous) != length)
196 {
197 //different length
198 return true;
199 }
200
201 boolean[] scoreBoard = new boolean[length];
202 for (int i = 0; i < length; i++)
203 {
204 Object p = Array.get(previous, i);
205 boolean found = false;
206 for (int j = 0; j < length; j++)
207 {
208 if (scoreBoard[j] == false)
209 {
210 Object v = Array.get(value, j);
211 if ((p == null && v == null)
212 || (p != null && v != null && p.equals(v)))
213 {
214 scoreBoard[j] = true;
215 found = true;
216 break;
217 }
218 }
219 }
220 if (!found)
221 {
222 return true; //current element of previous array not found in new array
223 }
224 }
225
226 return false; // arrays are identical
227 }
228
229 protected void validateValue(FacesContext context, Object convertedValue)
230 {
231 boolean empty = convertedValue == null
232 || ((convertedValue instanceof Object[]) && (((Object[]) convertedValue).length == 0))
233 || ((convertedValue instanceof List) && ((List) convertedValue).isEmpty());
234
235 if (isRequired() && empty)
236 {
237 _MessageUtils.addErrorMessage(context, this, REQUIRED_MESSAGE_ID,
238 new Object[] {getId()});
239 setValid(false);
240 return;
241 }
242
243 if (!empty)
244 {
245 _ComponentUtils.callValidators(context, this, convertedValue);
246 }
247
248 if (isValid() && convertedValue != null)
249 {
250 // all selected values must match to the values of the available options
251
252 if (! (convertedValue instanceof Object[]) && ! (convertedValue instanceof List)) {
253 _MessageUtils.addErrorMessage(context, this,
254 INVALID_MESSAGE_ID,
255 new Object[] {getId()});
256 setValid(false);
257 return;
258 }
259
260 _ValueConverter converter = new _ValueConverter()
261 {
262 public Object getConvertedValue(FacesContext context, String value)
263 {
264 Object convertedValue = UISelectMany.this.getConvertedValue(context, new String[] {value});
265 if(convertedValue instanceof Collection)
266 {
267 Iterator iter = ((Collection)convertedValue).iterator();
268 if(iter.hasNext())
269 {
270 return iter.next();
271 }
272 return null;
273 }
274 return ((Object[])convertedValue)[0];
275 }
276 };
277
278 if ( convertedValue instanceof Object[] ){
279 Object[] values = (Object[]) convertedValue;
280 if (values.length > 0)
281 {
282 Collection items = new ArrayList();
283 for (Iterator iter = new _SelectItemsIterator(this); iter.hasNext();)
284 {
285 items.add( iter.next() );
286 }
287 for (int i = 0, size = values.length; i < size; i++)
288 {
289 if (!_SelectItemsUtil.matchValue(context, values[i],
290 items.iterator(), converter))
291 {
292 _MessageUtils.addErrorMessage(context, this,
293 INVALID_MESSAGE_ID,
294 new Object[] {getId()});
295 setValid(false);
296 }
297 }
298 }
299 }else{ // convertedValue instanceof List
300 List values = (List) convertedValue;
301 if ( ! values.isEmpty() )
302 {
303 Collection items = new ArrayList();
304 for (Iterator iter = new _SelectItemsIterator(this); iter.hasNext();)
305 {
306 items.add( iter.next() );
307 }
308 for (Iterator i = values.iterator(); i.hasNext();)
309 {
310 if (!_SelectItemsUtil.matchValue(context, i.next(),
311 items.iterator(), converter))
312 {
313 _MessageUtils.addErrorMessage(context, this,
314 INVALID_MESSAGE_ID,
315 new Object[] {getId()});
316 setValid(false);
317 }
318 }
319 }
320 }
321 }
322 }
323
324 /**
325 * First part is identical to super.validate except the empty condition.
326 * Second part: iterate through UISelectItem and UISelectItems and check
327 * current values against these items
328 */
329 public void validate(FacesContext context)
330 {
331 // TODO : Setting the submitted value to null in the super class causes a bug, if set to null, you'll get the following error :
332 // java.lang.NullPointerException at org.apache.myfaces.renderkit._SharedRendererUtils.getConvertedUISelectManyValue(_SharedRendererUtils.java:118)
333 super.validate(context);
334 }
335
336 protected Object getConvertedValue(FacesContext context,
337 Object submittedValue)
338 {
339 try
340 {
341 Renderer renderer = getRenderer(context);
342 if (renderer != null)
343 {
344 return renderer
345 .getConvertedValue(context, this,
346 submittedValue);
347 }
348 else if (submittedValue == null)
349 {
350 return null;
351 }
352 else if (submittedValue instanceof String[])
353 {
354 return _SharedRendererUtils.getConvertedUISelectManyValue(
355 context, this, (String[]) submittedValue);
356 }
357 }
358 catch (ConverterException e)
359 {
360 FacesMessage facesMessage = e.getFacesMessage();
361 if (facesMessage != null)
362 {
363 context.addMessage(getClientId(context), facesMessage);
364 }
365 else
366 {
367 _MessageUtils.addErrorMessage(context, this,
368 CONVERSION_MESSAGE_ID, new Object[] {getId()});
369 }
370 setValid(false);
371 }
372 return submittedValue;
373 }
374
375 //------------------ GENERATED CODE BEGIN (do not modify!) --------------------
376
377 public static final String COMPONENT_TYPE = "javax.faces.SelectMany";
378 public static final String COMPONENT_FAMILY = "javax.faces.SelectMany";
379 private static final String DEFAULT_RENDERER_TYPE = "javax.faces.Listbox";
380
381 public UISelectMany()
382 {
383 setRendererType(DEFAULT_RENDERER_TYPE);
384 }
385
386 public String getFamily()
387 {
388 return COMPONENT_FAMILY;
389 }
390
391 //------------------ GENERATED CODE END ---------------------------------------
392 }