001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package javax.imageio.metadata;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.w3c.dom.Attr;
024: import org.w3c.dom.DOMException;
025: import org.w3c.dom.Document;
026: import org.w3c.dom.Element;
027: import org.w3c.dom.NamedNodeMap;
028: import org.w3c.dom.Node;
029: import org.w3c.dom.NodeList;
030: import org.w3c.dom.TypeInfo;
031: import org.w3c.dom.UserDataHandler;
032:
033: public class IIOMetadataNode implements Element, NodeList {
034:
035: private String nodeName;
036: private String nodeValue;
037: private IIOMetadataNodeList attrs = new IIOMetadataNodeList(
038: new ArrayList<IIOMetadataNode>());
039:
040: private IIOMetadataNode parent;
041: private IIOMetadataNode firstChild;
042: private IIOMetadataNode lastChild;
043: private IIOMetadataNode previousSibling;
044: private IIOMetadataNode nextSibling;
045:
046: private int nChildren;
047:
048: private Object userObject;
049:
050: private String textContent;
051:
052: public IIOMetadataNode() {
053: }
054:
055: public IIOMetadataNode(String nodeName) {
056: this .nodeName = nodeName;
057: }
058:
059: private IIOMetadataNode(String nodeName, String nodeValue) {
060: this .nodeName = nodeName;
061: this .nodeValue = nodeValue;
062: }
063:
064: public String getTagName() {
065: return nodeName;
066: }
067:
068: public String getAttribute(String name) {
069: Attr attrNode = (Attr) attrs.getNamedItem(name);
070: return (attrNode == null) ? "" : attrNode.getValue();
071: }
072:
073: public void setAttribute(String name, String value)
074: throws DOMException {
075: Attr attr = (Attr) attrs.getNamedItem(name);
076: if (attr != null) {
077: attr.setValue(value);
078: } else {
079: attrs.list.add(new IIOMetadataAttr(name, value, this ));
080: }
081: }
082:
083: public void removeAttribute(String name) throws DOMException {
084: IIOMetadataAttr attr = (IIOMetadataAttr) attrs
085: .getNamedItem(name);
086: if (attr != null) {
087: attr.setOwnerElement(null);
088: attrs.list.remove(attr);
089: }
090: }
091:
092: public Attr getAttributeNode(String name) {
093: return (Attr) attrs.getNamedItem(name);
094: }
095:
096: public Attr setAttributeNode(Attr newAttr) throws DOMException {
097: // Check if this attribute is already in use.
098: Element owner = newAttr.getOwnerElement();
099: if (owner != null) {
100: if (owner == this ) { // Replacing an attribute node by itself has no effect
101: return null;
102: } else {
103: throw new DOMException(
104: DOMException.INUSE_ATTRIBUTE_ERR,
105: "Attribute is already in use");
106: }
107: }
108:
109: String name = newAttr.getName();
110: Attr oldAttr = getAttributeNode(name);
111: if (oldAttr != null) {
112: removeAttributeNode(oldAttr);
113: }
114:
115: IIOMetadataAttr iioAttr;
116: if (newAttr instanceof IIOMetadataAttr) {
117: iioAttr = (IIOMetadataAttr) newAttr;
118: iioAttr.setOwnerElement(this );
119: } else {
120: iioAttr = new IIOMetadataAttr(name, newAttr.getValue(),
121: this );
122: }
123:
124: attrs.list.add(iioAttr);
125:
126: return oldAttr;
127: }
128:
129: public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
130: if (!attrs.list.remove(oldAttr)) { // Not found
131: throw new DOMException(DOMException.NOT_FOUND_ERR,
132: "No such attribute!");
133: }
134:
135: ((IIOMetadataAttr) oldAttr).setOwnerElement(null);
136:
137: return oldAttr;
138: }
139:
140: public NodeList getElementsByTagName(String name) {
141: ArrayList<IIOMetadataNode> nodes = new ArrayList<IIOMetadataNode>();
142:
143: // Non-recursive tree walk
144: Node pos = this ;
145:
146: while (pos != null) {
147: if (pos.getNodeName().equals(name)) {
148: nodes.add((IIOMetadataNode) pos);
149: }
150:
151: Node nextNode = pos.getFirstChild();
152:
153: while (nextNode == null) {
154: if (pos == this ) {
155: break;
156: }
157:
158: nextNode = pos.getNextSibling();
159:
160: if (nextNode == null) {
161: pos = pos.getParentNode();
162:
163: if (pos == null || pos == this ) {
164: nextNode = null;
165: break;
166: }
167: }
168: }
169: pos = nextNode;
170: }
171:
172: return new IIOMetadataNodeList(nodes);
173: }
174:
175: public String getAttributeNS(String namespaceURI, String localName)
176: throws DOMException {
177: return getAttribute(localName);
178: }
179:
180: public void setAttributeNS(String namespaceURI,
181: String qualifiedName, String value) throws DOMException {
182: setAttribute(qualifiedName, value);
183: }
184:
185: public void removeAttributeNS(String namespaceURI, String localName)
186: throws DOMException {
187: removeAttribute(localName);
188: }
189:
190: public Attr getAttributeNodeNS(String namespaceURI, String localName)
191: throws DOMException {
192: return getAttributeNode(localName);
193: }
194:
195: public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
196: return setAttributeNode(newAttr);
197: }
198:
199: public NodeList getElementsByTagNameNS(String namespaceURI,
200: String localName) throws DOMException {
201: return getElementsByTagName(localName);
202: }
203:
204: public boolean hasAttribute(String name) {
205: return attrs.getNamedItem(name) != null;
206: }
207:
208: public boolean hasAttributeNS(String namespaceURI, String localName)
209: throws DOMException {
210: return hasAttribute(localName);
211: }
212:
213: public TypeInfo getSchemaTypeInfo() {
214: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
215: "Method not supported");
216: }
217:
218: public void setIdAttribute(String name, boolean isId)
219: throws DOMException {
220: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
221: "Method not supported");
222: }
223:
224: public void setIdAttributeNS(String namespaceURI, String localName,
225: boolean isId) throws DOMException {
226: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
227: "Method not supported");
228: }
229:
230: public void setIdAttributeNode(Attr idAttr, boolean isId)
231: throws DOMException {
232: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
233: "Method not supported");
234: }
235:
236: public String getNodeName() {
237: return nodeName;
238: }
239:
240: public String getNodeValue() throws DOMException {
241: return nodeValue;
242: }
243:
244: public void setNodeValue(String nodeValue) throws DOMException {
245: this .nodeValue = nodeValue;
246: }
247:
248: public short getNodeType() {
249: return ELEMENT_NODE;
250: }
251:
252: public Node getParentNode() {
253: return parent;
254: }
255:
256: public NodeList getChildNodes() {
257: return this ;
258: }
259:
260: public Node getFirstChild() {
261: return firstChild;
262: }
263:
264: public Node getLastChild() {
265: return lastChild;
266: }
267:
268: public Node getPreviousSibling() {
269: return previousSibling;
270: }
271:
272: public Node getNextSibling() {
273: return nextSibling;
274: }
275:
276: public NamedNodeMap getAttributes() {
277: return attrs;
278: }
279:
280: public Document getOwnerDocument() {
281: return null;
282: }
283:
284: public Node insertBefore(Node newChild, Node refChild)
285: throws DOMException {
286: if (newChild == null) {
287: throw new IllegalArgumentException("newChild == null!");
288: }
289:
290: IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild;
291: IIOMetadataNode refIIOChild = (IIOMetadataNode) refChild;
292:
293: newIIOChild.parent = this ;
294:
295: if (refIIOChild == null) {
296: newIIOChild.nextSibling = null;
297: newIIOChild.previousSibling = lastChild;
298:
299: // Fix this node
300: lastChild = newIIOChild;
301: if (firstChild == null) {
302: firstChild = newIIOChild;
303: }
304: } else {
305: newIIOChild.nextSibling = refIIOChild;
306: newIIOChild.previousSibling = refIIOChild.previousSibling;
307:
308: // Fix this node
309: if (firstChild == refIIOChild) {
310: firstChild = newIIOChild;
311: }
312:
313: // Fix next node
314: if (refIIOChild != null) {
315: refIIOChild.previousSibling = newIIOChild;
316: }
317: }
318:
319: // Fix prev node
320: if (newIIOChild.previousSibling != null) {
321: newIIOChild.previousSibling.nextSibling = newIIOChild;
322: }
323:
324: nChildren++;
325:
326: return newIIOChild;
327: }
328:
329: public Node replaceChild(Node newChild, Node oldChild)
330: throws DOMException {
331: if (newChild == null) {
332: throw new IllegalArgumentException("newChild == null!");
333: }
334:
335: IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild;
336: IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild;
337:
338: IIOMetadataNode next = oldIIOChild.nextSibling;
339: IIOMetadataNode previous = oldIIOChild.previousSibling;
340:
341: // Fix new node
342: newIIOChild.parent = this ;
343: newIIOChild.nextSibling = next;
344: newIIOChild.previousSibling = previous;
345:
346: // Fix this node
347: if (lastChild == oldIIOChild) {
348: lastChild = newIIOChild;
349: }
350: if (firstChild == oldIIOChild) {
351: firstChild = newIIOChild;
352: }
353:
354: // Fix siblings
355: if (next != null) {
356: next.previousSibling = newIIOChild;
357: }
358: if (previous != null) {
359: previous.nextSibling = newIIOChild;
360: }
361:
362: // Fix old child
363: oldIIOChild.parent = null;
364: oldIIOChild.nextSibling = next;
365: oldIIOChild.previousSibling = previous;
366:
367: return oldIIOChild;
368: }
369:
370: public Node removeChild(Node oldChild) throws DOMException {
371: if (oldChild == null) {
372: throw new IllegalArgumentException("oldChild == null!");
373: }
374:
375: IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild;
376:
377: // Fix next and previous
378: IIOMetadataNode previous = oldIIOChild.previousSibling;
379: IIOMetadataNode next = oldIIOChild.nextSibling;
380:
381: if (previous != null) {
382: previous.nextSibling = next;
383: }
384: if (next != null) {
385: next.previousSibling = previous;
386: }
387:
388: // Fix this node
389: if (lastChild == oldIIOChild) {
390: lastChild = previous;
391: }
392: if (firstChild == oldIIOChild) {
393: firstChild = next;
394: }
395: nChildren--;
396:
397: // Fix old child
398: oldIIOChild.parent = null;
399: oldIIOChild.previousSibling = null;
400: oldIIOChild.nextSibling = null;
401:
402: return oldIIOChild;
403: }
404:
405: public Node appendChild(Node newChild) throws DOMException {
406: return insertBefore(newChild, null);
407: }
408:
409: public boolean hasChildNodes() {
410: return nChildren != 0;
411: }
412:
413: public Node cloneNode(boolean deep) {
414: IIOMetadataNode cloned = new IIOMetadataNode(nodeName);
415: cloned.setUserObject(getUserObject());
416:
417: if (deep) { // Clone recursively
418: IIOMetadataNode c = firstChild;
419: while (c != null) {
420: cloned.insertBefore(c.cloneNode(true), null);
421: c = c.nextSibling;
422: }
423: }
424:
425: return cloned; //To change body of implemented methods use File | Settings | File Templates.
426: }
427:
428: public void normalize() {
429: // Do nothing
430: }
431:
432: public boolean isSupported(String feature, String version) {
433: return false;
434: }
435:
436: public String getNamespaceURI() {
437: return null;
438: }
439:
440: public String getPrefix() {
441: return null;
442: }
443:
444: public void setPrefix(String prefix) throws DOMException {
445: // Do nothing
446: }
447:
448: public String getLocalName() {
449: return nodeName;
450: }
451:
452: public boolean hasAttributes() {
453: return attrs.list.size() > 0;
454: }
455:
456: public String getBaseURI() {
457: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
458: "Method not supported");
459: }
460:
461: public short compareDocumentPosition(Node other)
462: throws DOMException {
463: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
464: "Method not supported");
465: }
466:
467: public String getTextContent() throws DOMException {
468: return textContent;
469: }
470:
471: public void setTextContent(String textContent) throws DOMException {
472: this .textContent = textContent;
473: }
474:
475: public boolean isSameNode(Node other) {
476: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
477: "Method not supported");
478: }
479:
480: public String lookupPrefix(String namespaceURI) {
481: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
482: "Method not supported");
483: }
484:
485: public boolean isDefaultNamespace(String namespaceURI) {
486: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
487: "Method not supported");
488: }
489:
490: public String lookupNamespaceURI(String prefix) {
491: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
492: "Method not supported");
493: }
494:
495: public boolean isEqualNode(Node arg) {
496: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
497: "Method not supported");
498: }
499:
500: public Object getFeature(String feature, String version) {
501: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
502: "Method not supported");
503: }
504:
505: public Object setUserData(String key, Object data,
506: UserDataHandler handler) {
507: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
508: "Method not supported");
509: }
510:
511: public Object getUserData(String key) {
512: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
513: "Method not supported");
514: }
515:
516: public Node item(int index) {
517: if (index < 0 || index >= nChildren) {
518: return null;
519: }
520:
521: Node n;
522: for (n = getFirstChild(); index > 0; index--) {
523: n = n.getNextSibling();
524: }
525:
526: return n;
527: }
528:
529: public int getLength() {
530: return nChildren;
531: }
532:
533: public Object getUserObject() {
534: return userObject;
535: }
536:
537: public void setUserObject(Object userObject) {
538: this .userObject = userObject;
539: }
540:
541: private class IIOMetadataAttr extends IIOMetadataNode implements
542: Attr {
543: private Element ownerElement;
544:
545: public IIOMetadataAttr(String name, String value, Element owner) {
546: super (name, value);
547: this .ownerElement = owner;
548: }
549:
550: public String getName() {
551: return getNodeName();
552: }
553:
554: public boolean getSpecified() {
555: return true;
556: }
557:
558: public String getValue() {
559: return nodeValue;
560: }
561:
562: public void setValue(String value) throws DOMException {
563: nodeValue = value;
564: }
565:
566: public Element getOwnerElement() {
567: return ownerElement;
568: }
569:
570: public void setOwnerElement(Element ownerElement) {
571: this .ownerElement = ownerElement;
572: }
573:
574: public boolean isId() {
575: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
576: "Method not supported");
577: }
578:
579: @Override
580: public short getNodeType() {
581: return ATTRIBUTE_NODE;
582: }
583: }
584:
585: private class IIOMetadataNodeList implements NodeList, NamedNodeMap {
586: private List<IIOMetadataNode> list;
587:
588: IIOMetadataNodeList(List<IIOMetadataNode> list) {
589: this .list = list;
590: }
591:
592: public Node item(int index) {
593: try {
594: return list.get(index);
595: } catch (IndexOutOfBoundsException e) {
596: return null;
597: }
598: }
599:
600: public int getLength() {
601: return list.size();
602: }
603:
604: public Node getNamedItem(String name) {
605: for (IIOMetadataNode node : list) {
606: if (name.equals(node.getNodeName())) {
607: return node;
608: }
609: }
610: return null;
611: }
612:
613: public Node setNamedItem(Node arg) throws DOMException {
614: throw new DOMException(
615: DOMException.NO_MODIFICATION_ALLOWED_ERR,
616: "This NamedNodeMap is read-only!");
617: }
618:
619: public Node removeNamedItem(String name) throws DOMException {
620: throw new DOMException(
621: DOMException.NO_MODIFICATION_ALLOWED_ERR,
622: "This NamedNodeMap is read-only!");
623: }
624:
625: public Node getNamedItemNS(String namespaceURI, String localName)
626: throws DOMException {
627: return getNamedItem(localName);
628: }
629:
630: public Node setNamedItemNS(Node arg) throws DOMException {
631: throw new DOMException(
632: DOMException.NO_MODIFICATION_ALLOWED_ERR,
633: "This NamedNodeMap is read-only!");
634: }
635:
636: public Node removeNamedItemNS(String namespaceURI,
637: String localName) throws DOMException {
638: throw new DOMException(
639: DOMException.NO_MODIFICATION_ALLOWED_ERR,
640: "This NamedNodeMap is read-only!");
641: }
642: }
643: }
|