Save This Page
Home » openjdk-7 » javax » imageio » metadata » [javadoc | source]
    1   /*
    2    * Copyright 2000-2004 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.imageio.metadata;
   27   
   28   import java.util.ArrayList;
   29   import java.util.Collection;
   30   import java.util.HashMap;
   31   import java.util.Iterator;
   32   import java.util.List;
   33   import java.util.Locale;
   34   import java.util.Map;
   35   import java.util.MissingResourceException;
   36   import java.util.ResourceBundle;
   37   import javax.imageio.ImageTypeSpecifier;
   38   import com.sun.imageio.plugins.common.StandardMetadataFormat;
   39   
   40   /**
   41    * A concrete class providing a reusable implementation of the
   42    * <code>IIOMetadataFormat</code> interface.  In addition, a static
   43    * instance representing the standard, plug-in neutral
   44    * <code>javax_imageio_1.0</code> format is provided by the
   45    * <code>getStandardFormatInstance</code> method.
   46    *
   47    * <p> In order to supply localized descriptions of elements and
   48    * attributes, a <code>ResourceBundle</code> with a base name of
   49    * <code>this.getClass().getName() + "Resources"</code> should be
   50    * supplied via the usual mechanism used by
   51    * <code>ResourceBundle.getBundle</code>.  Briefly, the subclasser
   52    * supplies one or more additional classes according to a naming
   53    * convention (by default, the fully-qualified name of the subclass
   54    * extending <code>IIMetadataFormatImpl</code>, plus the string
   55    * "Resources", plus the country, language, and variant codes
   56    * separated by underscores).  At run time, calls to
   57    * <code>getElementDescription</code> or
   58    * <code>getAttributeDescription</code> will attempt to load such
   59    * classes dynamically according to the supplied locale, and will use
   60    * either the element name, or the element name followed by a '/'
   61    * character followed by the attribute name as a key.  This key will
   62    * be supplied to the <code>ResourceBundle</code>'s
   63    * <code>getString</code> method, and the resulting localized
   64    * description of the node or attribute is returned.
   65    *
   66    * <p> The subclass may supply a different base name for the resource
   67    * bundles using the <code>setResourceBaseName</code> method.
   68    *
   69    * <p> A subclass may choose its own localization mechanism, if so
   70    * desired, by overriding the supplied implementations of
   71    * <code>getElementDescription</code> and
   72    * <code>getAttributeDescription</code>.
   73    *
   74    * @see ResourceBundle#getBundle(String,Locale)
   75    *
   76    */
   77   public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat {
   78   
   79       /**
   80        * A <code>String</code> constant containing the standard format
   81        * name, <code>"javax_imageio_1.0"</code>.
   82        */
   83       public static final String standardMetadataFormatName =
   84           "javax_imageio_1.0";
   85   
   86       private static IIOMetadataFormat standardFormat = null;
   87   
   88       private String resourceBaseName = this.getClass().getName() + "Resources";
   89   
   90       private String rootName;
   91   
   92       // Element name (String) -> Element
   93       private HashMap elementMap = new HashMap();
   94   
   95       class Element {
   96           String elementName;
   97   
   98           int childPolicy;
   99           int minChildren = 0;
  100           int maxChildren = 0;
  101   
  102           // Child names (Strings)
  103           List childList = new ArrayList();
  104   
  105           // Parent names (Strings)
  106           List parentList = new ArrayList();
  107   
  108           // List of attribute names in the order they were added
  109           List attrList = new ArrayList();
  110           // Attr name (String) -> Attribute
  111           Map attrMap = new HashMap();
  112   
  113           ObjectValue objectValue;
  114       }
  115   
  116       class Attribute {
  117           String attrName;
  118   
  119           int valueType = VALUE_ARBITRARY;
  120           int dataType;
  121           boolean required;
  122           String defaultValue = null;
  123   
  124           // enumeration
  125           List enumeratedValues;
  126   
  127           // range
  128           String minValue;
  129           String maxValue;
  130   
  131           // list
  132           int listMinLength;
  133           int listMaxLength;
  134       }
  135   
  136       class ObjectValue {
  137           int valueType = VALUE_NONE;
  138           Class classType = null;
  139           Object defaultValue = null;
  140   
  141           // Meaningful only if valueType == VALUE_ENUMERATION
  142           List enumeratedValues = null;
  143   
  144           // Meaningful only if valueType == VALUE_RANGE
  145           Comparable minValue = null;
  146           Comparable maxValue = null;
  147   
  148           // Meaningful only if valueType == VALUE_LIST
  149           int arrayMinLength = 0;
  150           int arrayMaxLength = 0;
  151       }
  152   
  153       /**
  154        * Constructs a blank <code>IIOMetadataFormatImpl</code> instance,
  155        * with a given root element name and child policy (other than
  156        * <code>CHILD_POLICY_REPEAT</code>).  Additional elements, and
  157        * their attributes and <code>Object</code> reference information
  158        * may be added using the various <code>add</code> methods.
  159        *
  160        * @param rootName the name of the root element.
  161        * @param childPolicy one of the <code>CHILD_POLICY_*</code> constants,
  162        * other than <code>CHILD_POLICY_REPEAT</code>.
  163        *
  164        * @exception IllegalArgumentException if <code>rootName</code> is
  165        * <code>null</code>.
  166        * @exception IllegalArgumentException if <code>childPolicy</code> is
  167        * not one of the predefined constants.
  168        */
  169       public IIOMetadataFormatImpl(String rootName,
  170                                    int childPolicy) {
  171           if (rootName == null) {
  172               throw new IllegalArgumentException("rootName == null!");
  173           }
  174           if (childPolicy < CHILD_POLICY_EMPTY ||
  175               childPolicy > CHILD_POLICY_MAX ||
  176               childPolicy == CHILD_POLICY_REPEAT) {
  177               throw new IllegalArgumentException("Invalid value for childPolicy!");
  178           }
  179   
  180           this.rootName = rootName;
  181   
  182           Element root = new Element();
  183           root.elementName = rootName;
  184           root.childPolicy = childPolicy;
  185   
  186           elementMap.put(rootName, root);
  187       }
  188   
  189       /**
  190        * Constructs a blank <code>IIOMetadataFormatImpl</code> instance,
  191        * with a given root element name and a child policy of
  192        * <code>CHILD_POLICY_REPEAT</code>.  Additional elements, and
  193        * their attributes and <code>Object</code> reference information
  194        * may be added using the various <code>add</code> methods.
  195        *
  196        * @param rootName the name of the root element.
  197        * @param minChildren the minimum number of children of the node.
  198        * @param maxChildren the maximum number of children of the node.
  199        *
  200        * @exception IllegalArgumentException if <code>rootName</code> is
  201        * <code>null</code>.
  202        * @exception IllegalArgumentException if <code>minChildren</code>
  203        * is negative or larger than <code>maxChildren</code>.
  204        */
  205       public IIOMetadataFormatImpl(String rootName,
  206                                    int minChildren,
  207                                    int maxChildren) {
  208           if (rootName == null) {
  209               throw new IllegalArgumentException("rootName == null!");
  210           }
  211           if (minChildren < 0) {
  212               throw new IllegalArgumentException("minChildren < 0!");
  213           }
  214           if (minChildren > maxChildren) {
  215               throw new IllegalArgumentException("minChildren > maxChildren!");
  216           }
  217   
  218           Element root = new Element();
  219           root.elementName = rootName;
  220           root.childPolicy = CHILD_POLICY_REPEAT;
  221           root.minChildren = minChildren;
  222           root.maxChildren = maxChildren;
  223   
  224           this.rootName = rootName;
  225           elementMap.put(rootName, root);
  226       }
  227   
  228       /**
  229        * Sets a new base name for locating <code>ResourceBundle</code>s
  230        * containing descriptions of elements and attributes for this
  231        * format.
  232        *
  233        * <p> Prior to the first time this method is called, the base
  234        * name will be equal to <code>this.getClass().getName() +
  235        * "Resources"</code>.
  236        *
  237        * @param resourceBaseName a <code>String</code> containg the new
  238        * base name.
  239        *
  240        * @exception IllegalArgumentException if
  241        * <code>resourceBaseName</code> is <code>null</code>.
  242        *
  243        * @see #getResourceBaseName
  244        */
  245       protected void setResourceBaseName(String resourceBaseName) {
  246           if (resourceBaseName == null) {
  247               throw new IllegalArgumentException("resourceBaseName == null!");
  248           }
  249           this.resourceBaseName = resourceBaseName;
  250       }
  251   
  252       /**
  253        * Returns the currently set base name for locating
  254        * <code>ResourceBundle</code>s.
  255        *
  256        * @return a <code>String</code> containing the base name.
  257        *
  258        * @see #setResourceBaseName
  259        */
  260       protected String getResourceBaseName() {
  261           return resourceBaseName;
  262       }
  263   
  264       /**
  265        * Utility method for locating an element.
  266        *
  267        * @param mustAppear if <code>true</code>, throw an
  268        * <code>IllegalArgumentException</code> if no such node exists;
  269        * if <code>false</code>, just return null.
  270        */
  271       private Element getElement(String elementName, boolean mustAppear) {
  272           if (mustAppear && (elementName == null)) {
  273               throw new IllegalArgumentException("element name is null!");
  274           }
  275           Element element = (Element)elementMap.get(elementName);
  276           if (mustAppear && (element == null)) {
  277               throw new IllegalArgumentException("No such element: " +
  278                                                  elementName);
  279           }
  280           return element;
  281       }
  282   
  283       private Element getElement(String elementName) {
  284           return getElement(elementName, true);
  285       }
  286   
  287       // Utility method for locating an attribute
  288       private Attribute getAttribute(String elementName, String attrName) {
  289           Element element = getElement(elementName);
  290           Attribute attr = (Attribute)element.attrMap.get(attrName);
  291           if (attr == null) {
  292               throw new IllegalArgumentException("No such attribute \"" +
  293                                                  attrName + "\"!");
  294           }
  295           return attr;
  296       }
  297   
  298       // Setup
  299   
  300       /**
  301        * Adds a new element type to this metadata document format with a
  302        * child policy other than <code>CHILD_POLICY_REPEAT</code>.
  303        *
  304        * @param elementName the name of the new element.
  305        * @param parentName the name of the element that will be the
  306        * parent of the new element.
  307        * @param childPolicy one of the <code>CHILD_POLICY_*</code>
  308        * constants, other than <code>CHILD_POLICY_REPEAT</code>,
  309        * indicating the child policy of the new element.
  310        *
  311        * @exception IllegalArgumentException if <code>parentName</code>
  312        * is <code>null</code>, or is not a legal element name for this
  313        * format.
  314        * @exception IllegalArgumentException if <code>childPolicy</code>
  315        * is not one of the predefined constants.
  316        */
  317       protected void addElement(String elementName,
  318                                 String parentName,
  319                                 int childPolicy) {
  320           Element parent = getElement(parentName);
  321           if (childPolicy < CHILD_POLICY_EMPTY ||
  322               childPolicy > CHILD_POLICY_MAX ||
  323               childPolicy == CHILD_POLICY_REPEAT) {
  324               throw new IllegalArgumentException
  325                   ("Invalid value for childPolicy!");
  326           }
  327   
  328           Element element = new Element();
  329           element.elementName = elementName;
  330           element.childPolicy = childPolicy;
  331   
  332           parent.childList.add(elementName);
  333           element.parentList.add(parentName);
  334   
  335           elementMap.put(elementName, element);
  336       }
  337   
  338       /**
  339        * Adds a new element type to this metadata document format with a
  340        * child policy of <code>CHILD_POLICY_REPEAT</code>.
  341        *
  342        * @param elementName the name of the new element.
  343        * @param parentName the name of the element that will be the
  344        * parent of the new element.
  345        * @param minChildren the minimum number of children of the node.
  346        * @param maxChildren the maximum number of children of the node.
  347        *
  348        * @exception IllegalArgumentException if <code>parentName</code>
  349        * is <code>null</code>, or is not a legal element name for this
  350        * format.
  351        * @exception IllegalArgumentException if <code>minChildren</code>
  352        * is negative or larger than <code>maxChildren</code>.
  353        */
  354       protected void addElement(String elementName,
  355                                 String parentName,
  356                                 int minChildren,
  357                                 int maxChildren) {
  358           Element parent = getElement(parentName);
  359           if (minChildren < 0) {
  360               throw new IllegalArgumentException("minChildren < 0!");
  361           }
  362           if (minChildren > maxChildren) {
  363               throw new IllegalArgumentException("minChildren > maxChildren!");
  364           }
  365   
  366           Element element = new Element();
  367           element.elementName = elementName;
  368           element.childPolicy = CHILD_POLICY_REPEAT;
  369           element.minChildren = minChildren;
  370           element.maxChildren = maxChildren;
  371   
  372           parent.childList.add(elementName);
  373           element.parentList.add(parentName);
  374   
  375           elementMap.put(elementName, element);
  376       }
  377   
  378       /**
  379        * Adds an existing element to the list of legal children for a
  380        * given parent node type.
  381        *
  382        * @param parentName the name of the element that will be the
  383        * new parent of the element.
  384        * @param elementName the name of the element to be addded as a
  385        * child.
  386        *
  387        * @exception IllegalArgumentException if <code>elementName</code>
  388        * is <code>null</code>, or is not a legal element name for this
  389        * format.
  390        * @exception IllegalArgumentException if <code>parentName</code>
  391        * is <code>null</code>, or is not a legal element name for this
  392        * format.
  393        */
  394       protected void addChildElement(String elementName, String parentName) {
  395           Element parent = getElement(parentName);
  396           Element element = getElement(elementName);
  397           parent.childList.add(elementName);
  398           element.parentList.add(parentName);
  399       }
  400   
  401       /**
  402        * Removes an element from the format.  If no element with the
  403        * given name was present, nothing happens and no exception is
  404        * thrown.
  405        *
  406        * @param elementName the name of the element to be removed.
  407        */
  408       protected void removeElement(String elementName) {
  409           Element element = getElement(elementName, false);
  410           if (element != null) {
  411               Iterator iter = element.parentList.iterator();
  412               while (iter.hasNext()) {
  413                   String parentName = (String)iter.next();
  414                   Element parent = getElement(parentName, false);
  415                   if (parent != null) {
  416                       parent.childList.remove(elementName);
  417                   }
  418               }
  419               elementMap.remove(elementName);
  420           }
  421       }
  422   
  423       /**
  424        * Adds a new attribute to a previously defined element that may
  425        * be set to an arbitrary value.
  426        *
  427        * @param elementName the name of the element.
  428        * @param attrName the name of the attribute being added.
  429        * @param dataType the data type (string format) of the attribute,
  430        * one of the <code>DATATYPE_*</code> constants.
  431        * @param required <code>true</code> if the attribute must be present.
  432        * @param defaultValue the default value for the attribute, or
  433        * <code>null</code>.
  434        *
  435        * @exception IllegalArgumentException if <code>elementName</code>
  436        * is <code>null</code>, or is not a legal element name for this
  437        * format.
  438        * @exception IllegalArgumentException if <code>attrName</code> is
  439        * <code>null</code>.
  440        * @exception IllegalArgumentException if <code>dataType</code> is
  441        * not one of the predefined constants.
  442        */
  443       protected void addAttribute(String elementName,
  444                                   String attrName,
  445                                   int dataType,
  446                                   boolean required,
  447                                   String defaultValue) {
  448           Element element = getElement(elementName);
  449           if (attrName == null) {
  450               throw new IllegalArgumentException("attrName == null!");
  451           }
  452           if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
  453               throw new IllegalArgumentException("Invalid value for dataType!");
  454           }
  455   
  456           Attribute attr = new Attribute();
  457           attr.attrName = attrName;
  458           attr.valueType = VALUE_ARBITRARY;
  459           attr.dataType = dataType;
  460           attr.required = required;
  461           attr.defaultValue = defaultValue;
  462   
  463           element.attrList.add(attrName);
  464           element.attrMap.put(attrName, attr);
  465       }
  466   
  467       /**
  468        * Adds a new attribute to a previously defined element that will
  469        * be defined by a set of enumerated values.
  470        *
  471        * @param elementName the name of the element.
  472        * @param attrName the name of the attribute being added.
  473        * @param dataType the data type (string format) of the attribute,
  474        * one of the <code>DATATYPE_*</code> constants.
  475        * @param required <code>true</code> if the attribute must be present.
  476        * @param defaultValue the default value for the attribute, or
  477        * <code>null</code>.
  478        * @param enumeratedValues a <code>List</code> of
  479        * <code>String</code>s containing the legal values for the
  480        * attribute.
  481        *
  482        * @exception IllegalArgumentException if <code>elementName</code>
  483        * is <code>null</code>, or is not a legal element name for this
  484        * format.
  485        * @exception IllegalArgumentException if <code>attrName</code> is
  486        * <code>null</code>.
  487        * @exception IllegalArgumentException if <code>dataType</code> is
  488        * not one of the predefined constants.
  489        * @exception IllegalArgumentException if
  490        * <code>enumeratedValues</code> is <code>null</code>.
  491        * @exception IllegalArgumentException if
  492        * <code>enumeratedValues</code> does not contain at least one
  493        * entry.
  494        * @exception IllegalArgumentException if
  495        * <code>enumeratedValues</code> contains an element that is not a
  496        * <code>String</code> or is <code>null</code>.
  497        */
  498       protected void addAttribute(String elementName,
  499                                   String attrName,
  500                                   int dataType,
  501                                   boolean required,
  502                                   String defaultValue,
  503                                   List<String> enumeratedValues) {
  504           Element element = getElement(elementName);
  505           if (attrName == null) {
  506               throw new IllegalArgumentException("attrName == null!");
  507           }
  508           if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
  509               throw new IllegalArgumentException("Invalid value for dataType!");
  510           }
  511           if (enumeratedValues == null) {
  512               throw new IllegalArgumentException("enumeratedValues == null!");
  513           }
  514           if (enumeratedValues.size() == 0) {
  515               throw new IllegalArgumentException("enumeratedValues is empty!");
  516           }
  517           Iterator iter = enumeratedValues.iterator();
  518           while (iter.hasNext()) {
  519               Object o = iter.next();
  520               if (o == null) {
  521                   throw new IllegalArgumentException
  522                       ("enumeratedValues contains a null!");
  523               }
  524               if (!(o instanceof String)) {
  525                   throw new IllegalArgumentException
  526                       ("enumeratedValues contains a non-String value!");
  527               }
  528           }
  529   
  530           Attribute attr = new Attribute();
  531           attr.attrName = attrName;
  532           attr.valueType = VALUE_ENUMERATION;
  533           attr.dataType = dataType;
  534           attr.required = required;
  535           attr.defaultValue = defaultValue;
  536           attr.enumeratedValues = enumeratedValues;
  537   
  538           element.attrList.add(attrName);
  539           element.attrMap.put(attrName, attr);
  540       }
  541   
  542       /**
  543        * Adds a new attribute to a previously defined element that will
  544        * be defined by a range of values.
  545        *
  546        * @param elementName the name of the element.
  547        * @param attrName the name of the attribute being added.
  548        * @param dataType the data type (string format) of the attribute,
  549        * one of the <code>DATATYPE_*</code> constants.
  550        * @param required <code>true</code> if the attribute must be present.
  551        * @param defaultValue the default value for the attribute, or
  552        * <code>null</code>.
  553        * @param minValue the smallest (inclusive or exclusive depending
  554        * on the value of <code>minInclusive</code>) legal value for the
  555        * attribute, as a <code>String</code>.
  556        * @param maxValue the largest (inclusive or exclusive depending
  557        * on the value of <code>minInclusive</code>) legal value for the
  558        * attribute, as a <code>String</code>.
  559        * @param minInclusive <code>true</code> if <code>minValue</code>
  560        * is inclusive.
  561        * @param maxInclusive <code>true</code> if <code>maxValue</code>
  562        * is inclusive.
  563        *
  564        * @exception IllegalArgumentException if <code>elementName</code>
  565        * is <code>null</code>, or is not a legal element name for this
  566        * format.
  567        * @exception IllegalArgumentException if <code>attrName</code> is
  568        * <code>null</code>.
  569        * @exception IllegalArgumentException if <code>dataType</code> is
  570        * not one of the predefined constants.
  571        */
  572       protected void addAttribute(String elementName,
  573                                   String attrName,
  574                                   int dataType,
  575                                   boolean required,
  576                                   String defaultValue,
  577                                   String minValue,
  578                                   String maxValue,
  579                                   boolean minInclusive,
  580                                   boolean maxInclusive) {
  581           Element element = getElement(elementName);
  582           if (attrName == null) {
  583               throw new IllegalArgumentException("attrName == null!");
  584           }
  585           if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
  586               throw new IllegalArgumentException("Invalid value for dataType!");
  587           }
  588   
  589           Attribute attr = new Attribute();
  590           attr.attrName = attrName;
  591           attr.valueType = VALUE_RANGE;
  592           if (minInclusive) {
  593               attr.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;
  594           }
  595           if (maxInclusive) {
  596               attr.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;
  597           }
  598           attr.dataType = dataType;
  599           attr.required = required;
  600           attr.defaultValue = defaultValue;
  601           attr.minValue = minValue;
  602           attr.maxValue = maxValue;
  603   
  604           element.attrList.add(attrName);
  605           element.attrMap.put(attrName, attr);
  606       }
  607   
  608       /**
  609        * Adds a new attribute to a previously defined element that will
  610        * be defined by a list of values.
  611        *
  612        * @param elementName the name of the element.
  613        * @param attrName the name of the attribute being added.
  614        * @param dataType the data type (string format) of the attribute,
  615        * one of the <code>DATATYPE_*</code> constants.
  616        * @param required <code>true</code> if the attribute must be present.
  617        * @param listMinLength the smallest legal number of list items.
  618        * @param listMaxLength the largest legal number of list items.
  619        *
  620        * @exception IllegalArgumentException if <code>elementName</code>
  621        * is <code>null</code>, or is not a legal element name for this
  622        * format.
  623        * @exception IllegalArgumentException if <code>attrName</code> is
  624        * <code>null</code>.
  625        * @exception IllegalArgumentException if <code>dataType</code> is
  626        * not one of the predefined constants.
  627        * @exception IllegalArgumentException if
  628        * <code>listMinLength</code> is negative or larger than
  629        * <code>listMaxLength</code>.
  630        */
  631       protected void addAttribute(String elementName,
  632                                   String attrName,
  633                                   int dataType,
  634                                   boolean required,
  635                                   int listMinLength,
  636                                   int listMaxLength) {
  637           Element element = getElement(elementName);
  638           if (attrName == null) {
  639               throw new IllegalArgumentException("attrName == null!");
  640           }
  641           if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
  642               throw new IllegalArgumentException("Invalid value for dataType!");
  643           }
  644           if (listMinLength < 0 || listMinLength > listMaxLength) {
  645               throw new IllegalArgumentException("Invalid list bounds!");
  646           }
  647   
  648           Attribute attr = new Attribute();
  649           attr.attrName = attrName;
  650           attr.valueType = VALUE_LIST;
  651           attr.dataType = dataType;
  652           attr.required = required;
  653           attr.listMinLength = listMinLength;
  654           attr.listMaxLength = listMaxLength;
  655   
  656           element.attrList.add(attrName);
  657           element.attrMap.put(attrName, attr);
  658       }
  659   
  660       /**
  661        * Adds a new attribute to a previously defined element that will
  662        * be defined by the enumerated values <code>TRUE</code> and
  663        * <code>FALSE</code>, with a datatype of
  664        * <code>DATATYPE_BOOLEAN</code>.
  665        *
  666        * @param elementName the name of the element.
  667        * @param attrName the name of the attribute being added.
  668        * @param hasDefaultValue <code>true</code> if a default value
  669        * should be present.
  670        * @param defaultValue the default value for the attribute as a
  671        * <code>boolean</code>, ignored if <code>hasDefaultValue</code>
  672        * is <code>false</code>.
  673        *
  674        * @exception IllegalArgumentException if <code>elementName</code>
  675        * is <code>null</code>, or is not a legal element name for this
  676        * format.
  677        * @exception IllegalArgumentException if <code>attrName</code> is
  678        * <code>null</code>.
  679        */
  680       protected void addBooleanAttribute(String elementName,
  681                                          String attrName,
  682                                          boolean hasDefaultValue,
  683                                          boolean defaultValue) {
  684           List values = new ArrayList();
  685           values.add("TRUE");
  686           values.add("FALSE");
  687   
  688           String dval = null;
  689           if (hasDefaultValue) {
  690               dval = defaultValue ? "TRUE" : "FALSE";
  691           }
  692           addAttribute(elementName,
  693                        attrName,
  694                        DATATYPE_BOOLEAN,
  695                        true,
  696                        dval,
  697                        values);
  698       }
  699   
  700       /**
  701        * Removes an attribute from a previously defined element.  If no
  702        * attribute with the given name was present in the given element,
  703        * nothing happens and no exception is thrown.
  704        *
  705        * @param elementName the name of the element.
  706        * @param attrName the name of the attribute being removed.
  707        *
  708        * @exception IllegalArgumentException if <code>elementName</code>
  709        * is <code>null</code>, or is not a legal element name for this format.
  710        */
  711       protected void removeAttribute(String elementName, String attrName) {
  712           Element element = getElement(elementName);
  713           element.attrList.remove(attrName);
  714           element.attrMap.remove(attrName);
  715       }
  716   
  717       /**
  718        * Allows an <code>Object</code> reference of a given class type
  719        * to be stored in nodes implementing the named element.  The
  720        * value of the <code>Object</code> is unconstrained other than by
  721        * its class type.
  722        *
  723        * <p> If an <code>Object</code> reference was previously allowed,
  724        * the previous settings are overwritten.
  725        *
  726        * @param elementName the name of the element.
  727        * @param classType a <code>Class</code> variable indicating the
  728        * legal class type for the object value.
  729        * @param required <code>true</code> if an object value must be present.
  730        * @param defaultValue the default value for the
  731        * <code>Object</code> reference, or <code>null</code>.
  732        *
  733        * @exception IllegalArgumentException if <code>elementName</code>
  734        * is <code>null</code>, or is not a legal element name for this format.
  735        */
  736       protected <T> void addObjectValue(String elementName,
  737                                         Class<T> classType,
  738                                         boolean required,
  739                                         T defaultValue)
  740       {
  741           Element element = getElement(elementName);
  742           ObjectValue obj = new ObjectValue();
  743           obj.valueType = VALUE_ARBITRARY;
  744           obj.classType = classType;
  745           obj.defaultValue = defaultValue;
  746   
  747           element.objectValue = obj;
  748       }
  749   
  750       /**
  751        * Allows an <code>Object</code> reference of a given class type
  752        * to be stored in nodes implementing the named element.  The
  753        * value of the <code>Object</code> must be one of the values
  754        * given by <code>enumeratedValues</code>.
  755        *
  756        * <p> If an <code>Object</code> reference was previously allowed,
  757        * the previous settings are overwritten.
  758        *
  759        * @param elementName the name of the element.
  760        * @param classType a <code>Class</code> variable indicating the
  761        * legal class type for the object value.
  762        * @param required <code>true</code> if an object value must be present.
  763        * @param defaultValue the default value for the
  764        * <code>Object</code> reference, or <code>null</code>.
  765        * @param enumeratedValues a <code>List</code> of
  766        * <code>Object</code>s containing the legal values for the
  767        * object reference.
  768        *
  769        * @exception IllegalArgumentException if <code>elementName</code>
  770        * is <code>null</code>, or is not a legal element name for this format.
  771        * @exception IllegalArgumentException if
  772        * <code>enumeratedValues</code> is <code>null</code>.
  773        * @exception IllegalArgumentException if
  774        * <code>enumeratedValues</code> does not contain at least one
  775        * entry.
  776        * @exception IllegalArgumentException if
  777        * <code>enumeratedValues</code> contains an element that is not
  778        * an instance of the class type denoted by <code>classType</code>
  779        * or is <code>null</code>.
  780        */
  781       protected <T> void addObjectValue(String elementName,
  782                                         Class<T> classType,
  783                                         boolean required,
  784                                         T defaultValue,
  785                                         List<? extends T> enumeratedValues)
  786       {
  787           Element element = getElement(elementName);
  788           if (enumeratedValues == null) {
  789               throw new IllegalArgumentException("enumeratedValues == null!");
  790           }
  791           if (enumeratedValues.size() == 0) {
  792               throw new IllegalArgumentException("enumeratedValues is empty!");
  793           }
  794           Iterator iter = enumeratedValues.iterator();
  795           while (iter.hasNext()) {
  796               Object o = iter.next();
  797               if (o == null) {
  798                   throw new IllegalArgumentException("enumeratedValues contains a null!");
  799               }
  800               if (!classType.isInstance(o)) {
  801                   throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!");
  802               }
  803           }
  804   
  805           ObjectValue obj = new ObjectValue();
  806           obj.valueType = VALUE_ENUMERATION;
  807           obj.classType = classType;
  808           obj.defaultValue = defaultValue;
  809           obj.enumeratedValues = enumeratedValues;
  810   
  811           element.objectValue = obj;
  812       }
  813   
  814       /**
  815        * Allows an <code>Object</code> reference of a given class type
  816        * to be stored in nodes implementing the named element.  The
  817        * value of the <code>Object</code> must be within the range given
  818        * by <code>minValue</code> and <code>maxValue</code>.
  819        * Furthermore, the class type must implement the
  820        * <code>Comparable</code> interface.
  821        *
  822        * <p> If an <code>Object</code> reference was previously allowed,
  823        * the previous settings are overwritten.
  824        *
  825        * @param elementName the name of the element.
  826        * @param classType a <code>Class</code> variable indicating the
  827        * legal class type for the object value.
  828        * @param defaultValue the default value for the
  829        * @param minValue the smallest (inclusive or exclusive depending
  830        * on the value of <code>minInclusive</code>) legal value for the
  831        * object value, as a <code>String</code>.
  832        * @param maxValue the largest (inclusive or exclusive depending
  833        * on the value of <code>minInclusive</code>) legal value for the
  834        * object value, as a <code>String</code>.
  835        * @param minInclusive <code>true</code> if <code>minValue</code>
  836        * is inclusive.
  837        * @param maxInclusive <code>true</code> if <code>maxValue</code>
  838        * is inclusive.
  839        *
  840        * @exception IllegalArgumentException if <code>elementName</code>
  841        * is <code>null</code>, or is not a legal element name for this
  842        * format.
  843        */
  844       protected <T extends Object & Comparable<? super T>> void
  845           addObjectValue(String elementName,
  846                          Class<T> classType,
  847                          T defaultValue,
  848                          Comparable<? super T> minValue,
  849                          Comparable<? super T> maxValue,
  850                          boolean minInclusive,
  851                          boolean maxInclusive)
  852       {
  853           Element element = getElement(elementName);
  854           ObjectValue obj = new ObjectValue();
  855           obj.valueType = VALUE_RANGE;
  856           if (minInclusive) {
  857               obj.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;
  858           }
  859           if (maxInclusive) {
  860               obj.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;
  861           }
  862           obj.classType = classType;
  863           obj.defaultValue = defaultValue;
  864           obj.minValue = minValue;
  865           obj.maxValue = maxValue;
  866   
  867           element.objectValue = obj;
  868       }
  869   
  870       /**
  871        * Allows an <code>Object</code> reference of a given class type
  872        * to be stored in nodes implementing the named element.  The
  873        * value of the <code>Object</code> must an array of objects of
  874        * class type given by <code>classType</code>, with at least
  875        * <code>arrayMinLength</code> and at most
  876        * <code>arrayMaxLength</code> elements.
  877        *
  878        * <p> If an <code>Object</code> reference was previously allowed,
  879        * the previous settings are overwritten.
  880        *
  881        * @param elementName the name of the element.
  882        * @param classType a <code>Class</code> variable indicating the
  883        * legal class type for the object value.
  884        * @param arrayMinLength the smallest legal length for the array.
  885        * @param arrayMaxLength the largest legal length for the array.
  886        *
  887        * @exception IllegalArgumentException if <code>elementName</code> is
  888        * not a legal element name for this format.
  889        */
  890       protected void addObjectValue(String elementName,
  891                                     Class<?> classType,
  892                                     int arrayMinLength,
  893                                     int arrayMaxLength) {
  894           Element element = getElement(elementName);
  895           ObjectValue obj = new ObjectValue();
  896           obj.valueType = VALUE_LIST;
  897           obj.classType = classType;
  898           obj.arrayMinLength = arrayMinLength;
  899           obj.arrayMaxLength = arrayMaxLength;
  900   
  901           element.objectValue = obj;
  902       }
  903   
  904       /**
  905        * Disallows an <code>Object</code> reference from being stored in
  906        * nodes implementing the named element.
  907        *
  908        * @param elementName the name of the element.
  909        *
  910        * @exception IllegalArgumentException if <code>elementName</code> is
  911        * not a legal element name for this format.
  912        */
  913       protected void removeObjectValue(String elementName) {
  914           Element element = getElement(elementName);
  915           element.objectValue = null;
  916       }
  917   
  918       // Utility method
  919   
  920       // Methods from IIOMetadataFormat
  921   
  922       // Root
  923   
  924       public String getRootName() {
  925           return rootName;
  926       }
  927   
  928       // Multiplicity
  929   
  930       public abstract boolean canNodeAppear(String elementName,
  931                                             ImageTypeSpecifier imageType);
  932   
  933       public int getElementMinChildren(String elementName) {
  934           Element element = getElement(elementName);
  935           if (element.childPolicy != CHILD_POLICY_REPEAT) {
  936               throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!");
  937           }
  938           return element.minChildren;
  939       }
  940   
  941       public int getElementMaxChildren(String elementName) {
  942           Element element = getElement(elementName);
  943           if (element.childPolicy != CHILD_POLICY_REPEAT) {
  944               throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!");
  945           }
  946           return element.maxChildren;
  947       }
  948   
  949       private String getResource(String key, Locale locale) {
  950           if (locale == null) {
  951               locale = Locale.getDefault();
  952           }
  953   
  954           /**
  955            * If an applet supplies an implementation of IIOMetadataFormat and
  956            * resource bundles, then the resource bundle will need to be
  957            * accessed via the applet class loader. So first try the context
  958            * class loader to locate the resource bundle.
  959            * If that throws MissingResourceException, then try the
  960            * system class loader.
  961            */
  962           ClassLoader loader = (ClassLoader)
  963               java.security.AccessController.doPrivileged(
  964                   new java.security.PrivilegedAction() {
  965                      public Object run() {
  966                          return Thread.currentThread().getContextClassLoader();
  967                      }
  968               });
  969   
  970           ResourceBundle bundle = null;
  971           try {
  972               bundle = ResourceBundle.getBundle(resourceBaseName,
  973                                                 locale, loader);
  974           } catch (MissingResourceException mre) {
  975               try {
  976                   bundle = ResourceBundle.getBundle(resourceBaseName, locale);
  977               } catch (MissingResourceException mre1) {
  978                   return null;
  979               }
  980           }
  981   
  982           try {
  983               return bundle.getString(key);
  984           } catch (MissingResourceException e) {
  985               return null;
  986           }
  987       }
  988   
  989       /**
  990        * Returns a <code>String</code> containing a description of the
  991        * named element, or <code>null</code>.  The desciption will be
  992        * localized for the supplied <code>Locale</code> if possible.
  993        *
  994        * <p> The default implementation will first locate a
  995        * <code>ResourceBundle</code> using the current resource base
  996        * name set by <code>setResourceBaseName</code> and the supplied
  997        * <code>Locale</code>, using the fallback mechanism described in
  998        * the comments for <code>ResourceBundle.getBundle</code>.  If a
  999        * <code>ResourceBundle</code> is found, the element name will be
 1000        * used as a key to its <code>getString</code> method, and the
 1001        * result returned.  If no <code>ResourceBundle</code> is found,
 1002        * or no such key is present, <code>null</code> will be returned.
 1003        *
 1004        * <p> If <code>locale</code> is <code>null</code>, the current
 1005        * default <code>Locale</code> returned by <code>Locale.getLocale</code>
 1006        * will be used.
 1007        *
 1008        * @param elementName the name of the element.
 1009        * @param locale the <code>Locale</code> for which localization
 1010        * will be attempted.
 1011        *
 1012        * @return the element description.
 1013        *
 1014        * @exception IllegalArgumentException if <code>elementName</code>
 1015        * is <code>null</code>, or is not a legal element name for this format.
 1016        *
 1017        * @see #setResourceBaseName
 1018        */
 1019       public String getElementDescription(String elementName,
 1020                                           Locale locale) {
 1021           Element element = getElement(elementName);
 1022           return getResource(elementName, locale);
 1023       }
 1024   
 1025       // Children
 1026   
 1027       public int getChildPolicy(String elementName) {
 1028           Element element = getElement(elementName);
 1029           return element.childPolicy;
 1030       }
 1031   
 1032       public String[] getChildNames(String elementName) {
 1033           Element element = getElement(elementName);
 1034           if (element.childPolicy == CHILD_POLICY_EMPTY) {
 1035               return null;
 1036           }
 1037           return (String[])element.childList.toArray(new String[0]);
 1038       }
 1039   
 1040       // Attributes
 1041   
 1042       public String[] getAttributeNames(String elementName) {
 1043           Element element = getElement(elementName);
 1044           List names = element.attrList;
 1045   
 1046           String[] result = new String[names.size()];
 1047           return (String[])names.toArray(result);
 1048       }
 1049   
 1050       public int getAttributeValueType(String elementName, String attrName) {
 1051           Attribute attr = getAttribute(elementName, attrName);
 1052           return attr.valueType;
 1053       }
 1054   
 1055       public int getAttributeDataType(String elementName, String attrName) {
 1056           Attribute attr = getAttribute(elementName, attrName);
 1057           return attr.dataType;
 1058       }
 1059   
 1060       public boolean isAttributeRequired(String elementName, String attrName) {
 1061           Attribute attr = getAttribute(elementName, attrName);
 1062           return attr.required;
 1063       }
 1064   
 1065       public String getAttributeDefaultValue(String elementName,
 1066                                              String attrName) {
 1067           Attribute attr = getAttribute(elementName, attrName);
 1068           return attr.defaultValue;
 1069       }
 1070   
 1071       public String[] getAttributeEnumerations(String elementName,
 1072                                                String attrName) {
 1073           Attribute attr = getAttribute(elementName, attrName);
 1074           if (attr.valueType != VALUE_ENUMERATION) {
 1075               throw new IllegalArgumentException
 1076                   ("Attribute not an enumeration!");
 1077           }
 1078   
 1079           List values = attr.enumeratedValues;
 1080           Iterator iter = values.iterator();
 1081           String[] result = new String[values.size()];
 1082           return (String[])values.toArray(result);
 1083       }
 1084   
 1085       public String getAttributeMinValue(String elementName, String attrName) {
 1086           Attribute attr = getAttribute(elementName, attrName);
 1087           if (attr.valueType != VALUE_RANGE &&
 1088               attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
 1089               attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
 1090               attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {
 1091               throw new IllegalArgumentException("Attribute not a range!");
 1092           }
 1093   
 1094           return attr.minValue;
 1095       }
 1096   
 1097       public String getAttributeMaxValue(String elementName, String attrName) {
 1098           Attribute attr = getAttribute(elementName, attrName);
 1099           if (attr.valueType != VALUE_RANGE &&
 1100               attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
 1101               attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
 1102               attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {
 1103               throw new IllegalArgumentException("Attribute not a range!");
 1104           }
 1105   
 1106           return attr.maxValue;
 1107       }
 1108   
 1109       public int getAttributeListMinLength(String elementName, String attrName) {
 1110           Attribute attr = getAttribute(elementName, attrName);
 1111           if (attr.valueType != VALUE_LIST) {
 1112               throw new IllegalArgumentException("Attribute not a list!");
 1113           }
 1114   
 1115           return attr.listMinLength;
 1116       }
 1117   
 1118       public int getAttributeListMaxLength(String elementName, String attrName) {
 1119           Attribute attr = getAttribute(elementName, attrName);
 1120           if (attr.valueType != VALUE_LIST) {
 1121               throw new IllegalArgumentException("Attribute not a list!");
 1122           }
 1123   
 1124           return attr.listMaxLength;
 1125       }
 1126   
 1127       /**
 1128        * Returns a <code>String</code> containing a description of the
 1129        * named attribute, or <code>null</code>.  The desciption will be
 1130        * localized for the supplied <code>Locale</code> if possible.
 1131        *
 1132        * <p> The default implementation will first locate a
 1133        * <code>ResourceBundle</code> using the current resource base
 1134        * name set by <code>setResourceBaseName</code> and the supplied
 1135        * <code>Locale</code>, using the fallback mechanism described in
 1136        * the comments for <code>ResourceBundle.getBundle</code>.  If a
 1137        * <code>ResourceBundle</code> is found, the element name followed
 1138        * by a "/" character followed by the attribute name
 1139        * (<code>elementName + "/" + attrName</code>) will be used as a
 1140        * key to its <code>getString</code> method, and the result
 1141        * returned.  If no <code>ResourceBundle</code> is found, or no
 1142        * such key is present, <code>null</code> will be returned.
 1143        *
 1144        * <p> If <code>locale</code> is <code>null</code>, the current
 1145        * default <code>Locale</code> returned by <code>Locale.getLocale</code>
 1146        * will be used.
 1147        *
 1148        * @param elementName the name of the element.
 1149        * @param attrName the name of the attribute.
 1150        * @param locale the <code>Locale</code> for which localization
 1151        * will be attempted, or <code>null</code>.
 1152        *
 1153        * @return the attribute description.
 1154        *
 1155        * @exception IllegalArgumentException if <code>elementName</code>
 1156        * is <code>null</code>, or is not a legal element name for this format.
 1157        * @exception IllegalArgumentException if <code>attrName</code> is
 1158        * <code>null</code> or is not a legal attribute name for this
 1159        * element.
 1160        *
 1161        * @see #setResourceBaseName
 1162        */
 1163       public String getAttributeDescription(String elementName,
 1164                                             String attrName,
 1165                                             Locale locale) {
 1166           Element element = getElement(elementName);
 1167           if (attrName == null) {
 1168               throw new IllegalArgumentException("attrName == null!");
 1169           }
 1170           Attribute attr = (Attribute)element.attrMap.get(attrName);
 1171           if (attr == null) {
 1172               throw new IllegalArgumentException("No such attribute!");
 1173           }
 1174   
 1175           String key = elementName + "/" + attrName;
 1176           return getResource(key, locale);
 1177       }
 1178   
 1179       private ObjectValue getObjectValue(String elementName) {
 1180           Element element = getElement(elementName);
 1181           ObjectValue objv = (ObjectValue)element.objectValue;
 1182           if (objv == null) {
 1183               throw new IllegalArgumentException("No object within element " +
 1184                                                  elementName + "!");
 1185           }
 1186           return objv;
 1187       }
 1188   
 1189       public int getObjectValueType(String elementName) {
 1190           Element element = getElement(elementName);
 1191           ObjectValue objv = (ObjectValue)element.objectValue;
 1192           if (objv == null) {
 1193               return VALUE_NONE;
 1194           }
 1195           return objv.valueType;
 1196       }
 1197   
 1198       public Class<?> getObjectClass(String elementName) {
 1199           ObjectValue objv = getObjectValue(elementName);
 1200           return objv.classType;
 1201       }
 1202   
 1203       public Object getObjectDefaultValue(String elementName) {
 1204           ObjectValue objv = getObjectValue(elementName);
 1205           return objv.defaultValue;
 1206       }
 1207   
 1208       public Object[] getObjectEnumerations(String elementName) {
 1209           ObjectValue objv = getObjectValue(elementName);
 1210           if (objv.valueType != VALUE_ENUMERATION) {
 1211               throw new IllegalArgumentException("Not an enumeration!");
 1212           }
 1213           List vlist = objv.enumeratedValues;
 1214           Object[] values = new Object[vlist.size()];
 1215           return vlist.toArray(values);
 1216       }
 1217   
 1218       public Comparable<?> getObjectMinValue(String elementName) {
 1219           ObjectValue objv = getObjectValue(elementName);
 1220           if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
 1221               throw new IllegalArgumentException("Not a range!");
 1222           }
 1223           return objv.minValue;
 1224       }
 1225   
 1226       public Comparable<?> getObjectMaxValue(String elementName) {
 1227           ObjectValue objv = getObjectValue(elementName);
 1228           if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
 1229               throw new IllegalArgumentException("Not a range!");
 1230           }
 1231           return objv.maxValue;
 1232       }
 1233   
 1234       public int getObjectArrayMinLength(String elementName) {
 1235           ObjectValue objv = getObjectValue(elementName);
 1236           if (objv.valueType != VALUE_LIST) {
 1237               throw new IllegalArgumentException("Not a list!");
 1238           }
 1239           return objv.arrayMinLength;
 1240       }
 1241   
 1242       public int getObjectArrayMaxLength(String elementName) {
 1243           ObjectValue objv = getObjectValue(elementName);
 1244           if (objv.valueType != VALUE_LIST) {
 1245               throw new IllegalArgumentException("Not a list!");
 1246           }
 1247           return objv.arrayMaxLength;
 1248       }
 1249   
 1250       // Standard format descriptor
 1251   
 1252       private synchronized static void createStandardFormat() {
 1253           if (standardFormat == null) {
 1254               standardFormat = new StandardMetadataFormat();
 1255           }
 1256       }
 1257   
 1258       /**
 1259        * Returns an <code>IIOMetadataFormat</code> object describing the
 1260        * standard, plug-in neutral <code>javax.imageio_1.0</code>
 1261        * metadata document format described in the comment of the
 1262        * <code>javax.imageio.metadata</code> package.
 1263        *
 1264        * @return a predefined <code>IIOMetadataFormat</code> instance.
 1265        */
 1266       public static IIOMetadataFormat getStandardFormatInstance() {
 1267           createStandardFormat();
 1268           return standardFormat;
 1269       }
 1270   }

Save This Page
Home » openjdk-7 » javax » imageio » metadata » [javadoc | source]