1. /*
  2. * @(#)EnumSyntax.java 1.5 04/01/07
  3. *
  4. * Copyright 2004 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. private static final long serialVersionUID = -2739521845085831642L;
  90. /**
  91. * This enumeration value's integer value.
  92. * @serial
  93. */
  94. private int value;
  95. /**
  96. * Construct a new enumeration value with the given integer value.
  97. *
  98. * @param value Integer value.
  99. */
  100. protected EnumSyntax(int value) {
  101. this.value = value;
  102. }
  103. /**
  104. * Returns this enumeration value's integer value.
  105. * @return the value
  106. */
  107. public int getValue() {
  108. return value;
  109. }
  110. /**
  111. * Returns a clone of this enumeration value, which to preserve the
  112. * semantics of enumeration values is the same object as this enumeration
  113. * value.
  114. */
  115. public Object clone() {
  116. return this;
  117. }
  118. /**
  119. * Returns a hash code value for this enumeration value. The hash code is
  120. * just this enumeration value's integer value.
  121. */
  122. public int hashCode() {
  123. return value;
  124. }
  125. /**
  126. * Returns a string value corresponding to this enumeration value.
  127. */
  128. public String toString() {
  129. String[] theTable = getStringTable();
  130. int theIndex = value - getOffset();
  131. return
  132. theTable != null && theIndex >= 0 && theIndex < theTable.length ?
  133. theTable[theIndex] :
  134. Integer.toString (value);
  135. }
  136. /**
  137. * During object input, convert this deserialized enumeration instance to
  138. * the proper enumeration value defined in the enumeration attribute class.
  139. *
  140. * @return The enumeration singleton value stored at index
  141. * <I>i</I>-<I>L</I> in the enumeration value table returned by
  142. * {@link #getEnumValueTable() <CODE>getEnumValueTable()</CODE>},
  143. * where <I>i</I> is this enumeration value's integer value and
  144. * <I>L</I> is the value returned by {@link #getOffset()
  145. * <CODE>getOffset()</CODE>}.
  146. *
  147. * @throws ObjectStreamException if the stream can't be deserialised
  148. * @throws InvalidObjectException
  149. * Thrown if the enumeration value table is null, this enumeration
  150. * value's integer value does not correspond to an element in the
  151. * enumeration value table, or the corresponding element in the
  152. * enumeration value table is null. (Note: {@link
  153. * java.io.InvalidObjectException InvalidObjectException} is a subclass
  154. * of {@link java.io.ObjectStreamException ObjectStreamException}, which
  155. * <CODE>readResolve()</CODE> is declared to throw.)
  156. */
  157. protected Object readResolve() throws ObjectStreamException {
  158. EnumSyntax[] theTable = getEnumValueTable();
  159. if (theTable == null) {
  160. throw new InvalidObjectException(
  161. "Null enumeration value table for class " +
  162. getClass());
  163. }
  164. int theOffset = getOffset();
  165. int theIndex = value - theOffset;
  166. if (0 > theIndex || theIndex >= theTable.length) {
  167. throw new InvalidObjectException
  168. ("Integer value = " + value + " not in valid range " +
  169. theOffset + ".." + (theOffset + theTable.length - 1) +
  170. "for class " + getClass());
  171. }
  172. EnumSyntax result = theTable[theIndex];
  173. if (result == null) {
  174. throw new InvalidObjectException
  175. ("No enumeration value for integer value = " +
  176. value + "for class " + getClass());
  177. }
  178. return result;
  179. }
  180. // Hidden operations to be implemented in a subclass.
  181. /**
  182. * Returns the string table for this enumeration value's enumeration class.
  183. * The enumeration class's integer values are assumed to lie in the range
  184. * <I>L</I>..<I>L</I>+<I>N</I>-1, where <I>L</I> is the value returned by
  185. * {@link #getOffset() <CODE>getOffset()</CODE>} and <I>N</I> is the length
  186. * of the string table. The element in the string table at index
  187. * <I>i</I>-<I>L</I> is the value returned by {@link #toString()
  188. * <CODE>toString()</CODE>} for the enumeration value whose integer value
  189. * is <I>i</I>. If an integer within the above range is not used by any
  190. * enumeration value, leave the corresponding table element null.
  191. * <P>
  192. * The default implementation returns null. If the enumeration class (a
  193. * subclass of class EnumSyntax) does not override this method to return a
  194. * non-null string table, and the subclass does not override the {@link
  195. * #toString() <CODE>toString()</CODE>} method, the base class {@link
  196. * #toString() <CODE>toString()</CODE>} method will return just a string
  197. * representation of this enumeration value's integer value.
  198. * @return the string table
  199. */
  200. protected String[] getStringTable() {
  201. return null;
  202. }
  203. /**
  204. * Returns the enumeration value table for this enumeration value's
  205. * enumeration class. The enumeration class's integer values are assumed to
  206. * lie in the range <I>L</I>..<I>L</I>+<I>N</I>-1, where <I>L</I> is the
  207. * value returned by {@link #getOffset() <CODE>getOffset()</CODE>} and
  208. * <I>N</I> is the length of the enumeration value table. The element in the
  209. * enumeration value table at index <I>i</I>-<I>L</I> is the enumeration
  210. * value object whose integer value is <I>i</I> the {@link #readResolve()
  211. * <CODE>readResolve()</CODE>} method needs this to preserve singleton
  212. * semantics during deserialization of an enumeration instance. If an
  213. * integer within the above range is not used by any enumeration value,
  214. * leave the corresponding table element null.
  215. * <P>
  216. * The default implementation returns null. If the enumeration class (a
  217. * subclass of class EnumSyntax) does not override this method to return
  218. * a non-null enumeration value table, and the subclass does not override
  219. * the {@link #readResolve() <CODE>readResolve()</CODE>} method, the base
  220. * class {@link #readResolve() <CODE>readResolve()</CODE>} method will throw
  221. * an exception whenever an enumeration instance is deserialized from an
  222. * object input stream.
  223. * @return the value table
  224. */
  225. protected EnumSyntax[] getEnumValueTable() {
  226. return null;
  227. }
  228. /**
  229. * Returns the lowest integer value used by this enumeration value's
  230. * enumeration class.
  231. * <P>
  232. * The default implementation returns 0. If the enumeration class (a
  233. * subclass of class EnumSyntax) uses integer values starting at other than
  234. * 0, override this method in the subclass.
  235. * @return the offset of the lowest enumeration value.
  236. */
  237. protected int getOffset() {
  238. return 0;
  239. }
  240. }