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.commons.util;
014
015import java.util.Map;
016
017import org.apache.tapestry5.commons.services.Coercion;
018
019/**
020 * A {@link org.apache.tapestry5.commons.services.Coercion} for converting strings into an instance of a particular
021 * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
022 * fashion.
023 *
024 * Moved from tapestry-core to tapestry-ioc in release 5.3, but kept in same package for compatibility.
025 * Moved tapestry-ioc to commons in release 5.4, but kept in same package for compatibility.
026 * 
027 * @param <T>
028 *            the type of enumeration
029 */
030public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
031{
032    private final Class<T> enumClass;
033
034    private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
035
036    public StringToEnumCoercion(Class<T> enumClass)
037    {
038        this(enumClass, enumClass.getEnumConstants());
039    }
040
041    public StringToEnumCoercion(Class<T> enumClass, T... values)
042    {
043        this.enumClass = enumClass;
044
045        for (T value : values)
046            stringToEnum.put(value.name(), value);
047    }
048
049    @Override
050    public T coerce(String input)
051    {
052        if (CommonsUtils.isBlank(input))
053            return null;
054
055        T result = stringToEnum.get(input);
056
057        if (result == null)
058        {
059            String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
060                    enumClass.getName());
061
062            throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
063                    stringToEnum));
064        }
065
066        return result;
067    }
068
069    /**
070     * Allows an alias value (alternate) string to reference a value.
071     * 
072     * @since 5.2.2
073     */
074    public StringToEnumCoercion<T> addAlias(String alias, T value)
075    {
076        stringToEnum.put(alias, value);
077
078        return this;
079    }
080
081    public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
082    {
083        return new StringToEnumCoercion<T>(enumClass);
084    }
085
086}