KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > imageio > metadata > IIOMetadataFormatImpl


1 /*
2  * @(#)IIOMetadataFormatImpl.java 1.28 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.imageio.metadata;
9
10 import java.util.ArrayList JavaDoc;
11 import java.util.Collection JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Locale JavaDoc;
16 import java.util.Map JavaDoc;
17 import java.util.MissingResourceException JavaDoc;
18 import java.util.ResourceBundle JavaDoc;
19 import javax.imageio.ImageTypeSpecifier JavaDoc;
20 import com.sun.imageio.plugins.common.StandardMetadataFormat;
21
22 /**
23  * A concrete class providing a reusable implementation of the
24  * <code>IIOMetadataFormat</code> interface. In addition, a static
25  * instance representing the standard, plug-in neutral
26  * <code>javax_imageio_1.0</code> format is provided by the
27  * <code>getStandardFormatInstance</code> method.
28  *
29  * <p> In order to supply localized descriptions of elements and
30  * attributes, a <code>ResourceBundle</code> with a base name of
31  * <code>this.getClass().getName() + "Resources"</code> should be
32  * supplied via the usual mechanism used by
33  * <code>ResourceBundle.getBundle</code>. Briefly, the subclasser
34  * supplies one or more additional classes according to a naming
35  * convention (by default, the fully-qualified name of the subclass
36  * extending <code>IIMetadataFormatImpl</code>, plus the string
37  * "Resources", plus the country, language, and variant codes
38  * separated by underscores). At run time, calls to
39  * <code>getElementDescription</code> or
40  * <code>getAttributeDescription</code> will attempt to load such
41  * classes dynamically according to the supplied locale, and will use
42  * either the element name, or the element name followed by a '/'
43  * character followed by the attribute name as a key. This key will
44  * be supplied to the <code>ResourceBundle</code>'s
45  * <code>getString</code> method, and the resulting localized
46  * description of the node or attribute is returned.
47  *
48  * <p> The subclass may supply a different base name for the resource
49  * bundles using the <code>setResourceBaseName</code> method.
50  *
51  * <p> A subclass may choose its own localization mechanism, if so
52  * desired, by overriding the supplied implementations of
53  * <code>getElementDescription</code> and
54  * <code>getAttributeDescription</code>.
55  *
56  * @see ResourceBundle#getBundle(String,Locale)
57  *
58  * @version 0.5
59  */

60 public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat JavaDoc {
61
62     /**
63      * A <code>String</code> constant containing the standard format
64      * name, <code>"javax_imageio_1.0"</code>.
65      */

66     public static final String JavaDoc standardMetadataFormatName =
67         "javax_imageio_1.0";
68
69     private static IIOMetadataFormat JavaDoc standardFormat = null;
70
71     private String JavaDoc resourceBaseName = this.getClass().getName() + "Resources";
72
73     private String JavaDoc rootName;
74
75     // Element name (String) -> Element
76
private HashMap JavaDoc elementMap = new HashMap JavaDoc();
77
78     class Element {
79         String JavaDoc elementName;
80
81         int childPolicy;
82         int minChildren = 0;
83         int maxChildren = 0;
84
85         // Child names (Strings)
86
List JavaDoc childList = new ArrayList JavaDoc();
87
88         // Parent names (Strings)
89
List JavaDoc parentList = new ArrayList JavaDoc();
90
91         // List of attribute names in the order they were added
92
List JavaDoc attrList = new ArrayList JavaDoc();
93         // Attr name (String) -> Attribute
94
Map JavaDoc attrMap = new HashMap JavaDoc();
95
96         ObjectValue objectValue;
97     }
98     
99     class Attribute {
100         String JavaDoc attrName;
101
102         int valueType = VALUE_ARBITRARY;
103         int dataType;
104         boolean required;
105         String JavaDoc defaultValue = null;
106
107         // enumeration
108
List JavaDoc enumeratedValues;
109
110         // range
111
String JavaDoc minValue;
112         String JavaDoc maxValue;
113
114         // list
115
int listMinLength;
116         int listMaxLength;
117     }
118
119     class ObjectValue {
120         int valueType = VALUE_NONE;
121         Class JavaDoc classType = null;
122         Object JavaDoc defaultValue = null;
123
124         // Meaningful only if valueType == VALUE_ENUMERATION
125
List JavaDoc enumeratedValues = null;
126         
127         // Meaningful only if valueType == VALUE_RANGE
128
Comparable JavaDoc minValue = null;
129         Comparable JavaDoc maxValue = null;
130
131         // Meaningful only if valueType == VALUE_LIST
132
int arrayMinLength = 0;
133         int arrayMaxLength = 0;
134     }
135
136     /**
137      * Constructs a blank <code>IIOMetadataFormatImpl</code> instance,
138      * with a given root element name and child policy (other than
139      * <code>CHILD_POLICY_REPEAT</code>). Additional elements, and
140      * their attributes and <code>Object</code> reference information
141      * may be added using the various <code>add</code> methods.
142      *
143      * @param rootName the name of the root element.
144      * @param childPolicy one of the <code>CHILD_POLICY_*</code> constants,
145      * other than <code>CHILD_POLICY_REPEAT</code>.
146      *
147      * @exception IllegalArgumentException if <code>rootName</code> is
148      * <code>null</code>.
149      * @exception IllegalArgumentException if <code>childPolicy</code> is
150      * not one of the predefined constants.
151      */

152     public IIOMetadataFormatImpl(String JavaDoc rootName,
153                                  int childPolicy) {
154         if (rootName == null) {
155             throw new IllegalArgumentException JavaDoc("rootName == null!");
156         }
157         if (childPolicy < CHILD_POLICY_EMPTY ||
158             childPolicy > CHILD_POLICY_MAX ||
159             childPolicy == CHILD_POLICY_REPEAT) {
160             throw new IllegalArgumentException JavaDoc("Invalid value for childPolicy!");
161         }
162
163         this.rootName = rootName;
164
165         Element root = new Element();
166         root.elementName = rootName;
167         root.childPolicy = childPolicy;
168
169         elementMap.put(rootName, root);
170     }
171
172     /**
173      * Constructs a blank <code>IIOMetadataFormatImpl</code> instance,
174      * with a given root element name and a child policy of
175      * <code>CHILD_POLICY_REPEAT</code>. Additional elements, and
176      * their attributes and <code>Object</code> reference information
177      * may be added using the various <code>add</code> methods.
178      *
179      * @param rootName the name of the root element.
180      * @param minChildren the minimum number of children of the node.
181      * @param maxChildren the maximum number of children of the node.
182      *
183      * @exception IllegalArgumentException if <code>rootName</code> is
184      * <code>null</code>.
185      * @exception IllegalArgumentException if <code>minChildren</code>
186      * is negative or larger than <code>maxChildren</code>.
187      */

188     public IIOMetadataFormatImpl(String JavaDoc rootName,
189                                  int minChildren,
190                                  int maxChildren) {
191         if (rootName == null) {
192             throw new IllegalArgumentException JavaDoc("rootName == null!");
193         }
194         if (minChildren < 0) {
195             throw new IllegalArgumentException JavaDoc("minChildren < 0!");
196         }
197         if (minChildren > maxChildren) {
198             throw new IllegalArgumentException JavaDoc("minChildren > maxChildren!");
199         }
200
201         Element root = new Element();
202         root.elementName = rootName;
203         root.childPolicy = CHILD_POLICY_REPEAT;
204         root.minChildren = minChildren;
205         root.maxChildren = maxChildren;
206
207         this.rootName = rootName;
208         elementMap.put(rootName, root);
209     }
210
211     /**
212      * Sets a new base name for locating <code>ResourceBundle</code>s
213      * containing descriptions of elements and attributes for this
214      * format.
215      *
216      * <p> Prior to the first time this method is called, the base
217      * name will be equal to <code>this.getClass().getName() +
218      * "Resources"</code>.
219      *
220      * @param resourceBaseName a <code>String</code> containg the new
221      * base name.
222      *
223      * @exception IllegalArgumentException if
224      * <code>resourceBaseName</code> is <code>null</code>.
225      *
226      * @see #getResourceBaseName
227      */

228     protected void setResourceBaseName(String JavaDoc resourceBaseName) {
229         if (resourceBaseName == null) {
230             throw new IllegalArgumentException JavaDoc("resourceBaseName == null!");
231         }
232         this.resourceBaseName = resourceBaseName;
233     }
234
235     /**
236      * Returns the currently set base name for locating
237      * <code>ResourceBundle</code>s.
238      *
239      * @return a <code>String</code> containing the base name.
240      *
241      * @see #setResourceBaseName
242      */

243     protected String JavaDoc getResourceBaseName() {
244         return resourceBaseName;
245     }
246
247     /**
248      * Utility method for locating an element.
249      *
250      * @param mustAppear if <code>true</code>, throw an
251      * <code>IllegalArgumentException</code> if no such node exists;
252      * if <code>false</code>, just return null.
253      */

254     private Element getElement(String JavaDoc elementName, boolean mustAppear) {
255         if (mustAppear && (elementName == null)) {
256             throw new IllegalArgumentException JavaDoc("element name is null!");
257         }
258         Element element = (Element)elementMap.get(elementName);
259         if (mustAppear && (element == null)) {
260             throw new IllegalArgumentException JavaDoc("No such element: " +
261                                                elementName);
262         }
263         return element;
264     }
265
266     private Element getElement(String JavaDoc elementName) {
267         return getElement(elementName, true);
268     }
269
270     // Utility method for locating an attribute
271
private Attribute getAttribute(String JavaDoc elementName, String JavaDoc attrName) {
272         Element element = getElement(elementName);
273         Attribute attr = (Attribute)element.attrMap.get(attrName);
274         if (attr == null) {
275             throw new IllegalArgumentException JavaDoc("No such attribute \"" +
276                                                attrName + "\"!");
277         }
278         return attr;
279     }
280
281     // Setup
282

283     /**
284      * Adds a new element type to this metadata document format with a
285      * child policy other than <code>CHILD_POLICY_REPEAT</code>.
286      *
287      * @param elementName the name of the new element.
288      * @param parentName the name of the element that will be the
289      * parent of the new element.
290      * @param childPolicy one of the <code>CHILD_POLICY_*</code>
291      * constants, other than <code>CHILD_POLICY_REPEAT</code>,
292      * indicating the child policy of the new element.
293      *
294      * @exception IllegalArgumentException if <code>parentName</code>
295      * is <code>null</code>, or is not a legal element name for this
296      * format.
297      * @exception IllegalArgumentException if <code>childPolicy</code>
298      * is not one of the predefined constants.
299      */

300     protected void addElement(String JavaDoc elementName,
301                               String JavaDoc parentName,
302                               int childPolicy) {
303         Element parent = getElement(parentName);
304         if (childPolicy < CHILD_POLICY_EMPTY ||
305             childPolicy > CHILD_POLICY_MAX ||
306             childPolicy == CHILD_POLICY_REPEAT) {
307             throw new IllegalArgumentException JavaDoc
308                 ("Invalid value for childPolicy!");
309         }
310
311         Element element = new Element();
312         element.elementName = elementName;
313         element.childPolicy = childPolicy;
314
315         parent.childList.add(elementName);
316         element.parentList.add(parentName);
317
318         elementMap.put(elementName, element);
319     }
320
321     /**
322      * Adds a new element type to this metadata document format with a
323      * child policy of <code>CHILD_POLICY_REPEAT</code>.
324      *
325      * @param elementName the name of the new element.
326      * @param parentName the name of the element that will be the
327      * parent of the new element.
328      * @param minChildren the minimum number of children of the node.
329      * @param maxChildren the maximum number of children of the node.
330      *
331      * @exception IllegalArgumentException if <code>parentName</code>
332      * is <code>null</code>, or is not a legal element name for this
333      * format.
334      * @exception IllegalArgumentException if <code>minChildren</code>
335      * is negative or larger than <code>maxChildren</code>.
336      */

337     protected void addElement(String JavaDoc elementName,
338                               String JavaDoc parentName,
339                               int minChildren,
340                               int maxChildren) {
341         Element parent = getElement(parentName);
342         if (minChildren < 0) {
343             throw new IllegalArgumentException JavaDoc("minChildren < 0!");
344         }
345         if (minChildren > maxChildren) {
346             throw new IllegalArgumentException JavaDoc("minChildren > maxChildren!");
347         }
348
349         Element element = new Element();
350         element.elementName = elementName;
351         element.childPolicy = CHILD_POLICY_REPEAT;
352         element.minChildren = minChildren;
353         element.maxChildren = maxChildren;
354
355         parent.childList.add(elementName);
356         element.parentList.add(parentName);
357
358         elementMap.put(elementName, element);
359     }
360
361     /**
362      * Adds an existing element to the list of legal children for a
363      * given parent node type.
364      *
365      * @param parentName the name of the element that will be the
366      * new parent of the element.
367      * @param elementName the name of the element to be addded as a
368      * child.
369      *
370      * @exception IllegalArgumentException if <code>elementName</code>
371      * is <code>null</code>, or is not a legal element name for this
372      * format.
373      * @exception IllegalArgumentException if <code>parentName</code>
374      * is <code>null</code>, or is not a legal element name for this
375      * format.
376      */

377     protected void addChildElement(String JavaDoc elementName, String JavaDoc parentName) {
378         Element parent = getElement(parentName);
379         Element element = getElement(elementName);
380         parent.childList.add(elementName);
381         element.parentList.add(parentName);
382     }
383
384     /**
385      * Removes an element from the format. If no element with the
386      * given name was present, nothing happens and no exception is
387      * thrown.
388      *
389      * @param elementName the name of the element to be removed.
390      */

391     protected void removeElement(String JavaDoc elementName) {
392         Element element = getElement(elementName, false);
393         if (element != null) {
394             Iterator JavaDoc iter = element.parentList.iterator();
395             while (iter.hasNext()) {
396                 String JavaDoc parentName = (String JavaDoc)iter.next();
397                 Element parent = getElement(parentName, false);
398                 if (parent != null) {
399                     parent.childList.remove(elementName);
400                 }
401             }
402             elementMap.remove(elementName);
403         }
404     }
405
406     /**
407      * Adds a new attribute to a previously defined element that may
408      * be set to an arbitrary value.
409      *
410      * @param elementName the name of the element.
411      * @param attrName the name of the attribute being added.
412      * @param dataType the data type (string format) of the attribute,
413      * one of the <code>DATATYPE_*</code> constants.
414      * @param required <code>true</code> if the attribute must be present.
415      * @param defaultValue the default value for the attribute, or
416      * <code>null</code>.
417      *
418      * @exception IllegalArgumentException if <code>elementName</code>
419      * is <code>null</code>, or is not a legal element name for this
420      * format.
421      * @exception IllegalArgumentException if <code>attrName</code> is
422      * <code>null</code>.
423      * @exception IllegalArgumentException if <code>dataType</code> is
424      * not one of the predefined constants.
425      */

426     protected void addAttribute(String JavaDoc elementName,
427                                 String JavaDoc attrName,
428                                 int dataType,
429                                 boolean required,
430                                 String JavaDoc defaultValue) {
431         Element element = getElement(elementName);
432         if (attrName == null) {
433             throw new IllegalArgumentException JavaDoc("attrName == null!");
434         }
435         if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
436             throw new IllegalArgumentException JavaDoc("Invalid value for dataType!");
437         }
438
439         Attribute attr = new Attribute();
440         attr.attrName = attrName;
441         attr.valueType = VALUE_ARBITRARY;
442         attr.dataType = dataType;
443         attr.required = required;
444         attr.defaultValue = defaultValue;
445
446         element.attrList.add(attrName);
447         element.attrMap.put(attrName, attr);
448     }
449
450     /**
451      * Adds a new attribute to a previously defined element that will
452      * be defined by a set of enumerated values.
453      *
454      * @param elementName the name of the element.
455      * @param attrName the name of the attribute being added.
456      * @param dataType the data type (string format) of the attribute,
457      * one of the <code>DATATYPE_*</code> constants.
458      * @param required <code>true</code> if the attribute must be present.
459      * @param defaultValue the default value for the attribute, or
460      * <code>null</code>.
461      * @param enumeratedValues a <code>List</code> of
462      * <code>String</code>s containing the legal values for the
463      * attribute.
464      *
465      * @exception IllegalArgumentException if <code>elementName</code>
466      * is <code>null</code>, or is not a legal element name for this
467      * format.
468      * @exception IllegalArgumentException if <code>attrName</code> is
469      * <code>null</code>.
470      * @exception IllegalArgumentException if <code>dataType</code> is
471      * not one of the predefined constants.
472      * @exception IllegalArgumentException if
473      * <code>enumeratedValues</code> is <code>null</code>.
474      * @exception IllegalArgumentException if
475      * <code>enumeratedValues</code> does not contain at least one
476      * entry.
477      * @exception IllegalArgumentException if
478      * <code>enumeratedValues</code> contains an element that is not a
479      * <code>String</code> or is <code>null</code>.
480      */

481     protected void addAttribute(String JavaDoc elementName,
482                                 String JavaDoc attrName,
483                                 int dataType,
484                                 boolean required,
485                                 String JavaDoc defaultValue,
486                                 List JavaDoc<String JavaDoc> enumeratedValues) {
487         Element element = getElement(elementName);
488         if (attrName == null) {
489             throw new IllegalArgumentException JavaDoc("attrName == null!");
490         }
491         if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
492             throw new IllegalArgumentException JavaDoc("Invalid value for dataType!");
493         }
494         if (enumeratedValues == null) {
495             throw new IllegalArgumentException JavaDoc("enumeratedValues == null!");
496         }
497         if (enumeratedValues.size() == 0) {
498             throw new IllegalArgumentException JavaDoc("enumeratedValues is empty!");
499         }
500         Iterator JavaDoc iter = enumeratedValues.iterator();
501         while (iter.hasNext()) {
502             Object JavaDoc o = iter.next();
503             if (o == null) {
504                 throw new IllegalArgumentException JavaDoc
505                     ("enumeratedValues contains a null!");
506             }
507             if (!(o instanceof String JavaDoc)) {
508                 throw new IllegalArgumentException JavaDoc
509                     ("enumeratedValues contains a non-String value!");
510             }
511         }
512
513         Attribute attr = new Attribute();
514         attr.attrName = attrName;
515         attr.valueType = VALUE_ENUMERATION;
516         attr.dataType = dataType;
517         attr.required = required;
518         attr.defaultValue = defaultValue;
519         attr.enumeratedValues = enumeratedValues;
520
521         element.attrList.add(attrName);
522         element.attrMap.put(attrName, attr);
523     }
524
525     /**
526      * Adds a new attribute to a previously defined element that will
527      * be defined by a range of values.
528      *
529      * @param elementName the name of the element.
530      * @param attrName the name of the attribute being added.
531      * @param dataType the data type (string format) of the attribute,
532      * one of the <code>DATATYPE_*</code> constants.
533      * @param required <code>true</code> if the attribute must be present.
534      * @param defaultValue the default value for the attribute, or
535      * <code>null</code>.
536      * @param minValue the smallest (inclusive or exclusive depending
537      * on the value of <code>minInclusive</code>) legal value for the
538      * attribute, as a <code>String</code>.
539      * @param maxValue the largest (inclusive or exclusive depending
540      * on the value of <code>minInclusive</code>) legal value for the
541      * attribute, as a <code>String</code>.
542      * @param minInclusive <code>true</code> if <code>minValue</code>
543      * is inclusive.
544      * @param maxInclusive <code>true</code> if <code>maxValue</code>
545      * is inclusive.
546      *
547      * @exception IllegalArgumentException if <code>elementName</code>
548      * is <code>null</code>, or is not a legal element name for this
549      * format.
550      * @exception IllegalArgumentException if <code>attrName</code> is
551      * <code>null</code>.
552      * @exception IllegalArgumentException if <code>dataType</code> is
553      * not one of the predefined constants.
554      */

555     protected void addAttribute(String JavaDoc elementName,
556                                 String JavaDoc attrName,
557                                 int dataType,
558                                 boolean required,
559                                 String JavaDoc defaultValue,
560                                 String JavaDoc minValue,
561                                 String JavaDoc maxValue,
562                                 boolean minInclusive,
563                                 boolean maxInclusive) {
564         Element element = getElement(elementName);
565         if (attrName == null) {
566             throw new IllegalArgumentException JavaDoc("attrName == null!");
567         }
568         if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
569             throw new IllegalArgumentException JavaDoc("Invalid value for dataType!");
570         }
571
572         Attribute attr = new Attribute();
573         attr.attrName = attrName;
574         attr.valueType = VALUE_RANGE;
575         if (minInclusive) {
576             attr.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;
577         }
578         if (maxInclusive) {
579             attr.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;
580         }
581         attr.dataType = dataType;
582         attr.required = required;
583         attr.defaultValue = defaultValue;
584         attr.minValue = minValue;
585         attr.maxValue = maxValue;
586
587         element.attrList.add(attrName);
588         element.attrMap.put(attrName, attr);
589     }
590
591     /**
592      * Adds a new attribute to a previously defined element that will
593      * be defined by a list of values.
594      *
595      * @param elementName the name of the element.
596      * @param attrName the name of the attribute being added.
597      * @param dataType the data type (string format) of the attribute,
598      * one of the <code>DATATYPE_*</code> constants.
599      * @param required <code>true</code> if the attribute must be present.
600      * @param listMinLength the smallest legal number of list items.
601      * @param listMaxLength the largest legal number of list items.
602      *
603      * @exception IllegalArgumentException if <code>elementName</code>
604      * is <code>null</code>, or is not a legal element name for this
605      * format.
606      * @exception IllegalArgumentException if <code>attrName</code> is
607      * <code>null</code>.
608      * @exception IllegalArgumentException if <code>dataType</code> is
609      * not one of the predefined constants.
610      * @exception IllegalArgumentException if
611      * <code>listMinLength</code> is negative or larger than
612      * <code>listMaxLength</code>.
613      */

614     protected void addAttribute(String JavaDoc elementName,
615                                 String JavaDoc attrName,
616                                 int dataType,
617                                 boolean required,
618                                 int listMinLength,
619                                 int listMaxLength) {
620         Element element = getElement(elementName);
621         if (attrName == null) {
622             throw new IllegalArgumentException JavaDoc("attrName == null!");
623         }
624         if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
625             throw new IllegalArgumentException JavaDoc("Invalid value for dataType!");
626         }
627         if (listMinLength < 0 || listMinLength > listMaxLength) {
628             throw new IllegalArgumentException JavaDoc("Invalid list bounds!");
629         }
630
631         Attribute attr = new Attribute();
632         attr.attrName = attrName;
633         attr.valueType = VALUE_LIST;
634         attr.dataType = dataType;
635         attr.required = required;
636         attr.listMinLength = listMinLength;
637         attr.listMaxLength = listMaxLength;
638
639         element.attrList.add(attrName);
640         element.attrMap.put(attrName, attr);
641     }
642
643     /**
644      * Adds a new attribute to a previously defined element that will
645      * be defined by the enumerated values <code>TRUE</code> and
646      * <code>FALSE</code>, with a datatype of
647      * <code>DATATYPE_BOOLEAN</code>.
648      *
649      * @param elementName the name of the element.
650      * @param attrName the name of the attribute being added.
651      * @param hasDefaultValue <code>true</code> if a default value
652      * should be present.
653      * @param defaultValue the default value for the attribute as a
654      * <code>boolean</code>, ignored if <code>hasDefaultValue</code>
655      * is <code>false</code>.
656      *
657      * @exception IllegalArgumentException if <code>elementName</code>
658      * is <code>null</code>, or is not a legal element name for this
659      * format.
660      * @exception IllegalArgumentException if <code>attrName</code> is
661      * <code>null</code>.
662      */

663     protected void addBooleanAttribute(String JavaDoc elementName,
664                                        String JavaDoc attrName,
665                                        boolean hasDefaultValue,
666                                        boolean defaultValue) {
667         List JavaDoc values = new ArrayList JavaDoc();
668         values.add("TRUE");
669         values.add("FALSE");
670         
671         String JavaDoc dval = null;
672         if (hasDefaultValue) {
673             dval = defaultValue ? "TRUE" : "FALSE";
674         }
675         addAttribute(elementName,
676                      attrName,
677                      DATATYPE_BOOLEAN,
678                      true,
679                      dval,
680                      values);
681     }
682
683     /**
684      * Removes an attribute from a previously defined element. If no
685      * attribute with the given name was present in the given element,
686      * nothing happens and no exception is thrown.
687      *
688      * @param elementName the name of the element.
689      * @param attrName the name of the attribute being removed.
690      *
691      * @exception IllegalArgumentException if <code>elementName</code>
692      * is <code>null</code>, or is not a legal element name for this format.
693      */

694     protected void removeAttribute(String JavaDoc elementName, String JavaDoc attrName) {
695         Element element = getElement(elementName);
696         element.attrList.remove(attrName);
697         element.attrMap.remove(attrName);
698     }
699
700     /**
701      * Allows an <code>Object</code> reference of a given class type
702      * to be stored in nodes implementing the named element. The
703      * value of the <code>Object</code> is unconstrained other than by
704      * its class type.
705      *
706      * <p> If an <code>Object</code> reference was previously allowed,
707      * the previous settings are overwritten.
708      *
709      * @param elementName the name of the element.
710      * @param classType a <code>Class</code> variable indicating the
711      * legal class type for the object value.
712      * @param required <code>true</code> if an object value must be present.
713      * @param defaultValue the default value for the
714      * <code>Object</code> reference, or <code>null</code>.
715      *
716      * @exception IllegalArgumentException if <code>elementName</code>
717      * is <code>null</code>, or is not a legal element name for this format.
718      */

719     protected <T> void addObjectValue(String JavaDoc elementName,
720                       Class JavaDoc<T> classType,
721                       boolean required,
722                       T defaultValue)
723     {
724         Element element = getElement(elementName);
725         ObjectValue obj = new ObjectValue();
726         obj.valueType = VALUE_ARBITRARY;
727         obj.classType = classType;
728         obj.defaultValue = defaultValue;
729
730         element.objectValue = obj;
731     }
732
733     /**
734      * Allows an <code>Object</code> reference of a given class type
735      * to be stored in nodes implementing the named element. The
736      * value of the <code>Object</code> must be one of the values
737      * given by <code>enumeratedValues</code>.
738      *
739      * <p> If an <code>Object</code> reference was previously allowed,
740      * the previous settings are overwritten.
741      *
742      * @param elementName the name of the element.
743      * @param classType a <code>Class</code> variable indicating the
744      * legal class type for the object value.
745      * @param required <code>true</code> if an object value must be present.
746      * @param defaultValue the default value for the
747      * <code>Object</code> reference, or <code>null</code>.
748      * @param enumeratedValues a <code>List</code> of
749      * <code>Object</code>s containing the legal values for the
750      * object reference.
751      *
752      * @exception IllegalArgumentException if <code>elementName</code>
753      * is <code>null</code>, or is not a legal element name for this format.
754      * @exception IllegalArgumentException if
755      * <code>enumeratedValues</code> is <code>null</code>.
756      * @exception IllegalArgumentException if
757      * <code>enumeratedValues</code> does not contain at least one
758      * entry.
759      * @exception IllegalArgumentException if
760      * <code>enumeratedValues</code> contains an element that is not
761      * an instance of the class type denoted by <code>classType</code>
762      * or is <code>null</code>.
763      */

764     protected <T> void addObjectValue(String JavaDoc elementName,
765                       Class JavaDoc<T> classType,
766                       boolean required,
767                       T defaultValue,
768                       List JavaDoc<? extends T> enumeratedValues)
769     {
770         Element element = getElement(elementName);
771         if (enumeratedValues == null) {
772             throw new IllegalArgumentException JavaDoc("enumeratedValues == null!");
773         }
774         if (enumeratedValues.size() == 0) {
775             throw new IllegalArgumentException JavaDoc("enumeratedValues is empty!");
776         }
777         Iterator JavaDoc iter = enumeratedValues.iterator();
778         while (iter.hasNext()) {
779             Object JavaDoc o = iter.next();
780             if (o == null) {
781                 throw new IllegalArgumentException JavaDoc("enumeratedValues contains a null!");
782             }
783             if (!classType.isInstance(o)) {
784                 throw new IllegalArgumentException JavaDoc("enumeratedValues contains a value not of class classType!");
785             }
786         }
787
788         ObjectValue obj = new ObjectValue();
789         obj.valueType = VALUE_ENUMERATION;
790         obj.classType = classType;
791         obj.defaultValue = defaultValue;
792         obj.enumeratedValues = enumeratedValues;
793
794         element.objectValue = obj;
795     }
796
797     /**
798      * Allows an <code>Object</code> reference of a given class type
799      * to be stored in nodes implementing the named element. The
800      * value of the <code>Object</code> must be within the range given
801      * by <code>minValue</code> and <code>maxValue</code>.
802      * Furthermore, the class type must implement the
803      * <code>Comparable</code> interface.
804      *
805      * <p> If an <code>Object</code> reference was previously allowed,
806      * the previous settings are overwritten.
807      *
808      * @param elementName the name of the element.
809      * @param classType a <code>Class</code> variable indicating the
810      * legal class type for the object value.
811      * @param defaultValue the default value for the
812      * @param minValue the smallest (inclusive or exclusive depending
813      * on the value of <code>minInclusive</code>) legal value for the
814      * object value, as a <code>String</code>.
815      * @param maxValue the largest (inclusive or exclusive depending
816      * on the value of <code>minInclusive</code>) legal value for the
817      * object value, as a <code>String</code>.
818      * @param minInclusive <code>true</code> if <code>minValue</code>
819      * is inclusive.
820      * @param maxInclusive <code>true</code> if <code>maxValue</code>
821      * is inclusive.
822      *
823      * @exception IllegalArgumentException if <code>elementName</code>
824      * is <code>null</code>, or is not a legal element name for this
825      * format.
826      */

827     protected <T extends Object JavaDoc & Comparable JavaDoc<? super T>> void
828     addObjectValue(String JavaDoc elementName,
829                Class JavaDoc<T> classType,
830                T defaultValue,
831                Comparable JavaDoc<? super T> minValue,
832                Comparable JavaDoc<? super T> maxValue,
833                boolean minInclusive,
834                boolean maxInclusive)
835     {
836         Element element = getElement(elementName);
837         ObjectValue obj = new ObjectValue();
838         obj.valueType = VALUE_RANGE;
839         if (minInclusive) {
840             obj.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;
841         }
842         if (maxInclusive) {
843             obj.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;
844         }
845         obj.classType = classType;
846         obj.defaultValue = defaultValue;
847         obj.minValue = minValue;
848         obj.maxValue = maxValue;
849
850         element.objectValue = obj;
851     }
852
853     /**
854      * Allows an <code>Object</code> reference of a given class type
855      * to be stored in nodes implementing the named element. The
856      * value of the <code>Object</code> must an array of objects of
857      * class type given by <code>classType</code>, with at least
858      * <code>arrayMinLength</code> and at most
859      * <code>arrayMaxLength</code> elements.
860      *
861      * <p> If an <code>Object</code> reference was previously allowed,
862      * the previous settings are overwritten.
863      *
864      * @param elementName the name of the element.
865      * @param classType a <code>Class</code> variable indicating the
866      * legal class type for the object value.
867      * @param arrayMinLength the smallest legal length for the array.
868      * @param arrayMaxLength the largest legal length for the array.
869      *
870      * @exception IllegalArgumentException if <code>elementName</code> is
871      * not a legal element name for this format.
872      */

873     protected void addObjectValue(String JavaDoc elementName,
874                                   Class JavaDoc<?> classType,
875                                   int arrayMinLength,
876                                   int arrayMaxLength) {
877         Element element = getElement(elementName);
878         ObjectValue obj = new ObjectValue();
879         obj.valueType = VALUE_LIST;
880         obj.classType = classType;
881         obj.arrayMinLength = arrayMinLength;
882         obj.arrayMaxLength = arrayMaxLength;
883
884         element.objectValue = obj;
885     }
886
887     /**
888      * Disallows an <code>Object</code> reference from being stored in
889      * nodes implementing the named element.
890      *
891      * @param elementName the name of the element.
892      *
893      * @exception IllegalArgumentException if <code>elementName</code> is
894      * not a legal element name for this format.
895      */

896     protected void removeObjectValue(String JavaDoc elementName) {
897         Element element = getElement(elementName);
898         element.objectValue = null;
899     }
900
901     // Utility method
902

903     // Methods from IIOMetadataFormat
904

905     // Root
906

907     public String JavaDoc getRootName() {
908         return rootName;
909     }
910
911     // Multiplicity
912

913     public abstract boolean canNodeAppear(String JavaDoc elementName,
914                                           ImageTypeSpecifier JavaDoc imageType);
915
916     public int getElementMinChildren(String JavaDoc elementName) {
917         Element element = getElement(elementName);
918         if (element.childPolicy != CHILD_POLICY_REPEAT) {
919             throw new IllegalArgumentException JavaDoc("Child policy not CHILD_POLICY_REPEAT!");
920         }
921         return element.minChildren;
922     }
923
924     public int getElementMaxChildren(String JavaDoc elementName) {
925         Element element = getElement(elementName);
926         if (element.childPolicy != CHILD_POLICY_REPEAT) {
927             throw new IllegalArgumentException JavaDoc("Child policy not CHILD_POLICY_REPEAT!");
928         }
929         return element.maxChildren;
930     }
931
932     private String JavaDoc getResource(String JavaDoc key, Locale JavaDoc locale) {
933         if (locale == null) {
934             locale = Locale.getDefault();
935         }
936
937         /**
938          * If an applet supplies an implementation of IIOMetadataFormat and
939          * resource bundles, then the resource bundle will need to be
940          * accessed via the applet class loader. So first try the context
941          * class loader to locate the resource bundle.
942          * If that throws MissingResourceException, then try the
943          * system class loader.
944          */

945         ClassLoader JavaDoc loader = (ClassLoader JavaDoc)
946             java.security.AccessController.doPrivileged(
947                 new java.security.PrivilegedAction JavaDoc() {
948                    public Object JavaDoc run() {
949                        return Thread.currentThread().getContextClassLoader();
950                    }
951             });
952
953         ResourceBundle JavaDoc bundle = null;
954         try {
955             bundle = ResourceBundle.getBundle(resourceBaseName,
956                                               locale, loader);
957         } catch (MissingResourceException JavaDoc mre) {
958             try {
959                 bundle = ResourceBundle.getBundle(resourceBaseName, locale);
960             } catch (MissingResourceException JavaDoc mre1) {
961                 return null;
962             }
963         }
964
965         try {
966             return bundle.getString(key);
967         } catch (MissingResourceException JavaDoc e) {
968             return null;
969         }
970     }
971
972     /**
973      * Returns a <code>String</code> containing a description of the
974      * named element, or <code>null</code>. The desciption will be
975      * localized for the supplied <code>Locale</code> if possible.
976      *
977      * <p> The default implementation will first locate a
978      * <code>ResourceBundle</code> using the current resource base
979      * name set by <code>setResourceBaseName</code> and the supplied
980      * <code>Locale</code>, using the fallback mechanism described in
981      * the comments for <code>ResourceBundle.getBundle</code>. If a
982      * <code>ResourceBundle</code> is found, the element name will be
983      * used as a key to its <code>getString</code> method, and the
984      * result returned. If no <code>ResourceBundle</code> is found,
985      * or no such key is present, <code>null</code> will be returned.
986      *
987      * <p> If <code>locale</code> is <code>null</code>, the current
988      * default <code>Locale</code> returned by <code>Locale.getLocale</code>
989      * will be used.
990      *
991      * @param elementName the name of the element.
992      * @param locale the <code>Locale</code> for which localization
993      * will be attempted.
994      *
995      * @return the element description.
996      *
997      * @exception IllegalArgumentException if <code>elementName</code>
998      * is <code>null</code>, or is not a legal element name for this format.
999      *
1000     * @see #setResourceBaseName
1001     */

1002    public String JavaDoc getElementDescription(String JavaDoc elementName,
1003                                        Locale JavaDoc locale) {
1004        Element element = getElement(elementName);
1005        return getResource(elementName, locale);
1006    }
1007
1008    // Children
1009

1010    public int getChildPolicy(String JavaDoc elementName) {
1011        Element element = getElement(elementName);
1012        return element.childPolicy;
1013    }
1014
1015    public String JavaDoc[] getChildNames(String JavaDoc elementName) {
1016        Element element = getElement(elementName);
1017        if (element.childPolicy == CHILD_POLICY_EMPTY) {
1018            return null;
1019        }
1020        return (String JavaDoc[])element.childList.toArray(new String JavaDoc[0]);
1021    }
1022
1023    // Attributes
1024

1025    public String JavaDoc[] getAttributeNames(String JavaDoc elementName) {
1026        Element element = getElement(elementName);
1027        List JavaDoc names = element.attrList;
1028
1029        String JavaDoc[] result = new String JavaDoc[names.size()];
1030        return (String JavaDoc[])names.toArray(result);
1031    }
1032
1033    public int getAttributeValueType(String JavaDoc elementName, String JavaDoc attrName) {
1034        Attribute attr = getAttribute(elementName, attrName);
1035        return attr.valueType;
1036    }
1037    
1038    public int getAttributeDataType(String JavaDoc elementName, String JavaDoc attrName) {
1039        Attribute attr = getAttribute(elementName, attrName);
1040        return attr.dataType;
1041    }
1042
1043    public boolean isAttributeRequired(String JavaDoc elementName, String JavaDoc attrName) {
1044        Attribute attr = getAttribute(elementName, attrName);
1045        return attr.required;
1046    }
1047
1048    public String JavaDoc getAttributeDefaultValue(String JavaDoc elementName,
1049                                           String JavaDoc attrName) {
1050        Attribute attr = getAttribute(elementName, attrName);
1051        return attr.defaultValue;
1052    }
1053
1054    public String JavaDoc[] getAttributeEnumerations(String JavaDoc elementName,
1055                                             String JavaDoc attrName) {
1056        Attribute attr = getAttribute(elementName, attrName);
1057        if (attr.valueType != VALUE_ENUMERATION) {
1058            throw new IllegalArgumentException JavaDoc
1059                ("Attribute not an enumeration!");
1060        }
1061        
1062        List JavaDoc values = attr.enumeratedValues;
1063        Iterator JavaDoc iter = values.iterator();
1064        String JavaDoc[] result = new String JavaDoc[values.size()];
1065        return (String JavaDoc[])values.toArray(result);
1066    }
1067
1068    public String JavaDoc getAttributeMinValue(String JavaDoc elementName, String JavaDoc attrName) {
1069        Attribute attr = getAttribute(elementName, attrName);
1070        if (attr.valueType != VALUE_RANGE &&
1071            attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
1072            attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
1073            attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {
1074            throw new IllegalArgumentException JavaDoc("Attribute not a range!");
1075        }
1076
1077        return attr.minValue;
1078    }
1079
1080    public String JavaDoc getAttributeMaxValue(String JavaDoc elementName, String JavaDoc attrName) {
1081        Attribute attr = getAttribute(elementName, attrName);
1082        if (attr.valueType != VALUE_RANGE &&
1083            attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
1084            attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
1085            attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {
1086            throw new IllegalArgumentException JavaDoc("Attribute not a range!");
1087        }
1088
1089        return attr.maxValue;
1090    }
1091
1092    public int getAttributeListMinLength(String JavaDoc elementName, String JavaDoc attrName) {
1093        Attribute attr = getAttribute(elementName, attrName);
1094        if (attr.valueType != VALUE_LIST) {
1095            throw new IllegalArgumentException JavaDoc("Attribute not a list!");
1096        }
1097
1098        return attr.listMinLength;
1099    }
1100
1101    public int getAttributeListMaxLength(String JavaDoc elementName, String JavaDoc attrName) {
1102        Attribute attr = getAttribute(elementName, attrName);
1103        if (attr.valueType != VALUE_LIST) {
1104            throw new IllegalArgumentException JavaDoc("Attribute not a list!");
1105        }
1106
1107        return attr.listMaxLength;
1108    }
1109
1110    /**
1111     * Returns a <code>String</code> containing a description of the
1112     * named attribute, or <code>null</code>. The desciption will be
1113     * localized for the supplied <code>Locale</code> if possible.
1114     *
1115     * <p> The default implementation will first locate a
1116     * <code>ResourceBundle</code> using the current resource base
1117     * name set by <code>setResourceBaseName</code> and the supplied
1118     * <code>Locale</code>, using the fallback mechanism described in
1119     * the comments for <code>ResourceBundle.getBundle</code>. If a
1120     * <code>ResourceBundle</code> is found, the element name followed
1121     * by a "/" character followed by the attribute name
1122     * (<code>elementName + "/" + attrName</code>) will be used as a
1123     * key to its <code>getString</code> method, and the result
1124     * returned. If no <code>ResourceBundle</code> is found, or no
1125     * such key is present, <code>null</code> will be returned.
1126     *
1127     * <p> If <code>locale</code> is <code>null</code>, the current
1128     * default <code>Locale</code> returned by <code>Locale.getLocale</code>
1129     * will be used.
1130     *
1131     * @param elementName the name of the element.
1132     * @param attrName the name of the attribute.
1133     * @param locale the <code>Locale</code> for which localization
1134     * will be attempted, or <code>null</code>.
1135     *
1136     * @return the attribute description.
1137     *
1138     * @exception IllegalArgumentException if <code>elementName</code>
1139     * is <code>null</code>, or is not a legal element name for this format.
1140     * @exception IllegalArgumentException if <code>attrName</code> is
1141     * <code>null</code> or is not a legal attribute name for this
1142     * element.
1143     *
1144     * @see #setResourceBaseName
1145     */

1146    public String JavaDoc getAttributeDescription(String JavaDoc elementName,
1147                                          String JavaDoc attrName,
1148                                          Locale JavaDoc locale) {
1149        Element element = getElement(elementName);
1150        if (attrName == null) {
1151            throw new IllegalArgumentException JavaDoc("attrName == null!");
1152        }
1153        Attribute attr = (Attribute)element.attrMap.get(attrName);
1154        if (attr == null) {
1155            throw new IllegalArgumentException JavaDoc("No such attribute!");
1156        }
1157
1158        String JavaDoc key = elementName + "/" + attrName;
1159        return getResource(key, locale);
1160    }
1161
1162    private ObjectValue getObjectValue(String JavaDoc elementName) {
1163        Element element = getElement(elementName);
1164        ObjectValue objv = (ObjectValue)element.objectValue;
1165        if (objv == null) {
1166            throw new IllegalArgumentException JavaDoc("No object within element " +
1167                                               elementName + "!");
1168        }
1169        return objv;
1170    }
1171
1172    public int getObjectValueType(String JavaDoc elementName) {
1173        Element element = getElement(elementName);
1174        ObjectValue objv = (ObjectValue)element.objectValue;
1175        if (objv == null) {
1176            return VALUE_NONE;
1177        }
1178        return objv.valueType;
1179    }
1180
1181    public Class JavaDoc<?> getObjectClass(String JavaDoc elementName) {
1182        ObjectValue objv = getObjectValue(elementName);
1183        return objv.classType;
1184    }
1185
1186    public Object JavaDoc getObjectDefaultValue(String JavaDoc elementName) {
1187        ObjectValue objv = getObjectValue(elementName);
1188        return objv.defaultValue;
1189    }
1190
1191    public Object JavaDoc[] getObjectEnumerations(String JavaDoc elementName) {
1192        ObjectValue objv = getObjectValue(elementName);
1193        if (objv.valueType != VALUE_ENUMERATION) {
1194            throw new IllegalArgumentException JavaDoc("Not an enumeration!");
1195        }
1196        List JavaDoc vlist = objv.enumeratedValues;
1197        Object JavaDoc[] values = new Object JavaDoc[vlist.size()];
1198        return vlist.toArray(values);
1199    }
1200
1201    public Comparable JavaDoc<?> getObjectMinValue(String JavaDoc elementName) {
1202        ObjectValue objv = getObjectValue(elementName);
1203        if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
1204            throw new IllegalArgumentException JavaDoc("Not a range!");
1205        }
1206        return objv.minValue;
1207    }
1208
1209    public Comparable JavaDoc<?> getObjectMaxValue(String JavaDoc elementName) {
1210        ObjectValue objv = getObjectValue(elementName);
1211        if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
1212            throw new IllegalArgumentException JavaDoc("Not a range!");
1213        }
1214        return objv.maxValue;
1215    }
1216
1217    public int getObjectArrayMinLength(String JavaDoc elementName) {
1218        ObjectValue objv = getObjectValue(elementName);
1219        if (objv.valueType != VALUE_LIST) {
1220            throw new IllegalArgumentException JavaDoc("Not a list!");
1221        }
1222        return objv.arrayMinLength;
1223    }
1224
1225    public int getObjectArrayMaxLength(String JavaDoc elementName) {
1226        ObjectValue objv = getObjectValue(elementName);
1227        if (objv.valueType != VALUE_LIST) {
1228            throw new IllegalArgumentException JavaDoc("Not a list!");
1229        }
1230        return objv.arrayMaxLength;
1231    }
1232
1233    // Standard format descriptor
1234

1235    private synchronized static void createStandardFormat() {
1236        if (standardFormat == null) {
1237            standardFormat = new StandardMetadataFormat();
1238        }
1239    }
1240
1241    /**
1242     * Returns an <code>IIOMetadataFormat</code> object describing the
1243     * standard, plug-in neutral <code>javax.imageio_1.0</code>
1244     * metadata document format described in the comment of the
1245     * <code>javax.imageio.metadata</code> package.
1246     *
1247     * @return a predefined <code>IIOMetadataFormat</code> instance.
1248     */

1249    public static IIOMetadataFormat JavaDoc getStandardFormatInstance() {
1250        createStandardFormat();
1251        return standardFormat;
1252    }
1253}
1254
Popular Tags