001: /*
002: * $Id: SelectTag.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts.taglib.html;
022:
023: import org.apache.commons.beanutils.BeanUtils;
024: import org.apache.struts.taglib.TagUtils;
025: import org.apache.struts.util.MessageResources;
026:
027: import javax.servlet.jsp.JspException;
028:
029: import java.lang.reflect.InvocationTargetException;
030:
031: /**
032: * Custom tag that represents an HTML select element, associated with a bean
033: * property specified by our attributes. This tag must be nested inside a
034: * form tag.
035: *
036: * @version $Rev: 471754 $ $Date: 2004-10-16 12:38:42 -0400 (Sat, 16 Oct 2004)
037: * $
038: */
039: public class SelectTag extends BaseHandlerTag {
040: /**
041: * The message resources for this package.
042: */
043: protected static MessageResources messages = MessageResources
044: .getMessageResources(Constants.Package + ".LocalStrings");
045:
046: // ----------------------------------------------------- Instance Variables
047:
048: /**
049: * The actual values we will match against, calculated in doStartTag().
050: */
051: protected String[] match = null;
052:
053: /**
054: * Should multiple selections be allowed. Any non-null value will trigger
055: * rendering this.
056: */
057: protected String multiple = null;
058:
059: /**
060: * The name of the bean containing our underlying property.
061: */
062: protected String name = Constants.BEAN_KEY;
063:
064: /**
065: * The property name we are associated with.
066: */
067: protected String property = null;
068:
069: /**
070: * The saved body content of this tag.
071: */
072: protected String saveBody = null;
073:
074: /**
075: * How many available options should be displayed when this element is
076: * rendered?
077: */
078: protected String size = null;
079:
080: /**
081: * The value to compare with for marking an option selected.
082: */
083: protected String value = null;
084:
085: public String getMultiple() {
086: return (this .multiple);
087: }
088:
089: public void setMultiple(String multiple) {
090: this .multiple = multiple;
091: }
092:
093: public String getName() {
094: return (this .name);
095: }
096:
097: public void setName(String name) {
098: this .name = name;
099: }
100:
101: public String getSize() {
102: return (this .size);
103: }
104:
105: public void setSize(String size) {
106: this .size = size;
107: }
108:
109: // ------------------------------------------------------------- Properties
110:
111: /**
112: * Does the specified value match one of those we are looking for?
113: *
114: * @param value Value to be compared.
115: */
116: public boolean isMatched(String value) {
117: if ((this .match == null) || (value == null)) {
118: return false;
119: }
120:
121: for (int i = 0; i < this .match.length; i++) {
122: if (value.equals(this .match[i])) {
123: return true;
124: }
125: }
126:
127: return false;
128: }
129:
130: /**
131: * Return the property name.
132: */
133: public String getProperty() {
134: return (this .property);
135: }
136:
137: /**
138: * Set the property name.
139: *
140: * @param property The new property name
141: */
142: public void setProperty(String property) {
143: this .property = property;
144: }
145:
146: /**
147: * Return the comparison value.
148: */
149: public String getValue() {
150: return (this .value);
151: }
152:
153: /**
154: * Set the comparison value.
155: *
156: * @param value The new comparison value
157: */
158: public void setValue(String value) {
159: this .value = value;
160: }
161:
162: // --------------------------------------------------------- Public Methods
163:
164: /**
165: * Render the beginning of this select tag. <p> Support for indexed
166: * property since Struts 1.1
167: *
168: * @throws JspException if a JSP exception has occurred
169: */
170: public int doStartTag() throws JspException {
171: TagUtils.getInstance().write(pageContext,
172: renderSelectStartElement());
173:
174: // Store this tag itself as a page attribute
175: pageContext.setAttribute(Constants.SELECT_KEY, this );
176:
177: this .calculateMatchValues();
178:
179: return (EVAL_BODY_TAG);
180: }
181:
182: /**
183: * Create an appropriate select start element based on our parameters.
184: *
185: * @throws JspException
186: * @since Struts 1.1
187: */
188: protected String renderSelectStartElement() throws JspException {
189: StringBuffer results = new StringBuffer("<select");
190:
191: prepareAttribute(results, "name", prepareName());
192: prepareAttribute(results, "accesskey", getAccesskey());
193:
194: if (multiple != null) {
195: results.append(" multiple=\"multiple\"");
196: }
197:
198: prepareAttribute(results, "size", getSize());
199: prepareAttribute(results, "tabindex", getTabindex());
200: results.append(prepareEventHandlers());
201: results.append(prepareStyles());
202: prepareOtherAttributes(results);
203: results.append(">");
204:
205: return results.toString();
206: }
207:
208: /**
209: * Calculate the match values we will actually be using.
210: *
211: * @throws JspException
212: */
213: private void calculateMatchValues() throws JspException {
214: if (this .value != null) {
215: this .match = new String[1];
216: this .match[0] = this .value;
217: } else {
218: Object bean = TagUtils.getInstance().lookup(pageContext,
219: name, null);
220:
221: if (bean == null) {
222: JspException e = new JspException(messages.getMessage(
223: "getter.bean", name));
224:
225: TagUtils.getInstance().saveException(pageContext, e);
226: throw e;
227: }
228:
229: try {
230: this .match = BeanUtils.getArrayProperty(bean, property);
231:
232: if (this .match == null) {
233: this .match = new String[0];
234: }
235: } catch (IllegalAccessException e) {
236: TagUtils.getInstance().saveException(pageContext, e);
237: throw new JspException(messages.getMessage(
238: "getter.access", property, name));
239: } catch (InvocationTargetException e) {
240: Throwable t = e.getTargetException();
241:
242: TagUtils.getInstance().saveException(pageContext, t);
243: throw new JspException(messages.getMessage(
244: "getter.result", property, t.toString()));
245: } catch (NoSuchMethodException e) {
246: TagUtils.getInstance().saveException(pageContext, e);
247: throw new JspException(messages.getMessage(
248: "getter.method", property, name));
249: }
250: }
251: }
252:
253: /**
254: * Save any body content of this tag, which will generally be the
255: * option(s) representing the values displayed to the user.
256: *
257: * @throws JspException if a JSP exception has occurred
258: */
259: public int doAfterBody() throws JspException {
260: if (bodyContent != null) {
261: String value = bodyContent.getString();
262:
263: if (value == null) {
264: value = "";
265: }
266:
267: this .saveBody = value.trim();
268: }
269:
270: return (SKIP_BODY);
271: }
272:
273: /**
274: * Render the end of this form.
275: *
276: * @throws JspException if a JSP exception has occurred
277: */
278: public int doEndTag() throws JspException {
279: // Remove the page scope attributes we created
280: pageContext.removeAttribute(Constants.SELECT_KEY);
281:
282: // Render a tag representing the end of our current form
283: StringBuffer results = new StringBuffer();
284:
285: if (saveBody != null) {
286: results.append(saveBody);
287: saveBody = null;
288: }
289:
290: results.append("</select>");
291:
292: TagUtils.getInstance().write(pageContext, results.toString());
293:
294: return (EVAL_PAGE);
295: }
296:
297: /**
298: * Prepare the name element
299: *
300: * @return The element name.
301: */
302: protected String prepareName() 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: }
|