##### Coverage Report - org.seasar.cubby.tags.SelectTag

Classes in this File | Line Coverage | Branch Coverage | Complexity
SelectTag |
88% | 44/50
60% | 12/20
| 2.263157894736842;2.263
SelectTag$BeanItemAdaptor |
100% | 12/12
100% | 4/4
| 2.263157894736842;2.263
SelectTag$EntryItemAdaptor |
100% | 12/12
75% | 6/8
| 2.263157894736842;2.263
SelectTag$ItemAdaptor |
N/A | N/A
N/A | N/A
| 2.263157894736842;2.263
SelectTag$OptionWriter |
94% | 17/18
66% | 4/6
| 2.263157894736842;2.263

1 |  |
     /*
2 |  |
      * Copyright 2004-2009 the Seasar Foundation and the Others.
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,
13 |  |
      * either express or implied. See the License for the specific language
14 |  |
      * governing permissions and limitations under the License.
15 |  |
      */
16 |  |
     package org.seasar.cubby.tags;
17 |  |
18 |  |
     import static org.seasar.cubby.internal.util.LogMessages.format;
19 |  |
     import static org.seasar.cubby.tags.TagUtils.addCSSClassName;
20 |  |
     import static org.seasar.cubby.tags.TagUtils.contains;
21 |  |
     import static org.seasar.cubby.tags.TagUtils.errors;
22 |  |
     import static org.seasar.cubby.tags.TagUtils.getFormWrapper;
23 |  |
     import static org.seasar.cubby.tags.TagUtils.multipleFormValues;
24 |  |
     import static org.seasar.cubby.tags.TagUtils.toAttr;
25 |  |
26 |  |
     import java.io.IOException;
27 |  |
     import java.util.Collection;
28 |  |
     import java.util.Map;
29 |  |
     import java.util.Map.Entry;
30 |  |
31 |  |
     import javax.servlet.jsp.JspContext;
32 |  |
     import javax.servlet.jsp.JspException;
33 |  |
     import javax.servlet.jsp.JspTagException;
34 |  |
     import javax.servlet.jsp.JspWriter;
35 |  |
36 |  |
     import org.seasar.cubby.action.ActionErrors;
37 |  |
     import org.seasar.cubby.controller.FormWrapper;
38 |  |
     import org.seasar.cubby.spi.beans.Attribute;
39 |  |
     import org.seasar.cubby.spi.beans.BeanDesc;
40 |  |
     import org.seasar.cubby.spi.beans.BeanDescFactory;
41 |  |
     import org.slf4j.Logger;
42 |  |
     import org.slf4j.LoggerFactory;
43 |  |
44 |  |
     /**
45 |  |
      * <code>&lt;select&gt;</code> タグを出力します。
46 |  |
      *
47 |  |
      * @author agata
48 |  |
      * @author baba
49 |  |
      */
50 | 91 |
     public class SelectTag extends DynamicAttributesSimpleTagSupport {
51 |  |
52 |  |
             /** <code>name</code> 属性。 */
53 |  |
             private String name;
54 |  |
55 |  |
             /** <code>&lt;option&gt;</code> 要素のリスト。 */
56 |  |
             private Object items;
57 |  |
58 |  |
             /** <code>option</code> のラベルのプロパティ名。 */
59 |  |
             private String labelProperty;
60 |  |
61 |  |
             /** <code>option</code> の値のプロパティ名。 */
62 |  |
             private String valueProperty;
63 |  |
64 |  |
             /** 空の <code>&lt;option&gt;</code> 要素を出力するかどうか。 */
65 | 14 |
             private Boolean emptyOption = Boolean.TRUE;
66 |  |
67 |  |
             /** 空の <code>&lt;option&gt;</code> 要素を出力した場合のラベル文字列。 */
68 |  |
             private String emptyOptionLabel;
69 |  |
70 |  |
             /**
71 |  |
              * <code>&lt;option&gt;</code> 要素のリストを設定します。
72 |  |
              *
73 |  |
              * @param items
74 |  |
              *            <code>&lt;option&gt;</code> 要素のリスト
75 |  |
              */
76 |  |
             public void setItems(final Object items) {
77 | 14 |
                     this.items = items;
78 | 14 |
             }
79 |  |
80 |  |
             /**
81 |  |
              * <code>items</code> から <code>&lt;option&gtl</code> 要素をのラベルを取得する時の名前を設定します。
82 |  |
              *
83 |  |
              * @param labelProperty
84 |  |
              *            <code>items</code> から <code>&lt;option&gtl</code>
85 |  |
              *            要素をのラベルを取得する時の名前
86 |  |
              */
87 |  |
             public void setLabelProperty(final String labelProperty) {
88 | 6 |
                     this.labelProperty = labelProperty;
89 | 6 |
             }
90 |  |
91 |  |
             /**
92 |  |
              * <code>items</code> から <code>&lt;option&gtl</code> 要素をの値を取得する時の名前を設定します。
93 |  |
              *
94 |  |
              * @param valueProperty
95 |  |
              *            <code>items</code> から <code>&lt;option&gtl</code>
96 |  |
              *            要素をの値を取得する時の名前
97 |  |
              */
98 |  |
             public void setValueProperty(final String valueProperty) {
99 | 7 |
                     this.valueProperty = valueProperty;
100 | 7 |
             }
101 |  |
102 |  |
             /**
103 |  |
              * 空の <code>&lt;option&gtl</code> 要素を出力するかどうかを設定します。
104 |  |
              *
105 |  |
              * @param emptyOption
106 |  |
              *            空の <code>&lt;option&gtl</code> 要素を出力するかどうか
107 |  |
              */
108 |  |
             public void setEmptyOption(final Boolean emptyOption) {
109 | 2 |
                     this.emptyOption = emptyOption;
110 | 2 |
             }
111 |  |
112 |  |
             /**
113 |  |
              * 空の <code>&lt;option&gtl</code> 要素を出力した場合のラベル文字列を設定します。
114 |  |
              *
115 |  |
              * @param emptyOptionLabel
116 |  |
              *            空の <code>&lt;option&gtl</code> 要素を出力した場合のラベル文字列
117 |  |
              */
118 |  |
             public void setEmptyOptionLabel(final String emptyOptionLabel) {
119 | 3 |
                     this.emptyOptionLabel = emptyOptionLabel;
120 | 3 |
             }
121 |  |
122 |  |
             /**
123 |  |
              * <code>name</code> 属性を設定します。
124 |  |
              *
125 |  |
              * @param name
126 |  |
              *            <code>name</code> 属性
127 |  |
              */
128 |  |
             public void setName(final String name) {
129 | 14 |
                     this.name = name;
130 | 14 |
             }
131 |  |
132 |  |
             /**
133 |  |
              * {@inheritDoc}
134 |  |
              */
135 |  |
             @Override
136 |  |
             public void doTag() throws JspException, IOException {
137 | 14 |
                     if (items == null) {
138 | 1 |
                             throw new JspTagException(format("ECUB1005"));
139 |  |
                     }
140 | 13 |
                     final JspContext context = this.getJspContext();
141 | 13 |
                     final JspWriter out = context.getOut();
142 | 13 |
                     final ActionErrors errors = errors(context);
143 | 13 |
                     final Map<String, Object> dyn = this.getDynamicAttributes();
144 | 13 |
                     final FormWrapper formWrapper = getFormWrapper(this);
145 |  |
146 | 13 |
                     if (!errors.getFields().get(this.name).isEmpty()) {
147 | 0 |
                             addCSSClassName(dyn, "fieldError");
148 |  |
                     }
149 |  |
150 | 13 |
                     final Object[] value = multipleFormValues(context, formWrapper,
151 |  |
                                     this.name);
152 |  |
153 | 13 |
                     out.write("<select name=\"");
154 | 13 |
                     out.write(this.name);
155 | 13 |
                     out.write("\" ");
156 | 13 |
                     out.write(toAttr(dyn));
157 | 13 |
                     out.write(">\n");
158 |  |
159 | 13 |
                     if (emptyOption) {
160 | 11 |
                             out.write("<option value=\"\">");
161 | 11 |
                             out.write(CubbyFunctions.out(emptyOptionLabel));
162 | 11 |
                             out.write("</option>\n");
163 |  |
                     }
164 |  |
165 | 13 |
                     if (items != null && items.getClass().isArray()) {
166 | 0 |
                             final OptionWriter optionWriter = new OptionWriter(
167 |  |
                                             new BeanItemAdaptor());
168 | 0 |
                             for (final Object item : (Object[]) items) {
169 | 0 |
                                     optionWriter.write(out, item, value);
170 |  |
                             }
171 | 0 |
                     } else {
172 |  |
                             final OptionWriter optionWriter;
173 |  |
                             final Collection<?> collection;
174 | 13 |
                             if (items instanceof Collection) {
175 | 6 |
                                     optionWriter = new OptionWriter(new BeanItemAdaptor());
176 | 5 |
                                     collection = (Collection<?>) items;
177 | 7 |
                             } else if (items instanceof Map) {
178 | 7 |
                                     optionWriter = new OptionWriter(new EntryItemAdaptor());
179 | 7 |
                                     collection = ((Map<?, ?>) items).entrySet();
180 |  |
                             } else {
181 | 0 |
                                     throw new JspTagException(format("ECUB1001", "items",
182 |  |
                                                     items == null ? null : items.getClass()));
183 |  |
                             }
184 | 12 |
                             for (final Object item : collection) {
185 | 36 |
                                     optionWriter.write(out, item, value);
186 |  |
                             }
187 |  |
                     }
188 |  |
189 | 12 |
                     out.write("</select>");
190 | 12 |
             }
191 |  |
192 |  |
             private static class OptionWriter {
193 |  |
194 |  |
                     private final ItemAdaptor itemAdaptor;
195 |  |
196 | 12 |
                     OptionWriter(final ItemAdaptor itemAdaptor) {
197 | 12 |
                             this.itemAdaptor = itemAdaptor;
198 | 12 |
                     }
199 |  |
200 |  |
                     void write(final JspWriter out, final Object item, final Object value)
201 |  |
                                     throws IOException {
202 | 36 |
                             out.write("<option value=\"");
203 | 36 |
                             final String itemValue = TagUtils.toString(itemAdaptor
204 |  |
                                             .getItemValue(item));
205 | 36 |
                             final String labelValue = TagUtils.toString(itemAdaptor
206 |  |
                                             .getLabelValue(item));
207 | 36 |
                             out.write(CubbyFunctions.out(itemValue));
208 | 36 |
                             out.write("\" ");
209 | 36 |
                             out.write(selected(itemValue, value));
210 | 36 |
                             out.write(">");
211 | 36 |
                             out.write(CubbyFunctions.out(labelValue));
212 | 36 |
                             out.write("</option>\n");
213 | 36 |
                     }
214 |  |
215 |  |
                     private String selected(final String value, final Object values) {
216 | 36 |
                             if (value == null || values == null) {
217 | 0 |
                                     return "";
218 |  |
                             }
219 | 36 |
                             if (contains(values, value)) {
220 | 14 |
                                     return "selected=\"selected\"";
221 |  |
                             } else {
222 | 22 |
                                     return "";
223 |  |
                             }
224 |  |
                     }
225 |  |
             }
226 |  |
227 |  |
             private interface ItemAdaptor {
228 |  |
229 |  |
                     /**
230 |  |
                      * 要素の値を取得します。
231 |  |
                      *
232 |  |
                      * @param item
233 |  |
                      *            要素
234 |  |
                      * @return 要素の値
235 |  |
                      */
236 |  |
                     Object getItemValue(Object item);
237 |  |
238 |  |
                     /**
239 |  |
                      * 要素のラベルを取得します。
240 |  |
                      *
241 |  |
                      * @param item
242 |  |
                      *            要素
243 |  |
                      * @return 要素のラベル
244 |  |
                      */
245 |  |
                     Object getLabelValue(Object item);
246 |  |
247 |  |
             }
248 |  |
249 |  |
             private class BeanItemAdaptor implements ItemAdaptor {
250 |  |
251 | 6 |
                     BeanItemAdaptor() throws JspTagException {
252 | 6 |
                             if (valueProperty == null) {
253 | 1 |
                                     throw new JspTagException(format("ECUB1002", "items",
254 |  |
                                                     "valueProperty"));
255 |  |
                             }
256 | 5 |
                     }
257 |  |
258 |  |
                     /**
259 |  |
                      * {@inheritDoc}
260 |  |
                      */
261 |  |
                     public Object getItemValue(final Object item) {
262 | 18 |
                             return property(item, valueProperty);
263 |  |
                     }
264 |  |
265 |  |
                     /**
266 |  |
                      * {@inheritDoc}
267 |  |
                      */
268 |  |
                     public Object getLabelValue(final Object item) {
269 |  |
                             final Object labelValue;
270 | 15 |
                             if (labelProperty == null) {
271 | 3 |
                                     labelValue = getItemValue(item);
272 |  |
                             } else {
273 | 12 |
                                     labelValue = property(item, labelProperty);
274 |  |
                             }
275 | 15 |
                             return labelValue;
276 |  |
                     }
277 |  |
278 |  |
                     /**
279 |  |
                      * 指定されたオブジェクトからプロパティの値を取得します。
280 |  |
                      *
281 |  |
                      * @param bean
282 |  |
                      *            値を取得するオブジェクト
283 |  |
                      * @param propertyName
284 |  |
                      *            プロパティ名
285 |  |
                      * @return プロパティの値
286 |  |
                      */
287 |  |
                     private Object property(final Object bean, final String propertyName) {
288 | 30 |
                             final BeanDesc beanDesc = BeanDescFactory.getBeanDesc(bean
289 |  |
                                             .getClass());
290 | 30 |
                             final Attribute attribute = beanDesc
291 |  |
                                             .getPropertyAttribute(propertyName);
292 | 30 |
                             return attribute.getValue(bean);
293 |  |
                     }
294 |  |
295 |  |
             }
296 |  |
297 | 14 |
             private class EntryItemAdaptor implements ItemAdaptor {
298 |  |
299 | 7 |
                     EntryItemAdaptor() {
300 | 7 |
                             if (valueProperty != null) {
301 | 2 |
                                     final Logger logger = LoggerFactory.getLogger(SelectTag.class);
302 | 2 |
                                     if (logger.isWarnEnabled()) {
303 | 2 |
                                             logger.warn(format("WCUB1001", "items", Map.class
304 |  |
                                                             .getSimpleName(), "valueProperty", valueProperty,
305 |  |
                                                             Entry.class.getSimpleName() + "#getKey()"));
306 |  |
                                     }
307 |  |
                             }
308 | 7 |
                             if (labelProperty != null) {
309 | 2 |
                                     final Logger logger = LoggerFactory.getLogger(SelectTag.class);
310 | 2 |
                                     if (logger.isWarnEnabled()) {
311 | 2 |
                                             logger.warn(format("WCUB1002", "items", Map.class
312 |  |
                                                             .getSimpleName(), "labelProperty", labelProperty,
313 |  |
                                                             Entry.class.getSimpleName() + "#getValue()"));
314 |  |
                                     }
315 |  |
                             }
316 | 7 |
                     }
317 |  |
318 |  |
                     /**
319 |  |
                      * {@inheritDoc}
320 |  |
                      */
321 |  |
                     public Object getItemValue(final Object item) {
322 | 21 |
                             return ((Entry<?, ?>) item).getKey();
323 |  |
                     }
324 |  |
325 |  |
                     /**
326 |  |
                      * {@inheritDoc}
327 |  |
                      */
328 |  |
                     public Object getLabelValue(final Object item) {
329 | 21 |
                             return ((Entry<?, ?>) item).getValue();
330 |  |
                     }
331 |  |
332 |  |
             }
333 |  |
334 |  |
     }