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