001    /*
002     * Copyright 1997-2004 The Apache Software Foundation
003     * Copyright 2005 Stephen J. McConnell, OSM
004     * 
005     * Licensed  under the  Apache License,  Version 2.0  (the "License");
006     * you may not use  this file  except in  compliance with the License.
007     * You may obtain a copy of the License at 
008     * 
009     *   http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed  under the  License is distributed on an "AS IS" BASIS,
013     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
014     * implied.
015     * 
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    package net.dpml.lang;
021    
022    import java.util.Map;
023    
024    /**
025     * Basic enum class for type-safe enums with values. Valued enum items can be compared and ordered
026     * with the provided methods. Should be used as an abstract base. For example:
027     *
028     * <pre>
029     * import net.dpml.lang.ValuedEnum;
030     *
031     * public final class JavaVersion
032     *   extends ValuedEnum
033     * {
034     *   //standard enums for version of JVM
035     *   public static final JavaVersion  JAVA1_0  = new JavaVersion( "Java 1.0", 100 );
036     *   public static final JavaVersion  JAVA1_1  = new JavaVersion( "Java 1.1", 110 );
037     *   public static final JavaVersion  JAVA1_2  = new JavaVersion( "Java 1.2", 120 );
038     *   public static final JavaVersion  JAVA1_3  = new JavaVersion( "Java 1.3", 130 );
039     *   public static final JavaVersion  JAVA1_4  = new JavaVersion( "Java 1.4", 140 );
040     *
041     *   private JavaVersion( final String name, final int value )
042     *   {
043     *     super( name, value );
044     *   }
045     * }
046     * </pre>
047     * Usage:
048     * <pre>
049     *   JavaVersion requiredVer = JavaVersion.JAVA1_2;
050     *
051     *   public Widget( Context context )
052     *   {
053     *     JavaVersion ver = (JavaVersion)context.get("java.version");
054     *     if( ver.isLessThan( requiredVer ) )
055     *     {
056     *       throw new RuntimeException( requiredVer.getName()+ " or higher required" );
057     *     }
058     *   }
059     * }
060     * </pre>
061     *
062     * As with <code>Enum</code>, the {@link #ValuedEnum(String, int, Map)} constructor can be used to
063     * populate a <code>Map</code>, from which further functionality can be derived.
064     *
065     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
066     * @version 1.1.0
067     */
068    public abstract class ValuedEnum extends Enum implements Comparable
069    {
070        /**
071         * The value contained in enum.
072         */
073        private final int m_value;
074    
075        /**
076         * Constructor for enum item.
077         *
078         * @param name the name of enum item.
079         * @param value the value of enum item.
080         */
081        protected ValuedEnum( final String name, final int value )
082        {
083            this( name, value, null );
084        }
085    
086        /**
087         * Constructor for enum item so that it gets added to Map at creation.
088         * Adding to a map is useful for implementing find...() style methods.
089         *
090         * @param name the name of enum item.
091         * @param value the value of enum item.
092         * @param map the <code>Map</code> to add enum item to.
093         */
094        protected ValuedEnum( final String name, final int value, final Map map )
095        {
096            super( name, map );
097            m_value = value;
098        }
099    
100        /**
101         * Get value of enum item.
102         *
103         * @return the enum item's value.
104         */
105        public final int getValue()
106        {
107            return m_value;
108        }
109    
110        /**
111         * Test if enum item is equal in value to other enum.
112         *
113         * @param other the other enum
114         * @return true if equal
115         */
116        public final boolean isEqualTo( final ValuedEnum other )
117        {
118            return m_value == other.m_value;
119        }
120    
121        /**
122         * Test if enum item is greater than in value to other enum.
123         *
124         * @param other the other enum
125         * @return true if greater than
126         */
127        public final boolean isGreaterThan( final ValuedEnum other )
128        {
129            return m_value > other.m_value;
130        }
131    
132        /**
133         * Test if enum item is greater than or equal in value to other enum.
134         *
135         * @param other the other enum
136         * @return true if greater than or equal
137         */
138        public final boolean isGreaterThanOrEqual( final ValuedEnum other )
139        {
140            return m_value >= other.m_value;
141        }
142    
143        /**
144         * Test if enum item is less than in value to other enum.
145         *
146         * @param other the other enum
147         * @return true if less than
148         */
149        public final boolean isLessThan( final ValuedEnum other )
150        {
151            return m_value < other.m_value;
152        }
153    
154        /**
155         * Test if enum item is less than or equal in value to other enum.
156         *
157         * @param other the other enum
158         * @return true if less than or equal
159         */
160        public final boolean isLessThanOrEqual( final ValuedEnum other )
161        {
162            return m_value <= other.m_value;
163        }
164    
165        /**
166         * Tests for equality. Two Enum:s are considered equal
167         * if they are of the same class, have the same name, and same value.
168         *
169         * @param o the other object
170         * @return the equality status
171         */
172        public boolean equals( Object o )
173        {
174            boolean prelim = super.equals( o );
175            if( !prelim )
176            {
177                return false;
178            }
179            if( !( o instanceof ValuedEnum ) )
180            {
181                return false;
182            }
183            final ValuedEnum enumerated = (ValuedEnum) o;
184            return m_value == enumerated.m_value;
185        }
186        
187       /**
188        * Compute the hashcode value.
189        * @return the hashcode value
190        */
191        public int hashCode()
192        {
193            int hash = super.hashCode();
194            hash ^= m_value;
195            hash >>>= ( m_value & 31 );
196            return hash;
197        }
198        
199        /**
200         * Override toString method to produce human readable description.
201         *
202         * @return String in the form <code>type:name#value</code>, eg.:
203         * <code>JavaVersion[Java 1.0=100]</code>.
204         */
205        public String toString()
206        {
207            return getClass().getName() + ":" + getName() + "#" + m_value;
208        }
209        
210       /**
211        * Compare this instance with the supplied object.
212        * @param other the object to compare against
213        * @return int 1 if this instance is ranked higher than the supplied instance, 
214        *    0 if the ranking is equivalent, and -1 if this instance is ranked lower than
215        *    the supplied instance
216        */
217        public int compareTo( Object other )
218        {
219            if( other instanceof ValuedEnum )
220            {
221                ValuedEnum enummeration = (ValuedEnum) other;
222                int value = enummeration.m_value;
223                if( m_value > value )
224                {
225                    return 1;
226                }
227                else if( m_value == value )
228                {
229                    return 0;
230                }
231                else
232                {
233                    return -1;
234                }
235            }
236            else
237            {
238                return 1;
239            }
240        }
241    }
242