KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > tags > form > OptionWriter


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.servlet.tags.form;
18
19 import java.util.Collection JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.Map JavaDoc;
22
23 import javax.servlet.jsp.JspException JavaDoc;
24
25 import org.springframework.beans.BeanWrapper;
26 import org.springframework.beans.BeanWrapperImpl;
27 import org.springframework.util.Assert;
28 import org.springframework.util.CollectionUtils;
29 import org.springframework.web.servlet.support.BindStatus;
30
31 /**
32  * Provides supporting functionality to render a list of '<code>option</code>'
33  * tags based on some source object. This object can be either an array, a
34  * {@link Collection} or a {@link Map}.
35  *
36  * <h3>Using an array or a {@link Collection}</h3>
37  * In the first approach you specify an array or {@link Collection} source object
38  * which are used to render the inner '<code>option</code>' tags. When using
39  * this approach you specify the name of the property on the objects which
40  * corresponds to the value of the rendered '<code>option</code>' and the name
41  * of the property that corresponds to the label. These properties are then used
42  * when rendering each element of the array/{@link Collection} as an '<code>option</code>'.
43  * When the either property name is ommitted the name of the {@link Object#toString()} of
44  * the array/{@link Collection} element is used.
45  * Property names are specified as arguments to the constructor.
46  * <h3>Using a {@link Map}</h3>
47  * In the second approach, '<code>option</code>' tags are rendered from a source
48  * {@link Map}. The key and value of the entries in the {@link Map} correspond
49  * to the value and label of the rendered '<code>option</code>'.
50  *
51  * <p>When using any of these approaches, an '<code>option</code>' is marked
52  * as 'selected' if its key {@link #isSelected matches} the value that
53  * is bound to the tag instance.
54  *
55  * @author Rob Harrop
56  * @since 2.0
57  */

58 final class OptionWriter {
59
60     private final ValueFormatter valueFormatter = new ValueFormatter();
61
62     private final Object JavaDoc optionSource;
63
64     private final BindStatus bindStatus;
65
66     private final String JavaDoc valueProperty;
67
68     private final String JavaDoc labelProperty;
69
70     private final boolean htmlEscape;
71
72
73     /**
74      * Creates a new <code>OptionWriter</code> for the supplied <code>objectSource</code>.
75      * @param optionSource the source of the <code>options</code> (never <code>null</code>)
76      * @param bindStatus the {@link BindStatus} for the bound value (never <code>null</code>)
77      * @param valueProperty the name of the property used to render <code>option</code> values
78      * (optional)
79      * @param labelProperty the name of the property used to render <code>option</code> labels
80      * (optional)
81      */

82     public OptionWriter(
83             Object JavaDoc optionSource, BindStatus bindStatus, String JavaDoc valueProperty, String JavaDoc labelProperty, boolean htmlEscape) {
84
85         Assert.notNull(optionSource, "'optionSource' must not be null");
86         Assert.notNull(bindStatus, "'bindStatus' must not be null");
87         this.optionSource = optionSource;
88         this.bindStatus = bindStatus;
89         this.valueProperty = valueProperty;
90         this.labelProperty = labelProperty;
91         this.htmlEscape = htmlEscape;
92     }
93
94     /**
95      * Write the '<code>option</code>' tags for the configured {@link #optionSource} to
96      * the supplied {@link TagWriter}.
97      */

98     public void writeOptions(TagWriter tagWriter) throws JspException JavaDoc {
99         if (this.optionSource.getClass().isArray()) {
100             renderFromArray(tagWriter);
101         }
102         else if (this.optionSource instanceof Collection JavaDoc) {
103             renderFromCollection(tagWriter);
104         }
105         else if (this.optionSource instanceof Map JavaDoc) {
106             renderFromMap(tagWriter);
107         }
108         else {
109             throw new JspException JavaDoc(
110                     "Type [" + this.optionSource.getClass().getName() + "] is not valid for option items");
111         }
112     }
113
114     /**
115      * Renders the inner '<code>option</code>' tags using the {@link #optionSource}.
116      * @see #doRenderFromCollection(java.util.Collection, TagWriter)
117      */

118     private void renderFromArray(TagWriter tagWriter) throws JspException JavaDoc {
119         doRenderFromCollection(CollectionUtils.arrayToList(this.optionSource), tagWriter);
120     }
121
122     /**
123      * Renders the inner '<code>option</code>' tags using the supplied {@link Map} as
124      * the source.
125      * @see #renderOption
126      */

127     private void renderFromMap(TagWriter tagWriter) throws JspException JavaDoc {
128         Map JavaDoc optionMap = (Map JavaDoc) this.optionSource;
129         for (Iterator JavaDoc iterator = optionMap.entrySet().iterator(); iterator.hasNext();) {
130             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
131             renderOption(tagWriter, entry, entry.getKey().toString(), entry.getValue().toString());
132         }
133     }
134
135     /**
136      * Renders the inner '<code>option</code>' tags using the {@link #optionSource}.
137      * @see #doRenderFromCollection(java.util.Collection, TagWriter)
138      */

139     private void renderFromCollection(TagWriter tagWriter) throws JspException JavaDoc {
140         doRenderFromCollection((Collection JavaDoc) this.optionSource, tagWriter);
141     }
142
143     /**
144      * Renders the inner '<code>option</code>' tags using the supplied {@link Collection} of
145      * objects as the source. The value of the {@link #valueProperty} field is used
146      * when rendering the '<code>value</code>' of the '<code>option</code>' and the value of the
147      * {@link #labelProperty} property is used when rendering the label.
148      */

149     private void doRenderFromCollection(Collection JavaDoc optionCollection, TagWriter tagWriter) throws JspException JavaDoc {
150         for (Iterator JavaDoc it = optionCollection.iterator(); it.hasNext();) {
151             Object JavaDoc item = it.next();
152             BeanWrapper wrapper = new BeanWrapperImpl(item);
153             Object JavaDoc value = (this.valueProperty != null ? wrapper.getPropertyValue(this.valueProperty) : item);
154             Object JavaDoc label = (this.labelProperty != null ? wrapper.getPropertyValue(this.labelProperty) : item);
155             renderOption(tagWriter, item, value, label);
156         }
157     }
158
159     /**
160      * Renders an HTML '<code>option</code>' with the supplied value and label. Marks the
161      * value as 'selected' if either the item itself or its value match the bound value.
162      */

163     private void renderOption(TagWriter tagWriter, Object JavaDoc item, Object JavaDoc value, Object JavaDoc label) throws JspException JavaDoc {
164         tagWriter.startTag("option");
165
166         String JavaDoc valueDisplayString = getDisplayString(value);
167         String JavaDoc labelDisplayString = getDisplayString(label);
168
169         // allows render values to handle some strange browser compat issues.
170
tagWriter.writeAttribute("value", valueDisplayString);
171
172         if (isSelected(value) || isSelected(item)) {
173             tagWriter.writeAttribute("selected", "selected");
174         }
175         tagWriter.appendValue(labelDisplayString);
176         tagWriter.endTag();
177     }
178
179     /**
180      * Determine whether the supplied values matched the selected value.
181      * Delegates to {@link SelectedValueComparator#isSelected}.
182      */

183     private boolean isSelected(Object JavaDoc resolvedValue) {
184         return SelectedValueComparator.isSelected(this.bindStatus, resolvedValue);
185     }
186
187     /**
188      * Determines the display value of the supplied <code>Object</code>,
189      * HTML-escaped as required.
190      * @see ValueFormatter
191      */

192     private String JavaDoc getDisplayString(Object JavaDoc value) {
193         return this.valueFormatter.getDisplayString(value, this.bindStatus.getEditor(), this.htmlEscape);
194     }
195
196 }
197
Popular Tags