/*
* Copyright (c) 2000, 2014, 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 IIOMetadataFormat
interface. In addition, a static instance representing the standard, plug-in neutral javax_imageio_1.0
format is provided by the getStandardFormatInstance
method. In order to supply localized descriptions of elements and attributes, a ResourceBundle
with a base name of this.getClass().getName() + "Resources"
should be supplied via the usual mechanism used by ResourceBundle.getBundle
. Briefly, the subclasser supplies one or more additional classes according to a naming convention (by default, the fully-qualified name of the subclass extending IIMetadataFormatImpl
, plus the string "Resources", plus the country, language, and variant codes separated by underscores). At run time, calls to getElementDescription
or getAttributeDescription
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 ResourceBundle
's getString
method, and the resulting localized description of the node or attribute is returned.
The subclass may supply a different base name for the resource bundles using the setResourceBaseName
method.
A subclass may choose its own localization mechanism, if so desired, by overriding the supplied implementations of getElementDescription
and getAttributeDescription
.
See Also:
/**
* A concrete class providing a reusable implementation of the
* {@code IIOMetadataFormat} interface. In addition, a static
* instance representing the standard, plug-in neutral
* {@code javax_imageio_1.0} format is provided by the
* {@code getStandardFormatInstance} method.
*
* <p> In order to supply localized descriptions of elements and
* attributes, a {@code ResourceBundle} with a base name of
* {@code this.getClass().getName() + "Resources"} should be
* supplied via the usual mechanism used by
* {@code ResourceBundle.getBundle}. 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}, plus the string
* "Resources", plus the country, language, and variant codes
* separated by underscores). At run time, calls to
* {@code getElementDescription} or
* {@code getAttributeDescription} 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}'s
* {@code getString} 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} method.
*
* <p> A subclass may choose its own localization mechanism, if so
* desired, by overriding the supplied implementations of
* {@code getElementDescription} and
* {@code getAttributeDescription}.
*
* @see ResourceBundle#getBundle(String,Locale)
*
*/
public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat {
A String
constant containing the standard format name, "javax_imageio_1.0"
. /**
* A {@code String} constant containing the standard format
* name, {@code "javax_imageio_1.0"}.
*/
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<String, Element> elementMap = new HashMap<>();
class Element {
String elementName;
int childPolicy;
int minChildren = 0;
int maxChildren = 0;
// Child names (Strings)
List<String> childList = new ArrayList<>();
// Parent names (Strings)
List<String> parentList = new ArrayList<>();
// List of attribute names in the order they were added
List<String> attrList = new ArrayList<>();
// Attr name (String) -> Attribute
Map<String, Attribute> attrMap = new HashMap<>();
ObjectValue<?> objectValue;
}
class Attribute {
String attrName;
int valueType = VALUE_ARBITRARY;
int dataType;
boolean required;
String defaultValue = null;
// enumeration
List<String> enumeratedValues;
// range
String minValue;
String maxValue;
// list
int listMinLength;
int listMaxLength;
}
class ObjectValue<T> {
int valueType = VALUE_NONE;
// ? extends T So that ObjectValue<Object> can take Class<?>
Class<? extends T> classType = null;
T defaultValue = null;
// Meaningful only if valueType == VALUE_ENUMERATION
List<? extends T> enumeratedValues = null;
// Meaningful only if valueType == VALUE_RANGE
Comparable<? super T> minValue = null;
Comparable<? super T> maxValue = null;
// Meaningful only if valueType == VALUE_LIST
int arrayMinLength = 0;
int arrayMaxLength = 0;
}
Constructs a blank IIOMetadataFormatImpl
instance, with a given root element name and child policy (other than CHILD_POLICY_REPEAT
). Additional elements, and their attributes and Object
reference information may be added using the various add
methods. Params: - rootName – the name of the root element.
- childPolicy – one of the
CHILD_POLICY_*
constants, other than CHILD_POLICY_REPEAT
.
Throws: - IllegalArgumentException – if
rootName
is null
. - IllegalArgumentException – if
childPolicy
is not one of the predefined constants.
/**
* Constructs a blank {@code IIOMetadataFormatImpl} instance,
* with a given root element name and child policy (other than
* {@code CHILD_POLICY_REPEAT}). Additional elements, and
* their attributes and {@code Object} reference information
* may be added using the various {@code add} methods.
*
* @param rootName the name of the root element.
* @param childPolicy one of the {@code CHILD_POLICY_*} constants,
* other than {@code CHILD_POLICY_REPEAT}.
*
* @exception IllegalArgumentException if {@code rootName} is
* {@code null}.
* @exception IllegalArgumentException if {@code childPolicy} 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 IIOMetadataFormatImpl
instance, with a given root element name and a child policy of CHILD_POLICY_REPEAT
. Additional elements, and their attributes and Object
reference information may be added using the various add
methods. Params: - rootName – the name of the root element.
- minChildren – the minimum number of children of the node.
- maxChildren – the maximum number of children of the node.
Throws: - IllegalArgumentException – if
rootName
is null
. - IllegalArgumentException – if
minChildren
is negative or larger than maxChildren
.
/**
* Constructs a blank {@code IIOMetadataFormatImpl} instance,
* with a given root element name and a child policy of
* {@code CHILD_POLICY_REPEAT}. Additional elements, and
* their attributes and {@code Object} reference information
* may be added using the various {@code add} 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} is
* {@code null}.
* @exception IllegalArgumentException if {@code minChildren}
* is negative or larger than {@code maxChildren}.
*/
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 ResourceBundle
s containing descriptions of elements and attributes for this format. Prior to the first time this method is called, the base name will be equal to this.getClass().getName() + "Resources"
.
Params: - resourceBaseName – a
String
containing the new base name.
Throws: - IllegalArgumentException – if
resourceBaseName
is null
.
See Also:
/**
* Sets a new base name for locating {@code ResourceBundle}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"}.
*
* @param resourceBaseName a {@code String} containing the new
* base name.
*
* @exception IllegalArgumentException if
* {@code resourceBaseName} is {@code null}.
*
* @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 ResourceBundle
s. See Also: Returns: a String
containing the base name.
/**
* Returns the currently set base name for locating
* {@code ResourceBundle}s.
*
* @return a {@code String} containing the base name.
*
* @see #setResourceBaseName
*/
protected String getResourceBaseName() {
return resourceBaseName;
}
Utility method for locating an element.
Params: - mustAppear – if
true
, throw an IllegalArgumentException
if no such node exists; if false
, just return null.
/**
* Utility method for locating an element.
*
* @param mustAppear if {@code true}, throw an
* {@code IllegalArgumentException} if no such node exists;
* if {@code false}, just return null.
*/
private Element getElement(String elementName, boolean mustAppear) {
if (mustAppear && (elementName == null)) {
throw new IllegalArgumentException("element name is null!");
}
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 = 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 CHILD_POLICY_REPEAT
. Params: - elementName – the name of the new element.
- parentName – the name of the element that will be the
parent of the new element.
- childPolicy – one of the
CHILD_POLICY_*
constants, other than CHILD_POLICY_REPEAT
, indicating the child policy of the new element.
Throws: - IllegalArgumentException – if
parentName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
childPolicy
is not one of the predefined constants.
/**
* Adds a new element type to this metadata document format with a
* child policy other than {@code CHILD_POLICY_REPEAT}.
*
* @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_*}
* constants, other than {@code CHILD_POLICY_REPEAT},
* indicating the child policy of the new element.
*
* @exception IllegalArgumentException if {@code parentName}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code childPolicy}
* 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 CHILD_POLICY_REPEAT
. Params: - elementName – the name of the new element.
- parentName – the name of the element that will be the
parent of the new element.
- minChildren – the minimum number of children of the node.
- maxChildren – the maximum number of children of the node.
Throws: - IllegalArgumentException – if
parentName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
minChildren
is negative or larger than maxChildren
.
/**
* Adds a new element type to this metadata document format with a
* child policy of {@code CHILD_POLICY_REPEAT}.
*
* @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}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code minChildren}
* is negative or larger than {@code maxChildren}.
*/
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.
Params: - parentName – the name of the element that will be the
new parent of the element.
- elementName – the name of the element to be added as a
child.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
parentName
is null
, or is not a legal element name for this format.
/**
* 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 added as a
* child.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code parentName}
* is {@code null}, 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.
Params: - elementName – the name of the element to be removed.
/**
* 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<String> iter = element.parentList.iterator();
while (iter.hasNext()) {
String parentName = 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.
Params: - elementName – the name of the element.
- attrName – the name of the attribute being added.
- dataType – the data type (string format) of the attribute, one of the
DATATYPE_*
constants. - required –
true
if the attribute must be present. - defaultValue – the default value for the attribute, or
null
.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
attrName
is null
. - IllegalArgumentException – if
dataType
is not one of the predefined constants.
/**
* 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_*} constants.
* @param required {@code true} if the attribute must be present.
* @param defaultValue the default value for the attribute, or
* {@code null}.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code attrName} is
* {@code null}.
* @exception IllegalArgumentException if {@code dataType} 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.
Params: - elementName – the name of the element.
- attrName – the name of the attribute being added.
- dataType – the data type (string format) of the attribute, one of the
DATATYPE_*
constants. - required –
true
if the attribute must be present. - defaultValue – the default value for the attribute, or
null
. - enumeratedValues – a
List
of String
s containing the legal values for the attribute.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
attrName
is null
. - IllegalArgumentException – if
dataType
is not one of the predefined constants. - IllegalArgumentException – if
enumeratedValues
is null
. - IllegalArgumentException – if
enumeratedValues
does not contain at least one entry. - IllegalArgumentException – if
enumeratedValues
contains an element that is not a String
or is null
.
/**
* 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_*} constants.
* @param required {@code true} if the attribute must be present.
* @param defaultValue the default value for the attribute, or
* {@code null}.
* @param enumeratedValues a {@code List} of
* {@code String}s containing the legal values for the
* attribute.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code attrName} is
* {@code null}.
* @exception IllegalArgumentException if {@code dataType} is
* not one of the predefined constants.
* @exception IllegalArgumentException if
* {@code enumeratedValues} is {@code null}.
* @exception IllegalArgumentException if
* {@code enumeratedValues} does not contain at least one
* entry.
* @exception IllegalArgumentException if
* {@code enumeratedValues} contains an element that is not a
* {@code String} or is {@code null}.
*/
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<String> 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.
Params: - elementName – the name of the element.
- attrName – the name of the attribute being added.
- dataType – the data type (string format) of the attribute, one of the
DATATYPE_*
constants. - required –
true
if the attribute must be present. - defaultValue – the default value for the attribute, or
null
. - minValue – the smallest (inclusive or exclusive depending on the value of
minInclusive
) legal value for the attribute, as a String
. - maxValue – the largest (inclusive or exclusive depending on the value of
minInclusive
) legal value for the attribute, as a String
. - minInclusive –
true
if minValue
is inclusive. - maxInclusive –
true
if maxValue
is inclusive.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
attrName
is null
. - IllegalArgumentException – if
dataType
is not one of the predefined constants.
/**
* 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_*} constants.
* @param required {@code true} if the attribute must be present.
* @param defaultValue the default value for the attribute, or
* {@code null}.
* @param minValue the smallest (inclusive or exclusive depending
* on the value of {@code minInclusive}) legal value for the
* attribute, as a {@code String}.
* @param maxValue the largest (inclusive or exclusive depending
* on the value of {@code minInclusive}) legal value for the
* attribute, as a {@code String}.
* @param minInclusive {@code true} if {@code minValue}
* is inclusive.
* @param maxInclusive {@code true} if {@code maxValue}
* is inclusive.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code attrName} is
* {@code null}.
* @exception IllegalArgumentException if {@code dataType} 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.
Params: - elementName – the name of the element.
- attrName – the name of the attribute being added.
- dataType – the data type (string format) of the attribute, one of the
DATATYPE_*
constants. - required –
true
if the attribute must be present. - listMinLength – the smallest legal number of list items.
- listMaxLength – the largest legal number of list items.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
attrName
is null
. - IllegalArgumentException – if
dataType
is not one of the predefined constants. - IllegalArgumentException – if
listMinLength
is negative or larger than listMaxLength
.
/**
* 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_*} constants.
* @param required {@code true} 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}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code attrName} is
* {@code null}.
* @exception IllegalArgumentException if {@code dataType} is
* not one of the predefined constants.
* @exception IllegalArgumentException if
* {@code listMinLength} is negative or larger than
* {@code listMaxLength}.
*/
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 TRUE
and FALSE
, with a datatype of DATATYPE_BOOLEAN
. Params: - elementName – the name of the element.
- attrName – the name of the attribute being added.
- hasDefaultValue –
true
if a default value should be present. - defaultValue – the default value for the attribute as a
boolean
, ignored if hasDefaultValue
is false
.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
attrName
is null
.
/**
* Adds a new attribute to a previously defined element that will
* be defined by the enumerated values {@code TRUE} and
* {@code FALSE}, with a datatype of
* {@code DATATYPE_BOOLEAN}.
*
* @param elementName the name of the element.
* @param attrName the name of the attribute being added.
* @param hasDefaultValue {@code true} if a default value
* should be present.
* @param defaultValue the default value for the attribute as a
* {@code boolean}, ignored if {@code hasDefaultValue}
* is {@code false}.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, or is not a legal element name for this
* format.
* @exception IllegalArgumentException if {@code attrName} is
* {@code null}.
*/
protected void addBooleanAttribute(String elementName,
String attrName,
boolean hasDefaultValue,
boolean defaultValue) {
List<String> 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.
Params: - elementName – the name of the element.
- attrName – the name of the attribute being removed.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format.
/**
* 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}
* is {@code null}, 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 Object
reference of a given class type to be stored in nodes implementing the named element. The value of the Object
is unconstrained other than by its class type. If an Object
reference was previously allowed, the previous settings are overwritten.
Params: - elementName – the name of the element.
- classType – a
Class
variable indicating the legal class type for the object value. - required –
true
if an object value must be present. - defaultValue – the default value for the
Object
reference, or null
.
Type parameters: - <T> – the type of the object.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format.
/**
* Allows an {@code Object} reference of a given class type
* to be stored in nodes implementing the named element. The
* value of the {@code Object} is unconstrained other than by
* its class type.
*
* <p> If an {@code Object} reference was previously allowed,
* the previous settings are overwritten.
*
* @param elementName the name of the element.
* @param classType a {@code Class} variable indicating the
* legal class type for the object value.
* @param required {@code true} if an object value must be present.
* @param defaultValue the default value for the
* {@code Object} reference, or {@code null}.
* @param <T> the type of the object.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, 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<T> obj = new ObjectValue<>();
obj.valueType = VALUE_ARBITRARY;
obj.classType = classType;
obj.defaultValue = defaultValue;
element.objectValue = obj;
}
Allows an Object
reference of a given class type to be stored in nodes implementing the named element. The value of the Object
must be one of the values given by enumeratedValues
. If an Object
reference was previously allowed, the previous settings are overwritten.
Params: - elementName – the name of the element.
- classType – a
Class
variable indicating the legal class type for the object value. - required –
true
if an object value must be present. - defaultValue – the default value for the
Object
reference, or null
. - enumeratedValues – a
List
of Object
s containing the legal values for the object reference.
Type parameters: - <T> – the type of the object.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
enumeratedValues
is null
. - IllegalArgumentException – if
enumeratedValues
does not contain at least one entry. - IllegalArgumentException – if
enumeratedValues
contains an element that is not an instance of the class type denoted by classType
or is null
.
/**
* Allows an {@code Object} reference of a given class type
* to be stored in nodes implementing the named element. The
* value of the {@code Object} must be one of the values
* given by {@code enumeratedValues}.
*
* <p> If an {@code Object} reference was previously allowed,
* the previous settings are overwritten.
*
* @param elementName the name of the element.
* @param classType a {@code Class} variable indicating the
* legal class type for the object value.
* @param required {@code true} if an object value must be present.
* @param defaultValue the default value for the
* {@code Object} reference, or {@code null}.
* @param enumeratedValues a {@code List} of
* {@code Object}s containing the legal values for the
* object reference.
* @param <T> the type of the object.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, or is not a legal element name for this format.
* @exception IllegalArgumentException if
* {@code enumeratedValues} is {@code null}.
* @exception IllegalArgumentException if
* {@code enumeratedValues} does not contain at least one
* entry.
* @exception IllegalArgumentException if
* {@code enumeratedValues} contains an element that is not
* an instance of the class type denoted by {@code classType}
* or is {@code null}.
*/
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<? extends T> 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<T> obj = new ObjectValue<>();
obj.valueType = VALUE_ENUMERATION;
obj.classType = classType;
obj.defaultValue = defaultValue;
obj.enumeratedValues = enumeratedValues;
element.objectValue = obj;
}
Allows an Object
reference of a given class type to be stored in nodes implementing the named element. The value of the Object
must be within the range given by minValue
and maxValue
. Furthermore, the class type must implement the Comparable
interface. If an Object
reference was previously allowed, the previous settings are overwritten.
Params: - elementName – the name of the element.
- classType – a
Class
variable indicating the legal class type for the object value. - defaultValue – the default value for the
- minValue – the smallest (inclusive or exclusive depending on the value of
minInclusive
) legal value for the object value, as a String
. - maxValue – the largest (inclusive or exclusive depending on the value of
minInclusive
) legal value for the object value, as a String
. - minInclusive –
true
if minValue
is inclusive. - maxInclusive –
true
if maxValue
is inclusive.
Type parameters: - <T> – the type of the object.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format.
/**
* Allows an {@code Object} reference of a given class type
* to be stored in nodes implementing the named element. The
* value of the {@code Object} must be within the range given
* by {@code minValue} and {@code maxValue}.
* Furthermore, the class type must implement the
* {@code Comparable} interface.
*
* <p> If an {@code Object} reference was previously allowed,
* the previous settings are overwritten.
*
* @param elementName the name of the element.
* @param classType a {@code Class} 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}) legal value for the
* object value, as a {@code String}.
* @param maxValue the largest (inclusive or exclusive depending
* on the value of {@code minInclusive}) legal value for the
* object value, as a {@code String}.
* @param minInclusive {@code true} if {@code minValue}
* is inclusive.
* @param maxInclusive {@code true} if {@code maxValue}
* is inclusive.
* @param <T> the type of the object.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, 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<T> 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 Object
reference of a given class type to be stored in nodes implementing the named element. The value of the Object
must an array of objects of class type given by classType
, with at least arrayMinLength
and at most arrayMaxLength
elements. If an Object
reference was previously allowed, the previous settings are overwritten.
Params: - elementName – the name of the element.
- classType – a
Class
variable indicating the legal class type for the object value. - arrayMinLength – the smallest legal length for the array.
- arrayMaxLength – the largest legal length for the array.
Throws: - IllegalArgumentException – if
elementName
is not a legal element name for this format.
/**
* Allows an {@code Object} reference of a given class type
* to be stored in nodes implementing the named element. The
* value of the {@code Object} must an array of objects of
* class type given by {@code classType}, with at least
* {@code arrayMinLength} and at most
* {@code arrayMaxLength} elements.
*
* <p> If an {@code Object} reference was previously allowed,
* the previous settings are overwritten.
*
* @param elementName the name of the element.
* @param classType a {@code Class} 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} 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<Object> obj = new ObjectValue<>();
obj.valueType = VALUE_LIST;
obj.classType = classType;
obj.arrayMinLength = arrayMinLength;
obj.arrayMaxLength = arrayMaxLength;
element.objectValue = obj;
}
Disallows an Object
reference from being stored in nodes implementing the named element. Params: - elementName – the name of the element.
Throws: - IllegalArgumentException – if
elementName
is not a legal element name for this format.
/**
* Disallows an {@code Object} reference from being stored in
* nodes implementing the named element.
*
* @param elementName the name of the element.
*
* @exception IllegalArgumentException if {@code elementName} 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();
}
/**
* Per the class documentation, resource bundles, including localized ones
* are intended to be delivered by the subclasser - ie supplier of the
* metadataformat. For the standard format and all standard plugins that
* is the JDK. For 3rd party plugins that they will supply their own.
* This includes plugins bundled with applets/applications.
* In all cases this means it is sufficient to search for those resource
* in the module that is providing the MetadataFormatImpl subclass.
*/
try {
ResourceBundle bundle = ResourceBundle.getBundle(resourceBaseName, locale,
this.getClass().getModule());
return bundle.getString(key);
} catch (MissingResourceException e) {
return null;
}
}
Returns a String
containing a description of the named element, or null
. The description will be localized for the supplied Locale
if possible. The default implementation will first locate a ResourceBundle
using the current resource base name set by setResourceBaseName
and the supplied Locale
, using the fallback mechanism described in the comments for ResourceBundle.getBundle
. If a ResourceBundle
is found, the element name will be used as a key to its getString
method, and the result returned. If no ResourceBundle
is found, or no such key is present, null
will be returned.
If locale
is null
, the current default Locale
returned by Locale.getLocale
will be used.
Params: - elementName – the name of the element.
- locale – the
Locale
for which localization will be attempted.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format.
See Also: Returns: the element description.
/**
* Returns a {@code String} containing a description of the
* named element, or {@code null}. The description will be
* localized for the supplied {@code Locale} if possible.
*
* <p> The default implementation will first locate a
* {@code ResourceBundle} using the current resource base
* name set by {@code setResourceBaseName} and the supplied
* {@code Locale}, using the fallback mechanism described in
* the comments for {@code ResourceBundle.getBundle}. If a
* {@code ResourceBundle} is found, the element name will be
* used as a key to its {@code getString} method, and the
* result returned. If no {@code ResourceBundle} is found,
* or no such key is present, {@code null} will be returned.
*
* <p> If {@code locale} is {@code null}, the current
* default {@code Locale} returned by {@code Locale.getLocale}
* will be used.
*
* @param elementName the name of the element.
* @param locale the {@code Locale} for which localization
* will be attempted.
*
* @return the element description.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, 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 element.childList.toArray(new String[0]);
}
// Attributes
public String[] getAttributeNames(String elementName) {
Element element = getElement(elementName);
List<String> names = element.attrList;
String[] result = new String[names.size()];
return 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<String> values = attr.enumeratedValues;
String[] result = new String[values.size()];
return 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 String
containing a description of the named attribute, or null
. The description will be localized for the supplied Locale
if possible. The default implementation will first locate a ResourceBundle
using the current resource base name set by setResourceBaseName
and the supplied Locale
, using the fallback mechanism described in the comments for ResourceBundle.getBundle
. If a ResourceBundle
is found, the element name followed by a "/" character followed by the attribute name (elementName + "/" + attrName
) will be used as a key to its getString
method, and the result returned. If no ResourceBundle
is found, or no such key is present, null
will be returned.
If locale
is null
, the current default Locale
returned by Locale.getLocale
will be used.
Params: - elementName – the name of the element.
- attrName – the name of the attribute.
- locale – the
Locale
for which localization will be attempted, or null
.
Throws: - IllegalArgumentException – if
elementName
is null
, or is not a legal element name for this format. - IllegalArgumentException – if
attrName
is null
or is not a legal attribute name for this element.
See Also: Returns: the attribute description.
/**
* Returns a {@code String} containing a description of the
* named attribute, or {@code null}. The description will be
* localized for the supplied {@code Locale} if possible.
*
* <p> The default implementation will first locate a
* {@code ResourceBundle} using the current resource base
* name set by {@code setResourceBaseName} and the supplied
* {@code Locale}, using the fallback mechanism described in
* the comments for {@code ResourceBundle.getBundle}. If a
* {@code ResourceBundle} is found, the element name followed
* by a "/" character followed by the attribute name
* ({@code elementName + "/" + attrName}) will be used as a
* key to its {@code getString} method, and the result
* returned. If no {@code ResourceBundle} is found, or no
* such key is present, {@code null} will be returned.
*
* <p> If {@code locale} is {@code null}, the current
* default {@code Locale} returned by {@code Locale.getLocale}
* will be used.
*
* @param elementName the name of the element.
* @param attrName the name of the attribute.
* @param locale the {@code Locale} for which localization
* will be attempted, or {@code null}.
*
* @return the attribute description.
*
* @exception IllegalArgumentException if {@code elementName}
* is {@code null}, or is not a legal element name for this format.
* @exception IllegalArgumentException if {@code attrName} is
* {@code null} 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 = 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 = 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 = 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 static synchronized void createStandardFormat() {
if (standardFormat == null) {
standardFormat = new StandardMetadataFormat();
}
}
Returns an IIOMetadataFormat
object describing the standard, plug-in neutral javax.imageio_1.0
metadata document format described in the comment of the javax.imageio.metadata
package. Returns: a predefined IIOMetadataFormat
instance.
/**
* Returns an {@code IIOMetadataFormat} object describing the
* standard, plug-in neutral {@code javax.imageio_1.0}
* metadata document format described in the comment of the
* {@code javax.imageio.metadata} package.
*
* @return a predefined {@code IIOMetadataFormat} instance.
*/
public static IIOMetadataFormat getStandardFormatInstance() {
createStandardFormat();
return standardFormat;
}
}