001: /*
002: * $Id: OptionsCollectionTag.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.PropertyUtils;
024: import org.apache.struts.taglib.TagUtils;
025: import org.apache.struts.util.IteratorAdapter;
026: import org.apache.struts.util.MessageResources;
027:
028: import javax.servlet.jsp.JspException;
029: import javax.servlet.jsp.tagext.TagSupport;
030:
031: import java.lang.reflect.InvocationTargetException;
032:
033: import java.util.Arrays;
034: import java.util.Collection;
035: import java.util.Enumeration;
036: import java.util.Iterator;
037: import java.util.Map;
038:
039: /**
040: * Tag for creating multiple <select> options from a collection. The
041: * collection may be part of the enclosing form, or may be independent of the
042: * form. Each element of the collection must expose a 'label' and a 'value',
043: * the property names of which are configurable by attributes of this tag. <p>
044: * The collection may be an array of objects, a Collection, an Enumeration, an
045: * Iterator, or a Map. <p> <b>NOTE</b> - This tag requires a Java2 (JDK 1.2 or
046: * later) platform.
047: *
048: * @version $Rev: 471754 $ $Date: 2004-11-03 14:20:47 -0500 (Wed, 03 Nov 2004)
049: * $
050: * @since Struts 1.1
051: */
052: public class OptionsCollectionTag extends TagSupport {
053: // ----------------------------------------------------- Instance Variables
054:
055: /**
056: * The message resources for this package.
057: */
058: protected static MessageResources messages = MessageResources
059: .getMessageResources(Constants.Package + ".LocalStrings");
060:
061: // ------------------------------------------------------------- Properties
062:
063: /**
064: * Should the label values be filtered for HTML sensitive characters?
065: */
066: protected boolean filter = true;
067:
068: /**
069: * The name of the bean property containing the label.
070: */
071: protected String label = "label";
072:
073: /**
074: * The name of the bean containing the values collection.
075: */
076: protected String name = Constants.BEAN_KEY;
077:
078: /**
079: * The name of the property to use to build the values collection.
080: */
081: protected String property = null;
082:
083: /**
084: * The style associated with this tag.
085: */
086: private String style = null;
087:
088: /**
089: * The named style class associated with this tag.
090: */
091: private String styleClass = null;
092:
093: /**
094: * The name of the bean property containing the value.
095: */
096: protected String value = "value";
097:
098: public boolean getFilter() {
099: return filter;
100: }
101:
102: public void setFilter(boolean filter) {
103: this .filter = filter;
104: }
105:
106: public String getLabel() {
107: return label;
108: }
109:
110: public void setLabel(String label) {
111: this .label = label;
112: }
113:
114: public String getName() {
115: return name;
116: }
117:
118: public void setName(String name) {
119: this .name = name;
120: }
121:
122: public String getProperty() {
123: return property;
124: }
125:
126: public void setProperty(String property) {
127: this .property = property;
128: }
129:
130: public String getStyle() {
131: return style;
132: }
133:
134: public void setStyle(String style) {
135: this .style = style;
136: }
137:
138: public String getStyleClass() {
139: return styleClass;
140: }
141:
142: public void setStyleClass(String styleClass) {
143: this .styleClass = styleClass;
144: }
145:
146: public String getValue() {
147: return value;
148: }
149:
150: public void setValue(String value) {
151: this .value = value;
152: }
153:
154: // --------------------------------------------------------- Public Methods
155:
156: /**
157: * Process the start of this tag.
158: *
159: * @throws JspException if a JSP exception has occurred
160: */
161: public int doStartTag() throws JspException {
162: // Acquire the select tag we are associated with
163: SelectTag selectTag = (SelectTag) pageContext
164: .getAttribute(Constants.SELECT_KEY);
165:
166: if (selectTag == null) {
167: JspException e = new JspException(messages
168: .getMessage("optionsCollectionTag.select"));
169:
170: TagUtils.getInstance().saveException(pageContext, e);
171: throw e;
172: }
173:
174: // Acquire the collection containing our options
175: Object collection = TagUtils.getInstance().lookup(pageContext,
176: name, property, null);
177:
178: if (collection == null) {
179: JspException e = new JspException(messages
180: .getMessage("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 = new JspException(messages
206: .getMessage("getter.access", label, bean));
207:
208: TagUtils.getInstance().saveException(pageContext, jspe);
209: throw jspe;
210: } catch (InvocationTargetException e) {
211: Throwable t = e.getTargetException();
212: JspException jspe = new JspException(messages
213: .getMessage("getter.result", label, t
214: .toString()));
215:
216: TagUtils.getInstance().saveException(pageContext, jspe);
217: throw jspe;
218: } catch (NoSuchMethodException e) {
219: JspException jspe = new JspException(messages
220: .getMessage("getter.method", label, bean));
221:
222: TagUtils.getInstance().saveException(pageContext, jspe);
223: throw jspe;
224: }
225:
226: // Get the value for this option
227: try {
228: beanValue = PropertyUtils.getProperty(bean, value);
229:
230: if (beanValue == null) {
231: beanValue = "";
232: }
233: } catch (IllegalAccessException e) {
234: JspException jspe = new JspException(messages
235: .getMessage("getter.access", value, bean));
236:
237: TagUtils.getInstance().saveException(pageContext, jspe);
238: throw jspe;
239: } catch (InvocationTargetException e) {
240: Throwable t = e.getTargetException();
241: JspException jspe = new JspException(messages
242: .getMessage("getter.result", value, t
243: .toString()));
244:
245: TagUtils.getInstance().saveException(pageContext, jspe);
246: throw jspe;
247: } catch (NoSuchMethodException e) {
248: JspException jspe = new JspException(messages
249: .getMessage("getter.method", value, bean));
250:
251: TagUtils.getInstance().saveException(pageContext, jspe);
252: throw jspe;
253: }
254:
255: String stringLabel = beanLabel.toString();
256: String stringValue = beanValue.toString();
257:
258: // Render this option
259: addOption(sb, stringLabel, stringValue, selectTag
260: .isMatched(stringValue));
261: }
262:
263: TagUtils.getInstance().write(pageContext, sb.toString());
264:
265: return SKIP_BODY;
266: }
267:
268: /**
269: * Release any acquired resources.
270: */
271: public void release() {
272: super .release();
273: filter = true;
274: label = "label";
275: name = Constants.BEAN_KEY;
276: property = null;
277: style = null;
278: styleClass = null;
279: value = "value";
280: }
281:
282: // ------------------------------------------------------ Protected Methods
283:
284: /**
285: * Add an option element to the specified StringBuffer based on the
286: * specified parameters. <p> Note that this tag specifically does not
287: * support the <code>styleId</code> tag attribute, which causes the HTML
288: * <code>id</code> attribute to be emitted. This is because the HTML
289: * specification states that all "id" attributes in a document have to be
290: * unique. This tag will likely generate more than one
291: * <code>option</code> element element, but it cannot use the same
292: * <code>id</code> value. It's conceivable some sort of mechanism to
293: * supply an array of <code>id</code> values could be devised, but that
294: * doesn't seem to be worth the trouble.
295: *
296: * @param sb StringBuffer accumulating our results
297: * @param value Value to be returned to the server for this option
298: * @param label Value to be shown to the user for this option
299: * @param matched Should this value be marked as selected?
300: */
301: protected void addOption(StringBuffer sb, String label,
302: String value, boolean matched) {
303: sb.append("<option value=\"");
304:
305: if (filter) {
306: sb.append(TagUtils.getInstance().filter(value));
307: } else {
308: sb.append(value);
309: }
310:
311: sb.append("\"");
312:
313: if (matched) {
314: sb.append(" selected=\"selected\"");
315: }
316:
317: if (style != null) {
318: sb.append(" style=\"");
319: sb.append(style);
320: sb.append("\"");
321: }
322:
323: if (styleClass != null) {
324: sb.append(" class=\"");
325: sb.append(styleClass);
326: sb.append("\"");
327: }
328:
329: sb.append(">");
330:
331: if (filter) {
332: sb.append(TagUtils.getInstance().filter(label));
333: } else {
334: sb.append(label);
335: }
336:
337: sb.append("</option>\r\n");
338: }
339:
340: /**
341: * Return an iterator for the options collection.
342: *
343: * @param collection Collection to be iterated over
344: * @throws JspException if an error occurs
345: */
346: protected Iterator getIterator(Object collection)
347: throws JspException {
348: if (collection.getClass().isArray()) {
349: collection = Arrays.asList((Object[]) collection);
350: }
351:
352: if (collection instanceof Collection) {
353: return (((Collection) collection).iterator());
354: } else if (collection instanceof Iterator) {
355: return ((Iterator) collection);
356: } else if (collection instanceof Map) {
357: return (((Map) collection).entrySet().iterator());
358: } else if (collection instanceof Enumeration) {
359: return new IteratorAdapter((Enumeration) collection);
360: } else {
361: throw new JspException(messages.getMessage(
362: "optionsCollectionTag.iterator", collection
363: .toString()));
364: }
365: }
366: }
|