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