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