001: /*
002: * $RCSfile: ParameterListDescriptorImpl.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:14 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import com.sun.media.jai.util.CaselessStringArrayTable;
015: import java.lang.reflect.Field;
016: import java.lang.reflect.Modifier;
017: import java.util.HashSet;
018: import java.util.Hashtable;
019: import java.util.Iterator;
020: import java.util.Locale;
021: import java.util.Map;
022: import java.util.Set;
023: import java.util.Vector;
024: import javax.media.jai.util.Range;
025:
026: /**
027: * A concrete implementation of the <code>ParameterListDescriptor</code>
028: * interface.
029: *
030: * @see ParameterListDescriptor
031: *
032: * @since JAI 1.1
033: */
034: public class ParameterListDescriptorImpl implements
035: ParameterListDescriptor, java.io.Serializable {
036:
037: /** The number of parameters in the list described by this parameter. */
038: private int numParams;
039:
040: /** The names of each parameter. */
041: private String[] paramNames;
042:
043: /** The <code>Class</code> type of each parameter. There is one-to-one
044: * mapping between this and <code>paramNames</code>.
045: */
046: private Class[] paramClasses;
047:
048: /**
049: * The default values for of each parameter. There is one-to-one
050: * mapping between this and <code>paramNames</code>. If there is
051: * no default value for a given parameter, it is initialized with
052: * <code>ParameterListDescriptor.NO_PARAMETER_DEFAULT</code>
053: */
054: private Object[] paramDefaults;
055:
056: /**
057: * Defines the valid parameter values for each parameter.
058: */
059: private Object[] validParamValues;
060:
061: /**
062: * A <code>CaselessStringArrayTable</code> mapping the parameter
063: * names to their indices in the above arrays in a case-insensitive
064: * manner.
065: */
066: private CaselessStringArrayTable paramIndices;
067:
068: /** The <code>Object</code> to reflect upon for enumerated parameters. */
069: private Object descriptor;
070:
071: /**
072: * Indicates if the <code>validParamValues</code> field has been
073: * initialized.
074: */
075: private boolean validParamsInitialized = false;
076:
077: /**
078: * Uses reflection to examine "descriptor" for <code>public</code>,
079: * <code>static</code> <code>final</code> <code>Field</code>s
080: * that are instances of "paramClass".
081: *
082: * @param descriptor the object to be reflected upon.
083: * @param paramClass the parameter class
084: *
085: * @return a <code>Set</code> of enumerated values.
086: *
087: * @throws IllegalArgumentException if descriptor is <code>null</code>
088: * or paramClass is <code>null</code>
089: * @throws IllegalArgumentException if "paramClass" is not an instance of
090: * <code>EnumeratedParameter</code>
091: */
092: public static Set getEnumeratedValues(Object descriptor,
093: Class paramClass) {
094:
095: if ((descriptor == null) || (paramClass == null))
096: throw new IllegalArgumentException(JaiI18N
097: .getString("Generic0"));
098:
099: // If not an enumerated parameter, return null
100: if (!EnumeratedParameter.class.isAssignableFrom(paramClass))
101: throw new IllegalArgumentException(JaiI18N.formatMsg(
102: "ParameterListDescriptorImpl10",
103: new Object[] { paramClass.getName() }));
104:
105: Field[] fields = descriptor.getClass().getDeclaredFields();
106:
107: if (fields == null)
108: return null;
109:
110: // Look for all parameters which are instance of EnumeratedParameter.
111: int numFields = fields.length;
112: Set valueSet = null;
113:
114: // Look for all fields which are static, final
115: // instances of the class of this parameter.
116: for (int j = 0; j < numFields; j++) {
117: Field field = fields[j];
118: int modifiers = field.getModifiers();
119: if (Modifier.isPublic(modifiers)
120: && Modifier.isStatic(modifiers)
121: && Modifier.isFinal(modifiers)) {
122: Object fieldValue = null;
123: try {
124: fieldValue = field.get(null);
125: } catch (Exception e) {
126: // Ignore exception
127: }
128: if (paramClass.isInstance(fieldValue)) {
129: if (valueSet == null) {
130: valueSet = new HashSet();
131: }
132:
133: if (valueSet.contains(fieldValue)) {
134: // This error is a coding error
135: // which should be caught by the
136: // developer the first time the
137: // bogus descriptor is loaded.
138: throw new UnsupportedOperationException(
139: JaiI18N
140: .getString("ParameterListDescriptorImpl0"));
141: }
142: // Save parameter value in Set.
143: valueSet.add(fieldValue);
144: }
145: }
146: }
147:
148: return valueSet;
149: }
150:
151: /**
152: * A wrapper method to get the valid parameter values for
153: * the specified parameter index. This makes sure that the
154: * field has been initialized if it wasnt done before.
155: */
156: private Object getValidParamValue(int index) {
157:
158: if (validParamsInitialized)
159: return validParamValues[index];
160:
161: synchronized (this ) {
162: if (validParamValues == null) {
163: validParamValues = new Object[numParams];
164: }
165:
166: Class enumeratedClass = EnumeratedParameter.class;
167:
168: for (int i = 0; i < numParams; i++) {
169: if (validParamValues[i] != null)
170: continue;
171:
172: if (enumeratedClass.isAssignableFrom(paramClasses[i])) {
173: validParamValues[i] = getEnumeratedValues(
174: descriptor, paramClasses[i]);
175: }
176: }
177: }
178:
179: validParamsInitialized = true;
180:
181: return validParamValues[index];
182: }
183:
184: /**
185: * Constructor for descriptors that dont have any parameters.
186: */
187: public ParameterListDescriptorImpl() {
188: this .numParams = 0;
189: this .paramNames = null;
190: this .paramClasses = null;
191: this .paramDefaults = null;
192: this .paramIndices = new CaselessStringArrayTable();
193: this .validParamValues = null;
194: }
195:
196: /**
197: * Constructor.
198: *
199: * @param descriptor the object to be reflected upon for enumerated values
200: * @param paramNames the names of each parameter. can be <code>null</code>
201: * if there are no parameters.
202: * @param paramClasses the <code>Class</code> type of each parameter.
203: * can be <code>null</code> if there are no parameters.
204: * @param paramDefaults the default values for each parameter. can be
205: * <code>null</code> if there are no parameters or if
206: * there are no default values, in which case the parameter
207: * defaults are assumed to be <code>
208: * ParameterListDescriptor.NO_PARAMETER_DEFAULT</code>
209: * @param validParamValues defines the valid values for each parameter.
210: *
211: * <p>Each element of this array can be <code>null</code> (if the parameter
212: * can take on any value of its class or if it is an enumerated parameter
213: * whose values are to be auto-detected - see <code>getEnumeratedValues
214: * </code>), or a <code>Set</code> (for user specified enumerated
215: * values) or a <code>Range</code> (for parameters that are
216: * <code>Comparable</code>.)
217: *
218: * <p>The valid set of values for an object which is neither an
219: * <code>EnumeratedParameter</code> nor <code>Comparable</code>
220: * should just be the set of all possible instances of the associated
221: * class, i.e., the parameter has to be an instance of the specified
222: * class.
223: *
224: * <p>If this array itself is <code>null</code> then it is treated
225: * as an array full of <code>null</code>s as described above.
226: *
227: * @throws IllegalArgumentException if <code>paramNames</code> is non-null
228: * and the number of <code>paramClasses</code> or a non-null
229: * <code>paramDefaults</code> does not match the length of
230: * <code>paramNames</code>
231: * @throws IllegalArgumentException if <code>null</code> is passed in for
232: * <code>validParamValues</code> for a parameter whose
233: * class is of <code>EnumeratedParameter</code> type.
234: */
235: public ParameterListDescriptorImpl(Object descriptor,
236: String[] paramNames, Class[] paramClasses,
237: Object[] paramDefaults, Object[] validParamValues) {
238:
239: int numParams = (paramNames == null) ? 0 : paramNames.length;
240:
241: if ((paramDefaults != null)
242: && (paramDefaults.length != numParams))
243: throw new IllegalArgumentException("paramDefaults"
244: + JaiI18N.getString("ParameterListDescriptorImpl1"));
245:
246: if ((validParamValues != null)
247: && (validParamValues.length != numParams))
248: throw new IllegalArgumentException("validParamValues"
249: + JaiI18N.getString("ParameterListDescriptorImpl2"));
250:
251: this .descriptor = descriptor;
252:
253: if (numParams == 0) {
254:
255: if ((paramClasses != null) && (paramClasses.length != 0))
256: throw new IllegalArgumentException(
257: "paramClasses"
258: + JaiI18N
259: .getString("ParameterListDescriptorImpl3"));
260:
261: this .numParams = 0;
262: this .paramNames = null;
263: this .paramClasses = null;
264: this .paramDefaults = null;
265: this .paramIndices = new CaselessStringArrayTable();
266: this .validParamValues = null;
267:
268: } else {
269:
270: if ((paramClasses == null)
271: || (paramClasses.length != numParams))
272: throw new IllegalArgumentException(
273: "paramClasses"
274: + JaiI18N
275: .getString("ParameterListDescriptorImpl3"));
276:
277: this .numParams = numParams;
278: this .paramNames = paramNames;
279: this .paramClasses = paramClasses;
280: this .validParamValues = validParamValues;
281:
282: //
283: // If the defaults are null, fill in NO_PARAMETER_DEFAULT
284: // Else, make sure they belong to the right class.
285: //
286: if (paramDefaults == null) {
287: this .paramDefaults = new Object[numParams];
288:
289: for (int i = 0; i < numParams; i++)
290: this .paramDefaults[i] = ParameterListDescriptor.NO_PARAMETER_DEFAULT;
291: } else {
292:
293: this .paramDefaults = paramDefaults;
294:
295: for (int i = 0; i < numParams; i++) {
296: if ((paramDefaults[i] == null)
297: || (paramDefaults[i] == ParameterListDescriptor.NO_PARAMETER_DEFAULT))
298: continue;
299:
300: if (!paramClasses[i].isInstance(paramDefaults[i])) {
301: throw new IllegalArgumentException(JaiI18N
302: .formatMsg(
303: "ParameterListDescriptorImpl4",
304: new Object[] {
305: paramDefaults[i]
306: .getClass()
307: .getName(),
308: paramClasses[i]
309: .getName(),
310: paramNames[i] }));
311: }
312: }
313: }
314:
315: //
316: // Make sure that validParamValues belongs to the right class.
317: //
318: if (validParamValues != null) {
319:
320: Class enumeratedClass = EnumeratedParameter.class;
321:
322: for (int i = 0; i < numParams; i++) {
323:
324: if (validParamValues[i] == null)
325: continue;
326:
327: if (enumeratedClass
328: .isAssignableFrom(paramClasses[i])) {
329:
330: // If paramClass[i] is an enumerated parameter, then
331: // the validParamValues[i] has to be a Set
332: if (!(validParamValues[i] instanceof Set))
333: throw new IllegalArgumentException(
334: JaiI18N
335: .formatMsg(
336: "ParameterListDescriptorImpl5",
337: new Object[] { paramNames[i] }));
338:
339: } else if (validParamValues[i] instanceof Range) {
340:
341: Range range = (Range) validParamValues[i];
342:
343: // If the validParamValues[i] is a Range, then
344: // the Range's class must match with paramClass[i]
345: if (!paramClasses[i].isAssignableFrom(range
346: .getElementClass()))
347: throw new IllegalArgumentException(
348: JaiI18N
349: .formatMsg(
350: "ParameterListDescriptorImpl6",
351: new Object[] {
352: range
353: .getElementClass()
354: .getName(),
355: paramClasses[i]
356: .getName(),
357: paramNames[i] }));
358:
359: } else {
360:
361: // Otherwise, the validParamValues[i] has to be
362: // an instance of the paramClasses[i]
363: if (!paramClasses[i]
364: .isInstance(validParamValues[i]))
365: throw new IllegalArgumentException(
366: JaiI18N
367: .formatMsg(
368: "ParameterListDescriptorImpl7",
369: new Object[] {
370: validParamValues[i]
371: .getClass()
372: .getName(),
373: paramClasses[i]
374: .getName(),
375: paramNames[i] }));
376: }
377: }
378: }
379:
380: paramIndices = new CaselessStringArrayTable(paramNames);
381: }
382: }
383:
384: /**
385: * Returns the total number of parameters.
386: */
387: public int getNumParameters() {
388: return numParams;
389: }
390:
391: /**
392: * Returns an array of <code>Class</code>es that describe the types
393: * of parameters. If there are no parameters, this method returns
394: * <code>null</code>.
395: */
396: public Class[] getParamClasses() {
397: return paramClasses;
398: }
399:
400: /**
401: * Returns an array of <code>String</code>s that are the
402: * names of the parameters associated with this descriptor. If there
403: * are no parameters, this method returns <code>null</code>.
404: */
405: public String[] getParamNames() {
406: return paramNames;
407: }
408:
409: /**
410: * Returns an array of <code>Object</code>s that define the default
411: * values of the parameters. Default values may be <code>null</code>.
412: * The <code>NO_PARAMETER_DEFAULT</code> static <code>Object</code>
413: * indicates that a parameter has no default value. If there are no
414: * parameters, this method returns <code>null</code>.
415: */
416: public Object[] getParamDefaults() {
417: return paramDefaults;
418: }
419:
420: /**
421: * Returns the default value of a specified parameter. The default
422: * value may be <code>null</code>. If a parameter has no default
423: * value, this method returns <code>NO_PARAMETER_DEFAULT</code>.
424: *
425: * @param parameterName The name of the parameter whose default
426: * value is queried.
427: *
428: * @throws IllegalArgumentException if <code>parameterName</code> is null
429: * or if the parameter does not exist.
430: */
431: public Object getParamDefaultValue(String parameterName) {
432: return paramDefaults[paramIndices.indexOf(parameterName)];
433: }
434:
435: /**
436: * Returns the <code>Range</code> that represents the range of valid
437: * values for the specified parameter. Returns <code>null</code> if
438: * the parameter can take on any value or if the valid values are
439: * not representable as a Range.
440: *
441: * @param parameterName The name of the parameter whose valid range
442: * of values is to be determined.
443: *
444: * @throws IllegalArgumentException if <code>parameterName</code> is null
445: * or if the parameter does not exist.
446: */
447: public Range getParamValueRange(String parameterName) {
448:
449: Object values = getValidParamValue(paramIndices
450: .indexOf(parameterName));
451:
452: if ((values == null) || (values instanceof Range))
453: return (Range) values;
454:
455: return null;
456: }
457:
458: /**
459: * Return an array of the names of all parameters the type of which is
460: * <code>EnumeratedParameter</code>.
461: *
462: * @return The requested array of names or <code>null</code> if there
463: * are no parameters with <code>EnumeratedParameter</code> type.
464: */
465: public String[] getEnumeratedParameterNames() {
466:
467: Vector v = new Vector();
468:
469: for (int i = 0; i < numParams; i++) {
470: if (EnumeratedParameter.class
471: .isAssignableFrom(paramClasses[i]))
472: v.add(paramNames[i]);
473: }
474:
475: if (v.size() <= 0)
476: return null;
477:
478: return (String[]) v.toArray(new String[0]);
479: }
480:
481: /**
482: * Return an array of <code>EnumeratedParameter</code> objects
483: * corresponding to the parameter with the specified name.
484: *
485: * @param parameterName The name of the parameter for which the
486: * <code>EnumeratedParameter</code> array is to be returned.
487: *
488: * @throws IllegalArgumentException if <code>parameterName</code> is null
489: * or if the parameter does not exist.
490: * @throws UnsupportedOperationException if there are no enumerated
491: * parameters associated with the descriptor.
492: * @throws IllegalArgumentException if <code>parameterName</code> is
493: * a parameter the class of which is not a subclass of
494: * <code>EnumeratedParameter</code>.
495: *
496: * @return An array of <code>EnumeratedParameter</code> objects
497: * representing the range of values for the named parameter.
498: */
499: public EnumeratedParameter[] getEnumeratedParameterValues(
500: String parameterName) {
501:
502: int i = paramIndices.indexOf(parameterName);
503:
504: if (!EnumeratedParameter.class
505: .isAssignableFrom(paramClasses[i]))
506: throw new IllegalArgumentException(parameterName + ":"
507: + JaiI18N.getString("ParameterListDescriptorImpl8"));
508:
509: Set enumSet = (Set) getValidParamValue(i);
510:
511: if (enumSet == null)
512: return null;
513:
514: return (EnumeratedParameter[]) enumSet
515: .toArray(new EnumeratedParameter[0]);
516: }
517:
518: /**
519: * Checks to see if the specified parameter can take on the specified
520: * value.
521: *
522: * @param parameterName The name of the parameter for which the
523: * validity check is to be performed.
524: *
525: * @throws IllegalArgumentException if <code>parameterName</code> is null
526: * or if the parameter does not exist.
527: * @throws IllegalArgumentException if the class of the object "value"
528: * is not an instance of the class type of parameter
529: * pointed to by the parameterName
530: *
531: * @return true, if it is valid to pass this value in for this
532: * parameter, false otherwise.
533: */
534: public boolean isParameterValueValid(String parameterName,
535: Object value) {
536: int index = paramIndices.indexOf(parameterName);
537:
538: if ((value == null) && (paramDefaults[index] == null)) {
539: return true;
540: }
541:
542: // Make sure the object belongs to the right class
543: if ((value != null) && !paramClasses[index].isInstance(value)) {
544: throw new IllegalArgumentException(JaiI18N.formatMsg(
545: "ParameterListDescriptorImpl9", new Object[] {
546: value.getClass().getName(),
547: paramClasses[index].getName(),
548: parameterName }));
549: }
550:
551: Object validValues = getValidParamValue(index);
552:
553: // If validValues is null then any value is acceptable.
554: if (validValues == null)
555: return true;
556:
557: // If validValues is a Range, make sure "value" lies within it.
558: if (validValues instanceof Range)
559: return ((Range) validValues).contains((Comparable) value);
560:
561: // If validValues is a Set, then make sure that "value" is contained
562: // in the Set.
563: if (validValues instanceof Set)
564: return ((Set) validValues).contains(value);
565:
566: // Otherwise the value must be the same as validValues
567: return value == validValues;
568: }
569: }
|