    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.util;
    014
    015import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    016import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
    017import org.apache.tapestry5.ioc.services.Coercion;
    018import org.apache.tapestry5.ioc.util.AvailableValues;
    019import org.apache.tapestry5.ioc.util.UnknownValueException;
    020
    021import java.util.Map;
    022
    023/**
    024 * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
    025 * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
    026 * fashion.
    027 *
    028 * Moved from tapestry-core to tapestry-ioc in release 5.3, but kept in same package for compatibility.
    029 * Moved tapestry-ioc to commons in release 5.4, but kept in same package for compatibility.
    030 *
    031 * @param <T>
    032 *            the type of enumeration
    033 */
    034public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
    035{
    036    private final Class<T> enumClass;
    037
    038    private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
    039
    040    public StringToEnumCoercion(Class<T> enumClass)
    041    {
    042        this(enumClass, enumClass.getEnumConstants());
    043    }
    044
    045    public StringToEnumCoercion(Class<T> enumClass, T... values)
    046    {
    047        this.enumClass = enumClass;
    048
    049        for (T value : values)
    050            stringToEnum.put(value.name(), value);
    051    }
    052
    053    @Override
    054    public T coerce(String input)
    055    {
    056        if (InternalCommonsUtils.isBlank(input))
    057            return null;
    058
    059        T result = stringToEnum.get(input);
    060
    061        if (result == null)
    062        {
    063            String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
    064                    enumClass.getName());
    065
    066            throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
    067                    stringToEnum));
    068        }
    069
    070        return result;
    071    }
    072
    073    /**
    074     * Allows an alias value (alternate) string to reference a value.
    075     *
    076     * @since 5.2.2
    077     */
    078    public StringToEnumCoercion<T> addAlias(String alias, T value)
    079    {
    080        stringToEnum.put(alias, value);
    081
    082        return this;
    083    }
    084
    085    public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
    086    {
    087        return new StringToEnumCoercion<T>(enumClass);
    088    }
    089
    090}