1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.taglib.html;
19
20 import org.apache.commons.beanutils.PropertyUtils;
21 import org.apache.struts.taglib.TagUtils;
22 import org.apache.struts.util.IteratorAdapter;
23 import org.apache.struts.util.MessageResources;
24
25 import javax.servlet.jsp.JspException;
26 import javax.servlet.jsp.tagext.TagSupport;
27
28 import java.lang.reflect.InvocationTargetException;
29
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Enumeration;
33 import java.util.Iterator;
34 import java.util.Map;
35
36 /***
37 * Tag for creating multiple <select> options from a collection. The
38 * associated values displayed to the user may optionally be specified by a
39 * second collection, or will be the same as the values themselves. Each
40 * collection may be an array of objects, a Collection, an Enumeration, an
41 * Iterator, or a Map. <b>NOTE</b> - This tag requires a Java2 (JDK 1.2 or
42 * later) platform.
43 */
44 public class OptionsTag extends TagSupport {
45 /***
46 * The message resources for this package.
47 */
48 protected static MessageResources messages =
49 MessageResources.getMessageResources(Constants.Package
50 + ".LocalStrings");
51
52 /***
53 * The name of the collection containing beans that have properties to
54 * provide both the values and the labels (identified by the
55 * <code>property</code> and <code>labelProperty</code> attributes).
56 */
57 protected String collection = null;
58
59 /***
60 * Should the label values be filtered for HTML sensitive characters?
61 */
62 protected boolean filter = true;
63
64 /***
65 * The name of the bean containing the labels collection.
66 */
67 protected String labelName = null;
68
69 /***
70 * The bean property containing the labels collection.
71 */
72 protected String labelProperty = null;
73
74 /***
75 * The name of the bean containing the values collection.
76 */
77 protected String name = null;
78
79 /***
80 * The name of the property to use to build the values collection.
81 */
82 protected String property = null;
83
84 /***
85 * The style associated with this tag.
86 */
87 private String style = null;
88
89 /***
90 * The named style class associated with this tag.
91 */
92 private String styleClass = null;
93
94 public String getCollection() {
95 return (this.collection);
96 }
97
98 public void setCollection(String collection) {
99 this.collection = collection;
100 }
101
102 public boolean getFilter() {
103 return filter;
104 }
105
106 public void setFilter(boolean filter) {
107 this.filter = filter;
108 }
109
110 public String getLabelName() {
111 return labelName;
112 }
113
114 public void setLabelName(String labelName) {
115 this.labelName = labelName;
116 }
117
118 public String getLabelProperty() {
119 return labelProperty;
120 }
121
122 public void setLabelProperty(String labelProperty) {
123 this.labelProperty = labelProperty;
124 }
125
126 public String getName() {
127 return name;
128 }
129
130 public void setName(String name) {
131 this.name = name;
132 }
133
134 public String getProperty() {
135 return property;
136 }
137
138 public void setProperty(String property) {
139 this.property = property;
140 }
141
142 public String getStyle() {
143 return style;
144 }
145
146 public void setStyle(String style) {
147 this.style = style;
148 }
149
150 public String getStyleClass() {
151 return styleClass;
152 }
153
154 public void setStyleClass(String styleClass) {
155 this.styleClass = styleClass;
156 }
157
158 /***
159 * Process the start of this tag.
160 *
161 * @throws JspException if a JSP exception has occurred
162 */
163 public int doStartTag() throws JspException {
164 return SKIP_BODY;
165 }
166
167 /***
168 * Process the end of this tag.
169 *
170 * @throws JspException if a JSP exception has occurred
171 */
172 public int doEndTag() throws JspException {
173
174 SelectTag selectTag =
175 (SelectTag) pageContext.getAttribute(Constants.SELECT_KEY);
176
177 if (selectTag == null) {
178 throw new JspException(messages.getMessage("optionsTag.select"));
179 }
180
181 StringBuffer sb = new StringBuffer();
182
183
184 if (collection != null) {
185 Iterator collIterator = getIterator(collection, null);
186
187 while (collIterator.hasNext()) {
188 Object bean = collIterator.next();
189 Object value = null;
190 Object label = null;
191
192 try {
193 value = PropertyUtils.getProperty(bean, property);
194
195 if (value == null) {
196 value = "";
197 }
198 } catch (IllegalAccessException e) {
199 throw new JspException(messages.getMessage(
200 "getter.access", property, collection));
201 } catch (InvocationTargetException e) {
202 Throwable t = e.getTargetException();
203
204 throw new JspException(messages.getMessage(
205 "getter.result", property, t.toString()));
206 } catch (NoSuchMethodException e) {
207 throw new JspException(messages.getMessage(
208 "getter.method", property, collection));
209 }
210
211 try {
212 if (labelProperty != null) {
213 label = PropertyUtils.getProperty(bean, labelProperty);
214 } else {
215 label = value;
216 }
217
218 if (label == null) {
219 label = "";
220 }
221 } catch (IllegalAccessException e) {
222 throw new JspException(messages.getMessage(
223 "getter.access", labelProperty, collection));
224 } catch (InvocationTargetException e) {
225 Throwable t = e.getTargetException();
226
227 throw new JspException(messages.getMessage(
228 "getter.result", labelProperty, t.toString()));
229 } catch (NoSuchMethodException e) {
230 throw new JspException(messages.getMessage(
231 "getter.method", labelProperty, collection));
232 }
233
234 String stringValue = value.toString();
235
236 addOption(sb, stringValue, label.toString(),
237 selectTag.isMatched(stringValue));
238 }
239 }
240
241 else {
242
243 Iterator valuesIterator = getIterator(name, property);
244 Iterator labelsIterator = null;
245
246 if ((labelName != null) || (labelProperty != null)) {
247 labelsIterator = getIterator(labelName, labelProperty);
248 }
249
250
251 while (valuesIterator.hasNext()) {
252 Object valueObject = valuesIterator.next();
253
254 if (valueObject == null) {
255 valueObject = "";
256 }
257
258 String value = valueObject.toString();
259 String label = value;
260
261 if ((labelsIterator != null) && labelsIterator.hasNext()) {
262 Object labelObject = labelsIterator.next();
263
264 if (labelObject == null) {
265 labelObject = "";
266 }
267
268 label = labelObject.toString();
269 }
270
271 addOption(sb, value, label, selectTag.isMatched(value));
272 }
273 }
274
275 TagUtils.getInstance().write(pageContext, sb.toString());
276
277 return EVAL_PAGE;
278 }
279
280 /***
281 * Release any acquired resources.
282 */
283 public void release() {
284 super.release();
285 collection = null;
286 filter = true;
287 labelName = null;
288 labelProperty = null;
289 name = null;
290 property = null;
291 style = null;
292 styleClass = null;
293 }
294
295
296
297 /***
298 * Add an option element to the specified StringBuffer based on the
299 * specified parameters. <p> Note that this tag specifically does not
300 * support the <code>styleId</code> tag attribute, which causes the HTML
301 * <code>id</code> attribute to be emitted. This is because the HTML
302 * specification states that all "id" attributes in a document have to be
303 * unique. This tag will likely generate more than one
304 * <code>option</code> element element, but it cannot use the same
305 * <code>id</code> value. It's conceivable some sort of mechanism to
306 * supply an array of <code>id</code> values could be devised, but that
307 * doesn't seem to be worth the trouble.
308 *
309 * @param sb StringBuffer accumulating our results
310 * @param value Value to be returned to the server for this option
311 * @param label Value to be shown to the user for this option
312 * @param matched Should this value be marked as selected?
313 */
314 protected void addOption(StringBuffer sb, String value, String label,
315 boolean matched) {
316 sb.append("<option value=\"");
317
318 if (filter) {
319 sb.append(TagUtils.getInstance().filter(value));
320 } else {
321 sb.append(value);
322 }
323
324 sb.append("\"");
325
326 if (matched) {
327 sb.append(" selected=\"selected\"");
328 }
329
330 if (style != null) {
331 sb.append(" style=\"");
332 sb.append(style);
333 sb.append("\"");
334 }
335
336 if (styleClass != null) {
337 sb.append(" class=\"");
338 sb.append(styleClass);
339 sb.append("\"");
340 }
341
342 sb.append(">");
343
344 if (filter) {
345 sb.append(TagUtils.getInstance().filter(label));
346 } else {
347 sb.append(label);
348 }
349
350 sb.append("</option>\r\n");
351 }
352
353 /***
354 * Return an iterator for the option labels or values, based on our
355 * configured properties.
356 *
357 * @param name Name of the bean attribute (if any)
358 * @param property Name of the bean property (if any)
359 * @throws JspException if an error occurs
360 */
361 protected Iterator getIterator(String name, String property)
362 throws JspException {
363
364 String beanName = name;
365
366 if (beanName == null) {
367 beanName = Constants.BEAN_KEY;
368 }
369
370 Object bean =
371 TagUtils.getInstance().lookup(pageContext, beanName, null);
372
373 if (bean == null) {
374 throw new JspException(messages.getMessage("getter.bean", beanName));
375 }
376
377
378 Object collection = bean;
379
380 if (property != null) {
381 try {
382 collection = PropertyUtils.getProperty(bean, property);
383
384 if (collection == null) {
385 throw new JspException(messages.getMessage(
386 "getter.property", property));
387 }
388 } catch (IllegalAccessException e) {
389 throw new JspException(messages.getMessage("getter.access",
390 property, name));
391 } catch (InvocationTargetException e) {
392 Throwable t = e.getTargetException();
393
394 throw new JspException(messages.getMessage("getter.result",
395 property, t.toString()));
396 } catch (NoSuchMethodException e) {
397 throw new JspException(messages.getMessage("getter.method",
398 property, name));
399 }
400 }
401
402
403 if (collection.getClass().isArray()) {
404 collection = Arrays.asList((Object[]) collection);
405 }
406
407 if (collection instanceof Collection) {
408 return (((Collection) collection).iterator());
409 } else if (collection instanceof Iterator) {
410 return ((Iterator) collection);
411 } else if (collection instanceof Map) {
412 return (((Map) collection).entrySet().iterator());
413 } else if (collection instanceof Enumeration) {
414 return new IteratorAdapter((Enumeration) collection);
415 } else {
416 throw new JspException(messages.getMessage("optionsTag.iterator",
417 collection.toString()));
418 }
419 }
420 }