1. /*
  2. * @(#)EnumSyntax.java 1.3 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.print.attribute;
  8. import java.io.InvalidObjectException;
  9. import java.io.ObjectStreamException;
  10. import java.io.Serializable;
  11. /**
  12. * Class EnumSyntax is an abstract base class providing the common
  13. * implementation of all "type safe enumeration" objects. An enumeration class
  14. * (which extends class EnumSyntax) provides a group of enumeration values
  15. * (objects) that are singleton instances of the enumeration class; for example:
  16. * <PRE>
  17. * public class Bach extends EnumSyntax {
  18. * public static final Bach JOHANN_SEBASTIAN = new Bach(0);
  19. * public static final Bach WILHELM_FRIEDEMANN = new Bach(1);
  20. * public static final Bach CARL_PHILIP_EMMANUEL = new Bach(2);
  21. * public static final Bach JOHANN_CHRISTIAN = new Bach(3);
  22. * public static final Bach P_D_Q = new Bach(4);
  23. *
  24. * private static final String[] stringTable = {
  25. * "Johann Sebastian Bach",
  26. * "Wilhelm Friedemann Bach",
  27. * "Carl Philip Emmanuel Bach",
  28. * "Johann Christian Bach",
  29. * "P.D.Q. Bach"
  30. * };
  31. *
  32. * protected String[] getStringTable() {
  33. * return stringTable;
  34. * }
  35. *
  36. * private static final Bach[] enumValueTable = {
  37. * JOHANN_SEBASTIAN,
  38. * WILHELM_FRIEDEMANN,
  39. * CARL_PHILIP_EMMANUEL,
  40. * JOHANN_CHRISTIAN,
  41. * P_D_Q
  42. * };
  43. *
  44. * protected EnumSyntax[] getEnumValueTable() {
  45. * return enumValueTable;
  46. * }
  47. * }
  48. * </PRE>
  49. * You can then write code that uses the <CODE>==</CODE> and <CODE>!=</CODE>
  50. * operators to test enumeration values; for example:
  51. * <PRE>
  52. * Bach theComposer;
  53. * . . .
  54. * if (theComposer == Bach.JOHANN_SEBASTIAN) {
  55. * System.out.println ("The greatest composer of all time!");
  56. * }
  57. * </PRE>
  58. * The <CODE>equals()</CODE> method for an enumeration class just does a test
  59. * for identical objects (<CODE>==</CODE>).
  60. * <P>
  61. * You can convert an enumeration value to a string by calling {@link
  62. * #toString() <CODE>toString()</CODE>}. The string is obtained from a table
  63. * supplied by the enumeration class.
  64. * <P>
  65. * Under the hood, an enumeration value is just an integer, a different integer
  66. * for each enumeration value within an enumeration class. You can get an
  67. * enumeration value's integer value by calling {@link #getValue()
  68. * <CODE>getValue()</CODE>}. An enumeration value's integer value is established
  69. * when it is constructed (see {@link #EnumSyntax(int)
  70. * <CODE>EnumSyntax(int)</CODE>}). Since the constructor is protected, the only
  71. * possible enumeration values are the singleton objects declared in the
  72. * enumeration class; additional enumeration values cannot be created at run
  73. * time.
  74. * <P>
  75. * You can define a subclass of an enumeration class that extends it with
  76. * additional enumeration values. The subclass's enumeration values' integer
  77. * values need not be distinct from the superclass's enumeration values' integer
  78. * values; the <CODE>==</CODE>, <CODE>!=</CODE>, <CODE>equals()</CODE>, and
  79. * <CODE>toString()</CODE> methods will still work properly even if the subclass
  80. * uses some of the same integer values as the superclass. However, the
  81. * application in which the enumeration class and subclass are used may need to
  82. * have distinct integer values in the superclass and subclass.
  83. * <P>
  84. *
  85. * @author David Mendenhall
  86. * @author Alan Kaminsky
  87. */
  88. public abstract class EnumSyntax implements Serializable, Cloneable {
  89. /**
  90. * This enumeration value's integer value.
  91. * @serial
  92. */
  93. private int value;
  94. /**
  95. * Construct a new enumeration value with the given integer value.
  96. *
  97. * @param value Integer value.
  98. */
  99. protected EnumSyntax(int value) {
  100. this.value = value;
  101. }
  102. /**
  103. * Returns this enumeration value's integer value.
  104. * @return the value
  105. */
  106. public int getValue() {
  107. return value;
  108. }
  109. /**
  110. * Returns a clone of this enumeration value, which to preserve the
  111. * semantics of enumeration values is the same object as this enumeration
  112. * value.
  113. */
  114. public Object clone() {
  115. return this;
  116. }
  117. /**
  118. * Returns a hash code value for this enumeration value. The hash code is
  119. * just this enumeration value's integer value.
  120. */
  121. public int hashCode() {
  122. return value;
  123. }
  124. /**
  125. * Returns a string value corresponding to this enumeration value.
  126. */
  127. public String toString() {
  128. String[] theTable = getStringTable();
  129. int theIndex = value - getOffset();
  130. return
  131. theTable != null && theIndex >= 0 && theIndex < theTable.length ?
  132. theTable[theIndex] :
  133. Integer.toString (value);
  134. }
  135. /**
  136. * During object input, convert this deserialized enumeration instance to
  137. * the proper enumeration value defined in the enumeration attribute class.
  138. *
  139. * @return The enumeration singleton value stored at index
  140. * <I>i</I>-<I>L</I> in the enumeration value table returned by
  141. * {@link #getEnumValueTable() <CODE>getEnumValueTable()</CODE>},
  142. * where <I>i</I> is this enumeration value's integer value and
  143. * <I>L</I> is the value returned by {@link #getOffset()
  144. * <CODE>getOffset()</CODE>}.
  145. *
  146. * @throws ObjectStreamException if the stream can't be deserialised
  147. * @throws InvalidObjectException
  148. * Thrown if the enumeration value table is null, this enumeration
  149. * value's integer value does not correspond to an element in the
  150. * enumeration value table, or the corresponding element in the
  151. * enumeration value table is null. (Note: {@link
  152. * java.io.InvalidObjectException InvalidObjectException} is a subclass
  153. * of {@link java.io.ObjectStreamException ObjectStreamException}, which
  154. * <CODE>readResolve()</CODE> is declared to throw.)
  155. */
  156. protected Object readResolve() throws ObjectStreamException {
  157. EnumSyntax[] theTable = getEnumValueTable();
  158. if (theTable == null) {
  159. throw new InvalidObjectException(
  160. "Null enumeration value table for class " +
  161. getClass());
  162. }
  163. int theOffset = getOffset();
  164. int theIndex = value - theOffset;
  165. if (0 > theIndex || theIndex >= theTable.length) {
  166. throw new InvalidObjectException
  167. ("Integer value = " + value + " not in valid range " +
  168. theOffset + ".." + (theOffset + theTable.length - 1) +
  169. "for class " + getClass());
  170. }
  171. EnumSyntax result = theTable[theIndex];
  172. if (result == null) {
  173. throw new InvalidObjectException
  174. ("No enumeration value for integer value = " +
  175. value + "for class " + getClass());
  176. }
  177. return result;
  178. }
  179. // Hidden operations to be implemented in a subclass.
  180. /**
  181. * Returns the string table for this enumeration value's enumeration class.
  182. * The enumeration class's integer values are assumed to lie in the range
  183. * <I>L</I>..<I>L</I>+<I>N</I>-1, where <I>L</I> is the value returned by
  184. * {@link #getOffset() <CODE>getOffset()</CODE>} and <I>N</I> is the length
  185. * of the string table. The element in the string table at index
  186. * <I>i</I>-<I>L</I> is the value returned by {@link #toString()
  187. * <CODE>toString()</CODE>} for the enumeration value whose integer value
  188. * is <I>i</I>. If an integer within the above range is not used by any
  189. * enumeration value, leave the corresponding table element null.
  190. * <P>
  191. * The default implementation returns null. If the enumeration class (a
  192. * subclass of class EnumSyntax) does not override this method to return a
  193. * non-null string table, and the subclass does not override the {@link
  194. * #toString() <CODE>toString()</CODE>} method, the base class {@link
  195. * #toString() <CODE>toString()</CODE>} method will return just a string
  196. * representation of this enumeration value's integer value.
  197. * @return the string table
  198. */
  199. protected String[] getStringTable() {
  200. return null;
  201. }
  202. /**
  203. * Returns the enumeration value table for this enumeration value's
  204. * enumeration class. The enumeration class's integer values are assumed to
  205. * lie in the range <I>L</I>..<I>L</I>+<I>N</I>-1, where <I>L</I> is the
  206. * value returned by {@link #getOffset() <CODE>getOffset()</CODE>} and
  207. * <I>N</I> is the length of the enumeration value table. The element in the
  208. * enumeration value table at index <I>i</I>-<I>L</I> is the enumeration
  209. * value object whose integer value is <I>i</I> the {@link #readResolve()
  210. * <CODE>readResolve()</CODE>} method needs this to preserve singleton
  211. * semantics during deserialization of an enumeration instance. If an
  212. * integer within the above range is not used by any enumeration value,
  213. * leave the corresponding table element null.
  214. * <P>
  215. * The default implementation returns null. If the enumeration class (a
  216. * subclass of class EnumSyntax) does not override this method to return
  217. * a non-null enumeration value table, and the subclass does not override
  218. * the {@link #readResolve() <CODE>readResolve()</CODE>} method, the base
  219. * class {@link #readResolve() <CODE>readResolve()</CODE>} method will throw
  220. * an exception whenever an enumeration instance is deserialized from an
  221. * object input stream.
  222. * @return the value table
  223. */
  224. protected EnumSyntax[] getEnumValueTable() {
  225. return null;
  226. }
  227. /**
  228. * Returns the lowest integer value used by this enumeration value's
  229. * enumeration class.
  230. * <P>
  231. * The default implementation returns 0. If the enumeration class (a
  232. * subclass of class EnumSyntax) uses integer values starting at other than
  233. * 0, override this method in the subclass.
  234. * @return the offset of the lowest enumeration value.
  235. */
  236. protected int getOffset() {
  237. return 0;
  238. }
  239. }