View Javadoc

1   /*
2    * $Id: OptionsCollectionTag.java 376841 2006-02-10 21:01:28Z husted $
3    *
4    * Copyright 2002-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
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      // ----------------------------------------------------- Instance Variables
51  
52      /***
53       * The message resources for this package.
54       */
55      protected static MessageResources messages =
56          MessageResources.getMessageResources(Constants.Package
57              + ".LocalStrings");
58  
59      // ------------------------------------------------------------- Properties
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     // --------------------------------------------------------- Public Methods
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         // Acquire the select tag we are associated with
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         // Acquire the collection containing our options
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         // Acquire an iterator over the options collection
187         Iterator iter = getIterator(collection);
188 
189         StringBuffer sb = new StringBuffer();
190 
191         // Render the options
192         while (iter.hasNext()) {
193             Object bean = iter.next();
194             Object beanLabel = null;
195             Object beanValue = null;
196 
197             // Get the label for this option
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             // Get the value for this option
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             // Render this option
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     // ------------------------------------------------------ Protected Methods
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 }