1
2
3
4
5 package org.astrogrid.utils;
6
7
8 import java.util.Vector;
9 import java.util.Hashtable;
10 import java.util.Iterator;
11
12
13 /***
14 * A superclass and set of helper methods for easily making, using
15 * and streaming type-safe enumerations, if you don't have the new generic
16 * java stuff.
17 * <P>
18 * Type-safe enumerators are a way of creating pre-defined lists of things,
19 * ensuring that only things of those correct instances are used as arguments.
20 * A good example is the Severity class of the event logs; it is simply not
21 * possible to pass anything except a Severity into the relevant MessageLog methods.
22 * <P>
23 * By subclassing from util.TypeSafeEnumerator, you get lots of advantages:
24 * string lookups, ability to iterate through the options, automatic BML
25 * stream handling and combo-box property editor that lists all the options.
26 * <P>
27 * Subclasses might override getList() and getFor() as described in those method
28 * docs below, to provide properly typed methods.
29 * <P>
30 * For use with a PropertyEditor, all you need to do is create the subclass, the appropriate get/set
31 * property methods and register the class with the TypeSafeEnumEditor at
32 * the end of the PropertyPane class (plenty of examples there) and bobs your uncle.
33 * <P>
34 * Example use of TypeSafeEnumerator:
35 * <pre>
36 * public class Severity extends TypeSafeEnumerator {
37 * public final static Severity INFO = new Severity("Information only");
38 * public final static Severity WARNING = new Severity("Warning");
39 * public final static Severity ALARM = new Severity("Alarm");
40 *
41 * public Severity(String msg) {
42 * super(msg);
43 * }
44 * }
45 * </pre>
46 * You can now use Severity as a parameter, and you will only ever get the
47 * ones defined above (or subclasses if not final!).
48 * <p>
49 * Extended from a javaworld article
50 * <p>
51 * @author M Hill
52 */
53
54
55
56 public class TypeSafeEnumerator implements java.io.Serializable
57 {
58 /*** a hashtable of vectors... each class look up corresponds to the
59 * subclass of the typesafeenumerator. the vector consists of the list
60 * of that subclass's instance. */
61 protected static Hashtable classLookup = new Hashtable();
62
63
64 private String text;
65
66 /***
67 * Standard Constructor
68 */
69 protected TypeSafeEnumerator(String aString)
70 {
71 text = aString;
72 addInstance();
73 }
74
75 /***
76 * Adds instance to the classLookup table. Might be called by
77 * subclass constructors.
78 */
79 protected void addInstance()
80 {
81 Vector instanceList = (Vector) classLookup.get(this.getClass().getName());
82
83 if (instanceList == null)
84 {
85
86 instanceList = new Vector();
87 classLookup.put(this.getClass().getName(), instanceList);
88
89
90
91
92
93 }
94
95 instanceList.add(this);
96 }
97
98 /***
99 * Returns a string representing the enumeration instance
100 */
101 public String toString()
102 {
103
104 return text;
105 }
106
107 /***
108 * There can be problems when deserialising objects because a new instance
109 * is created (regardless of whether the constructor is private) by the
110 * stream instantiator.
111 * <p>
112 * See java tip 122 on www.javaworld.com
113 * <p>
114 * Note that we can use .getClass() here because it's an instance method -
115 * we can't use it in the static (class) methods because in those cases
116 * the class will always be TypeSafeEnumerator rather than the appropriate
117 * subclass...
118 */
119 private Object readResolve () throws java.io.ObjectStreamException
120 {
121 return getFor(this.getClass(), text);
122 }
123
124 /***
125 * Returns the text defining the enumeration instance
126 */
127 public String getText()
128 {
129 return text;
130 }
131
132 /***
133 * Gets an iterator over the list of all those instances for the
134 * given class. A nice subclass might implement:
135 * <pre>
136 * public static Iterator getIterator() { return getIterator(<SubClass>.class);
137 * </pre>
138 }
139 */
140 public static Iterator getIterator(Class aClass)
141 {
142 Vector instanceList = (Vector) classLookup.get(aClass.getName());
143
144 if (instanceList == null)
145 {
146
147
148 try {
149 aClass.newInstance();
150
151 instanceList = (Vector) classLookup.get(aClass.getName());
152 } catch (Exception e) {
153 throw new NullPointerException("Could not create instances of typesafe enumerator "+aClass);
154 }
155 }
156
157 return instanceList.iterator();
158 }
159
160 /***
161 * Returns a list of the various instances for a particular class. Suitable for combo boxes, etc.
162 * I don't really want to return the instance vector as it means people can
163 * fiddle with it...
164 * <P>
165 * A nice subclass might implement:
166 * <pre>
167 *
168 * public static Object[] getAll() { return getAll(<SubClass>.class); }
169 *
170 * </pre>
171 * or use getList() to return a typed array
172 * @see getList()
173 */
174 public static Object[] getAll(Class aClass)
175 {
176 return getList(aClass).toArray();
177 }
178
179 /***
180 * Provides a way for subclasses to do a typesafe getAll(), by implementing
181 * the following method:
182 * <pre>
183 * public static <SubClass>[] getAll() {
184 * return (<SubClass>[] getList(<SubClass>.class).toArray(new <SubClass>[])
185 * }
186 */
187 public static Vector getList(Class aClass)
188 {
189 return (Vector) classLookup.get(aClass.getName());
190 }
191
192 /***
193 * Return the instance of the subclass given the particular string
194 * A nice subclass might implement:
195 * <code>
196 public static <b>SubClass</b> getFor(String aString)
197 {
198 return (<b>SubClass</b>) getFor(<b>SubClass</b>.class, aString);
199 }
200 * </code>
201 */
202 public static TypeSafeEnumerator getFor(Class aClass, String aString)
203 {
204 TypeSafeEnumerator instance;
205
206 for (Iterator iterator = getIterator(aClass); iterator.hasNext(); )
207 {
208 instance = (TypeSafeEnumerator) iterator.next();
209
210 if (instance.getText().equalsIgnoreCase(aString))
211 return instance;
212 }
213 throw new IllegalArgumentException("No enumeration (instance) of "+aClass+" found for '"+aString+"'");
214 }
215
216
217 }
218
219
220
221
222
223
224
225
226
227
228
229
230