Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java
38918 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.imageio.metadata;2627import java.util.ArrayList;28import java.util.Collection;29import java.util.HashMap;30import java.util.Iterator;31import java.util.List;32import java.util.Locale;33import java.util.Map;34import java.util.MissingResourceException;35import java.util.ResourceBundle;36import javax.imageio.ImageTypeSpecifier;37import com.sun.imageio.plugins.common.StandardMetadataFormat;3839/**40* A concrete class providing a reusable implementation of the41* <code>IIOMetadataFormat</code> interface. In addition, a static42* instance representing the standard, plug-in neutral43* <code>javax_imageio_1.0</code> format is provided by the44* <code>getStandardFormatInstance</code> method.45*46* <p> In order to supply localized descriptions of elements and47* attributes, a <code>ResourceBundle</code> with a base name of48* <code>this.getClass().getName() + "Resources"</code> should be49* supplied via the usual mechanism used by50* <code>ResourceBundle.getBundle</code>. Briefly, the subclasser51* supplies one or more additional classes according to a naming52* convention (by default, the fully-qualified name of the subclass53* extending <code>IIMetadataFormatImpl</code>, plus the string54* "Resources", plus the country, language, and variant codes55* separated by underscores). At run time, calls to56* <code>getElementDescription</code> or57* <code>getAttributeDescription</code> will attempt to load such58* classes dynamically according to the supplied locale, and will use59* either the element name, or the element name followed by a '/'60* character followed by the attribute name as a key. This key will61* be supplied to the <code>ResourceBundle</code>'s62* <code>getString</code> method, and the resulting localized63* description of the node or attribute is returned.64*65* <p> The subclass may supply a different base name for the resource66* bundles using the <code>setResourceBaseName</code> method.67*68* <p> A subclass may choose its own localization mechanism, if so69* desired, by overriding the supplied implementations of70* <code>getElementDescription</code> and71* <code>getAttributeDescription</code>.72*73* @see ResourceBundle#getBundle(String,Locale)74*75*/76public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat {7778/**79* A <code>String</code> constant containing the standard format80* name, <code>"javax_imageio_1.0"</code>.81*/82public static final String standardMetadataFormatName =83"javax_imageio_1.0";8485private static IIOMetadataFormat standardFormat = null;8687private String resourceBaseName = this.getClass().getName() + "Resources";8889private String rootName;9091// Element name (String) -> Element92private HashMap elementMap = new HashMap();9394class Element {95String elementName;9697int childPolicy;98int minChildren = 0;99int maxChildren = 0;100101// Child names (Strings)102List childList = new ArrayList();103104// Parent names (Strings)105List parentList = new ArrayList();106107// List of attribute names in the order they were added108List attrList = new ArrayList();109// Attr name (String) -> Attribute110Map attrMap = new HashMap();111112ObjectValue objectValue;113}114115class Attribute {116String attrName;117118int valueType = VALUE_ARBITRARY;119int dataType;120boolean required;121String defaultValue = null;122123// enumeration124List enumeratedValues;125126// range127String minValue;128String maxValue;129130// list131int listMinLength;132int listMaxLength;133}134135class ObjectValue {136int valueType = VALUE_NONE;137Class classType = null;138Object defaultValue = null;139140// Meaningful only if valueType == VALUE_ENUMERATION141List enumeratedValues = null;142143// Meaningful only if valueType == VALUE_RANGE144Comparable minValue = null;145Comparable maxValue = null;146147// Meaningful only if valueType == VALUE_LIST148int arrayMinLength = 0;149int arrayMaxLength = 0;150}151152/**153* Constructs a blank <code>IIOMetadataFormatImpl</code> instance,154* with a given root element name and child policy (other than155* <code>CHILD_POLICY_REPEAT</code>). Additional elements, and156* their attributes and <code>Object</code> reference information157* may be added using the various <code>add</code> methods.158*159* @param rootName the name of the root element.160* @param childPolicy one of the <code>CHILD_POLICY_*</code> constants,161* other than <code>CHILD_POLICY_REPEAT</code>.162*163* @exception IllegalArgumentException if <code>rootName</code> is164* <code>null</code>.165* @exception IllegalArgumentException if <code>childPolicy</code> is166* not one of the predefined constants.167*/168public IIOMetadataFormatImpl(String rootName,169int childPolicy) {170if (rootName == null) {171throw new IllegalArgumentException("rootName == null!");172}173if (childPolicy < CHILD_POLICY_EMPTY ||174childPolicy > CHILD_POLICY_MAX ||175childPolicy == CHILD_POLICY_REPEAT) {176throw new IllegalArgumentException("Invalid value for childPolicy!");177}178179this.rootName = rootName;180181Element root = new Element();182root.elementName = rootName;183root.childPolicy = childPolicy;184185elementMap.put(rootName, root);186}187188/**189* Constructs a blank <code>IIOMetadataFormatImpl</code> instance,190* with a given root element name and a child policy of191* <code>CHILD_POLICY_REPEAT</code>. Additional elements, and192* their attributes and <code>Object</code> reference information193* may be added using the various <code>add</code> methods.194*195* @param rootName the name of the root element.196* @param minChildren the minimum number of children of the node.197* @param maxChildren the maximum number of children of the node.198*199* @exception IllegalArgumentException if <code>rootName</code> is200* <code>null</code>.201* @exception IllegalArgumentException if <code>minChildren</code>202* is negative or larger than <code>maxChildren</code>.203*/204public IIOMetadataFormatImpl(String rootName,205int minChildren,206int maxChildren) {207if (rootName == null) {208throw new IllegalArgumentException("rootName == null!");209}210if (minChildren < 0) {211throw new IllegalArgumentException("minChildren < 0!");212}213if (minChildren > maxChildren) {214throw new IllegalArgumentException("minChildren > maxChildren!");215}216217Element root = new Element();218root.elementName = rootName;219root.childPolicy = CHILD_POLICY_REPEAT;220root.minChildren = minChildren;221root.maxChildren = maxChildren;222223this.rootName = rootName;224elementMap.put(rootName, root);225}226227/**228* Sets a new base name for locating <code>ResourceBundle</code>s229* containing descriptions of elements and attributes for this230* format.231*232* <p> Prior to the first time this method is called, the base233* name will be equal to <code>this.getClass().getName() +234* "Resources"</code>.235*236* @param resourceBaseName a <code>String</code> containing the new237* base name.238*239* @exception IllegalArgumentException if240* <code>resourceBaseName</code> is <code>null</code>.241*242* @see #getResourceBaseName243*/244protected void setResourceBaseName(String resourceBaseName) {245if (resourceBaseName == null) {246throw new IllegalArgumentException("resourceBaseName == null!");247}248this.resourceBaseName = resourceBaseName;249}250251/**252* Returns the currently set base name for locating253* <code>ResourceBundle</code>s.254*255* @return a <code>String</code> containing the base name.256*257* @see #setResourceBaseName258*/259protected String getResourceBaseName() {260return resourceBaseName;261}262263/**264* Utility method for locating an element.265*266* @param mustAppear if <code>true</code>, throw an267* <code>IllegalArgumentException</code> if no such node exists;268* if <code>false</code>, just return null.269*/270private Element getElement(String elementName, boolean mustAppear) {271if (mustAppear && (elementName == null)) {272throw new IllegalArgumentException("element name is null!");273}274Element element = (Element)elementMap.get(elementName);275if (mustAppear && (element == null)) {276throw new IllegalArgumentException("No such element: " +277elementName);278}279return element;280}281282private Element getElement(String elementName) {283return getElement(elementName, true);284}285286// Utility method for locating an attribute287private Attribute getAttribute(String elementName, String attrName) {288Element element = getElement(elementName);289Attribute attr = (Attribute)element.attrMap.get(attrName);290if (attr == null) {291throw new IllegalArgumentException("No such attribute \"" +292attrName + "\"!");293}294return attr;295}296297// Setup298299/**300* Adds a new element type to this metadata document format with a301* child policy other than <code>CHILD_POLICY_REPEAT</code>.302*303* @param elementName the name of the new element.304* @param parentName the name of the element that will be the305* parent of the new element.306* @param childPolicy one of the <code>CHILD_POLICY_*</code>307* constants, other than <code>CHILD_POLICY_REPEAT</code>,308* indicating the child policy of the new element.309*310* @exception IllegalArgumentException if <code>parentName</code>311* is <code>null</code>, or is not a legal element name for this312* format.313* @exception IllegalArgumentException if <code>childPolicy</code>314* is not one of the predefined constants.315*/316protected void addElement(String elementName,317String parentName,318int childPolicy) {319Element parent = getElement(parentName);320if (childPolicy < CHILD_POLICY_EMPTY ||321childPolicy > CHILD_POLICY_MAX ||322childPolicy == CHILD_POLICY_REPEAT) {323throw new IllegalArgumentException324("Invalid value for childPolicy!");325}326327Element element = new Element();328element.elementName = elementName;329element.childPolicy = childPolicy;330331parent.childList.add(elementName);332element.parentList.add(parentName);333334elementMap.put(elementName, element);335}336337/**338* Adds a new element type to this metadata document format with a339* child policy of <code>CHILD_POLICY_REPEAT</code>.340*341* @param elementName the name of the new element.342* @param parentName the name of the element that will be the343* parent of the new element.344* @param minChildren the minimum number of children of the node.345* @param maxChildren the maximum number of children of the node.346*347* @exception IllegalArgumentException if <code>parentName</code>348* is <code>null</code>, or is not a legal element name for this349* format.350* @exception IllegalArgumentException if <code>minChildren</code>351* is negative or larger than <code>maxChildren</code>.352*/353protected void addElement(String elementName,354String parentName,355int minChildren,356int maxChildren) {357Element parent = getElement(parentName);358if (minChildren < 0) {359throw new IllegalArgumentException("minChildren < 0!");360}361if (minChildren > maxChildren) {362throw new IllegalArgumentException("minChildren > maxChildren!");363}364365Element element = new Element();366element.elementName = elementName;367element.childPolicy = CHILD_POLICY_REPEAT;368element.minChildren = minChildren;369element.maxChildren = maxChildren;370371parent.childList.add(elementName);372element.parentList.add(parentName);373374elementMap.put(elementName, element);375}376377/**378* Adds an existing element to the list of legal children for a379* given parent node type.380*381* @param parentName the name of the element that will be the382* new parent of the element.383* @param elementName the name of the element to be added as a384* child.385*386* @exception IllegalArgumentException if <code>elementName</code>387* is <code>null</code>, or is not a legal element name for this388* format.389* @exception IllegalArgumentException if <code>parentName</code>390* is <code>null</code>, or is not a legal element name for this391* format.392*/393protected void addChildElement(String elementName, String parentName) {394Element parent = getElement(parentName);395Element element = getElement(elementName);396parent.childList.add(elementName);397element.parentList.add(parentName);398}399400/**401* Removes an element from the format. If no element with the402* given name was present, nothing happens and no exception is403* thrown.404*405* @param elementName the name of the element to be removed.406*/407protected void removeElement(String elementName) {408Element element = getElement(elementName, false);409if (element != null) {410Iterator iter = element.parentList.iterator();411while (iter.hasNext()) {412String parentName = (String)iter.next();413Element parent = getElement(parentName, false);414if (parent != null) {415parent.childList.remove(elementName);416}417}418elementMap.remove(elementName);419}420}421422/**423* Adds a new attribute to a previously defined element that may424* be set to an arbitrary value.425*426* @param elementName the name of the element.427* @param attrName the name of the attribute being added.428* @param dataType the data type (string format) of the attribute,429* one of the <code>DATATYPE_*</code> constants.430* @param required <code>true</code> if the attribute must be present.431* @param defaultValue the default value for the attribute, or432* <code>null</code>.433*434* @exception IllegalArgumentException if <code>elementName</code>435* is <code>null</code>, or is not a legal element name for this436* format.437* @exception IllegalArgumentException if <code>attrName</code> is438* <code>null</code>.439* @exception IllegalArgumentException if <code>dataType</code> is440* not one of the predefined constants.441*/442protected void addAttribute(String elementName,443String attrName,444int dataType,445boolean required,446String defaultValue) {447Element element = getElement(elementName);448if (attrName == null) {449throw new IllegalArgumentException("attrName == null!");450}451if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {452throw new IllegalArgumentException("Invalid value for dataType!");453}454455Attribute attr = new Attribute();456attr.attrName = attrName;457attr.valueType = VALUE_ARBITRARY;458attr.dataType = dataType;459attr.required = required;460attr.defaultValue = defaultValue;461462element.attrList.add(attrName);463element.attrMap.put(attrName, attr);464}465466/**467* Adds a new attribute to a previously defined element that will468* be defined by a set of enumerated values.469*470* @param elementName the name of the element.471* @param attrName the name of the attribute being added.472* @param dataType the data type (string format) of the attribute,473* one of the <code>DATATYPE_*</code> constants.474* @param required <code>true</code> if the attribute must be present.475* @param defaultValue the default value for the attribute, or476* <code>null</code>.477* @param enumeratedValues a <code>List</code> of478* <code>String</code>s containing the legal values for the479* attribute.480*481* @exception IllegalArgumentException if <code>elementName</code>482* is <code>null</code>, or is not a legal element name for this483* format.484* @exception IllegalArgumentException if <code>attrName</code> is485* <code>null</code>.486* @exception IllegalArgumentException if <code>dataType</code> is487* not one of the predefined constants.488* @exception IllegalArgumentException if489* <code>enumeratedValues</code> is <code>null</code>.490* @exception IllegalArgumentException if491* <code>enumeratedValues</code> does not contain at least one492* entry.493* @exception IllegalArgumentException if494* <code>enumeratedValues</code> contains an element that is not a495* <code>String</code> or is <code>null</code>.496*/497protected void addAttribute(String elementName,498String attrName,499int dataType,500boolean required,501String defaultValue,502List<String> enumeratedValues) {503Element element = getElement(elementName);504if (attrName == null) {505throw new IllegalArgumentException("attrName == null!");506}507if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {508throw new IllegalArgumentException("Invalid value for dataType!");509}510if (enumeratedValues == null) {511throw new IllegalArgumentException("enumeratedValues == null!");512}513if (enumeratedValues.size() == 0) {514throw new IllegalArgumentException("enumeratedValues is empty!");515}516Iterator iter = enumeratedValues.iterator();517while (iter.hasNext()) {518Object o = iter.next();519if (o == null) {520throw new IllegalArgumentException521("enumeratedValues contains a null!");522}523if (!(o instanceof String)) {524throw new IllegalArgumentException525("enumeratedValues contains a non-String value!");526}527}528529Attribute attr = new Attribute();530attr.attrName = attrName;531attr.valueType = VALUE_ENUMERATION;532attr.dataType = dataType;533attr.required = required;534attr.defaultValue = defaultValue;535attr.enumeratedValues = enumeratedValues;536537element.attrList.add(attrName);538element.attrMap.put(attrName, attr);539}540541/**542* Adds a new attribute to a previously defined element that will543* be defined by a range of values.544*545* @param elementName the name of the element.546* @param attrName the name of the attribute being added.547* @param dataType the data type (string format) of the attribute,548* one of the <code>DATATYPE_*</code> constants.549* @param required <code>true</code> if the attribute must be present.550* @param defaultValue the default value for the attribute, or551* <code>null</code>.552* @param minValue the smallest (inclusive or exclusive depending553* on the value of <code>minInclusive</code>) legal value for the554* attribute, as a <code>String</code>.555* @param maxValue the largest (inclusive or exclusive depending556* on the value of <code>minInclusive</code>) legal value for the557* attribute, as a <code>String</code>.558* @param minInclusive <code>true</code> if <code>minValue</code>559* is inclusive.560* @param maxInclusive <code>true</code> if <code>maxValue</code>561* is inclusive.562*563* @exception IllegalArgumentException if <code>elementName</code>564* is <code>null</code>, or is not a legal element name for this565* format.566* @exception IllegalArgumentException if <code>attrName</code> is567* <code>null</code>.568* @exception IllegalArgumentException if <code>dataType</code> is569* not one of the predefined constants.570*/571protected void addAttribute(String elementName,572String attrName,573int dataType,574boolean required,575String defaultValue,576String minValue,577String maxValue,578boolean minInclusive,579boolean maxInclusive) {580Element element = getElement(elementName);581if (attrName == null) {582throw new IllegalArgumentException("attrName == null!");583}584if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {585throw new IllegalArgumentException("Invalid value for dataType!");586}587588Attribute attr = new Attribute();589attr.attrName = attrName;590attr.valueType = VALUE_RANGE;591if (minInclusive) {592attr.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;593}594if (maxInclusive) {595attr.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;596}597attr.dataType = dataType;598attr.required = required;599attr.defaultValue = defaultValue;600attr.minValue = minValue;601attr.maxValue = maxValue;602603element.attrList.add(attrName);604element.attrMap.put(attrName, attr);605}606607/**608* Adds a new attribute to a previously defined element that will609* be defined by a list of values.610*611* @param elementName the name of the element.612* @param attrName the name of the attribute being added.613* @param dataType the data type (string format) of the attribute,614* one of the <code>DATATYPE_*</code> constants.615* @param required <code>true</code> if the attribute must be present.616* @param listMinLength the smallest legal number of list items.617* @param listMaxLength the largest legal number of list items.618*619* @exception IllegalArgumentException if <code>elementName</code>620* is <code>null</code>, or is not a legal element name for this621* format.622* @exception IllegalArgumentException if <code>attrName</code> is623* <code>null</code>.624* @exception IllegalArgumentException if <code>dataType</code> is625* not one of the predefined constants.626* @exception IllegalArgumentException if627* <code>listMinLength</code> is negative or larger than628* <code>listMaxLength</code>.629*/630protected void addAttribute(String elementName,631String attrName,632int dataType,633boolean required,634int listMinLength,635int listMaxLength) {636Element element = getElement(elementName);637if (attrName == null) {638throw new IllegalArgumentException("attrName == null!");639}640if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {641throw new IllegalArgumentException("Invalid value for dataType!");642}643if (listMinLength < 0 || listMinLength > listMaxLength) {644throw new IllegalArgumentException("Invalid list bounds!");645}646647Attribute attr = new Attribute();648attr.attrName = attrName;649attr.valueType = VALUE_LIST;650attr.dataType = dataType;651attr.required = required;652attr.listMinLength = listMinLength;653attr.listMaxLength = listMaxLength;654655element.attrList.add(attrName);656element.attrMap.put(attrName, attr);657}658659/**660* Adds a new attribute to a previously defined element that will661* be defined by the enumerated values <code>TRUE</code> and662* <code>FALSE</code>, with a datatype of663* <code>DATATYPE_BOOLEAN</code>.664*665* @param elementName the name of the element.666* @param attrName the name of the attribute being added.667* @param hasDefaultValue <code>true</code> if a default value668* should be present.669* @param defaultValue the default value for the attribute as a670* <code>boolean</code>, ignored if <code>hasDefaultValue</code>671* is <code>false</code>.672*673* @exception IllegalArgumentException if <code>elementName</code>674* is <code>null</code>, or is not a legal element name for this675* format.676* @exception IllegalArgumentException if <code>attrName</code> is677* <code>null</code>.678*/679protected void addBooleanAttribute(String elementName,680String attrName,681boolean hasDefaultValue,682boolean defaultValue) {683List values = new ArrayList();684values.add("TRUE");685values.add("FALSE");686687String dval = null;688if (hasDefaultValue) {689dval = defaultValue ? "TRUE" : "FALSE";690}691addAttribute(elementName,692attrName,693DATATYPE_BOOLEAN,694true,695dval,696values);697}698699/**700* Removes an attribute from a previously defined element. If no701* attribute with the given name was present in the given element,702* nothing happens and no exception is thrown.703*704* @param elementName the name of the element.705* @param attrName the name of the attribute being removed.706*707* @exception IllegalArgumentException if <code>elementName</code>708* is <code>null</code>, or is not a legal element name for this format.709*/710protected void removeAttribute(String elementName, String attrName) {711Element element = getElement(elementName);712element.attrList.remove(attrName);713element.attrMap.remove(attrName);714}715716/**717* Allows an <code>Object</code> reference of a given class type718* to be stored in nodes implementing the named element. The719* value of the <code>Object</code> is unconstrained other than by720* its class type.721*722* <p> If an <code>Object</code> reference was previously allowed,723* the previous settings are overwritten.724*725* @param elementName the name of the element.726* @param classType a <code>Class</code> variable indicating the727* legal class type for the object value.728* @param required <code>true</code> if an object value must be present.729* @param defaultValue the default value for the730* <code>Object</code> reference, or <code>null</code>.731* @param <T> the type of the object.732*733* @exception IllegalArgumentException if <code>elementName</code>734* is <code>null</code>, or is not a legal element name for this format.735*/736protected <T> void addObjectValue(String elementName,737Class<T> classType,738boolean required,739T defaultValue)740{741Element element = getElement(elementName);742ObjectValue obj = new ObjectValue();743obj.valueType = VALUE_ARBITRARY;744obj.classType = classType;745obj.defaultValue = defaultValue;746747element.objectValue = obj;748}749750/**751* Allows an <code>Object</code> reference of a given class type752* to be stored in nodes implementing the named element. The753* value of the <code>Object</code> must be one of the values754* given by <code>enumeratedValues</code>.755*756* <p> If an <code>Object</code> reference was previously allowed,757* the previous settings are overwritten.758*759* @param elementName the name of the element.760* @param classType a <code>Class</code> variable indicating the761* legal class type for the object value.762* @param required <code>true</code> if an object value must be present.763* @param defaultValue the default value for the764* <code>Object</code> reference, or <code>null</code>.765* @param enumeratedValues a <code>List</code> of766* <code>Object</code>s containing the legal values for the767* object reference.768* @param <T> the type of the object.769*770* @exception IllegalArgumentException if <code>elementName</code>771* is <code>null</code>, or is not a legal element name for this format.772* @exception IllegalArgumentException if773* <code>enumeratedValues</code> is <code>null</code>.774* @exception IllegalArgumentException if775* <code>enumeratedValues</code> does not contain at least one776* entry.777* @exception IllegalArgumentException if778* <code>enumeratedValues</code> contains an element that is not779* an instance of the class type denoted by <code>classType</code>780* or is <code>null</code>.781*/782protected <T> void addObjectValue(String elementName,783Class<T> classType,784boolean required,785T defaultValue,786List<? extends T> enumeratedValues)787{788Element element = getElement(elementName);789if (enumeratedValues == null) {790throw new IllegalArgumentException("enumeratedValues == null!");791}792if (enumeratedValues.size() == 0) {793throw new IllegalArgumentException("enumeratedValues is empty!");794}795Iterator iter = enumeratedValues.iterator();796while (iter.hasNext()) {797Object o = iter.next();798if (o == null) {799throw new IllegalArgumentException("enumeratedValues contains a null!");800}801if (!classType.isInstance(o)) {802throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!");803}804}805806ObjectValue obj = new ObjectValue();807obj.valueType = VALUE_ENUMERATION;808obj.classType = classType;809obj.defaultValue = defaultValue;810obj.enumeratedValues = enumeratedValues;811812element.objectValue = obj;813}814815/**816* Allows an <code>Object</code> reference of a given class type817* to be stored in nodes implementing the named element. The818* value of the <code>Object</code> must be within the range given819* by <code>minValue</code> and <code>maxValue</code>.820* Furthermore, the class type must implement the821* <code>Comparable</code> interface.822*823* <p> If an <code>Object</code> reference was previously allowed,824* the previous settings are overwritten.825*826* @param elementName the name of the element.827* @param classType a <code>Class</code> variable indicating the828* legal class type for the object value.829* @param defaultValue the default value for the830* @param minValue the smallest (inclusive or exclusive depending831* on the value of <code>minInclusive</code>) legal value for the832* object value, as a <code>String</code>.833* @param maxValue the largest (inclusive or exclusive depending834* on the value of <code>minInclusive</code>) legal value for the835* object value, as a <code>String</code>.836* @param minInclusive <code>true</code> if <code>minValue</code>837* is inclusive.838* @param maxInclusive <code>true</code> if <code>maxValue</code>839* is inclusive.840* @param <T> the type of the object.841*842* @exception IllegalArgumentException if <code>elementName</code>843* is <code>null</code>, or is not a legal element name for this844* format.845*/846protected <T extends Object & Comparable<? super T>> void847addObjectValue(String elementName,848Class<T> classType,849T defaultValue,850Comparable<? super T> minValue,851Comparable<? super T> maxValue,852boolean minInclusive,853boolean maxInclusive)854{855Element element = getElement(elementName);856ObjectValue obj = new ObjectValue();857obj.valueType = VALUE_RANGE;858if (minInclusive) {859obj.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;860}861if (maxInclusive) {862obj.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;863}864obj.classType = classType;865obj.defaultValue = defaultValue;866obj.minValue = minValue;867obj.maxValue = maxValue;868869element.objectValue = obj;870}871872/**873* Allows an <code>Object</code> reference of a given class type874* to be stored in nodes implementing the named element. The875* value of the <code>Object</code> must an array of objects of876* class type given by <code>classType</code>, with at least877* <code>arrayMinLength</code> and at most878* <code>arrayMaxLength</code> elements.879*880* <p> If an <code>Object</code> reference was previously allowed,881* the previous settings are overwritten.882*883* @param elementName the name of the element.884* @param classType a <code>Class</code> variable indicating the885* legal class type for the object value.886* @param arrayMinLength the smallest legal length for the array.887* @param arrayMaxLength the largest legal length for the array.888*889* @exception IllegalArgumentException if <code>elementName</code> is890* not a legal element name for this format.891*/892protected void addObjectValue(String elementName,893Class<?> classType,894int arrayMinLength,895int arrayMaxLength) {896Element element = getElement(elementName);897ObjectValue obj = new ObjectValue();898obj.valueType = VALUE_LIST;899obj.classType = classType;900obj.arrayMinLength = arrayMinLength;901obj.arrayMaxLength = arrayMaxLength;902903element.objectValue = obj;904}905906/**907* Disallows an <code>Object</code> reference from being stored in908* nodes implementing the named element.909*910* @param elementName the name of the element.911*912* @exception IllegalArgumentException if <code>elementName</code> is913* not a legal element name for this format.914*/915protected void removeObjectValue(String elementName) {916Element element = getElement(elementName);917element.objectValue = null;918}919920// Utility method921922// Methods from IIOMetadataFormat923924// Root925926public String getRootName() {927return rootName;928}929930// Multiplicity931932public abstract boolean canNodeAppear(String elementName,933ImageTypeSpecifier imageType);934935public int getElementMinChildren(String elementName) {936Element element = getElement(elementName);937if (element.childPolicy != CHILD_POLICY_REPEAT) {938throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!");939}940return element.minChildren;941}942943public int getElementMaxChildren(String elementName) {944Element element = getElement(elementName);945if (element.childPolicy != CHILD_POLICY_REPEAT) {946throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!");947}948return element.maxChildren;949}950951private String getResource(String key, Locale locale) {952if (locale == null) {953locale = Locale.getDefault();954}955956/**957* If an applet supplies an implementation of IIOMetadataFormat and958* resource bundles, then the resource bundle will need to be959* accessed via the applet class loader. So first try the context960* class loader to locate the resource bundle.961* If that throws MissingResourceException, then try the962* system class loader.963*/964ClassLoader loader = (ClassLoader)965java.security.AccessController.doPrivileged(966new java.security.PrivilegedAction() {967public Object run() {968return Thread.currentThread().getContextClassLoader();969}970});971972ResourceBundle bundle = null;973try {974bundle = ResourceBundle.getBundle(resourceBaseName,975locale, loader);976} catch (MissingResourceException mre) {977try {978bundle = ResourceBundle.getBundle(resourceBaseName, locale);979} catch (MissingResourceException mre1) {980return null;981}982}983984try {985return bundle.getString(key);986} catch (MissingResourceException e) {987return null;988}989}990991/**992* Returns a <code>String</code> containing a description of the993* named element, or <code>null</code>. The description will be994* localized for the supplied <code>Locale</code> if possible.995*996* <p> The default implementation will first locate a997* <code>ResourceBundle</code> using the current resource base998* name set by <code>setResourceBaseName</code> and the supplied999* <code>Locale</code>, using the fallback mechanism described in1000* the comments for <code>ResourceBundle.getBundle</code>. If a1001* <code>ResourceBundle</code> is found, the element name will be1002* used as a key to its <code>getString</code> method, and the1003* result returned. If no <code>ResourceBundle</code> is found,1004* or no such key is present, <code>null</code> will be returned.1005*1006* <p> If <code>locale</code> is <code>null</code>, the current1007* default <code>Locale</code> returned by <code>Locale.getLocale</code>1008* will be used.1009*1010* @param elementName the name of the element.1011* @param locale the <code>Locale</code> for which localization1012* will be attempted.1013*1014* @return the element description.1015*1016* @exception IllegalArgumentException if <code>elementName</code>1017* is <code>null</code>, or is not a legal element name for this format.1018*1019* @see #setResourceBaseName1020*/1021public String getElementDescription(String elementName,1022Locale locale) {1023Element element = getElement(elementName);1024return getResource(elementName, locale);1025}10261027// Children10281029public int getChildPolicy(String elementName) {1030Element element = getElement(elementName);1031return element.childPolicy;1032}10331034public String[] getChildNames(String elementName) {1035Element element = getElement(elementName);1036if (element.childPolicy == CHILD_POLICY_EMPTY) {1037return null;1038}1039return (String[])element.childList.toArray(new String[0]);1040}10411042// Attributes10431044public String[] getAttributeNames(String elementName) {1045Element element = getElement(elementName);1046List names = element.attrList;10471048String[] result = new String[names.size()];1049return (String[])names.toArray(result);1050}10511052public int getAttributeValueType(String elementName, String attrName) {1053Attribute attr = getAttribute(elementName, attrName);1054return attr.valueType;1055}10561057public int getAttributeDataType(String elementName, String attrName) {1058Attribute attr = getAttribute(elementName, attrName);1059return attr.dataType;1060}10611062public boolean isAttributeRequired(String elementName, String attrName) {1063Attribute attr = getAttribute(elementName, attrName);1064return attr.required;1065}10661067public String getAttributeDefaultValue(String elementName,1068String attrName) {1069Attribute attr = getAttribute(elementName, attrName);1070return attr.defaultValue;1071}10721073public String[] getAttributeEnumerations(String elementName,1074String attrName) {1075Attribute attr = getAttribute(elementName, attrName);1076if (attr.valueType != VALUE_ENUMERATION) {1077throw new IllegalArgumentException1078("Attribute not an enumeration!");1079}10801081List values = attr.enumeratedValues;1082Iterator iter = values.iterator();1083String[] result = new String[values.size()];1084return (String[])values.toArray(result);1085}10861087public String getAttributeMinValue(String elementName, String attrName) {1088Attribute attr = getAttribute(elementName, attrName);1089if (attr.valueType != VALUE_RANGE &&1090attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&1091attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&1092attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {1093throw new IllegalArgumentException("Attribute not a range!");1094}10951096return attr.minValue;1097}10981099public String getAttributeMaxValue(String elementName, String attrName) {1100Attribute attr = getAttribute(elementName, attrName);1101if (attr.valueType != VALUE_RANGE &&1102attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&1103attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&1104attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {1105throw new IllegalArgumentException("Attribute not a range!");1106}11071108return attr.maxValue;1109}11101111public int getAttributeListMinLength(String elementName, String attrName) {1112Attribute attr = getAttribute(elementName, attrName);1113if (attr.valueType != VALUE_LIST) {1114throw new IllegalArgumentException("Attribute not a list!");1115}11161117return attr.listMinLength;1118}11191120public int getAttributeListMaxLength(String elementName, String attrName) {1121Attribute attr = getAttribute(elementName, attrName);1122if (attr.valueType != VALUE_LIST) {1123throw new IllegalArgumentException("Attribute not a list!");1124}11251126return attr.listMaxLength;1127}11281129/**1130* Returns a <code>String</code> containing a description of the1131* named attribute, or <code>null</code>. The description will be1132* localized for the supplied <code>Locale</code> if possible.1133*1134* <p> The default implementation will first locate a1135* <code>ResourceBundle</code> using the current resource base1136* name set by <code>setResourceBaseName</code> and the supplied1137* <code>Locale</code>, using the fallback mechanism described in1138* the comments for <code>ResourceBundle.getBundle</code>. If a1139* <code>ResourceBundle</code> is found, the element name followed1140* by a "/" character followed by the attribute name1141* (<code>elementName + "/" + attrName</code>) will be used as a1142* key to its <code>getString</code> method, and the result1143* returned. If no <code>ResourceBundle</code> is found, or no1144* such key is present, <code>null</code> will be returned.1145*1146* <p> If <code>locale</code> is <code>null</code>, the current1147* default <code>Locale</code> returned by <code>Locale.getLocale</code>1148* will be used.1149*1150* @param elementName the name of the element.1151* @param attrName the name of the attribute.1152* @param locale the <code>Locale</code> for which localization1153* will be attempted, or <code>null</code>.1154*1155* @return the attribute description.1156*1157* @exception IllegalArgumentException if <code>elementName</code>1158* is <code>null</code>, or is not a legal element name for this format.1159* @exception IllegalArgumentException if <code>attrName</code> is1160* <code>null</code> or is not a legal attribute name for this1161* element.1162*1163* @see #setResourceBaseName1164*/1165public String getAttributeDescription(String elementName,1166String attrName,1167Locale locale) {1168Element element = getElement(elementName);1169if (attrName == null) {1170throw new IllegalArgumentException("attrName == null!");1171}1172Attribute attr = (Attribute)element.attrMap.get(attrName);1173if (attr == null) {1174throw new IllegalArgumentException("No such attribute!");1175}11761177String key = elementName + "/" + attrName;1178return getResource(key, locale);1179}11801181private ObjectValue getObjectValue(String elementName) {1182Element element = getElement(elementName);1183ObjectValue objv = (ObjectValue)element.objectValue;1184if (objv == null) {1185throw new IllegalArgumentException("No object within element " +1186elementName + "!");1187}1188return objv;1189}11901191public int getObjectValueType(String elementName) {1192Element element = getElement(elementName);1193ObjectValue objv = (ObjectValue)element.objectValue;1194if (objv == null) {1195return VALUE_NONE;1196}1197return objv.valueType;1198}11991200public Class<?> getObjectClass(String elementName) {1201ObjectValue objv = getObjectValue(elementName);1202return objv.classType;1203}12041205public Object getObjectDefaultValue(String elementName) {1206ObjectValue objv = getObjectValue(elementName);1207return objv.defaultValue;1208}12091210public Object[] getObjectEnumerations(String elementName) {1211ObjectValue objv = getObjectValue(elementName);1212if (objv.valueType != VALUE_ENUMERATION) {1213throw new IllegalArgumentException("Not an enumeration!");1214}1215List vlist = objv.enumeratedValues;1216Object[] values = new Object[vlist.size()];1217return vlist.toArray(values);1218}12191220public Comparable<?> getObjectMinValue(String elementName) {1221ObjectValue objv = getObjectValue(elementName);1222if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {1223throw new IllegalArgumentException("Not a range!");1224}1225return objv.minValue;1226}12271228public Comparable<?> getObjectMaxValue(String elementName) {1229ObjectValue objv = getObjectValue(elementName);1230if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {1231throw new IllegalArgumentException("Not a range!");1232}1233return objv.maxValue;1234}12351236public int getObjectArrayMinLength(String elementName) {1237ObjectValue objv = getObjectValue(elementName);1238if (objv.valueType != VALUE_LIST) {1239throw new IllegalArgumentException("Not a list!");1240}1241return objv.arrayMinLength;1242}12431244public int getObjectArrayMaxLength(String elementName) {1245ObjectValue objv = getObjectValue(elementName);1246if (objv.valueType != VALUE_LIST) {1247throw new IllegalArgumentException("Not a list!");1248}1249return objv.arrayMaxLength;1250}12511252// Standard format descriptor12531254private synchronized static void createStandardFormat() {1255if (standardFormat == null) {1256standardFormat = new StandardMetadataFormat();1257}1258}12591260/**1261* Returns an <code>IIOMetadataFormat</code> object describing the1262* standard, plug-in neutral <code>javax.imageio_1.0</code>1263* metadata document format described in the comment of the1264* <code>javax.imageio.metadata</code> package.1265*1266* @return a predefined <code>IIOMetadataFormat</code> instance.1267*/1268public static IIOMetadataFormat getStandardFormatInstance() {1269createStandardFormat();1270return standardFormat;1271}1272}127312741275