Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java
38918 views
1
/*
2
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* 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> containing 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 added 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
* @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.
764
* @param defaultValue the default value for the
765
* <code>Object</code> reference, or <code>null</code>.
766
* @param enumeratedValues a <code>List</code> of
767
* <code>Object</code>s containing the legal values for the
768
* object reference.
769
* @param <T> the type of the object.
770
*
771
* @exception IllegalArgumentException if <code>elementName</code>
772
* is <code>null</code>, or is not a legal element name for this format.
773
* @exception IllegalArgumentException if
774
* <code>enumeratedValues</code> is <code>null</code>.
775
* @exception IllegalArgumentException if
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.
828
* @param classType a <code>Class</code> variable indicating the
829
* legal class type for the object value.
830
* @param defaultValue the default value for the
831
* @param minValue the smallest (inclusive or exclusive depending
832
* on the value of <code>minInclusive</code>) legal value for the
833
* object value, as a <code>String</code>.
834
* @param maxValue the largest (inclusive or exclusive depending
835
* on the value of <code>minInclusive</code>) legal value for the
836
* object value, as a <code>String</code>.
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;
919
}
920
921
// Utility method
922
923
// Methods from IIOMetadataFormat
924
925
// Root
926
927
public String getRootName() {
928
return rootName;
929
}
930
931
// Multiplicity
932
933
public abstract boolean canNodeAppear(String elementName,
934
ImageTypeSpecifier imageType);
935
936
public int getElementMinChildren(String elementName) {
937
Element element = getElement(elementName);
938
if (element.childPolicy != CHILD_POLICY_REPEAT) {
939
throw new IllegalArgumentException("Child policy not CHILD_POLICY_REPEAT!");
940
}
941
return element.minChildren;
942
}
943
944
public int getElementMaxChildren(String elementName) {
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;
989
}
990
}
991
992
/**
993
* Returns a <code>String</code> containing a description of the
994
* named element, or <code>null</code>. The description will be
995
* localized for the supplied <code>Locale</code> if possible.
996
*
997
* <p> The default implementation will first locate a
998
* <code>ResourceBundle</code> using the current resource base
999
* name set by <code>setResourceBaseName</code> and the supplied
1000
* <code>Locale</code>, using the fallback mechanism described in
1001
* the comments for <code>ResourceBundle.getBundle</code>. If a
1002
* <code>ResourceBundle</code> is found, the element name will be
1003
* used as a key to its <code>getString</code> method, and the
1004
* result returned. If no <code>ResourceBundle</code> is found,
1005
* or no such key is present, <code>null</code> will be returned.
1006
*
1007
* <p> If <code>locale</code> is <code>null</code>, the current
1008
* default <code>Locale</code> returned by <code>Locale.getLocale</code>
1009
* will be used.
1010
*
1011
* @param elementName the name of the element.
1012
* @param locale the <code>Locale</code> for which localization
1013
* will be attempted.
1014
*
1015
* @return the element description.
1016
*
1017
* @exception IllegalArgumentException if <code>elementName</code>
1018
* is <code>null</code>, or is not a legal element name for this format.
1019
*
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) {
1106
throw new IllegalArgumentException("Attribute not a range!");
1107
}
1108
1109
return attr.maxValue;
1110
}
1111
1112
public int getAttributeListMinLength(String elementName, String attrName) {
1113
Attribute attr = getAttribute(elementName, attrName);
1114
if (attr.valueType != VALUE_LIST) {
1115
throw new IllegalArgumentException("Attribute not a list!");
1116
}
1117
1118
return attr.listMinLength;
1119
}
1120
1121
public int getAttributeListMaxLength(String elementName, String attrName) {
1122
Attribute attr = getAttribute(elementName, attrName);
1123
if (attr.valueType != VALUE_LIST) {
1124
throw new IllegalArgumentException("Attribute not a list!");
1125
}
1126
1127
return attr.listMaxLength;
1128
}
1129
1130
/**
1131
* Returns a <code>String</code> containing a description of the
1132
* named attribute, or <code>null</code>. The description will be
1133
* localized for the supplied <code>Locale</code> if possible.
1134
*
1135
* <p> The default implementation will first locate a
1136
* <code>ResourceBundle</code> using the current resource base
1137
* name set by <code>setResourceBaseName</code> and the supplied
1138
* <code>Locale</code>, using the fallback mechanism described in
1139
* the comments for <code>ResourceBundle.getBundle</code>. If a
1140
* <code>ResourceBundle</code> is found, the element name followed
1141
* by a "/" character followed by the attribute name
1142
* (<code>elementName + "/" + attrName</code>) will be used as a
1143
* key to its <code>getString</code> method, and the result
1144
* returned. If no <code>ResourceBundle</code> is found, or no
1145
* such key is present, <code>null</code> will be returned.
1146
*
1147
* <p> If <code>locale</code> is <code>null</code>, the current
1148
* default <code>Locale</code> returned by <code>Locale.getLocale</code>
1149
* will be used.
1150
*
1151
* @param elementName the name of the element.
1152
* @param attrName the name of the attribute.
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 = (ObjectValue)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 = (ObjectValue)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
*
1267
* @return a predefined <code>IIOMetadataFormat</code> instance.
1268
*/
1269
public static IIOMetadataFormat getStandardFormatInstance() {
1270
createStandardFormat();
1271
return standardFormat;
1272
}
1273
}
1274
1275