001    // Copyright 2007, 2008, 2010, 2011 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.util;
016    
017    import java.util.Map;
018    
019    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
020    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
021    import org.apache.tapestry5.ioc.services.Coercion;
022    import org.apache.tapestry5.ioc.util.AvailableValues;
023    import org.apache.tapestry5.ioc.util.UnknownValueException;
024    
025    /**
026     * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
027     * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
028     * fashion.
029     * <p>
030     * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
031     * 
032     * @param <T>
033     *            the type of enumeration
034     */
035    public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
036    {
037        private final Class<T> enumClass;
038    
039        private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
040    
041        public StringToEnumCoercion(Class<T> enumClass)
042        {
043            this(enumClass, enumClass.getEnumConstants());
044        }
045    
046        public StringToEnumCoercion(Class<T> enumClass, T... values)
047        {
048            this.enumClass = enumClass;
049    
050            for (T value : values)
051                stringToEnum.put(value.name(), value);
052        }
053    
054        public T coerce(String input)
055        {
056            if (InternalUtils.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    }