1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.internal.util;
21
22 import org.apache.myfaces.tobago.component.Attributes;
23 import org.apache.myfaces.tobago.component.Visual;
24 import org.apache.myfaces.tobago.context.Markup;
25 import org.apache.myfaces.tobago.util.ComponentUtils;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import javax.el.ValueExpression;
30 import javax.faces.component.UIComponent;
31 import javax.faces.component.UISelectItem;
32 import javax.faces.component.UISelectItems;
33 import javax.faces.context.FacesContext;
34 import javax.faces.model.SelectItem;
35 import java.lang.invoke.MethodHandles;
36 import java.lang.reflect.Array;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.NoSuchElementException;
44
45
46
47
48 public class SelectItemUtils {
49
50 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
51
52
53
54
55 public static Iterable<SelectItem> getItemIterator(final FacesContext facesContext, final UIComponent selector) {
56 if (selector.getChildCount() == 0) {
57 return Collections.emptyList();
58 } else {
59 return new Iterable<SelectItem>() {
60
61 private SelectItemsIterator iterator;
62
63 @Override
64 public Iterator<SelectItem> iterator() {
65 if (iterator == null) {
66 iterator = new SelectItemsIterator(facesContext, selector);
67 }
68 return iterator;
69 }
70 };
71 }
72 }
73
74
75
76
77
78
79 public static List<SelectItem> getItemList(final FacesContext facesContext, final UIComponent selector) {
80 if (selector.getChildCount() == 0) {
81 return Collections.emptyList();
82 } else {
83 final Iterable<SelectItem> iterator = getItemIterator(facesContext, selector);
84 final List<SelectItem> result = new ArrayList<>();
85 for (final SelectItem selectItem : iterator) {
86 result.add(selectItem);
87 }
88 return result;
89 }
90 }
91
92 private static class SelectItemsIterator implements Iterator<SelectItem> {
93
94 private final FacesContext facesContext;
95 private final Iterator<UIComponent> children;
96 private Iterator<?> nestedItems;
97 private SelectItem nextItem;
98 private UISelectItems currentUISelectItems;
99
100 private SelectItemsIterator(final FacesContext facesContext, final UIComponent selector) {
101 this.children = selector.getChildren().iterator();
102 this.facesContext = facesContext;
103 }
104
105 @Override
106 @SuppressWarnings("unchecked")
107 public boolean hasNext() {
108 if (nextItem != null) {
109 return true;
110 }
111 if (nestedItems != null) {
112 if (nestedItems.hasNext()) {
113 return true;
114 }
115 nestedItems = null;
116 }
117
118 UIComponent child = null;
119 while (children.hasNext()) {
120 final UIComponent c = children.next();
121
122
123
124
125
126
127 if (c instanceof UISelectItem || c instanceof UISelectItems) {
128 child = c;
129 break;
130 }
131 }
132 if (child == null) {
133 return false;
134 }
135
136 if (child instanceof UISelectItem) {
137 final UISelectItem uiSelectItem = (UISelectItem) child;
138 Object item = uiSelectItem.getValue();
139 if (item == null) {
140
141 final Object itemValue = uiSelectItem.getItemValue();
142 String label = uiSelectItem.getItemLabel();
143 final String description = uiSelectItem.getItemDescription();
144 final boolean disabled = uiSelectItem.isItemDisabled();
145
146
147 if (label == null && itemValue != null) {
148 label = itemValue.toString();
149 }
150 String image = null;
151 Markup markup = null;
152 if (uiSelectItem instanceof org.apache.myfaces.tobago.component.UISelectItem) {
153 final org.apache.myfaces.tobago.component.UISelectItem tobagoSelectItem
154 = (org.apache.myfaces.tobago.component.UISelectItem) uiSelectItem;
155 image = tobagoSelectItem.getItemImage();
156 markup = tobagoSelectItem.getMarkup();
157 }
158 item = new org.apache.myfaces.tobago.model.SelectItem(itemValue, label, description, disabled, image, markup);
159 } else if (!(item instanceof SelectItem)) {
160 final ValueExpression expression = uiSelectItem.getValueExpression("value");
161 throw new IllegalArgumentException("ValueExpression '"
162 + (expression == null ? null : expression.getExpressionString()) + "' of UISelectItem : "
163 + child + " does not reference an Object of type SelectItem");
164 }
165 nextItem = (SelectItem) item;
166 return true;
167 } else {
168 currentUISelectItems = (UISelectItems) child;
169 final Object value = currentUISelectItems.getValue();
170
171 if (value instanceof SelectItem) {
172 nextItem = (SelectItem) value;
173 return true;
174 } else if (value != null && value.getClass().isArray()) {
175
176
177 final int length = Array.getLength(value);
178 final Collection<Object> items = new ArrayList<>(length);
179 for (int i = 0; i < length; i++) {
180 items.add(Array.get(value, i));
181 }
182 nestedItems = items.iterator();
183 return hasNext();
184 } else if (value instanceof Iterable) {
185
186 nestedItems = ((Iterable<?>) value).iterator();
187 return hasNext();
188 } else if (value instanceof Map) {
189 final Map<Object, Object> map = (Map<Object, Object>) value;
190 final Collection<SelectItem> items = new ArrayList<>(map.size());
191 for (final Map.Entry<Object, Object> entry : map.entrySet()) {
192 items.add(new org.apache.myfaces.tobago.model.SelectItem(entry.getValue(), entry.getKey().toString()));
193 }
194 nestedItems = items.iterator();
195 return hasNext();
196 }
197 }
198 return false;
199 }
200
201 @Override
202 public SelectItem next() {
203 if (!hasNext()) {
204 throw new NoSuchElementException();
205 }
206 if (nextItem != null) {
207 final SelectItem value = nextItem;
208 nextItem = null;
209 return value;
210 }
211 if (nestedItems != null) {
212 Object item = nestedItems.next();
213
214 if (!(item instanceof SelectItem)) {
215
216
217
218 final Map<String, Object> attributeMap = currentUISelectItems.getAttributes();
219
220
221 boolean wroteRequestMapVarValue = false;
222 Object oldRequestMapVarValue = null;
223 final String var = ComponentUtils.getStringAttribute(currentUISelectItems, Attributes.var);
224 if (var != null && !"".equals(var)) {
225
226 oldRequestMapVarValue = facesContext.getExternalContext().getRequestMap().put(var, item);
227 wroteRequestMapVarValue = true;
228 }
229
230
231 Object itemValue = ComponentUtils.getAttribute(currentUISelectItems, Attributes.itemValue);
232 if (itemValue == null) {
233
234
235 itemValue = item;
236 }
237
238
239
240 final Object itemLabelObject = ComponentUtils.getAttribute(currentUISelectItems, Attributes.itemLabel);
241 final String itemLabel;
242 if (itemLabelObject != null) {
243 itemLabel = itemLabelObject.toString();
244 } else if (itemValue != null) {
245 itemLabel = itemValue.toString();
246 } else {
247 LOG.warn("Label string can't be created!");
248 itemLabel = "???";
249 }
250 Object itemDescription = ComponentUtils.getAttribute(currentUISelectItems, Attributes.itemDescription);
251 if (itemDescription != null) {
252 itemDescription = itemDescription.toString();
253 }
254 final boolean itemDisabled
255 = ComponentUtils.getBooleanAttribute(currentUISelectItems, Attributes.itemDisabled, false);
256 final String itemImage = ComponentUtils.getStringAttribute(currentUISelectItems, Attributes.itemImage);
257 final Markup markup;
258 if (currentUISelectItems instanceof Visual) {
259 markup = ((Visual) currentUISelectItems).getMarkup();
260 } else {
261 markup = Markup.NULL;
262 }
263
264
265
266
267 item = new org.apache.myfaces.tobago.model.SelectItem(
268 itemValue, itemLabel, (String) itemDescription, itemDisabled, itemImage, markup);
269
270
271 if (wroteRequestMapVarValue) {
272
273 if (oldRequestMapVarValue != null) {
274 facesContext.getExternalContext().getRequestMap().put(var, oldRequestMapVarValue);
275 } else {
276 facesContext.getExternalContext().getRequestMap().remove(var);
277 }
278 }
279 }
280 return (SelectItem) item;
281 }
282 throw new NoSuchElementException();
283 }
284
285 @Override
286 public void remove() {
287 throw new UnsupportedOperationException();
288 }
289 }
290
291 }