| /* |
| * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package javax.imageio.metadata; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| import javax.imageio.ImageTypeSpecifier; |
| import com.sun.imageio.plugins.common.StandardMetadataFormat; |
| |
| /** |
| * A concrete class providing a reusable implementation of the |
| * <code>IIOMetadataFormat</code> interface. In addition, a static |
| * instance representing the standard, plug-in neutral |
| * <code>javax_imageio_1.0</code> format is provided by the |
| * <code>getStandardFormatInstance</code> method. |
| * |
| * <p> In order to supply localized descriptions of elements and |
| * attributes, a <code>ResourceBundle</code> with a base name of |
| * <code>this.getClass().getName() + "Resources"</code> should be |
| * supplied via the usual mechanism used by |
| * <code>ResourceBundle.getBundle</code>. Briefly, the subclasser |
| * supplies one or more additional classes according to a naming |
| * convention (by default, the fully-qualified name of the subclass |
| * extending <code>IIMetadataFormatImpl</code>, plus the string |
| * "Resources", plus the country, language, and variant codes |
| * separated by underscores). At run time, calls to |
| * <code>getElementDescription</code> or |
| * <code>getAttributeDescription</code> will attempt to load such |
| * classes dynamically according to the supplied locale, and will use |
| * either the element name, or the element name followed by a '/' |
| * character followed by the attribute name as a key. This key will |
| * be supplied to the <code>ResourceBundle</code>'s |
| * <code>getString</code> method, and the resulting localized |
| * description of the node or attribute is returned. |
| * |
| * <p> The subclass may supply a different base name for the resource |
| * bundles using the <code>setResourceBaseName</code> method. |
| * |
| * <p> A subclass may choose its own localization mechanism, if so |
| * desired, by overriding the supplied implementations of |
| * <code>getElementDescription</code> and |
| * <code>getAttributeDescription</code>. |
| * |
| * @see ResourceBundle#getBundle(String,Locale) |
| * |
| */ |
| public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { |
| |
| /** |
| * A <code>String</code> constant containing the standard format |
| * name, <code>"javax_imageio_1.0"</code>. |
| */ |
| public static final String standardMetadataFormatName = |
| "javax_imageio_1.0"; |
| |
| private static IIOMetadataFormat standardFormat = null; |
| |
| private String resourceBaseName = this.getClass().getName() + "Resources"; |
| |
| private String rootName; |
| |
| // Element name (String) -> Element |
| private HashMap elementMap = new HashMap(); |
| |
| class Element { |
| String elementName; |
| |
| int childPolicy; |
| int minChildren = 0; |
| int maxChildren = 0; |
| |
| // Child names (Strings) |
| List childList = new ArrayList(); |
| |
| // Parent names (Strings) |
| List parentList = new ArrayList(); |
| |
| // List of attribute names in the order they were added |
| List attrList = new ArrayList(); |
| // Attr name (String) -> Attribute |
| Map attrMap = new HashMap(); |
| |
| ObjectValue objectValue; |
| } |
| |
| class Attribute { |
| String attrName; |
| |
| int valueType = VALUE_ARBITRARY; |
| int dataType; |
| boolean required; |
| String defaultValue = null; |
| |
| // enumeration |
| List enumeratedValues; |
| |
| // range |
| String minValue; |
| String maxValue; |
| |
| // list |
| int listMinLength; |
| int listMaxLength; |
| } |
| |
| class ObjectValue { |
| int valueType = VALUE_NONE; |
| Class classType = null; |
| Object defaultValue = null; |
| |
| // Meaningful only if valueType == VALUE_ENUMERATION |
| List enumeratedValues = null; |
| |
| // Meaningful only if valueType == VALUE_RANGE |
| Comparable minValue = null; |
| Comparable maxValue = null; |
| |
| // Meaningful only if valueType == VALUE_LIST |
| int arrayMinLength = 0; |
| int arrayMaxLength = 0; |
| } |
| |
| /** |
| * Constructs a blank <code>IIOMetadataFormatImpl</code> instance, |
| * with a given root element name and child policy (other than |
| * <code>CHILD_POLICY_REPEAT</code>). Additional elements, and |
| * their attributes and <code>Object</code> reference information |
| * may be added using the various <code>add</code> methods. |
| * |
| * @param rootName the name of the root element. |
| * @param childPolicy one of the <code>CHILD_POLICY_*</code> constants, |
| * other than <code>CHILD_POLICY_REPEAT</code>. |
| * |
| * @exception IllegalArgumentException if <code>rootName</code> is |
| * <code>null</code>. |
| * @exception IllegalArgumentException if <code>childPolicy</code> is |
| * not one of the predefined constants. |
| */ |
| public IIOMetadataFormatImpl(String rootName, |
| int childPolicy) { |
| if (rootName == null) { |
| throw new IllegalArgumentException("rootName == null!"); |
| } |
| if (childPolicy < CHILD_POLICY_EMPTY || |
| childPolicy > CHILD_POLICY_MAX || |
| childPolicy == CHILD_POLICY_REPEAT) { |
| throw new IllegalArgumentException("Invalid value for childPolicy!"); |
| } |
| |
| this.rootName = rootName; |
| |
| Element root = new Element(); |
| root.elementName = rootName; |
| root.childPolicy = childPolicy; |
| |
| elementMap.put(rootName, root); |
| } |
| |
| /** |
| * Constructs a blank <code>IIOMetadataFormatImpl</code> instance, |
| * with a given root element name and a child policy of |
| * <code>CHILD_POLICY_REPEAT</code>. Additional elements, and |
| * their attributes and <code>Object</code> reference information |
| * may be added using the various <code>add</code> methods. |
| * |
| * @param rootName the name of the root element. |
| * @param minChildren the minimum number of children of the node. |
| * @param maxChildren the maximum number of children of the node. |
| * |
| * @exception IllegalArgumentException if <code>rootName</code> is |
| * <code>null</code>. |
| * @exception IllegalArgumentException if <code>minChildren</code> |
| * is negative or larger than <code>maxChildren</code>. |
| */ |
| public IIOMetadataFormatImpl(String rootName, |
| int minChildren, |
| int maxChildren) { |
| if (rootName == null) { |
| throw new IllegalArgumentException("rootName == null!"); |
| } |
| if (minChildren < 0) { |
| throw new IllegalArgumentException("minChildren < 0!"); |
| } |
| if (minChildren > maxChildren) { |
| throw new IllegalArgumentException("minChildren > maxChildren!"); |
| } |
| |
| Element root = new Element(); |
| root.elementName = rootName; |
| root.childPolicy = CHILD_POLICY_REPEAT; |
| root.minChildren = minChildren; |
| root.maxChildren = maxChildren; |
| |
| this.rootName = rootName; |
| elementMap.put(rootName, root); |
| } |
| |
| /** |
| * Sets a new base name for locating <code>ResourceBundle</code>s |
| * containing descriptions of elements and attributes for this |
| * format. |
| * |
| * <p> Prior to the first time this method is called, the base |
| * name will be equal to <code>this.getClass().getName() + |
| * "Resources"</code>. |
| * |
| * @param resourceBaseName a <code>String</code> containg the new |
| * base name. |
| * |
| * @exception IllegalArgumentException if |
| * <code>resourceBaseName</code> is <code>null</code>. |
| * |
| * @see #getResourceBaseName |
| */ |
| protected void setResourceBaseName(String resourceBaseName) { |
| if (resourceBaseName == null) { |
| throw new IllegalArgumentException("resourceBaseName == null!"); |
| } |
| this.resourceBaseName = resourceBaseName; |
| } |
| |
| /** |
| * Returns the currently set base name for locating |
| * <code>ResourceBundle</code>s. |
| * |
| * @return a <code>String</code> containing the base name. |
| * |
| * @see #setResourceBaseName |
| */ |
| protected String getResourceBaseName() { |
| return resourceBaseName; |
| } |
| |
| /** |
| * Utility method for locating an element. |
| * |
| * @param mustAppear if <code>true</code>, throw an |
| * <code>IllegalArgumentException</code> if no such node exists; |
| * if <code>false</code>, just return null. |
| */ |
| private Element getElement(String elementName, boolean mustAppear) { |
| if (mustAppear && (elementName == null)) { |
| throw new IllegalArgumentException("element name is null!"); |
| } |
| Element element = (Element)elementMap.get(elementName); |
| if (mustAppear && (element == null)) { |
| throw new IllegalArgumentException("No such element: " + |
| elementName); |
| } |
| return element; |
| } |
| |
| private Element getElement(String elementName) { |
| return getElement(elementName, true); |
| } |
| |
| // Utility method for locating an attribute |
| private Attribute getAttribute(String elementName, String attrName) { |
| Element element = getElement(elementName); |
| Attribute attr = (Attribute)element.attrMap.get(attrName); |
| if (attr == null) { |
| throw new IllegalArgumentException("No such attribute \"" + |
| attrName + "\"!"); |
| } |
| return attr; |
| } |
| |
| // Setup |
| |
| /** |
| * Adds a new element type to this metadata document format with a |
| * child policy other than <code>CHILD_POLICY_REPEAT</code>. |
| * |
| * @param elementName the name of the new element. |
| * @param parentName the name of the element that will be the |
| * parent of the new element. |
| * @param childPolicy one of the <code>CHILD_POLICY_*</code> |
| * constants, other than <code>CHILD_POLICY_REPEAT</code>, |
| * indicating the child policy of the new element. |
| * |
| * @exception IllegalArgumentException if <code>parentName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>childPolicy</code> |
| * is not one of the predefined constants. |
| */ |
| protected void addElement(String elementName, |
| String parentName, |
| int childPolicy) { |
| Element parent = getElement(parentName); |
| if (childPolicy < CHILD_POLICY_EMPTY || |
| childPolicy > CHILD_POLICY_MAX || |
| childPolicy == CHILD_POLICY_REPEAT) { |
| throw new IllegalArgumentException |
| ("Invalid value for childPolicy!"); |
| } |
| |
| Element element = new Element(); |
| element.elementName = elementName; |
| element.childPolicy = childPolicy; |
| |
| parent.childList.add(elementName); |
| element.parentList.add(parentName); |
| |
| elementMap.put(elementName, element); |
| } |
| |
| /** |
| * Adds a new element type to this metadata document format with a |
| * child policy of <code>CHILD_POLICY_REPEAT</code>. |
| * |
| * @param elementName the name of the new element. |
| * @param parentName the name of the element that will be the |
| * parent of the new element. |
| * @param minChildren the minimum number of children of the node. |
| * @param maxChildren the maximum number of children of the node. |
| * |
| * @exception IllegalArgumentException if <code>parentName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>minChildren</code> |
| * is negative or larger than <code>maxChildren</code>. |
| */ |
| protected void addElement(String elementName, |
| String parentName, |
| int minChildren, |
| int maxChildren) { |
| Element parent = getElement(parentName); |
| if (minChildren < 0) { |
| throw new IllegalArgumentException("minChildren < 0!"); |
| } |
| if (minChildren > maxChildren) { |
| throw new IllegalArgumentException("minChildren > maxChildren!"); |
| } |
| |
| Element element = new Element(); |
| element.elementName = elementName; |
| element.childPolicy = CHILD_POLICY_REPEAT; |
| element.minChildren = minChildren; |
| element.maxChildren = maxChildren; |
| |
| parent.childList.add(elementName); |
| element.parentList.add(parentName); |
| |
| elementMap.put(elementName, element); |
| } |
| |
| /** |
| * Adds an existing element to the list of legal children for a |
| * given parent node type. |
| * |
| * @param parentName the name of the element that will be the |
| * new parent of the element. |
| * @param elementName the name of the element to be addded as a |
| * child. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>parentName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| */ |
| protected void addChildElement(String elementName, String parentName) { |
| Element parent = getElement(parentName); |
| Element element = getElement(elementName); |
| parent.childList.add(elementName); |
| element.parentList.add(parentName); |
| } |
| |
| /** |
| * Removes an element from the format. If no element with the |
| * given name was present, nothing happens and no exception is |
| * thrown. |
| * |
| * @param elementName the name of the element to be removed. |
| */ |
| protected void removeElement(String elementName) { |
| Element element = getElement(elementName, false); |
| if (element != null) { |
| Iterator iter = element.parentList.iterator(); |
| while (iter.hasNext()) { |
| String parentName = (String)iter.next(); |
| Element parent = getElement(parentName, false); |
| if (parent != null) { |
| parent.childList.remove(elementName); |
| } |
| } |
| elementMap.remove(elementName); |
| } |
| } |
| |
| /** |
| * Adds a new attribute to a previously defined element that may |
| * be set to an arbitrary value. |
| * |
| * @param elementName the name of the element. |
| * @param attrName the name of the attribute being added. |
| * @param dataType the data type (string format) of the attribute, |
| * one of the <code>DATATYPE_*</code> constants. |
| * @param required <code>true</code> if the attribute must be present. |
| * @param defaultValue the default value for the attribute, or |
| * <code>null</code>. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>attrName</code> is |
| * <code>null</code>. |
| * @exception IllegalArgumentException if <code>dataType</code> is |
| * not one of the predefined constants. |
| */ |
| protected void addAttribute(String elementName, |
| String attrName, |
| int dataType, |
| boolean required, |
| String defaultValue) { |
| Element element = getElement(elementName); |
| if (attrName == null) { |
| throw new IllegalArgumentException("attrName == null!"); |
| } |
| if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { |
| throw new IllegalArgumentException("Invalid value for dataType!"); |
| } |
| |
| Attribute attr = new Attribute(); |
| attr.attrName = attrName; |
| attr.valueType = VALUE_ARBITRARY; |
| attr.dataType = dataType; |
| attr.required = required; |
| attr.defaultValue = defaultValue; |
| |
| element.attrList.add(attrName); |
| element.attrMap.put(attrName, attr); |
| } |
| |
| /** |
| * Adds a new attribute to a previously defined element that will |
| * be defined by a set of enumerated values. |
| * |
| * @param elementName the name of the element. |
| * @param attrName the name of the attribute being added. |
| * @param dataType the data type (string format) of the attribute, |
| * one of the <code>DATATYPE_*</code> constants. |
| * @param required <code>true</code> if the attribute must be present. |
| * @param defaultValue the default value for the attribute, or |
| * <code>null</code>. |
| * @param enumeratedValues a <code>List</code> of |
| * <code>String</code>s containing the legal values for the |
| * attribute. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>attrName</code> is |
| * <code>null</code>. |
| * @exception IllegalArgumentException if <code>dataType</code> is |
| * not one of the predefined constants. |
| * @exception IllegalArgumentException if |
| * <code>enumeratedValues</code> is <code>null</code>. |
| * @exception IllegalArgumentException if |
| * <code>enumeratedValues</code> does not contain at least one |
| * entry. |
| * @exception IllegalArgumentException if |
| * <code>enumeratedValues</code> contains an element that is not a |
| * <code>String</code> or is <code>null</code>. |
| */ |
| protected void addAttribute(String elementName, |
| String attrName, |
| int dataType, |
| boolean required, |
| String defaultValue, |
| List<String> enumeratedValues) { |
| Element element = getElement(elementName); |
| if (attrName == null) { |
| throw new IllegalArgumentException("attrName == null!"); |
| } |
| if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { |
| throw new IllegalArgumentException("Invalid value for dataType!"); |
| } |
| if (enumeratedValues == null) { |
| throw new IllegalArgumentException("enumeratedValues == null!"); |
| } |
| if (enumeratedValues.size() == 0) { |
| throw new IllegalArgumentException("enumeratedValues is empty!"); |
| } |
| Iterator iter = enumeratedValues.iterator(); |
| while (iter.hasNext()) { |
| Object o = iter.next(); |
| if (o == null) { |
| throw new IllegalArgumentException |
| ("enumeratedValues contains a null!"); |
| } |
| if (!(o instanceof String)) { |
| throw new IllegalArgumentException |
| ("enumeratedValues contains a non-String value!"); |
| } |
| } |
| |
| Attribute attr = new Attribute(); |
| attr.attrName = attrName; |
| attr.valueType = VALUE_ENUMERATION; |
| attr.dataType = dataType; |
| attr.required = required; |
| attr.defaultValue = defaultValue; |
| attr.enumeratedValues = enumeratedValues; |
| |
| element.attrList.add(attrName); |
| element.attrMap.put(attrName, attr); |
| } |
| |
| /** |
| * Adds a new attribute to a previously defined element that will |
| * be defined by a range of values. |
| * |
| * @param elementName the name of the element. |
| * @param attrName the name of the attribute being added. |
| * @param dataType the data type (string format) of the attribute, |
| * one of the <code>DATATYPE_*</code> constants. |
| * @param required <code>true</code> if the attribute must be present. |
| * @param defaultValue the default value for the attribute, or |
| * <code>null</code>. |
| * @param minValue the smallest (inclusive or exclusive depending |
| * on the value of <code>minInclusive</code>) legal value for the |
| * attribute, as a <code>String</code>. |
| * @param maxValue the largest (inclusive or exclusive depending |
| * on the value of <code>minInclusive</code>) legal value for the |
| * attribute, as a <code>String</code>. |
| * @param minInclusive <code>true</code> if <code>minValue</code> |
| * is inclusive. |
| * @param maxInclusive <code>true</code> if <code>maxValue</code> |
| * is inclusive. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>attrName</code> is |
| * <code>null</code>. |
| * @exception IllegalArgumentException if <code>dataType</code> is |
| * not one of the predefined constants. |
| */ |
| protected void addAttribute(String elementName, |
| String attrName, |
| int dataType, |
| boolean required, |
| String defaultValue, |
| String minValue, |
| String maxValue, |
| boolean minInclusive, |
| boolean maxInclusive) { |
| Element element = getElement(elementName); |
| if (attrName == null) { |
| throw new IllegalArgumentException("attrName == null!"); |
| } |
| if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { |
| throw new IllegalArgumentException("Invalid value for dataType!"); |
| } |
| |
| Attribute attr = new Attribute(); |
| attr.attrName = attrName; |
| attr.valueType = VALUE_RANGE; |
| if (minInclusive) { |
| attr.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK; |
| } |
| if (maxInclusive) { |
| attr.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK; |
| } |
| attr.dataType = dataType; |
| attr.required = required; |
| attr.defaultValue = defaultValue; |
| attr.minValue = minValue; |
| attr.maxValue = maxValue; |
| |
| element.attrList.add(attrName); |
| element.attrMap.put(attrName, attr); |
| } |
| |
| /** |
| * Adds a new attribute to a previously defined element that will |
| * be defined by a list of values. |
| * |
| * @param elementName the name of the element. |
| * @param attrName the name of the attribute being added. |
| * @param dataType the data type (string format) of the attribute, |
| * one of the <code>DATATYPE_*</code> constants. |
| * @param required <code>true</code> if the attribute must be present. |
| * @param listMinLength the smallest legal number of list items. |
| * @param listMaxLength the largest legal number of list items. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>attrName</code> is |
| * <code>null</code>. |
| * @exception IllegalArgumentException if <code>dataType</code> is |
| * not one of the predefined constants. |
| * @exception IllegalArgumentException if |
| * <code>listMinLength</code> is negative or larger than |
| * <code>listMaxLength</code>. |
| */ |
| protected void addAttribute(String elementName, |
| String attrName, |
| int dataType, |
| boolean required, |
| int listMinLength, |
| int listMaxLength) { |
| Element element = getElement(elementName); |
| if (attrName == null) { |
| throw new IllegalArgumentException("attrName == null!"); |
| } |
| if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { |
| throw new IllegalArgumentException("Invalid value for dataType!"); |
| } |
| if (listMinLength < 0 || listMinLength > listMaxLength) { |
| throw new IllegalArgumentException("Invalid list bounds!"); |
| } |
| |
| Attribute attr = new Attribute(); |
| attr.attrName = attrName; |
| attr.valueType = VALUE_LIST; |
| attr.dataType = dataType; |
| attr.required = required; |
| attr.listMinLength = listMinLength; |
| attr.listMaxLength = listMaxLength; |
| |
| element.attrList.add(attrName); |
| element.attrMap.put(attrName, attr); |
| } |
| |
| /** |
| * Adds a new attribute to a previously defined element that will |
| * be defined by the enumerated values <code>TRUE</code> and |
| * <code>FALSE</code>, with a datatype of |
| * <code>DATATYPE_BOOLEAN</code>. |
| * |
| * @param elementName the name of the element. |
| * @param attrName the name of the attribute being added. |
| * @param hasDefaultValue <code>true</code> if a default value |
| * should be present. |
| * @param defaultValue the default value for the attribute as a |
| * <code>boolean</code>, ignored if <code>hasDefaultValue</code> |
| * is <code>false</code>. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| * @exception IllegalArgumentException if <code>attrName</code> is |
| * <code>null</code>. |
| */ |
| protected void addBooleanAttribute(String elementName, |
| String attrName, |
| boolean hasDefaultValue, |
| boolean defaultValue) { |
| List values = new ArrayList(); |
| values.add("TRUE"); |
| values.add("FALSE"); |
| |
| String dval = null; |
| if (hasDefaultValue) { |
| dval = defaultValue ? "TRUE" : "FALSE"; |
| } |
| addAttribute(elementName, |
| attrName, |
| DATATYPE_BOOLEAN, |
| true, |
| dval, |
| values); |
| } |
| |
| /** |
| * Removes an attribute from a previously defined element. If no |
| * attribute with the given name was present in the given element, |
| * nothing happens and no exception is thrown. |
| * |
| * @param elementName the name of the element. |
| * @param attrName the name of the attribute being removed. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this format. |
| */ |
| protected void removeAttribute(String elementName, String attrName) { |
| Element element = getElement(elementName); |
| element.attrList.remove(attrName); |
| element.attrMap.remove(attrName); |
| } |
| |
| /** |
| * Allows an <code>Object</code> reference of a given class type |
| * to be stored in nodes implementing the named element. The |
| * value of the <code>Object</code> is unconstrained other than by |
| * its class type. |
| * |
| * <p> If an <code>Object</code> reference was previously allowed, |
| * the previous settings are overwritten. |
| * |
| * @param elementName the name of the element. |
| * @param classType a <code>Class</code> variable indicating the |
| * legal class type for the object value. |
| * @param required <code>true</code> if an object value must be present. |
| * @param defaultValue the default value for the |
| * <code>Object</code> reference, or <code>null</code>. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this format. |
| */ |
| protected <T> void addObjectValue(String elementName, |
| Class<T> classType, |
| boolean required, |
| T defaultValue) |
| { |
| Element element = getElement(elementName); |
| ObjectValue obj = new ObjectValue(); |
| obj.valueType = VALUE_ARBITRARY; |
| obj.classType = classType; |
| obj.defaultValue = defaultValue; |
| |
| element.objectValue = obj; |
| } |
| |
| /** |
| * Allows an <code>Object</code> reference of a given class type |
| * to be stored in nodes implementing the named element. The |
| * value of the <code>Object</code> must be one of the values |
| * given by <code>enumeratedValues</code>. |
| * |
| * <p> If an <code>Object</code> reference was previously allowed, |
| * the previous settings are overwritten. |
| * |
| * @param elementName the name of the element. |
| * @param classType a <code>Class</code> variable indicating the |
| * legal class type for the object value. |
| * @param required <code>true</code> if an object value must be present. |
| * @param defaultValue the default value for the |
| * <code>Object</code> reference, or <code>null</code>. |
| * @param enumeratedValues a <code>List</code> of |
| * <code>Object</code>s containing the legal values for the |
| * object reference. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this format. |
| * @exception IllegalArgumentException if |
| * <code>enumeratedValues</code> is <code>null</code>. |
| * @exception IllegalArgumentException if |
| * <code>enumeratedValues</code> does not contain at least one |
| * entry. |
| * @exception IllegalArgumentException if |
| * <code>enumeratedValues</code> contains an element that is not |
| * an instance of the class type denoted by <code>classType</code> |
| * or is <code>null</code>. |
| */ |
| protected <T> void addObjectValue(String elementName, |
| Class<T> classType, |
| boolean required, |
| T defaultValue, |
| List<? extends T> enumeratedValues) |
| { |
| Element element = getElement(elementName); |
| if (enumeratedValues == null) { |
| throw new IllegalArgumentException("enumeratedValues == null!"); |
| } |
| if (enumeratedValues.size() == 0) { |
| throw new IllegalArgumentException("enumeratedValues is empty!"); |
| } |
| Iterator iter = enumeratedValues.iterator(); |
| while (iter.hasNext()) { |
| Object o = iter.next(); |
| if (o == null) { |
| throw new IllegalArgumentException("enumeratedValues contains a null!"); |
| } |
| if (!classType.isInstance(o)) { |
| throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!"); |
| } |
| } |
| |
| ObjectValue obj = new ObjectValue(); |
| obj.valueType = VALUE_ENUMERATION; |
| obj.classType = classType; |
| obj.defaultValue = defaultValue; |
| obj.enumeratedValues = enumeratedValues; |
| |
| element.objectValue = obj; |
| } |
| |
| /** |
| * Allows an <code>Object</code> reference of a given class type |
| * to be stored in nodes implementing the named element. The |
| * value of the <code>Object</code> must be within the range given |
| * by <code>minValue</code> and <code>maxValue</code>. |
| * Furthermore, the class type must implement the |
| * <code>Comparable</code> interface. |
| * |
| * <p> If an <code>Object</code> reference was previously allowed, |
| * the previous settings are overwritten. |
| * |
| * @param elementName the name of the element. |
| * @param classType a <code>Class</code> variable indicating the |
| * legal class type for the object value. |
| * @param defaultValue the default value for the |
| * @param minValue the smallest (inclusive or exclusive depending |
| * on the value of <code>minInclusive</code>) legal value for the |
| * object value, as a <code>String</code>. |
| * @param maxValue the largest (inclusive or exclusive depending |
| * on the value of <code>minInclusive</code>) legal value for the |
| * object value, as a <code>String</code>. |
| * @param minInclusive <code>true</code> if <code>minValue</code> |
| * is inclusive. |
| * @param maxInclusive <code>true</code> if <code>maxValue</code> |
| * is inclusive. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this |
| * format. |
| */ |
| protected <T extends Object & Comparable<? super T>> void |
| addObjectValue(String elementName, |
| Class<T> classType, |
| T defaultValue, |
| Comparable<? super T> minValue, |
| Comparable<? super T> maxValue, |
| boolean minInclusive, |
| boolean maxInclusive) |
| { |
| Element element = getElement(elementName); |
| ObjectValue obj = new ObjectValue(); |
| obj.valueType = VALUE_RANGE; |
| if (minInclusive) { |
| obj.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK; |
| } |
| if (maxInclusive) { |
| obj.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK; |
| } |
| obj.classType = classType; |
| obj.defaultValue = defaultValue; |
| obj.minValue = minValue; |
| obj.maxValue = maxValue; |
| |
| element.objectValue = obj; |
| } |
| |
| /** |
| * Allows an <code>Object</code> reference of a given class type |
| * to be stored in nodes implementing the named element. The |
| * value of the <code>Object</code> must an array of objects of |
| * class type given by <code>classType</code>, with at least |
| * <code>arrayMinLength</code> and at most |
| * <code>arrayMaxLength</code> elements. |
| * |
| * <p> If an <code>Object</code> reference was previously allowed, |
| * the previous settings are overwritten. |
| * |
| * @param elementName the name of the element. |
| * @param classType a <code>Class</code> variable indicating the |
| * legal class type for the object value. |
| * @param arrayMinLength the smallest legal length for the array. |
| * @param arrayMaxLength the largest legal length for the array. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> is |
| * not a legal element name for this format. |
| */ |
| protected void addObjectValue(String elementName, |
| Class<?> classType, |
| int arrayMinLength, |
| int arrayMaxLength) { |
| Element element = getElement(elementName); |
| ObjectValue obj = new ObjectValue(); |
| obj.valueType = VALUE_LIST; |
| obj.classType = classType; |
| obj.arrayMinLength = arrayMinLength; |
| obj.arrayMaxLength = arrayMaxLength; |
| |
| element.objectValue = obj; |
| } |
| |
| /** |
| * Disallows an <code>Object</code> reference from being stored in |
| * nodes implementing the named element. |
| * |
| * @param elementName the name of the element. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> is |
| * not a legal element name for this format. |
| */ |
| protected void removeObjectValue(String elementName) { |
| Element element = getElement(elementName); |
| element.objectValue = null; |
| } |
| |
| // Utility method |
| |
| // Methods from IIOMetadataFormat |
| |
| // Root |
| |
| public String getRootName() { |
| return rootName; |
| } |
| |
| // Multiplicity |
| |
| public abstract boolean canNodeAppear(String elementName, |
| ImageTypeSpecifier imageType); |
| |
| public int getElementMinChildren(String elementName) { |
| Element element = getElement(elementName); |
| if (element.childPolicy != CHILD_POLICY_REPEAT) { |
| throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!"); |
| } |
| return element.minChildren; |
| } |
| |
| public int getElementMaxChildren(String elementName) { |
| Element element = getElement(elementName); |
| if (element.childPolicy != CHILD_POLICY_REPEAT) { |
| throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!"); |
| } |
| return element.maxChildren; |
| } |
| |
| private String getResource(String key, Locale locale) { |
| if (locale == null) { |
| locale = Locale.getDefault(); |
| } |
| |
| /** |
| * If an applet supplies an implementation of IIOMetadataFormat and |
| * resource bundles, then the resource bundle will need to be |
| * accessed via the applet class loader. So first try the context |
| * class loader to locate the resource bundle. |
| * If that throws MissingResourceException, then try the |
| * system class loader. |
| */ |
| ClassLoader loader = (ClassLoader) |
| java.security.AccessController.doPrivileged( |
| new java.security.PrivilegedAction() { |
| public Object run() { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| }); |
| |
| ResourceBundle bundle = null; |
| try { |
| bundle = ResourceBundle.getBundle(resourceBaseName, |
| locale, loader); |
| } catch (MissingResourceException mre) { |
| try { |
| bundle = ResourceBundle.getBundle(resourceBaseName, locale); |
| } catch (MissingResourceException mre1) { |
| return null; |
| } |
| } |
| |
| try { |
| return bundle.getString(key); |
| } catch (MissingResourceException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns a <code>String</code> containing a description of the |
| * named element, or <code>null</code>. The desciption will be |
| * localized for the supplied <code>Locale</code> if possible. |
| * |
| * <p> The default implementation will first locate a |
| * <code>ResourceBundle</code> using the current resource base |
| * name set by <code>setResourceBaseName</code> and the supplied |
| * <code>Locale</code>, using the fallback mechanism described in |
| * the comments for <code>ResourceBundle.getBundle</code>. If a |
| * <code>ResourceBundle</code> is found, the element name will be |
| * used as a key to its <code>getString</code> method, and the |
| * result returned. If no <code>ResourceBundle</code> is found, |
| * or no such key is present, <code>null</code> will be returned. |
| * |
| * <p> If <code>locale</code> is <code>null</code>, the current |
| * default <code>Locale</code> returned by <code>Locale.getLocale</code> |
| * will be used. |
| * |
| * @param elementName the name of the element. |
| * @param locale the <code>Locale</code> for which localization |
| * will be attempted. |
| * |
| * @return the element description. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this format. |
| * |
| * @see #setResourceBaseName |
| */ |
| public String getElementDescription(String elementName, |
| Locale locale) { |
| Element element = getElement(elementName); |
| return getResource(elementName, locale); |
| } |
| |
| // Children |
| |
| public int getChildPolicy(String elementName) { |
| Element element = getElement(elementName); |
| return element.childPolicy; |
| } |
| |
| public String[] getChildNames(String elementName) { |
| Element element = getElement(elementName); |
| if (element.childPolicy == CHILD_POLICY_EMPTY) { |
| return null; |
| } |
| return (String[])element.childList.toArray(new String[0]); |
| } |
| |
| // Attributes |
| |
| public String[] getAttributeNames(String elementName) { |
| Element element = getElement(elementName); |
| List names = element.attrList; |
| |
| String[] result = new String[names.size()]; |
| return (String[])names.toArray(result); |
| } |
| |
| public int getAttributeValueType(String elementName, String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| return attr.valueType; |
| } |
| |
| public int getAttributeDataType(String elementName, String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| return attr.dataType; |
| } |
| |
| public boolean isAttributeRequired(String elementName, String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| return attr.required; |
| } |
| |
| public String getAttributeDefaultValue(String elementName, |
| String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| return attr.defaultValue; |
| } |
| |
| public String[] getAttributeEnumerations(String elementName, |
| String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| if (attr.valueType != VALUE_ENUMERATION) { |
| throw new IllegalArgumentException |
| ("Attribute not an enumeration!"); |
| } |
| |
| List values = attr.enumeratedValues; |
| Iterator iter = values.iterator(); |
| String[] result = new String[values.size()]; |
| return (String[])values.toArray(result); |
| } |
| |
| public String getAttributeMinValue(String elementName, String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| if (attr.valueType != VALUE_RANGE && |
| attr.valueType != VALUE_RANGE_MIN_INCLUSIVE && |
| attr.valueType != VALUE_RANGE_MAX_INCLUSIVE && |
| attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) { |
| throw new IllegalArgumentException("Attribute not a range!"); |
| } |
| |
| return attr.minValue; |
| } |
| |
| public String getAttributeMaxValue(String elementName, String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| if (attr.valueType != VALUE_RANGE && |
| attr.valueType != VALUE_RANGE_MIN_INCLUSIVE && |
| attr.valueType != VALUE_RANGE_MAX_INCLUSIVE && |
| attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) { |
| throw new IllegalArgumentException("Attribute not a range!"); |
| } |
| |
| return attr.maxValue; |
| } |
| |
| public int getAttributeListMinLength(String elementName, String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| if (attr.valueType != VALUE_LIST) { |
| throw new IllegalArgumentException("Attribute not a list!"); |
| } |
| |
| return attr.listMinLength; |
| } |
| |
| public int getAttributeListMaxLength(String elementName, String attrName) { |
| Attribute attr = getAttribute(elementName, attrName); |
| if (attr.valueType != VALUE_LIST) { |
| throw new IllegalArgumentException("Attribute not a list!"); |
| } |
| |
| return attr.listMaxLength; |
| } |
| |
| /** |
| * Returns a <code>String</code> containing a description of the |
| * named attribute, or <code>null</code>. The desciption will be |
| * localized for the supplied <code>Locale</code> if possible. |
| * |
| * <p> The default implementation will first locate a |
| * <code>ResourceBundle</code> using the current resource base |
| * name set by <code>setResourceBaseName</code> and the supplied |
| * <code>Locale</code>, using the fallback mechanism described in |
| * the comments for <code>ResourceBundle.getBundle</code>. If a |
| * <code>ResourceBundle</code> is found, the element name followed |
| * by a "/" character followed by the attribute name |
| * (<code>elementName + "/" + attrName</code>) will be used as a |
| * key to its <code>getString</code> method, and the result |
| * returned. If no <code>ResourceBundle</code> is found, or no |
| * such key is present, <code>null</code> will be returned. |
| * |
| * <p> If <code>locale</code> is <code>null</code>, the current |
| * default <code>Locale</code> returned by <code>Locale.getLocale</code> |
| * will be used. |
| * |
| * @param elementName the name of the element. |
| * @param attrName the name of the attribute. |
| * @param locale the <code>Locale</code> for which localization |
| * will be attempted, or <code>null</code>. |
| * |
| * @return the attribute description. |
| * |
| * @exception IllegalArgumentException if <code>elementName</code> |
| * is <code>null</code>, or is not a legal element name for this format. |
| * @exception IllegalArgumentException if <code>attrName</code> is |
| * <code>null</code> or is not a legal attribute name for this |
| * element. |
| * |
| * @see #setResourceBaseName |
| */ |
| public String getAttributeDescription(String elementName, |
| String attrName, |
| Locale locale) { |
| Element element = getElement(elementName); |
| if (attrName == null) { |
| throw new IllegalArgumentException("attrName == null!"); |
| } |
| Attribute attr = (Attribute)element.attrMap.get(attrName); |
| if (attr == null) { |
| throw new IllegalArgumentException("No such attribute!"); |
| } |
| |
| String key = elementName + "/" + attrName; |
| return getResource(key, locale); |
| } |
| |
| private ObjectValue getObjectValue(String elementName) { |
| Element element = getElement(elementName); |
| ObjectValue objv = (ObjectValue)element.objectValue; |
| if (objv == null) { |
| throw new IllegalArgumentException("No object within element " + |
| elementName + "!"); |
| } |
| return objv; |
| } |
| |
| public int getObjectValueType(String elementName) { |
| Element element = getElement(elementName); |
| ObjectValue objv = (ObjectValue)element.objectValue; |
| if (objv == null) { |
| return VALUE_NONE; |
| } |
| return objv.valueType; |
| } |
| |
| public Class<?> getObjectClass(String elementName) { |
| ObjectValue objv = getObjectValue(elementName); |
| return objv.classType; |
| } |
| |
| public Object getObjectDefaultValue(String elementName) { |
| ObjectValue objv = getObjectValue(elementName); |
| return objv.defaultValue; |
| } |
| |
| public Object[] getObjectEnumerations(String elementName) { |
| ObjectValue objv = getObjectValue(elementName); |
| if (objv.valueType != VALUE_ENUMERATION) { |
| throw new IllegalArgumentException("Not an enumeration!"); |
| } |
| List vlist = objv.enumeratedValues; |
| Object[] values = new Object[vlist.size()]; |
| return vlist.toArray(values); |
| } |
| |
| public Comparable<?> getObjectMinValue(String elementName) { |
| ObjectValue objv = getObjectValue(elementName); |
| if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) { |
| throw new IllegalArgumentException("Not a range!"); |
| } |
| return objv.minValue; |
| } |
| |
| public Comparable<?> getObjectMaxValue(String elementName) { |
| ObjectValue objv = getObjectValue(elementName); |
| if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) { |
| throw new IllegalArgumentException("Not a range!"); |
| } |
| return objv.maxValue; |
| } |
| |
| public int getObjectArrayMinLength(String elementName) { |
| ObjectValue objv = getObjectValue(elementName); |
| if (objv.valueType != VALUE_LIST) { |
| throw new IllegalArgumentException("Not a list!"); |
| } |
| return objv.arrayMinLength; |
| } |
| |
| public int getObjectArrayMaxLength(String elementName) { |
| ObjectValue objv = getObjectValue(elementName); |
| if (objv.valueType != VALUE_LIST) { |
| throw new IllegalArgumentException("Not a list!"); |
| } |
| return objv.arrayMaxLength; |
| } |
| |
| // Standard format descriptor |
| |
| private synchronized static void createStandardFormat() { |
| if (standardFormat == null) { |
| standardFormat = new StandardMetadataFormat(); |
| } |
| } |
| |
| /** |
| * Returns an <code>IIOMetadataFormat</code> object describing the |
| * standard, plug-in neutral <code>javax.imageio_1.0</code> |
| * metadata document format described in the comment of the |
| * <code>javax.imageio.metadata</code> package. |
| * |
| * @return a predefined <code>IIOMetadataFormat</code> instance. |
| */ |
| public static IIOMetadataFormat getStandardFormatInstance() { |
| createStandardFormat(); |
| return standardFormat; |
| } |
| } |