KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > olap > EnumeratedValues


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/olap/EnumeratedValues.java#19 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 1998-2002 Kana Software, Inc.
7 // Copyright (C) 2001-2006 Julian Hyde and others
8 // All Rights Reserved.
9 // You must accept the terms of that agreement to use this software.
10 //
11 */

12
13 package mondrian.olap;
14
15 import java.util.*;
16
17 /**
18  * <code>EnumeratedValues</code> is a helper class for declaring a set of
19  * symbolic constants which have names, ordinals, and possibly descriptions.
20  * The ordinals do not have to be contiguous.
21  *
22  * <p>Typically, for a particular set of constants, you derive a class from this
23  * interface, and declare the constants as <code>public static final</code>
24  * members. Give it a private constructor, and a <code>public static final
25  * <i>ClassName</i> instance</code> member to hold the singleton instance.
26  * {@link Access} is a simple example of this.</p>
27  */

28 public class EnumeratedValues<V extends EnumeratedValues.Value>
29     implements Cloneable JavaDoc
30 {
31     /** Map symbol names to values */
32     private Map<String JavaDoc, V> valuesByName = new LinkedHashMap<String JavaDoc, V>();
33
34     /** the smallest ordinal value */
35     private int min = Integer.MAX_VALUE;
36
37     /** the largest ordinal value */
38     private int max = Integer.MIN_VALUE;
39
40     // the variables below are only set AFTER makeImmutable() has been called
41

42     /** An array mapping ordinals to {@link Value}s. It is biased by the
43      * min value. It is built by {@link #makeImmutable}. */

44     private Value[] ordinalToValueMap;
45     private static final String JavaDoc[] emptyStringArray = new String JavaDoc[0];
46
47     /**
48      * Creates a new empty, mutable enumeration.
49      */

50     public EnumeratedValues() {
51     }
52
53     /**
54      * Creates an enumeration, with an array of values, and freezes it.
55      */

56     public EnumeratedValues(V[] values) {
57         for (V value : values) {
58             register(value);
59         }
60         makeImmutable();
61     }
62
63     /**
64      * Creates an enumeration, initialize it with an array of strings, and
65      * freezes it.
66      */

67     public EnumeratedValues(String JavaDoc[] names) {
68         for (int i = 0; i < names.length; i++) {
69             register((V) new BasicValue(names[i], i, names[i]));
70         }
71         makeImmutable();
72     }
73
74     /**
75      * Create an enumeration, initializes it with arrays of code/name pairs,
76      * and freezes it.
77      */

78     public EnumeratedValues(String JavaDoc[] names, int[] codes) {
79         for (int i = 0; i < names.length; i++) {
80             register((V) new BasicValue(names[i], codes[i], names[i]));
81         }
82         makeImmutable();
83     }
84
85     /**
86      * Create an enumeration, initializes it with arrays of code/name pairs,
87      * and freezes it.
88      */

89     public EnumeratedValues(String JavaDoc[] names, int[] codes, String JavaDoc[] descriptions) {
90         for (int i = 0; i < names.length; i++) {
91             register((V) new BasicValue(names[i], codes[i], descriptions[i]));
92         }
93         makeImmutable();
94     }
95
96     public EnumeratedValues(Class JavaDoc<? extends Enum JavaDoc> clazz) {
97         throw new UnsupportedOperationException JavaDoc();
98     }
99
100     public EnumeratedValues<V> clone() {
101         EnumeratedValues clone;
102         try {
103             clone = (EnumeratedValues) super.clone();
104         } catch (CloneNotSupportedException JavaDoc ex) {
105             throw Util.newInternal(ex, "error while cloning " + this);
106         }
107         clone.valuesByName = new HashMap<String JavaDoc, Value>(valuesByName);
108         clone.ordinalToValueMap = null;
109         return clone;
110     }
111
112     /**
113      * Creates a mutable enumeration from an existing enumeration, which may
114      * already be immutable.
115      */

116     public EnumeratedValues getMutableClone() {
117         return clone();
118     }
119
120     /**
121      * Associates a symbolic name with an ordinal value.
122      *
123      * @pre value != null
124      * @pre !isImmutable()
125      * @pre value.getName() != null
126      */

127     public void register(V value) {
128         assert value != null : "pre: value != null";
129         Util.assertPrecondition(!isImmutable(), "isImmutable()");
130         final String JavaDoc name = value.getName();
131         Util.assertPrecondition(name != null, "value.getName() != null");
132         Value old = valuesByName.put(name, value);
133         if (old != null) {
134             throw Util.newInternal("Enumeration already contained a value '" + old.getName() + "'");
135         }
136         final int ordinal = value.getOrdinal();
137         min = Math.min(min,ordinal);
138         max = Math.max(max,ordinal);
139     }
140
141     /**
142      * Freezes the enumeration, preventing it from being further modified.
143      */

144     public void makeImmutable() {
145         ordinalToValueMap = new Value[1 + max - min];
146         for (Value value : valuesByName.values()) {
147             final int index = value.getOrdinal() - min;
148             if (ordinalToValueMap[index] != null) {
149                 throw Util.newInternal(
150                     "Enumeration has more than one value with ordinal " +
151                         value.getOrdinal());
152             }
153             ordinalToValueMap[index] = value;
154         }
155     }
156
157     public final boolean isImmutable() {
158         return (ordinalToValueMap != null);
159     }
160
161     /**
162      * Returns the smallest ordinal defined by this enumeration.
163      */

164     public final int getMin() {
165         return min;
166     }
167
168     /**
169      * Returns the largest ordinal defined by this enumeration.
170      */

171     public final int getMax() {
172         return max;
173     }
174
175     /**
176      * Returns whether <code>ordinal</code> is valid for this enumeration.
177      * This method is particularly useful in pre- and post-conditions, for
178      * example
179      * <blockquote>
180      * <pre>&#64;param axisCode Axis code, must be a {&#64;link AxisCode} value
181      * &#64;pre AxisCode.instance.isValid(axisCode)</pre>
182      * </blockquote>
183      *
184      * @param ordinal Suspected ordinal from this enumeration.
185      * @return Whether <code>ordinal</code> is valid.
186      */

187     public final boolean isValid(int ordinal) {
188         if ((ordinal < min) || (ordinal > max)) {
189             return false;
190         }
191         if (getName(ordinal) == null) {
192             return false;
193         }
194         return true;
195     }
196
197     /**
198      * Returns the name associated with an ordinal; the return value
199      * is null if the ordinal is not a member of the enumeration.
200      *
201      * @pre isImmutable()
202      */

203     public final V getValue(int ordinal) {
204         Util.assertPrecondition(isImmutable());
205
206         return (V) ordinalToValueMap[ordinal - min];
207     }
208
209     /**
210      * Returns the name associated with an ordinal; the return value
211      * is null if the ordinal is not a member of the enumeration.
212      *
213      * @pre isImmutable()
214      */

215     public final String JavaDoc getName(int ordinal) {
216         Util.assertPrecondition(isImmutable());
217
218         final Value value = ordinalToValueMap[ordinal - min];
219         return (value == null) ? null : value.getName();
220     }
221
222     /**
223      * Returns the description associated with an ordinal; the return value
224      * is null if the ordinal is not a member of the enumeration.
225      *
226      * @pre isImmutable()
227      */

228     public final String JavaDoc getDescription(int ordinal)
229     {
230         Util.assertPrecondition(isImmutable());
231
232         final Value value = ordinalToValueMap[ordinal - min];
233         return (value == null) ? null : value.getDescription();
234     }
235
236     /**
237      * Returns the ordinal associated with a name
238      *
239      * @throws Error if the name is not a member of the enumeration
240      */

241     public final int getOrdinal(String JavaDoc name) {
242         return getValue(name, true).getOrdinal();
243     }
244
245     /**
246      * Returns the value associated with a name.
247      *
248      * @param name Name of enumerated value
249      * @param fail Whether to throw if not found
250      * @throws Error if the name is not a member of the enumeration and
251      * <code>fail</code> is true
252      */

253     public V getValue(String JavaDoc name, final boolean fail) {
254         final V value = valuesByName.get(name);
255         if (value == null && fail) {
256             throw new Error JavaDoc("Unknown enum name: " + name);
257         }
258         return value;
259     }
260
261     /**
262      * Returns the value associated with a name, case insensitive.
263      *
264      * @param name Name of enumerated value
265      * @param fail Whether to throw if not found
266      * @throws Error if the name is not a member of the enumeration and
267      * <code>fail</code> is true
268      */

269     public V getValueIgnoreCase(String JavaDoc name, boolean fail) {
270         for (Value value : ordinalToValueMap) {
271             if (value != null && value.getName().equalsIgnoreCase(name)) {
272                 return (V) value;
273             }
274         }
275         if (fail) {
276             throw new Error JavaDoc("Unknown enum name: " + name);
277         }
278         return null;
279     }
280
281     /**
282      * Returns the names in this enumeration, in declaration order.
283      */

284     public String JavaDoc[] getNames() {
285         return valuesByName.keySet().toArray(emptyStringArray);
286     }
287
288     /**
289      * Returns the members of this enumeration, sorted by name.
290      */

291     public List<V> getValuesSortedByName() {
292         List<V> list = new ArrayList<V>();
293         final String JavaDoc[] names = getNames();
294         Arrays.sort(names);
295         for (String JavaDoc name : names) {
296             list.add(getValue(name, true));
297         }
298         return list;
299     }
300
301     /**
302      * Returns an error indicating that the value is illegal. (The client needs
303      * to throw the error.)
304      */

305     public RuntimeException JavaDoc badValue(int ordinal) {
306         return Util.newInternal("bad value " + ordinal + "(" +
307                 getName(ordinal) + ") for enumeration '" +
308                 getClass().getName() + "'");
309     }
310
311     /**
312      * Returns an exception indicating that we didn't expect to find this value
313      * here.
314      */

315     public RuntimeException JavaDoc unexpected(V value) {
316         return Util.newInternal("Was not expecting value '" + value +
317                 "' for enumeration '" + getClass().getName() +
318                 "' in this context");
319     }
320
321     /**
322      * A <code>Value</code> represents a member of an enumerated type. If an
323      * enumerated type is not based upon an explicit array of values, an
324      * array of {@link BasicValue}s will implicitly be created.
325      */

326     public interface Value {
327         String JavaDoc getName();
328         int getOrdinal();
329         String JavaDoc getDescription();
330     }
331
332     /**
333      * <code>BasicValue</code> is an obvious implementation of {@link
334      * EnumeratedValues.Value}.
335      */

336     public static class BasicValue implements Value {
337         public final String JavaDoc name;
338         public final int ordinal;
339         public final String JavaDoc description;
340
341         /**
342          * @pre name != null
343          */

344         public BasicValue(String JavaDoc name, int ordinal, String JavaDoc description) {
345             Util.assertPrecondition(name != null, "name != null");
346             this.name = name;
347             this.ordinal = ordinal;
348             this.description = description;
349         }
350
351         public String JavaDoc getName() {
352             return name;
353         }
354
355         public int getOrdinal() {
356             return ordinal;
357         }
358
359         public String JavaDoc getDescription() {
360             return description;
361         }
362
363         /**
364          * Returns the value's name.
365          */

366         public String JavaDoc toString() {
367             return name;
368         }
369
370         /**
371          * Returns whether this value is equal to a given string.
372          *
373          * @deprecated I bet you meant to write
374          * <code>value.name_.equals(s)</code> rather than
375          * <code>value.equals(s)</code>, didn't you?
376          */

377         public boolean equals(String JavaDoc s) {
378             return super.equals(s);
379         }
380
381         /**
382          * Returns an error indicating that we did not expect to find this
383          * value in this context. Typical use is in a <code>switch</code>
384          * statement:
385          *
386          * <blockquote><pre>
387          * switch (fruit) {
388          * case Fruit.AppleORDINAL:
389          * return 1;
390          * case Fruir.OrangeORDINAL:
391          * return 2;
392          * default:
393          * throw fruit.unexpected();
394          * }</pre></blockquote>
395          */

396         public RuntimeException JavaDoc unexpected() {
397             return Util.newInternal("Value " + name + " of class " +
398                     getClass() + " unexpected here");
399         }
400     }
401
402 }
403
404 // End EnumeratedValues.java
405
Popular Tags