View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  
27  package javax.print.attribute;
28  
29  import java.io.InvalidObjectException;
30  import java.io.ObjectStreamException;
31  import java.io.Serializable;
32  
33  /**
34   * Class EnumSyntax is an abstract base class providing the common
35   * implementation of all "type safe enumeration" objects. An enumeration class
36   * (which extends class EnumSyntax) provides a group of enumeration values
37   * (objects) that are singleton instances of the enumeration class; for example:
38   * <PRE>
39   *     public class Bach extends EnumSyntax {
40   *         public static final Bach JOHANN_SEBASTIAN     = new Bach(0);
41   *         public static final Bach WILHELM_FRIEDEMANN   = new Bach(1);
42   *         public static final Bach CARL_PHILIP_EMMANUEL = new Bach(2);
43   *         public static final Bach JOHANN_CHRISTIAN     = new Bach(3);
44   *         public static final Bach P_D_Q                = new Bach(4);
45   *
46   *         private static final String[] stringTable = {
47   *             "Johann Sebastian Bach",
48   *              "Wilhelm Friedemann Bach",
49   *              "Carl Philip Emmanuel Bach",
50   *              "Johann Christian Bach",
51   *              "P.D.Q. Bach"
52   *         };
53   *
54   *         protected String[] getStringTable() {
55   *             return stringTable;
56   *         }
57   *
58   *         private static final Bach[] enumValueTable = {
59   *             JOHANN_SEBASTIAN,
60   *              WILHELM_FRIEDEMANN,
61   *              CARL_PHILIP_EMMANUEL,
62   *              JOHANN_CHRISTIAN,
63   *              P_D_Q
64   *         };
65   *
66   *         protected EnumSyntax[] getEnumValueTable() {
67   *             return enumValueTable;
68   *         }
69   *     }
70   * </PRE>
71   * You can then write code that uses the <CODE>==</CODE> and <CODE>!=</CODE>
72   * operators to test enumeration values; for example:
73   * <PRE>
74   *     Bach theComposer;
75   *     . . .
76   *     if (theComposer == Bach.JOHANN_SEBASTIAN) {
77   *         System.out.println ("The greatest composer of all time!");
78   *     }
79   * </PRE>
80   * The <CODE>equals()</CODE> method for an enumeration class just does a test
81   * for identical objects (<CODE>==</CODE>).
82   * <P>
83   * You can convert an enumeration value to a string by calling {@link
84   * #toString() toString()}. The string is obtained from a table
85   * supplied by the enumeration class.
86   * <P>
87   * Under the hood, an enumeration value is just an integer, a different integer
88   * for each enumeration value within an enumeration class. You can get an
89   * enumeration value's integer value by calling {@link #getValue()
90   * getValue()}. An enumeration value's integer value is established
91   * when it is constructed (see {@link #EnumSyntax(int)
92   * EnumSyntax(int)}). Since the constructor is protected, the only
93   * possible enumeration values are the singleton objects declared in the
94   * enumeration class; additional enumeration values cannot be created at run
95   * time.
96   * <P>
97   * You can define a subclass of an enumeration class that extends it with
98   * additional enumeration values. The subclass's enumeration values' integer
99   * values need not be distinct from the superclass's enumeration values' integer
100  * values; the <CODE>==</CODE>, <CODE>!=</CODE>, <CODE>equals()</CODE>, and
101  * <CODE>toString()</CODE> methods will still work properly even if the subclass
102  * uses some of the same integer values as the superclass. However, the
103  * application in which the enumeration class and subclass are used may need to
104  * have distinct integer values in the superclass and subclass.
105  * <P>
106  *
107  * @author  David Mendenhall
108  * @author  Alan Kaminsky
109  */
110 public abstract class EnumSyntax implements Serializable, Cloneable {
111 
112     private static final long serialVersionUID = -2739521845085831642L;
113 
114     /**
115      * This enumeration value's integer value.
116      * @serial
117      */
118     private int value;
119 
120     /**
121      * Construct a new enumeration value with the given integer value.
122      *
123      * @param  value  Integer value.
124      */
125     protected EnumSyntax(int value) {
126         this.value = value;
127     }
128 
129     /**
130      * Returns this enumeration value's integer value.
131      * @return the value
132      */
133     public int getValue() {
134         return value;
135     }
136 
137     /**
138      * Returns a clone of this enumeration value, which to preserve the
139      * semantics of enumeration values is the same object as this enumeration
140      * value.
141      */
142     public Object clone() {
143         return this;
144     }
145 
146     /**
147      * Returns a hash code value for this enumeration value. The hash code is
148      * just this enumeration value's integer value.
149      */
150     public int hashCode() {
151         return value;
152     }
153 
154     /**
155      * Returns a string value corresponding to this enumeration value.
156      */
157     public String toString() {
158 
159         String[] theTable = getStringTable();
160         int theIndex = value - getOffset();
161         return
162             theTable != null && theIndex >= 0 && theIndex < theTable.length ?
163             theTable[theIndex] :
164             Integer.toString (value);
165     }
166 
167     /**
168      * During object input, convert this deserialized enumeration instance to
169      * the proper enumeration value defined in the enumeration attribute class.
170      *
171      * @return  The enumeration singleton value stored at index
172      *          <I>i</I>-<I>L</I> in the enumeration value table returned by
173      *          {@link #getEnumValueTable() getEnumValueTable()},
174      *          where <I>i</I> is this enumeration value's integer value and
175      *          <I>L</I> is the value returned by {@link #getOffset()
176      *          getOffset()}.
177      *
178      * @throws ObjectStreamException if the stream can't be deserialised
179      * @throws  InvalidObjectException
180      *     Thrown if the enumeration value table is null, this enumeration
181      *     value's integer value does not correspond to an element in the
182      *     enumeration value table, or the corresponding element in the
183      *     enumeration value table is null. (Note: {@link
184      *     java.io.InvalidObjectException InvalidObjectException} is a subclass
185      *     of {@link java.io.ObjectStreamException ObjectStreamException}, which
186      *     <CODE>readResolve()</CODE> is declared to throw.)
187      */
188     protected Object readResolve() throws ObjectStreamException {
189 
190         EnumSyntax[] theTable = getEnumValueTable();
191 
192         if (theTable == null) {
193             throw new InvalidObjectException(
194                                 "Null enumeration value table for class " +
195                                 getClass());
196         }
197 
198         int theOffset = getOffset();
199         int theIndex = value - theOffset;
200 
201         if (0 > theIndex || theIndex >= theTable.length) {
202             throw new InvalidObjectException
203                 ("Integer value = " +  value + " not in valid range " +
204                  theOffset + ".." + (theOffset + theTable.length - 1) +
205                  "for class " + getClass());
206         }
207 
208         EnumSyntax result = theTable[theIndex];
209         if (result == null) {
210             throw new InvalidObjectException
211                 ("No enumeration value for integer value = " +
212                  value + "for class " + getClass());
213         }
214         return result;
215     }
216 
217     // Hidden operations to be implemented in a subclass.
218 
219     /**
220      * Returns the string table for this enumeration value's enumeration class.
221      * The enumeration class's integer values are assumed to lie in the range
222      * <I>L</I>..<I>L</I>+<I>N</I>-1, where <I>L</I> is the value returned by
223      * {@link #getOffset() getOffset()} and <I>N</I> is the length
224      * of the string table. The element in the string table at index
225      * <I>i</I>-<I>L</I> is the value returned by {@link #toString()
226      * toString()} for the enumeration value whose integer value
227      * is <I>i</I>. If an integer within the above range is not used by any
228      * enumeration value, leave the corresponding table element null.
229      * <P>
230      * The default implementation returns null. If the enumeration class (a
231      * subclass of class EnumSyntax) does not override this method to return a
232      * non-null string table, and the subclass does not override the {@link
233      * #toString() toString()} method, the base class {@link
234      * #toString() toString()} method will return just a string
235      * representation of this enumeration value's integer value.
236      * @return the string table
237      */
238     protected String[] getStringTable() {
239         return null;
240     }
241 
242     /**
243      * Returns the enumeration value table for this enumeration value's
244      * enumeration class. The enumeration class's integer values are assumed to
245      * lie in the range <I>L</I>..<I>L</I>+<I>N</I>-1, where <I>L</I> is the
246      * value returned by {@link #getOffset() getOffset()} and
247      * <I>N</I> is the length of the enumeration value table. The element in the
248      * enumeration value table at index <I>i</I>-<I>L</I> is the enumeration
249      * value object whose integer value is <I>i</I>; the {@link #readResolve()
250      * readResolve()} method needs this to preserve singleton
251      * semantics during deserialization of an enumeration instance. If an
252      * integer within the above range is not used by any enumeration value,
253      * leave the corresponding table element null.
254      * <P>
255      * The default implementation returns null. If the enumeration class (a
256      * subclass of class EnumSyntax) does not override this method to return
257      * a non-null enumeration value table, and the subclass does not override
258      * the {@link #readResolve() readResolve()} method, the base
259      * class {@link #readResolve() readResolve()} method will throw
260      * an exception whenever an enumeration instance is deserialized from an
261      * object input stream.
262      * @return the value table
263      */
264     protected EnumSyntax[] getEnumValueTable() {
265         return null;
266     }
267 
268     /**
269      * Returns the lowest integer value used by this enumeration value's
270      * enumeration class.
271      * <P>
272      * The default implementation returns 0. If the enumeration class (a
273      * subclass of class EnumSyntax) uses integer values starting at other than
274      * 0, override this method in the subclass.
275      * @return the offset of the lowest enumeration value.
276      */
277     protected int getOffset() {
278         return 0;
279     }
280 
281 }