src/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java

Print this page
rev 9293 : 8034998: Fix raw and unchecked lint warnings in javax.imageio
Reviewed-by:


  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


 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      *


 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>.


 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 


 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      *


 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      * @param <T> the type of the object.
 733      *
 734      * @exception IllegalArgumentException if <code>elementName</code>
 735      * is <code>null</code>, or is not a legal element name for this format.
 736      */
 737     protected <T> void addObjectValue(String elementName,
 738                                       Class<T> classType,
 739                                       boolean required,
 740                                       T defaultValue)
 741     {
 742         Element element = getElement(elementName);
 743         ObjectValue obj = new ObjectValue();
 744         obj.valueType = VALUE_ARBITRARY;
 745         obj.classType = classType;
 746         obj.defaultValue = defaultValue;
 747 
 748         element.objectValue = obj;
 749     }
 750 
 751     /**
 752      * Allows an <code>Object</code> reference of a given class type
 753      * to be stored in nodes implementing the named element.  The
 754      * value of the <code>Object</code> must be one of the values
 755      * given by <code>enumeratedValues</code>.
 756      *
 757      * <p> If an <code>Object</code> reference was previously allowed,
 758      * the previous settings are overwritten.
 759      *
 760      * @param elementName the name of the element.
 761      * @param classType a <code>Class</code> variable indicating the
 762      * legal class type for the object value.
 763      * @param required <code>true</code> if an object value must be present.


 776      * <code>enumeratedValues</code> does not contain at least one
 777      * entry.
 778      * @exception IllegalArgumentException if
 779      * <code>enumeratedValues</code> contains an element that is not
 780      * an instance of the class type denoted by <code>classType</code>
 781      * or is <code>null</code>.
 782      */
 783     protected <T> void addObjectValue(String elementName,
 784                                       Class<T> classType,
 785                                       boolean required,
 786                                       T defaultValue,
 787                                       List<? extends T> enumeratedValues)
 788     {
 789         Element element = getElement(elementName);
 790         if (enumeratedValues == null) {
 791             throw new IllegalArgumentException("enumeratedValues == null!");
 792         }
 793         if (enumeratedValues.size() == 0) {
 794             throw new IllegalArgumentException("enumeratedValues is empty!");
 795         }
 796         Iterator iter = enumeratedValues.iterator();
 797         while (iter.hasNext()) {
 798             Object o = iter.next();
 799             if (o == null) {
 800                 throw new IllegalArgumentException("enumeratedValues contains a null!");
 801             }
 802             if (!classType.isInstance(o)) {
 803                 throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!");
 804             }
 805         }
 806 
 807         ObjectValue obj = new ObjectValue();
 808         obj.valueType = VALUE_ENUMERATION;
 809         obj.classType = classType;
 810         obj.defaultValue = defaultValue;
 811         obj.enumeratedValues = enumeratedValues;
 812 
 813         element.objectValue = obj;
 814     }
 815 
 816     /**
 817      * Allows an <code>Object</code> reference of a given class type
 818      * to be stored in nodes implementing the named element.  The
 819      * value of the <code>Object</code> must be within the range given
 820      * by <code>minValue</code> and <code>maxValue</code>.
 821      * Furthermore, the class type must implement the
 822      * <code>Comparable</code> interface.
 823      *
 824      * <p> If an <code>Object</code> reference was previously allowed,
 825      * the previous settings are overwritten.
 826      *
 827      * @param elementName the name of the element.


 837      * @param minInclusive <code>true</code> if <code>minValue</code>
 838      * is inclusive.
 839      * @param maxInclusive <code>true</code> if <code>maxValue</code>
 840      * is inclusive.
 841      * @param <T> the type of the object.
 842      *
 843      * @exception IllegalArgumentException if <code>elementName</code>
 844      * is <code>null</code>, or is not a legal element name for this
 845      * format.
 846      */
 847     protected <T extends Object & Comparable<? super T>> void
 848         addObjectValue(String elementName,
 849                        Class<T> classType,
 850                        T defaultValue,
 851                        Comparable<? super T> minValue,
 852                        Comparable<? super T> maxValue,
 853                        boolean minInclusive,
 854                        boolean maxInclusive)
 855     {
 856         Element element = getElement(elementName);
 857         ObjectValue obj = new ObjectValue();
 858         obj.valueType = VALUE_RANGE;
 859         if (minInclusive) {
 860             obj.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;
 861         }
 862         if (maxInclusive) {
 863             obj.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;
 864         }
 865         obj.classType = classType;
 866         obj.defaultValue = defaultValue;
 867         obj.minValue = minValue;
 868         obj.maxValue = maxValue;
 869 
 870         element.objectValue = obj;
 871     }
 872 
 873     /**
 874      * Allows an <code>Object</code> reference of a given class type
 875      * to be stored in nodes implementing the named element.  The
 876      * value of the <code>Object</code> must an array of objects of
 877      * class type given by <code>classType</code>, with at least
 878      * <code>arrayMinLength</code> and at most
 879      * <code>arrayMaxLength</code> elements.
 880      *
 881      * <p> If an <code>Object</code> reference was previously allowed,
 882      * the previous settings are overwritten.
 883      *
 884      * @param elementName the name of the element.
 885      * @param classType a <code>Class</code> variable indicating the
 886      * legal class type for the object value.
 887      * @param arrayMinLength the smallest legal length for the array.
 888      * @param arrayMaxLength the largest legal length for the array.
 889      *
 890      * @exception IllegalArgumentException if <code>elementName</code> is
 891      * not a legal element name for this format.
 892      */
 893     protected void addObjectValue(String elementName,
 894                                   Class<?> classType,
 895                                   int arrayMinLength,
 896                                   int arrayMaxLength) {
 897         Element element = getElement(elementName);
 898         ObjectValue obj = new ObjectValue();
 899         obj.valueType = VALUE_LIST;
 900         obj.classType = classType;
 901         obj.arrayMinLength = arrayMinLength;
 902         obj.arrayMaxLength = arrayMaxLength;
 903 
 904         element.objectValue = obj;
 905     }
 906 
 907     /**
 908      * Disallows an <code>Object</code> reference from being stored in
 909      * nodes implementing the named element.
 910      *
 911      * @param elementName the name of the element.
 912      *
 913      * @exception IllegalArgumentException if <code>elementName</code> is
 914      * not a legal element name for this format.
 915      */
 916     protected void removeObjectValue(String elementName) {
 917         Element element = getElement(elementName);
 918         element.objectValue = null;


 945         Element element = getElement(elementName);
 946         if (element.childPolicy != CHILD_POLICY_REPEAT) {
 947             throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!");
 948         }
 949         return element.maxChildren;
 950     }
 951 
 952     private String getResource(String key, Locale locale) {
 953         if (locale == null) {
 954             locale = Locale.getDefault();
 955         }
 956 
 957         /**
 958          * If an applet supplies an implementation of IIOMetadataFormat and
 959          * resource bundles, then the resource bundle will need to be
 960          * accessed via the applet class loader. So first try the context
 961          * class loader to locate the resource bundle.
 962          * If that throws MissingResourceException, then try the
 963          * system class loader.
 964          */
 965         ClassLoader loader = (ClassLoader)
 966             java.security.AccessController.doPrivileged(
 967                 new java.security.PrivilegedAction() {
 968                    public Object run() {
 969                        return Thread.currentThread().getContextClassLoader();
 970                    }
 971             });
 972 
 973         ResourceBundle bundle = null;
 974         try {
 975             bundle = ResourceBundle.getBundle(resourceBaseName,
 976                                               locale, loader);
 977         } catch (MissingResourceException mre) {
 978             try {
 979                 bundle = ResourceBundle.getBundle(resourceBaseName, locale);
 980             } catch (MissingResourceException mre1) {
 981                 return null;
 982             }
 983         }
 984 
 985         try {
 986             return bundle.getString(key);
 987         } catch (MissingResourceException e) {
 988             return null;


1020      * @see #setResourceBaseName
1021      */
1022     public String getElementDescription(String elementName,
1023                                         Locale locale) {
1024         Element element = getElement(elementName);
1025         return getResource(elementName, locale);
1026     }
1027 
1028     // Children
1029 
1030     public int getChildPolicy(String elementName) {
1031         Element element = getElement(elementName);
1032         return element.childPolicy;
1033     }
1034 
1035     public String[] getChildNames(String elementName) {
1036         Element element = getElement(elementName);
1037         if (element.childPolicy == CHILD_POLICY_EMPTY) {
1038             return null;
1039         }
1040         return (String[])element.childList.toArray(new String[0]);
1041     }
1042 
1043     // Attributes
1044 
1045     public String[] getAttributeNames(String elementName) {
1046         Element element = getElement(elementName);
1047         List names = element.attrList;
1048 
1049         String[] result = new String[names.size()];
1050         return (String[])names.toArray(result);
1051     }
1052 
1053     public int getAttributeValueType(String elementName, String attrName) {
1054         Attribute attr = getAttribute(elementName, attrName);
1055         return attr.valueType;
1056     }
1057 
1058     public int getAttributeDataType(String elementName, String attrName) {
1059         Attribute attr = getAttribute(elementName, attrName);
1060         return attr.dataType;
1061     }
1062 
1063     public boolean isAttributeRequired(String elementName, String attrName) {
1064         Attribute attr = getAttribute(elementName, attrName);
1065         return attr.required;
1066     }
1067 
1068     public String getAttributeDefaultValue(String elementName,
1069                                            String attrName) {
1070         Attribute attr = getAttribute(elementName, attrName);
1071         return attr.defaultValue;
1072     }
1073 
1074     public String[] getAttributeEnumerations(String elementName,
1075                                              String attrName) {
1076         Attribute attr = getAttribute(elementName, attrName);
1077         if (attr.valueType != VALUE_ENUMERATION) {
1078             throw new IllegalArgumentException
1079                 ("Attribute not an enumeration!");
1080         }
1081 
1082         List values = attr.enumeratedValues;
1083         Iterator iter = values.iterator();
1084         String[] result = new String[values.size()];
1085         return (String[])values.toArray(result);
1086     }
1087 
1088     public String getAttributeMinValue(String elementName, String attrName) {
1089         Attribute attr = getAttribute(elementName, attrName);
1090         if (attr.valueType != VALUE_RANGE &&
1091             attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
1092             attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
1093             attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {
1094             throw new IllegalArgumentException("Attribute not a range!");
1095         }
1096 
1097         return attr.minValue;
1098     }
1099 
1100     public String getAttributeMaxValue(String elementName, String attrName) {
1101         Attribute attr = getAttribute(elementName, attrName);
1102         if (attr.valueType != VALUE_RANGE &&
1103             attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
1104             attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
1105             attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {


1153      * @param locale the <code>Locale</code> for which localization
1154      * will be attempted, or <code>null</code>.
1155      *
1156      * @return the attribute description.
1157      *
1158      * @exception IllegalArgumentException if <code>elementName</code>
1159      * is <code>null</code>, or is not a legal element name for this format.
1160      * @exception IllegalArgumentException if <code>attrName</code> is
1161      * <code>null</code> or is not a legal attribute name for this
1162      * element.
1163      *
1164      * @see #setResourceBaseName
1165      */
1166     public String getAttributeDescription(String elementName,
1167                                           String attrName,
1168                                           Locale locale) {
1169         Element element = getElement(elementName);
1170         if (attrName == null) {
1171             throw new IllegalArgumentException("attrName == null!");
1172         }
1173         Attribute attr = (Attribute)element.attrMap.get(attrName);
1174         if (attr == null) {
1175             throw new IllegalArgumentException("No such attribute!");
1176         }
1177 
1178         String key = elementName + "/" + attrName;
1179         return getResource(key, locale);
1180     }
1181 
1182     private ObjectValue getObjectValue(String elementName) {
1183         Element element = getElement(elementName);
1184         ObjectValue objv = element.objectValue;
1185         if (objv == null) {
1186             throw new IllegalArgumentException("No object within element " +
1187                                                elementName + "!");
1188         }
1189         return objv;
1190     }
1191 
1192     public int getObjectValueType(String elementName) {
1193         Element element = getElement(elementName);
1194         ObjectValue objv = element.objectValue;
1195         if (objv == null) {
1196             return VALUE_NONE;
1197         }
1198         return objv.valueType;
1199     }
1200 
1201     public Class<?> getObjectClass(String elementName) {
1202         ObjectValue objv = getObjectValue(elementName);
1203         return objv.classType;
1204     }
1205 
1206     public Object getObjectDefaultValue(String elementName) {
1207         ObjectValue objv = getObjectValue(elementName);
1208         return objv.defaultValue;
1209     }
1210 
1211     public Object[] getObjectEnumerations(String elementName) {
1212         ObjectValue objv = getObjectValue(elementName);
1213         if (objv.valueType != VALUE_ENUMERATION) {
1214             throw new IllegalArgumentException("Not an enumeration!");
1215         }
1216         List vlist = objv.enumeratedValues;
1217         Object[] values = new Object[vlist.size()];
1218         return vlist.toArray(values);
1219     }
1220 
1221     public Comparable<?> getObjectMinValue(String elementName) {
1222         ObjectValue objv = getObjectValue(elementName);
1223         if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
1224             throw new IllegalArgumentException("Not a range!");
1225         }
1226         return objv.minValue;
1227     }
1228 
1229     public Comparable<?> getObjectMaxValue(String elementName) {
1230         ObjectValue objv = getObjectValue(elementName);
1231         if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
1232             throw new IllegalArgumentException("Not a range!");
1233         }
1234         return objv.maxValue;
1235     }
1236 
1237     public int getObjectArrayMinLength(String elementName) {
1238         ObjectValue objv = getObjectValue(elementName);
1239         if (objv.valueType != VALUE_LIST) {
1240             throw new IllegalArgumentException("Not a list!");
1241         }
1242         return objv.arrayMinLength;
1243     }
1244 
1245     public int getObjectArrayMaxLength(String elementName) {
1246         ObjectValue objv = getObjectValue(elementName);
1247         if (objv.valueType != VALUE_LIST) {
1248             throw new IllegalArgumentException("Not a list!");
1249         }
1250         return objv.arrayMaxLength;
1251     }
1252 
1253     // Standard format descriptor
1254 
1255     private synchronized static void createStandardFormat() {
1256         if (standardFormat == null) {
1257             standardFormat = new StandardMetadataFormat();
1258         }
1259     }
1260 
1261     /**
1262      * Returns an <code>IIOMetadataFormat</code> object describing the
1263      * standard, plug-in neutral <code>javax.imageio_1.0</code>
1264      * metadata document format described in the comment of the
1265      * <code>javax.imageio.metadata</code> package.
1266      *


  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<String, Element> 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<String> childList = new ArrayList<>();
 104 
 105         // Parent names (Strings)
 106         List<String> parentList = new ArrayList<>();
 107 
 108         // List of attribute names in the order they were added
 109         List<String> attrList = new ArrayList<>();
 110         // Attr name (String) -> Attribute
 111         Map<String, Attribute> 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<String> enumeratedValues;
 126 
 127         // range
 128         String minValue;
 129         String maxValue;
 130 
 131         // list
 132         int listMinLength;
 133         int listMaxLength;
 134     }
 135 
 136     class ObjectValue<T> {
 137         int valueType = VALUE_NONE;
 138         // ? extends T So that ObjectValue<Object> can take Class<?>
 139         Class<? extends T> classType = null;
 140         T defaultValue = null;
 141 
 142         // Meaningful only if valueType == VALUE_ENUMERATION
 143         List<? extends T> enumeratedValues = null;
 144 
 145         // Meaningful only if valueType == VALUE_RANGE
 146         Comparable<? super T> minValue = null;
 147         Comparable<? super T> maxValue = null;
 148 
 149         // Meaningful only if valueType == VALUE_LIST
 150         int arrayMinLength = 0;
 151         int arrayMaxLength = 0;
 152     }
 153 
 154     /**
 155      * Constructs a blank <code>IIOMetadataFormatImpl</code> instance,
 156      * with a given root element name and child policy (other than
 157      * <code>CHILD_POLICY_REPEAT</code>).  Additional elements, and
 158      * their attributes and <code>Object</code> reference information
 159      * may be added using the various <code>add</code> methods.
 160      *
 161      * @param rootName the name of the root element.
 162      * @param childPolicy one of the <code>CHILD_POLICY_*</code> constants,
 163      * other than <code>CHILD_POLICY_REPEAT</code>.
 164      *
 165      * @exception IllegalArgumentException if <code>rootName</code> is
 166      * <code>null</code>.
 167      * @exception IllegalArgumentException if <code>childPolicy</code> is


 256      *
 257      * @return a <code>String</code> containing the base name.
 258      *
 259      * @see #setResourceBaseName
 260      */
 261     protected String getResourceBaseName() {
 262         return resourceBaseName;
 263     }
 264 
 265     /**
 266      * Utility method for locating an element.
 267      *
 268      * @param mustAppear if <code>true</code>, throw an
 269      * <code>IllegalArgumentException</code> if no such node exists;
 270      * if <code>false</code>, just return null.
 271      */
 272     private Element getElement(String elementName, boolean mustAppear) {
 273         if (mustAppear && (elementName == null)) {
 274             throw new IllegalArgumentException("element name is null!");
 275         }
 276         Element element = elementMap.get(elementName);
 277         if (mustAppear && (element == null)) {
 278             throw new IllegalArgumentException("No such element: " +
 279                                                elementName);
 280         }
 281         return element;
 282     }
 283 
 284     private Element getElement(String elementName) {
 285         return getElement(elementName, true);
 286     }
 287 
 288     // Utility method for locating an attribute
 289     private Attribute getAttribute(String elementName, String attrName) {
 290         Element element = getElement(elementName);
 291         Attribute attr = element.attrMap.get(attrName);
 292         if (attr == null) {
 293             throw new IllegalArgumentException("No such attribute \"" +
 294                                                attrName + "\"!");
 295         }
 296         return attr;
 297     }
 298 
 299     // Setup
 300 
 301     /**
 302      * Adds a new element type to this metadata document format with a
 303      * child policy other than <code>CHILD_POLICY_REPEAT</code>.
 304      *
 305      * @param elementName the name of the new element.
 306      * @param parentName the name of the element that will be the
 307      * parent of the new element.
 308      * @param childPolicy one of the <code>CHILD_POLICY_*</code>
 309      * constants, other than <code>CHILD_POLICY_REPEAT</code>,
 310      * indicating the child policy of the new element.
 311      *


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


 498      */
 499     protected void addAttribute(String elementName,
 500                                 String attrName,
 501                                 int dataType,
 502                                 boolean required,
 503                                 String defaultValue,
 504                                 List<String> enumeratedValues) {
 505         Element element = getElement(elementName);
 506         if (attrName == null) {
 507             throw new IllegalArgumentException("attrName == null!");
 508         }
 509         if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
 510             throw new IllegalArgumentException("Invalid value for dataType!");
 511         }
 512         if (enumeratedValues == null) {
 513             throw new IllegalArgumentException("enumeratedValues == null!");
 514         }
 515         if (enumeratedValues.size() == 0) {
 516             throw new IllegalArgumentException("enumeratedValues is empty!");
 517         }
 518         Iterator<String> iter = enumeratedValues.iterator();
 519         while (iter.hasNext()) {
 520             Object o = iter.next();
 521             if (o == null) {
 522                 throw new IllegalArgumentException
 523                     ("enumeratedValues contains a null!");
 524             }
 525             if (!(o instanceof String)) {
 526                 throw new IllegalArgumentException
 527                     ("enumeratedValues contains a non-String value!");
 528             }
 529         }
 530 
 531         Attribute attr = new Attribute();
 532         attr.attrName = attrName;
 533         attr.valueType = VALUE_ENUMERATION;
 534         attr.dataType = dataType;
 535         attr.required = required;
 536         attr.defaultValue = defaultValue;
 537         attr.enumeratedValues = enumeratedValues;
 538 


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


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


 777      * <code>enumeratedValues</code> does not contain at least one
 778      * entry.
 779      * @exception IllegalArgumentException if
 780      * <code>enumeratedValues</code> contains an element that is not
 781      * an instance of the class type denoted by <code>classType</code>
 782      * or is <code>null</code>.
 783      */
 784     protected <T> void addObjectValue(String elementName,
 785                                       Class<T> classType,
 786                                       boolean required,
 787                                       T defaultValue,
 788                                       List<? extends T> enumeratedValues)
 789     {
 790         Element element = getElement(elementName);
 791         if (enumeratedValues == null) {
 792             throw new IllegalArgumentException("enumeratedValues == null!");
 793         }
 794         if (enumeratedValues.size() == 0) {
 795             throw new IllegalArgumentException("enumeratedValues is empty!");
 796         }
 797         Iterator<? extends T> iter = enumeratedValues.iterator();
 798         while (iter.hasNext()) {
 799             Object o = iter.next();
 800             if (o == null) {
 801                 throw new IllegalArgumentException("enumeratedValues contains a null!");
 802             }
 803             if (!classType.isInstance(o)) {
 804                 throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!");
 805             }
 806         }
 807 
 808         ObjectValue<T> obj = new ObjectValue<>();
 809         obj.valueType = VALUE_ENUMERATION;
 810         obj.classType = classType;
 811         obj.defaultValue = defaultValue;
 812         obj.enumeratedValues = enumeratedValues;
 813 
 814         element.objectValue = obj;
 815     }
 816 
 817     /**
 818      * Allows an <code>Object</code> reference of a given class type
 819      * to be stored in nodes implementing the named element.  The
 820      * value of the <code>Object</code> must be within the range given
 821      * by <code>minValue</code> and <code>maxValue</code>.
 822      * Furthermore, the class type must implement the
 823      * <code>Comparable</code> interface.
 824      *
 825      * <p> If an <code>Object</code> reference was previously allowed,
 826      * the previous settings are overwritten.
 827      *
 828      * @param elementName the name of the element.


 838      * @param minInclusive <code>true</code> if <code>minValue</code>
 839      * is inclusive.
 840      * @param maxInclusive <code>true</code> if <code>maxValue</code>
 841      * is inclusive.
 842      * @param <T> the type of the object.
 843      *
 844      * @exception IllegalArgumentException if <code>elementName</code>
 845      * is <code>null</code>, or is not a legal element name for this
 846      * format.
 847      */
 848     protected <T extends Object & Comparable<? super T>> void
 849         addObjectValue(String elementName,
 850                        Class<T> classType,
 851                        T defaultValue,
 852                        Comparable<? super T> minValue,
 853                        Comparable<? super T> maxValue,
 854                        boolean minInclusive,
 855                        boolean maxInclusive)
 856     {
 857         Element element = getElement(elementName);
 858         ObjectValue<T> obj = new ObjectValue<>();
 859         obj.valueType = VALUE_RANGE;
 860         if (minInclusive) {
 861             obj.valueType |= VALUE_RANGE_MIN_INCLUSIVE_MASK;
 862         }
 863         if (maxInclusive) {
 864             obj.valueType |= VALUE_RANGE_MAX_INCLUSIVE_MASK;
 865         }
 866         obj.classType = classType;
 867         obj.defaultValue = defaultValue;
 868         obj.minValue = minValue;
 869         obj.maxValue = maxValue;
 870 
 871         element.objectValue = obj;
 872     }
 873 
 874     /**
 875      * Allows an <code>Object</code> reference of a given class type
 876      * to be stored in nodes implementing the named element.  The
 877      * value of the <code>Object</code> must an array of objects of
 878      * class type given by <code>classType</code>, with at least
 879      * <code>arrayMinLength</code> and at most
 880      * <code>arrayMaxLength</code> elements.
 881      *
 882      * <p> If an <code>Object</code> reference was previously allowed,
 883      * the previous settings are overwritten.
 884      *
 885      * @param elementName the name of the element.
 886      * @param classType a <code>Class</code> variable indicating the
 887      * legal class type for the object value.
 888      * @param arrayMinLength the smallest legal length for the array.
 889      * @param arrayMaxLength the largest legal length for the array.
 890      *
 891      * @exception IllegalArgumentException if <code>elementName</code> is
 892      * not a legal element name for this format.
 893      */
 894     protected void addObjectValue(String elementName,
 895                                   Class<?> classType,
 896                                   int arrayMinLength,
 897                                   int arrayMaxLength) {
 898         Element element = getElement(elementName);
 899         ObjectValue<Object> obj = new ObjectValue<>();
 900         obj.valueType = VALUE_LIST;
 901         obj.classType = classType;
 902         obj.arrayMinLength = arrayMinLength;
 903         obj.arrayMaxLength = arrayMaxLength;
 904 
 905         element.objectValue = obj;
 906     }
 907 
 908     /**
 909      * Disallows an <code>Object</code> reference from being stored in
 910      * nodes implementing the named element.
 911      *
 912      * @param elementName the name of the element.
 913      *
 914      * @exception IllegalArgumentException if <code>elementName</code> is
 915      * not a legal element name for this format.
 916      */
 917     protected void removeObjectValue(String elementName) {
 918         Element element = getElement(elementName);
 919         element.objectValue = null;


 946         Element element = getElement(elementName);
 947         if (element.childPolicy != CHILD_POLICY_REPEAT) {
 948             throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!");
 949         }
 950         return element.maxChildren;
 951     }
 952 
 953     private String getResource(String key, Locale locale) {
 954         if (locale == null) {
 955             locale = Locale.getDefault();
 956         }
 957 
 958         /**
 959          * If an applet supplies an implementation of IIOMetadataFormat and
 960          * resource bundles, then the resource bundle will need to be
 961          * accessed via the applet class loader. So first try the context
 962          * class loader to locate the resource bundle.
 963          * If that throws MissingResourceException, then try the
 964          * system class loader.
 965          */
 966         ClassLoader loader =
 967             java.security.AccessController.doPrivileged(
 968                 new java.security.PrivilegedAction<ClassLoader>() {
 969                    public ClassLoader run() {
 970                        return Thread.currentThread().getContextClassLoader();
 971                    }
 972             });
 973 
 974         ResourceBundle bundle = null;
 975         try {
 976             bundle = ResourceBundle.getBundle(resourceBaseName,
 977                                               locale, loader);
 978         } catch (MissingResourceException mre) {
 979             try {
 980                 bundle = ResourceBundle.getBundle(resourceBaseName, locale);
 981             } catch (MissingResourceException mre1) {
 982                 return null;
 983             }
 984         }
 985 
 986         try {
 987             return bundle.getString(key);
 988         } catch (MissingResourceException e) {
 989             return null;


1021      * @see #setResourceBaseName
1022      */
1023     public String getElementDescription(String elementName,
1024                                         Locale locale) {
1025         Element element = getElement(elementName);
1026         return getResource(elementName, locale);
1027     }
1028 
1029     // Children
1030 
1031     public int getChildPolicy(String elementName) {
1032         Element element = getElement(elementName);
1033         return element.childPolicy;
1034     }
1035 
1036     public String[] getChildNames(String elementName) {
1037         Element element = getElement(elementName);
1038         if (element.childPolicy == CHILD_POLICY_EMPTY) {
1039             return null;
1040         }
1041         return element.childList.toArray(new String[0]);
1042     }
1043 
1044     // Attributes
1045 
1046     public String[] getAttributeNames(String elementName) {
1047         Element element = getElement(elementName);
1048         List<String> names = element.attrList;
1049 
1050         String[] result = new String[names.size()];
1051         return names.toArray(result);
1052     }
1053 
1054     public int getAttributeValueType(String elementName, String attrName) {
1055         Attribute attr = getAttribute(elementName, attrName);
1056         return attr.valueType;
1057     }
1058 
1059     public int getAttributeDataType(String elementName, String attrName) {
1060         Attribute attr = getAttribute(elementName, attrName);
1061         return attr.dataType;
1062     }
1063 
1064     public boolean isAttributeRequired(String elementName, String attrName) {
1065         Attribute attr = getAttribute(elementName, attrName);
1066         return attr.required;
1067     }
1068 
1069     public String getAttributeDefaultValue(String elementName,
1070                                            String attrName) {
1071         Attribute attr = getAttribute(elementName, attrName);
1072         return attr.defaultValue;
1073     }
1074 
1075     public String[] getAttributeEnumerations(String elementName,
1076                                              String attrName) {
1077         Attribute attr = getAttribute(elementName, attrName);
1078         if (attr.valueType != VALUE_ENUMERATION) {
1079             throw new IllegalArgumentException
1080                 ("Attribute not an enumeration!");
1081         }
1082 
1083         List<String> values = attr.enumeratedValues;

1084         String[] result = new String[values.size()];
1085         return values.toArray(result);
1086     }
1087 
1088     public String getAttributeMinValue(String elementName, String attrName) {
1089         Attribute attr = getAttribute(elementName, attrName);
1090         if (attr.valueType != VALUE_RANGE &&
1091             attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
1092             attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
1093             attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {
1094             throw new IllegalArgumentException("Attribute not a range!");
1095         }
1096 
1097         return attr.minValue;
1098     }
1099 
1100     public String getAttributeMaxValue(String elementName, String attrName) {
1101         Attribute attr = getAttribute(elementName, attrName);
1102         if (attr.valueType != VALUE_RANGE &&
1103             attr.valueType != VALUE_RANGE_MIN_INCLUSIVE &&
1104             attr.valueType != VALUE_RANGE_MAX_INCLUSIVE &&
1105             attr.valueType != VALUE_RANGE_MIN_MAX_INCLUSIVE) {


1153      * @param locale the <code>Locale</code> for which localization
1154      * will be attempted, or <code>null</code>.
1155      *
1156      * @return the attribute description.
1157      *
1158      * @exception IllegalArgumentException if <code>elementName</code>
1159      * is <code>null</code>, or is not a legal element name for this format.
1160      * @exception IllegalArgumentException if <code>attrName</code> is
1161      * <code>null</code> or is not a legal attribute name for this
1162      * element.
1163      *
1164      * @see #setResourceBaseName
1165      */
1166     public String getAttributeDescription(String elementName,
1167                                           String attrName,
1168                                           Locale locale) {
1169         Element element = getElement(elementName);
1170         if (attrName == null) {
1171             throw new IllegalArgumentException("attrName == null!");
1172         }
1173         Attribute attr = element.attrMap.get(attrName);
1174         if (attr == null) {
1175             throw new IllegalArgumentException("No such attribute!");
1176         }
1177 
1178         String key = elementName + "/" + attrName;
1179         return getResource(key, locale);
1180     }
1181 
1182     private ObjectValue<?> getObjectValue(String elementName) {
1183         Element element = getElement(elementName);
1184         ObjectValue<?> objv = element.objectValue;
1185         if (objv == null) {
1186             throw new IllegalArgumentException("No object within element " +
1187                                                elementName + "!");
1188         }
1189         return objv;
1190     }
1191 
1192     public int getObjectValueType(String elementName) {
1193         Element element = getElement(elementName);
1194         ObjectValue<?> objv = element.objectValue;
1195         if (objv == null) {
1196             return VALUE_NONE;
1197         }
1198         return objv.valueType;
1199     }
1200 
1201     public Class<?> getObjectClass(String elementName) {
1202         ObjectValue<?> objv = getObjectValue(elementName);
1203         return objv.classType;
1204     }
1205 
1206     public Object getObjectDefaultValue(String elementName) {
1207         ObjectValue<?> objv = getObjectValue(elementName);
1208         return objv.defaultValue;
1209     }
1210 
1211     public Object[] getObjectEnumerations(String elementName) {
1212         ObjectValue<?> objv = getObjectValue(elementName);
1213         if (objv.valueType != VALUE_ENUMERATION) {
1214             throw new IllegalArgumentException("Not an enumeration!");
1215         }
1216         List<?> vlist = objv.enumeratedValues;
1217         Object[] values = new Object[vlist.size()];
1218         return vlist.toArray(values);
1219     }
1220 
1221     public Comparable<?> getObjectMinValue(String elementName) {
1222         ObjectValue<?> objv = getObjectValue(elementName);
1223         if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
1224             throw new IllegalArgumentException("Not a range!");
1225         }
1226         return objv.minValue;
1227     }
1228 
1229     public Comparable<?> getObjectMaxValue(String elementName) {
1230         ObjectValue<?> objv = getObjectValue(elementName);
1231         if ((objv.valueType & VALUE_RANGE) != VALUE_RANGE) {
1232             throw new IllegalArgumentException("Not a range!");
1233         }
1234         return objv.maxValue;
1235     }
1236 
1237     public int getObjectArrayMinLength(String elementName) {
1238         ObjectValue<?> objv = getObjectValue(elementName);
1239         if (objv.valueType != VALUE_LIST) {
1240             throw new IllegalArgumentException("Not a list!");
1241         }
1242         return objv.arrayMinLength;
1243     }
1244 
1245     public int getObjectArrayMaxLength(String elementName) {
1246         ObjectValue<?> objv = getObjectValue(elementName);
1247         if (objv.valueType != VALUE_LIST) {
1248             throw new IllegalArgumentException("Not a list!");
1249         }
1250         return objv.arrayMaxLength;
1251     }
1252 
1253     // Standard format descriptor
1254 
1255     private synchronized static void createStandardFormat() {
1256         if (standardFormat == null) {
1257             standardFormat = new StandardMetadataFormat();
1258         }
1259     }
1260 
1261     /**
1262      * Returns an <code>IIOMetadataFormat</code> object describing the
1263      * standard, plug-in neutral <code>javax.imageio_1.0</code>
1264      * metadata document format described in the comment of the
1265      * <code>javax.imageio.metadata</code> package.
1266      *