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 * collection may be part of the enclosing form, or may be independent of the
42 * form. Each element of the collection must expose a 'label' and a 'value',
43 * the property names of which are configurable by attributes of this tag. <p>
44 * The collection may be an array of objects, a Collection, an Enumeration, an
45 * Iterator, or a Map. <p> <b>NOTE</b> - This tag requires a Java2 (JDK 1.2 or
46 * later) platform.
47 *
48 * @version $Rev: 471754 $ $Date: 2004-11-03 14:20:47 -0500 (Wed, 03 Nov 2004)
49 * $
50 * @since Struts 1.1
51 */
52 public class OptionsCollectionTag extends TagSupport {
53
54
55 /**
56 * The message resources for this package.
57 */
58 protected static MessageResources messages =
59 MessageResources.getMessageResources(Constants.Package
60 + ".LocalStrings");
61
62
63
64 /**
65 * Should the label values be filtered for HTML sensitive characters?
66 */
67 protected boolean filter = true;
68
69 /**
70 * The name of the bean property containing the label.
71 */
72 protected String label = "label";
73
74 /**
75 * The name of the bean containing the values collection.
76 */
77 protected String name = Constants.BEAN_KEY;
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 /**
95 * The name of the bean property containing the value.
96 */
97 protected String value = "value";
98
99 public boolean getFilter() {
100 return filter;
101 }
102
103 public void setFilter(boolean filter) {
104 this.filter = filter;
105 }
106
107 public String getLabel() {
108 return label;
109 }
110
111 public void setLabel(String label) {
112 this.label = label;
113 }
114
115 public String getName() {
116 return name;
117 }
118
119 public void setName(String name) {
120 this.name = name;
121 }
122
123 public String getProperty() {
124 return property;
125 }
126
127 public void setProperty(String property) {
128 this.property = property;
129 }
130
131 public String getStyle() {
132 return style;
133 }
134
135 public void setStyle(String style) {
136 this.style = style;
137 }
138
139 public String getStyleClass() {
140 return styleClass;
141 }
142
143 public void setStyleClass(String styleClass) {
144 this.styleClass = styleClass;
145 }
146
147 public String getValue() {
148 return value;
149 }
150
151 public void setValue(String value) {
152 this.value = value;
153 }
154
155
156
157 /**
158 * Process the start of this tag.
159 *
160 * @throws JspException if a JSP exception has occurred
161 */
162 public int doStartTag() throws JspException {
163
164 SelectTag selectTag =
165 (SelectTag) pageContext.getAttribute(Constants.SELECT_KEY);
166
167 if (selectTag == null) {
168 JspException e =
169 new JspException(messages.getMessage(
170 "optionsCollectionTag.select"));
171
172 TagUtils.getInstance().saveException(pageContext, e);
173 throw e;
174 }
175
176
177 Object collection =
178 TagUtils.getInstance().lookup(pageContext, name, property, null);
179
180 if (collection == null) {
181 JspException e =
182 new JspException(messages.getMessage(
183 "optionsCollectionTag.collection"));
184
185 TagUtils.getInstance().saveException(pageContext, e);
186 throw e;
187 }
188
189
190 Iterator iter = getIterator(collection);
191
192 StringBuffer sb = new StringBuffer();
193
194
195 while (iter.hasNext()) {
196 Object bean = iter.next();
197 Object beanLabel = null;
198 Object beanValue = null;
199
200
201 try {
202 beanLabel = PropertyUtils.getProperty(bean, label);
203
204 if (beanLabel == null) {
205 beanLabel = "";
206 }
207 } catch (IllegalAccessException e) {
208 JspException jspe =
209 new JspException(messages.getMessage("getter.access",
210 label, bean));
211
212 TagUtils.getInstance().saveException(pageContext, jspe);
213 throw jspe;
214 } catch (InvocationTargetException e) {
215 Throwable t = e.getTargetException();
216 JspException jspe =
217 new JspException(messages.getMessage("getter.result",
218 label, t.toString()));
219
220 TagUtils.getInstance().saveException(pageContext, jspe);
221 throw jspe;
222 } catch (NoSuchMethodException e) {
223 JspException jspe =
224 new JspException(messages.getMessage("getter.method",
225 label, bean));
226
227 TagUtils.getInstance().saveException(pageContext, jspe);
228 throw jspe;
229 }
230
231
232 try {
233 beanValue = PropertyUtils.getProperty(bean, value);
234
235 if (beanValue == null) {
236 beanValue = "";
237 }
238 } catch (IllegalAccessException e) {
239 JspException jspe =
240 new JspException(messages.getMessage("getter.access",
241 value, bean));
242
243 TagUtils.getInstance().saveException(pageContext, jspe);
244 throw jspe;
245 } catch (InvocationTargetException e) {
246 Throwable t = e.getTargetException();
247 JspException jspe =
248 new JspException(messages.getMessage("getter.result",
249 value, t.toString()));
250
251 TagUtils.getInstance().saveException(pageContext, jspe);
252 throw jspe;
253 } catch (NoSuchMethodException e) {
254 JspException jspe =
255 new JspException(messages.getMessage("getter.method",
256 value, bean));
257
258 TagUtils.getInstance().saveException(pageContext, jspe);
259 throw jspe;
260 }
261
262 String stringLabel = beanLabel.toString();
263 String stringValue = beanValue.toString();
264
265
266 addOption(sb, stringLabel, stringValue,
267 selectTag.isMatched(stringValue));
268 }
269
270 TagUtils.getInstance().write(pageContext, sb.toString());
271
272 return SKIP_BODY;
273 }
274
275 /**
276 * Release any acquired resources.
277 */
278 public void release() {
279 super.release();
280 filter = true;
281 label = "label";
282 name = Constants.BEAN_KEY;
283 property = null;
284 style = null;
285 styleClass = null;
286 value = "value";
287 }
288
289
290
291 /**
292 * Add an option element to the specified StringBuffer based on the
293 * specified parameters. <p> Note that this tag specifically does not
294 * support the <code>styleId</code> tag attribute, which causes the HTML
295 * <code>id</code> attribute to be emitted. This is because the HTML
296 * specification states that all "id" attributes in a document have to be
297 * unique. This tag will likely generate more than one
298 * <code>option</code> element element, but it cannot use the same
299 * <code>id</code> value. It's conceivable some sort of mechanism to
300 * supply an array of <code>id</code> values could be devised, but that
301 * doesn't seem to be worth the trouble.
302 *
303 * @param sb StringBuffer accumulating our results
304 * @param value Value to be returned to the server for this option
305 * @param label Value to be shown to the user for this option
306 * @param matched Should this value be marked as selected?
307 */
308 protected void addOption(StringBuffer sb, String label, String value,
309 boolean matched) {
310 sb.append("<option value=\"");
311
312 if (filter) {
313 sb.append(TagUtils.getInstance().filter(value));
314 } else {
315 sb.append(value);
316 }
317
318 sb.append("\"");
319
320 if (matched) {
321 sb.append(" selected=\"selected\"");
322 }
323
324 if (style != null) {
325 sb.append(" style=\"");
326 sb.append(style);
327 sb.append("\"");
328 }
329
330 if (styleClass != null) {
331 sb.append(" class=\"");
332 sb.append(styleClass);
333 sb.append("\"");
334 }
335
336 sb.append(">");
337
338 if (filter) {
339 sb.append(TagUtils.getInstance().filter(label));
340 } else {
341 sb.append(label);
342 }
343
344 sb.append("</option>\r\n");
345 }
346
347 /**
348 * Return an iterator for the options collection.
349 *
350 * @param collection Collection to be iterated over
351 * @throws JspException if an error occurs
352 */
353 protected Iterator getIterator(Object collection)
354 throws JspException {
355 if (collection.getClass().isArray()) {
356 collection = Arrays.asList((Object[]) collection);
357 }
358
359 if (collection instanceof Collection) {
360 return (((Collection) collection).iterator());
361 } else if (collection instanceof Iterator) {
362 return ((Iterator) collection);
363 } else if (collection instanceof Map) {
364 return (((Map) collection).entrySet().iterator());
365 } else if (collection instanceof Enumeration) {
366 return new IteratorAdapter((Enumeration) collection);
367 } else {
368 throw new JspException(messages.getMessage(
369 "optionsCollectionTag.iterator", collection.toString()));
370 }
371 }
372 }