View Javadoc

    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  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  	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  		this.items = items;
    78  	}
    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  		this.labelProperty = labelProperty;
    89  	}
    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  		this.valueProperty = valueProperty;
    100 	}
    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 		this.emptyOption = emptyOption;
    110 	}
    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 		this.emptyOptionLabel = emptyOptionLabel;
    120 	}
    121
    122 	/**
    123 	 * <code>name</code> 属性を設定します。
    124 	 *
    125 	 * @param name
    126 	 *            <code>name</code> 属性
    127 	 */
    128 	public void setName(final String name) {
    129 		this.name = name;
    130 	}
    131
    132 	/**
    133 	 * {@inheritDoc}
    134 	 */
    135 	@Override
    136 	public void doTag() throws JspException, IOException {
    137 		if (items == null) {
    138 			throw new JspTagException(format("ECUB1005"));
    139 		}
    140 		final JspContext context = this.getJspContext();
    141 		final JspWriter out = context.getOut();
    142 		final ActionErrors errors = errors(context);
    143 		final Map<String, Object> dyn = this.getDynamicAttributes();
    144 		final FormWrapper formWrapper = getFormWrapper(this);
    145
    146 		if (!errors.getFields().get(this.name).isEmpty()) {
    147 			addCSSClassName(dyn, "fieldError");
    148 		}
    149
    150 		final Object[] value = multipleFormValues(context, formWrapper,
    151 				this.name);
    152
    153 		out.write("<select name=\"");
    154 		out.write(this.name);
    155 		out.write("\" ");
    156 		out.write(toAttr(dyn));
    157 		out.write(">\n");
    158
    159 		if (emptyOption) {
    160 			out.write("<option value=\"\">");
    161 			out.write(CubbyFunctions.out(emptyOptionLabel));
    162 			out.write("</option>\n");
    163 		}
    164
    165 		if (items != null && items.getClass().isArray()) {
    166 			final OptionWriter optionWriter = new OptionWriter(
    167 					new BeanItemAdaptor());
    168 			for (final Object item : (Object[]) items) {
    169 				optionWriter.write(out, item, value);
    170 			}
    171 		} else {
    172 			final OptionWriter optionWriter;
    173 			final Collection<?> collection;
    174 			if (items instanceof Collection) {
    175 				optionWriter = new OptionWriter(new BeanItemAdaptor());
    176 				collection = (Collection<?>) items;
    177 			} else if (items instanceof Map) {
    178 				optionWriter = new OptionWriter(new EntryItemAdaptor());
    179 				collection = ((Map<?, ?>) items).entrySet();
    180 			} else {
    181 				throw new JspTagException(format("ECUB1001", "items",
    182 						items == null ? null : items.getClass()));
    183 			}
    184 			for (final Object item : collection) {
    185 				optionWriter.write(out, item, value);
    186 			}
    187 		}
    188
    189 		out.write("</select>");
    190 	}
    191
    192 	private static class OptionWriter {
    193
    194 		private final ItemAdaptor itemAdaptor;
    195
    196 		OptionWriter(final ItemAdaptor itemAdaptor) {
    197 			this.itemAdaptor = itemAdaptor;
    198 		}
    199
    200 		void write(final JspWriter out, final Object item, final Object value)
    201 				throws IOException {
    202 			out.write("<option value=\"");
    203 			final String itemValue = TagUtils.toString(itemAdaptor
    204 					.getItemValue(item));
    205 			final String labelValue = TagUtils.toString(itemAdaptor
    206 					.getLabelValue(item));
    207 			out.write(CubbyFunctions.out(itemValue));
    208 			out.write("\" ");
    209 			out.write(selected(itemValue, value));
    210 			out.write(">");
    211 			out.write(CubbyFunctions.out(labelValue));
    212 			out.write("</option>\n");
    213 		}
    214
    215 		private String selected(final String value, final Object values) {
    216 			if (value == null || values == null) {
    217 				return "";
    218 			}
    219 			if (contains(values, value)) {
    220 				return "selected=\"selected\"";
    221 			} else {
    222 				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 		BeanItemAdaptor() throws JspTagException {
    252 			if (valueProperty == null) {
    253 				throw new JspTagException(format("ECUB1002", "items",
    254 						"valueProperty"));
    255 			}
    256 		}
    257
    258 		/**
    259 		 * {@inheritDoc}
    260 		 */
    261 		public Object getItemValue(final Object item) {
    262 			return property(item, valueProperty);
    263 		}
    264
    265 		/**
    266 		 * {@inheritDoc}
    267 		 */
    268 		public Object getLabelValue(final Object item) {
    269 			final Object labelValue;
    270 			if (labelProperty == null) {
    271 				labelValue = getItemValue(item);
    272 			} else {
    273 				labelValue = property(item, labelProperty);
    274 			}
    275 			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 			final BeanDesc beanDesc = BeanDescFactory.getBeanDesc(bean
    289 					.getClass());
    290 			final Attribute attribute = beanDesc
    291 					.getPropertyAttribute(propertyName);
    292 			return attribute.getValue(bean);
    293 		}
    294
    295 	}
    296
    297 	private class EntryItemAdaptor implements ItemAdaptor {
    298
    299 		EntryItemAdaptor() {
    300 			if (valueProperty != null) {
    301 				final Logger logger = LoggerFactory.getLogger(SelectTag.class);
    302 				if (logger.isWarnEnabled()) {
    303 					logger.warn(format("WCUB1001", "items", Map.class
    304 							.getSimpleName(), "valueProperty", valueProperty,
    305 							Entry.class.getSimpleName() + "#getKey()"));
    306 				}
    307 			}
    308 			if (labelProperty != null) {
    309 				final Logger logger = LoggerFactory.getLogger(SelectTag.class);
    310 				if (logger.isWarnEnabled()) {
    311 					logger.warn(format("WCUB1002", "items", Map.class
    312 							.getSimpleName(), "labelProperty", labelProperty,
    313 							Entry.class.getSimpleName() + "#getValue()"));
    314 				}
    315 			}
    316 		}
    317
    318 		/**
    319 		 * {@inheritDoc}
    320 		 */
    321 		public Object getItemValue(final Object item) {
    322 			return ((Entry<?, ?>) item).getKey();
    323 		}
    324
    325 		/**
    326 		 * {@inheritDoc}
    327 		 */
    328 		public Object getLabelValue(final Object item) {
    329 			return ((Entry<?, ?>) item).getValue();
    330 		}
    331
    332 	}
    333
    334 }