View Javadoc

1   /*
2    * $Id: SelectTag.java 376841 2006-02-10 21:01:28Z husted $
3    *
4    * Copyright 1999-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.BeanUtils;
21  import org.apache.struts.taglib.TagUtils;
22  import org.apache.struts.util.MessageResources;
23  
24  import javax.servlet.jsp.JspException;
25  
26  import java.lang.reflect.InvocationTargetException;
27  
28  /***
29   * Custom tag that represents an HTML select element, associated with a bean
30   * property specified by our attributes.  This tag must be nested inside a
31   * form tag.
32   *
33   * @version $Rev: 376841 $ $Date: 2004-10-16 12:38:42 -0400 (Sat, 16 Oct 2004)
34   *          $
35   */
36  public class SelectTag extends BaseHandlerTag {
37      /***
38       * The message resources for this package.
39       */
40      protected static MessageResources messages =
41          MessageResources.getMessageResources(Constants.Package
42              + ".LocalStrings");
43  
44      // ----------------------------------------------------- Instance Variables
45  
46      /***
47       * The actual values we will match against, calculated in doStartTag().
48       */
49      protected String[] match = null;
50  
51      /***
52       * Should multiple selections be allowed.  Any non-null value will trigger
53       * rendering this.
54       */
55      protected String multiple = null;
56  
57      /***
58       * The name of the bean containing our underlying property.
59       */
60      protected String name = Constants.BEAN_KEY;
61  
62      /***
63       * The property name we are associated with.
64       */
65      protected String property = null;
66  
67      /***
68       * The saved body content of this tag.
69       */
70      protected String saveBody = null;
71  
72      /***
73       * How many available options should be displayed when this element is
74       * rendered?
75       */
76      protected String size = null;
77  
78      /***
79       * The value to compare with for marking an option selected.
80       */
81      protected String value = null;
82  
83      public String getMultiple() {
84          return (this.multiple);
85      }
86  
87      public void setMultiple(String multiple) {
88          this.multiple = multiple;
89      }
90  
91      public String getName() {
92          return (this.name);
93      }
94  
95      public void setName(String name) {
96          this.name = name;
97      }
98  
99      public String getSize() {
100         return (this.size);
101     }
102 
103     public void setSize(String size) {
104         this.size = size;
105     }
106 
107     // ------------------------------------------------------------- Properties
108 
109     /***
110      * Does the specified value match one of those we are looking for?
111      *
112      * @param value Value to be compared.
113      */
114     public boolean isMatched(String value) {
115         if ((this.match == null) || (value == null)) {
116             return false;
117         }
118 
119         for (int i = 0; i < this.match.length; i++) {
120             if (value.equals(this.match[i])) {
121                 return true;
122             }
123         }
124 
125         return false;
126     }
127 
128     /***
129      * Return the property name.
130      */
131     public String getProperty() {
132         return (this.property);
133     }
134 
135     /***
136      * Set the property name.
137      *
138      * @param property The new property name
139      */
140     public void setProperty(String property) {
141         this.property = property;
142     }
143 
144     /***
145      * Return the comparison value.
146      */
147     public String getValue() {
148         return (this.value);
149     }
150 
151     /***
152      * Set the comparison value.
153      *
154      * @param value The new comparison value
155      */
156     public void setValue(String value) {
157         this.value = value;
158     }
159 
160     // --------------------------------------------------------- Public Methods
161 
162     /***
163      * Render the beginning of this select tag. <p> Support for indexed
164      * property since Struts 1.1
165      *
166      * @throws JspException if a JSP exception has occurred
167      */
168     public int doStartTag() throws JspException {
169         TagUtils.getInstance().write(pageContext, renderSelectStartElement());
170 
171         // Store this tag itself as a page attribute
172         pageContext.setAttribute(Constants.SELECT_KEY, this);
173 
174         this.calculateMatchValues();
175 
176         return (EVAL_BODY_TAG);
177     }
178 
179     /***
180      * Create an appropriate select start element based on our parameters.
181      *
182      * @throws JspException
183      * @since Struts 1.1
184      */
185     protected String renderSelectStartElement()
186         throws JspException {
187         StringBuffer results = new StringBuffer("<select");
188 
189         prepareAttribute(results, "name", prepareName());
190         prepareAttribute(results, "accesskey", getAccesskey());
191 
192         if (multiple != null) {
193             results.append(" multiple=\"multiple\"");
194         }
195 
196         prepareAttribute(results, "size", getSize());
197         prepareAttribute(results, "tabindex", getTabindex());
198         results.append(prepareEventHandlers());
199         results.append(prepareStyles());
200         prepareOtherAttributes(results);
201         results.append(">");
202 
203         return results.toString();
204     }
205 
206     /***
207      * Calculate the match values we will actually be using.
208      *
209      * @throws JspException
210      */
211     private void calculateMatchValues()
212         throws JspException {
213         if (this.value != null) {
214             this.match = new String[1];
215             this.match[0] = this.value;
216         } else {
217             Object bean =
218                 TagUtils.getInstance().lookup(pageContext, name, null);
219 
220             if (bean == null) {
221                 JspException e =
222                     new JspException(messages.getMessage("getter.bean", name));
223 
224                 TagUtils.getInstance().saveException(pageContext, e);
225                 throw e;
226             }
227 
228             try {
229                 this.match = BeanUtils.getArrayProperty(bean, property);
230 
231                 if (this.match == null) {
232                     this.match = new String[0];
233                 }
234             } catch (IllegalAccessException e) {
235                 TagUtils.getInstance().saveException(pageContext, e);
236                 throw new JspException(messages.getMessage("getter.access",
237                         property, name));
238             } catch (InvocationTargetException e) {
239                 Throwable t = e.getTargetException();
240 
241                 TagUtils.getInstance().saveException(pageContext, t);
242                 throw new JspException(messages.getMessage("getter.result",
243                         property, t.toString()));
244             } catch (NoSuchMethodException e) {
245                 TagUtils.getInstance().saveException(pageContext, e);
246                 throw new JspException(messages.getMessage("getter.method",
247                         property, name));
248             }
249         }
250     }
251 
252     /***
253      * Save any body content of this tag, which will generally be the
254      * option(s) representing the values displayed to the user.
255      *
256      * @throws JspException if a JSP exception has occurred
257      */
258     public int doAfterBody() throws JspException {
259         if (bodyContent != null) {
260             String value = bodyContent.getString();
261 
262             if (value == null) {
263                 value = "";
264             }
265 
266             this.saveBody = value.trim();
267         }
268 
269         return (SKIP_BODY);
270     }
271 
272     /***
273      * Render the end of this form.
274      *
275      * @throws JspException if a JSP exception has occurred
276      */
277     public int doEndTag() throws JspException {
278         // Remove the page scope attributes we created
279         pageContext.removeAttribute(Constants.SELECT_KEY);
280 
281         // Render a tag representing the end of our current form
282         StringBuffer results = new StringBuffer();
283 
284         if (saveBody != null) {
285             results.append(saveBody);
286             saveBody = null;
287         }
288 
289         results.append("</select>");
290 
291         TagUtils.getInstance().write(pageContext, results.toString());
292 
293         return (EVAL_PAGE);
294     }
295 
296     /***
297      * Prepare the name element
298      *
299      * @return The element name.
300      */
301     protected String prepareName()
302         throws JspException {
303         if (property == null) {
304             return null;
305         }
306 
307         // * @since Struts 1.1
308         if (indexed) {
309             StringBuffer results = new StringBuffer();
310 
311             prepareIndex(results, name);
312             results.append(property);
313 
314             return results.toString();
315         }
316 
317         return property;
318     }
319 
320     /***
321      * Release any acquired resources.
322      */
323     public void release() {
324         super.release();
325         match = null;
326         multiple = null;
327         name = Constants.BEAN_KEY;
328         property = null;
329         saveBody = null;
330         size = null;
331         value = null;
332     }
333 }