1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.shared.util;
20
21 import java.lang.reflect.Array;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.NoSuchElementException;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import javax.el.ValueExpression;
31 import javax.faces.application.ProjectStage;
32 import javax.faces.component.UIComponent;
33 import javax.faces.component.UISelectItem;
34 import javax.faces.component.UISelectItems;
35 import javax.faces.context.FacesContext;
36 import javax.faces.model.SelectItem;
37
38 import org.apache.myfaces.shared.util.renderkit.JsfProperties;
39
40
41
42
43
44 public class SelectItemsIterator implements Iterator<SelectItem>
45 {
46 private static final Logger log = Logger.getLogger(SelectItemsIterator.class.getName());
47
48 private static final String VAR_PROP = JsfProperties.VAR_PROP;
49 private static final String ITEM_VALUE_PROP = JsfProperties.ITEM_VALUE_PROP;
50 private static final String ITEM_LABEL_PROP = JsfProperties.ITEM_LABEL_PROP;
51 private static final String ITEM_DESCRIPTION_PROP = JsfProperties.ITEM_DESCRIPTION_PROP;
52 private static final String ITEM_DISABLED_PROP = JsfProperties.ITEM_DISABLED_PROP;
53 private static final String ITEM_LABEL_ESCAPED_PROP = JsfProperties.ITEM_LABEL_ESCAPED_PROP;
54 private static final String NO_SELECTION_VALUE_PROP = JsfProperties.NO_SELECTION_VALUE_PROP;
55
56 private static final Iterator<UIComponent> _EMPTY_UICOMPONENT_ITERATOR = new _EmptyIterator<UIComponent>();
57
58 private final Iterator<UIComponent> _children;
59 private Iterator<? extends Object> _nestedItems;
60 private SelectItem _nextItem;
61 private UIComponent _currentComponent;
62 private UISelectItems _currentUISelectItems;
63 private Object _currentValue;
64 private FacesContext _facesContext;
65
66 public SelectItemsIterator(UIComponent selectItemsParent, FacesContext facesContext)
67 {
68 _children = selectItemsParent.getChildCount() > 0
69 ? selectItemsParent.getChildren().iterator()
70 : _EMPTY_UICOMPONENT_ITERATOR;
71 _facesContext = facesContext;
72 }
73
74 @SuppressWarnings("unchecked")
75 public boolean hasNext()
76 {
77 if (_nextItem != null)
78 {
79 return true;
80 }
81 if (_nestedItems != null)
82 {
83 if (_nestedItems.hasNext())
84 {
85 return true;
86 }
87 _nestedItems = null;
88 _currentComponent = null;
89 _currentValue = null;
90 }
91 if (_children.hasNext())
92 {
93 UIComponent child = _children.next();
94
95
96
97
98
99
100 while (!(child instanceof UISelectItem) && !(child instanceof UISelectItems))
101 {
102
103 if (_children.hasNext())
104 {
105
106 child = _children.next();
107 }
108 else
109 {
110
111
112 return false;
113 }
114 }
115 if (child instanceof UISelectItem)
116 {
117 UISelectItem uiSelectItem = (UISelectItem) child;
118 Object item = uiSelectItem.getValue();
119 if (item == null)
120 {
121
122 Object itemValue = uiSelectItem.getItemValue();
123 String label = uiSelectItem.getItemLabel();
124 String description = uiSelectItem.getItemDescription();
125 boolean disabled = uiSelectItem.isItemDisabled();
126 boolean escape = uiSelectItem.isItemEscaped();
127 boolean noSelectionOption = uiSelectItem.isNoSelectionOption();
128 if (label == null && itemValue != null)
129 {
130 label = itemValue.toString();
131 }
132 item = new SelectItem(itemValue, label, description, disabled, escape, noSelectionOption);
133 }
134 else if (!(item instanceof SelectItem))
135 {
136 ValueExpression expression = uiSelectItem.getValueExpression("value");
137 throw new IllegalArgumentException("ValueExpression '"
138 + (expression == null ? null : expression.getExpressionString()) + "' of UISelectItem : "
139 + DebugUtils.getPathToComponent(child)
140 + " does not reference an Object of type SelectItem");
141 }
142 _nextItem = (SelectItem) item;
143 _currentComponent = child;
144 _currentValue = item;
145 return true;
146 }
147 else if (child instanceof UISelectItems)
148 {
149 _currentUISelectItems = ((UISelectItems) child);
150 Object value = _currentUISelectItems.getValue();
151 _currentComponent = child;
152
153 if (value instanceof SelectItem)
154 {
155 _nextItem = (SelectItem) value;
156 return true;
157 }
158 else if (value != null && value.getClass().isArray())
159 {
160
161
162 final int length = Array.getLength(value);
163 Collection<Object> items = new ArrayList<Object>(length);
164 for (int i = 0; i < length; i++)
165 {
166 items.add(Array.get(value, i));
167 }
168 _nestedItems = items.iterator();
169 return hasNext();
170 }
171 else if (value instanceof Iterable)
172 {
173
174 _nestedItems = ((Iterable<?>) value).iterator();
175 return hasNext();
176 }
177 else if (value instanceof Map)
178 {
179 Map<Object, Object> map = ((Map<Object, Object>) value);
180 Collection<SelectItem> items = new ArrayList<SelectItem>(map.size());
181 for (Map.Entry<Object, Object> entry : map.entrySet())
182 {
183 items.add(new SelectItem(entry.getValue(), entry.getKey().toString()));
184 }
185
186 _nestedItems = items.iterator();
187 return hasNext();
188 }
189 else
190 {
191 Level level = Level.FINE;
192 if (!_facesContext.isProjectStage(ProjectStage.Production))
193 {
194 level = Level.WARNING;
195 }
196
197 if (log.isLoggable(level))
198 {
199 ValueExpression expression = _currentUISelectItems.getValueExpression("value");
200 log.log(level, "ValueExpression {0} of UISelectItems with component-path {1}"
201 + " does not reference an Object of type SelectItem,"
202 + " array, Iterable or Map, but of type: {2}",
203 new Object[] {
204 (expression == null ? null : expression.getExpressionString()),
205 DebugUtils.getPathToComponent(child),
206 (value == null ? null : value.getClass().getName())
207 });
208 }
209 }
210 }
211 else
212 {
213 _currentComponent = null;
214 _currentValue = null;
215 }
216 }
217 return false;
218 }
219
220 public SelectItem next()
221 {
222 if (!hasNext())
223 {
224 throw new NoSuchElementException();
225 }
226 if (_nextItem != null)
227 {
228 SelectItem value = _nextItem;
229 _nextItem = null;
230 return value;
231 }
232 if (_nestedItems != null)
233 {
234 Object item = _nestedItems.next();
235
236 if (!(item instanceof SelectItem))
237 {
238
239
240
241 Map<String, Object> attributeMap = _currentUISelectItems.getAttributes();
242 _currentValue = item;
243
244
245 boolean wroteRequestMapVarValue = false;
246 Object oldRequestMapVarValue = null;
247 final String var = (String) attributeMap.get(VAR_PROP);
248 if(var != null && !"".equals(var))
249 {
250
251 oldRequestMapVarValue = _facesContext.getExternalContext().getRequestMap().put(var, item);
252 wroteRequestMapVarValue = true;
253 }
254
255
256 Object itemValue = attributeMap.get(ITEM_VALUE_PROP);
257 if (itemValue == null)
258 {
259
260
261 itemValue = item;
262 }
263
264
265
266 Object itemLabel = attributeMap.get(ITEM_LABEL_PROP);
267 if (itemLabel == null)
268 {
269 if (itemValue != null)
270 {
271 itemLabel = itemValue.toString();
272 }
273 }
274 else
275 {
276 itemLabel = itemLabel.toString();
277 }
278 Object itemDescription = attributeMap.get(ITEM_DESCRIPTION_PROP);
279 if (itemDescription != null)
280 {
281 itemDescription = itemDescription.toString();
282 }
283 Boolean itemDisabled = getBooleanAttribute(_currentUISelectItems, ITEM_DISABLED_PROP, false);
284 Boolean itemLabelEscaped = getBooleanAttribute(_currentUISelectItems, ITEM_LABEL_ESCAPED_PROP, true);
285 Object noSelectionValue = attributeMap.get(NO_SELECTION_VALUE_PROP);
286 item = new SelectItem(itemValue,
287 (String) itemLabel,
288 (String) itemDescription,
289 itemDisabled,
290 itemLabelEscaped,
291 itemValue.equals(noSelectionValue));
292
293
294 if(wroteRequestMapVarValue)
295 {
296
297 if (oldRequestMapVarValue != null)
298 {
299 _facesContext.getExternalContext()
300 .getRequestMap().put(var, oldRequestMapVarValue);
301 }
302 else
303 {
304 _facesContext.getExternalContext()
305 .getRequestMap().remove(var);
306 }
307 }
308 }
309 return (SelectItem) item;
310 }
311 throw new NoSuchElementException();
312 }
313
314 public void remove()
315 {
316 throw new UnsupportedOperationException();
317 }
318
319 public UIComponent getCurrentComponent()
320 {
321 return _currentComponent;
322 }
323
324 public Object getCurrentValue()
325 {
326 return _currentValue;
327 }
328
329 private boolean getBooleanAttribute(UIComponent component, String attrName, boolean defaultValue)
330 {
331 Object value = component.getAttributes().get(attrName);
332 if (value == null)
333 {
334 return defaultValue;
335 }
336 else if (value instanceof Boolean)
337 {
338 return (Boolean) value;
339 }
340 else
341 {
342
343
344
345 return Boolean.valueOf(value.toString());
346 }
347 }
348
349 }