1 18 package org.apache.batik.dom; 19 20 import java.io.IOException ; 21 import java.io.ObjectInputStream ; 22 import java.io.ObjectOutputStream ; 23 import java.lang.reflect.Method ; 24 import java.util.ArrayList ; 25 import java.util.HashMap ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.Locale ; 29 import java.util.Map ; 30 import java.util.MissingResourceException ; 31 import java.util.WeakHashMap ; 32 33 import org.apache.batik.dom.events.DocumentEventSupport; 34 import org.apache.batik.dom.traversal.TraversalSupport; 35 import org.apache.batik.i18n.Localizable; 36 import org.apache.batik.i18n.LocalizableSupport; 37 import org.apache.batik.util.CleanerThread; 38 import org.apache.batik.util.SoftDoublyIndexedTable; 39 import org.w3c.dom.Attr ; 40 import org.w3c.dom.DOMException ; 41 import org.w3c.dom.DOMImplementation ; 42 import org.w3c.dom.Document ; 43 import org.w3c.dom.DocumentType ; 44 import org.w3c.dom.Element ; 45 import org.w3c.dom.NamedNodeMap ; 46 import org.w3c.dom.Node ; 47 import org.w3c.dom.events.DocumentEvent ; 48 import org.w3c.dom.events.Event ; 49 import org.w3c.dom.traversal.DocumentTraversal; 50 import org.w3c.dom.traversal.NodeFilter; 51 import org.w3c.dom.traversal.NodeIterator; 52 import org.w3c.dom.traversal.TreeWalker; 53 54 60 public abstract class AbstractDocument 61 extends AbstractParentNode 62 implements Document , 63 DocumentEvent , 64 DocumentTraversal, 65 Localizable { 66 67 70 protected final static String RESOURCES = 71 "org.apache.batik.dom.resources.Messages"; 72 73 76 protected transient LocalizableSupport localizableSupport = 77 new LocalizableSupport 78 (RESOURCES, getClass().getClassLoader()); 79 80 83 protected transient DOMImplementation implementation; 84 85 88 protected transient TraversalSupport traversalSupport; 89 90 93 protected transient DocumentEventSupport documentEventSupport; 94 95 98 protected transient boolean eventsEnabled; 99 100 103 protected transient WeakHashMap elementsByTagNames; 104 105 108 protected transient WeakHashMap elementsByTagNamesNS; 109 110 117 protected transient Map elementsById; 118 119 122 protected AbstractDocument() { 123 } 124 125 128 public AbstractDocument(DocumentType dt, DOMImplementation impl) { 129 implementation = impl; 130 if (dt != null) { 131 if (dt instanceof GenericDocumentType) { 132 GenericDocumentType gdt = (GenericDocumentType)dt; 133 if (gdt.getOwnerDocument() == null) 134 gdt.setOwnerDocument(this); 135 } 136 appendChild(dt); 137 } 138 } 139 140 143 public void setLocale(Locale l) { 144 localizableSupport.setLocale(l); 145 } 146 147 150 public Locale getLocale() { 151 return localizableSupport.getLocale(); 152 } 153 154 158 public String formatMessage(String key, Object [] args) 159 throws MissingResourceException { 160 return localizableSupport.formatMessage(key, args); 161 } 162 163 166 public boolean getEventsEnabled() { 167 return eventsEnabled; 168 } 169 170 173 public void setEventsEnabled(boolean b) { 174 eventsEnabled = b; 175 } 176 177 181 public String getNodeName() { 182 return "#document"; 183 } 184 185 189 public short getNodeType() { 190 return DOCUMENT_NODE; 191 } 192 193 196 public DocumentType getDoctype() { 197 for (Node n = getFirstChild(); n != null; n = n.getNextSibling()) { 198 if (n.getNodeType() == DOCUMENT_TYPE_NODE) { 199 return (DocumentType )n; 200 } 201 } 202 return null; 203 } 204 205 208 public void setDoctype(DocumentType dt) { 209 if (dt != null) { 210 appendChild(dt); 211 ((ExtendedNode)dt).setReadonly(true); 212 } 213 } 214 215 219 public DOMImplementation getImplementation() { 220 return implementation; 221 } 222 223 227 public Element getDocumentElement() { 228 for (Node n = getFirstChild(); n != null; n = n.getNextSibling()) { 229 if (n.getNodeType() == ELEMENT_NODE) { 230 return (Element )n; 231 } 232 } 233 return null; 234 } 235 236 240 public Node importNode(Node importedNode, boolean deep) 241 throws DOMException { 242 return importNode(importedNode, deep, false); 243 } 244 245 252 public Node importNode(Node importedNode, boolean deep, boolean trimId) { 253 257 Node result; 258 switch (importedNode.getNodeType()) { 259 case ELEMENT_NODE: 260 Element e = createElementNS(importedNode.getNamespaceURI(), 261 importedNode.getNodeName()); 262 result = e; 263 if (importedNode.hasAttributes()) { 264 NamedNodeMap attr = importedNode.getAttributes(); 265 int len = attr.getLength(); 266 for (int i = 0; i < len; i++) { 267 Attr a = (Attr )attr.item(i); 268 if (!a.getSpecified()) continue; 269 AbstractAttr aa = (AbstractAttr)importNode(a, true); 270 if (trimId && aa.isId()) 271 aa.setIsId(false); e.setAttributeNodeNS(aa); 273 } 274 } 275 break; 276 277 case ATTRIBUTE_NODE: 278 result = createAttributeNS(importedNode.getNamespaceURI(), 279 importedNode.getNodeName()); 280 break; 281 282 case TEXT_NODE: 283 result = createTextNode(importedNode.getNodeValue()); 284 deep = false; 285 break; 286 287 case CDATA_SECTION_NODE: 288 result = createCDATASection(importedNode.getNodeValue()); 289 deep = false; 290 break; 291 292 case ENTITY_REFERENCE_NODE: 293 result = createEntityReference(importedNode.getNodeName()); 294 break; 295 296 case PROCESSING_INSTRUCTION_NODE: 297 result = createProcessingInstruction 298 (importedNode.getNodeName(), 299 importedNode.getNodeValue()); 300 deep = false; 301 break; 302 303 case COMMENT_NODE: 304 result = createComment(importedNode.getNodeValue()); 305 deep = false; 306 break; 307 308 case DOCUMENT_FRAGMENT_NODE: 309 result = createDocumentFragment(); 310 break; 311 312 default: 313 throw createDOMException(DOMException.NOT_SUPPORTED_ERR, 314 "import.node", 315 new Object [] {}); 316 } 317 318 if (deep) { 319 for (Node n = importedNode.getFirstChild(); 320 n != null; 321 n = n.getNextSibling()) { 322 result.appendChild(importNode(n, true)); 323 } 324 } 325 return result; 326 } 327 328 331 public Node cloneNode(boolean deep) { 332 Document n = (Document )newNode(); 333 copyInto(n); 334 if (deep) { 335 for (Node c = getFirstChild(); 336 c != null; 337 c = c.getNextSibling()) { 338 n.appendChild(n.importNode(c, deep)); 339 } 340 } 341 return n; 342 } 343 344 public abstract boolean isId(Attr node); 345 346 350 public Element getElementById(String id) { 351 return getChildElementById(getDocumentElement(), id); 352 } 353 354 358 public Element getChildElementById(Node requestor, String id) { 359 if ((id == null) || (id.length()==0)) return null; 360 if (elementsById == null) return null; 361 362 Node root = getRoot(requestor); 363 364 Object o = elementsById.get(id); 365 if (o == null) return null; 366 if (o instanceof IdSoftRef) { 367 o = ((IdSoftRef)o).get(); 368 if (o == null) { 369 elementsById.remove(id); 370 return null; 371 } 372 Element e = (Element )o; 373 if (getRoot(e) == root) 374 return e; 375 return null; 376 } 377 378 List l = (List )o; 380 Iterator li = l.iterator(); 381 while (li.hasNext()) { 382 IdSoftRef sr = (IdSoftRef)li.next(); 383 o = sr.get(); 384 if (o == null) { 385 li.remove(); 386 } else { 387 Element e = (Element )o; 388 if (getRoot(e) == root) 389 return e; 390 } 391 } 392 return null; 393 } 394 395 protected Node getRoot(Node n) { 396 Node r = n; 397 while (n != null) { 398 r = n; 399 n = n.getParentNode(); 400 } 401 return r; 402 } 403 404 protected class IdSoftRef extends CleanerThread.SoftReferenceCleared { 405 String id; 406 List list; 407 IdSoftRef(Object o, String id) { 408 super(o); 409 this.id = id; 410 } 411 IdSoftRef(Object o, String id, List list) { 412 super(o); 413 this.id = id; 414 this.list = list; 415 } 416 public void setList(List list) { 417 this.list = list; 418 } 419 public void cleared() { 420 if (elementsById == null) return; 421 synchronized (elementsById) { 422 if (list != null) 423 list.remove(this); 424 else { 425 Object o = elementsById.remove(id); 426 if (o != this) elementsById.put(id, o); 428 } 429 } 430 } 431 } 432 433 436 public void removeIdEntry(Element e, String id) { 437 if (id == null) return; 439 if (elementsById == null) return; 440 441 synchronized (elementsById) { 442 Object o = elementsById.get(id); 443 if (o == null) return; 444 445 if (o instanceof IdSoftRef) { 446 elementsById.remove(id); 447 return; 448 } 449 450 List l = (List )o; 451 Iterator li = l.iterator(); 452 while (li.hasNext()) { 453 IdSoftRef ip = (IdSoftRef)li.next(); 454 o = ip.get(); 455 if (o == null) { 456 li.remove(); 457 } else if (e == o) { 458 li.remove(); 459 break; 460 } 461 } 462 463 if (l.size() == 0) 464 elementsById.remove(id); 465 } 466 } 467 468 public void addIdEntry(Element e, String id) { 469 if (id == null) return; 470 471 if (elementsById == null) { 472 Map tmp = new HashMap (); 473 synchronized (tmp) { 474 elementsById = tmp; 475 elementsById.put(id, new IdSoftRef(e, id)); 476 } 477 return; 478 } 479 480 synchronized (elementsById) { 481 Object o = elementsById.get(id); 483 if (o == null) { 484 elementsById.put(id, new IdSoftRef(e, id)); 485 return; 486 } 487 if (o instanceof IdSoftRef) { 488 IdSoftRef ip = (IdSoftRef)o; 489 Object r = ip.get(); 490 if (r == null) { elementsById.put(id, new IdSoftRef(e, id)); 492 return; 493 } 494 495 List l = new ArrayList (4); 497 ip.setList(l); 498 l.add(ip); 499 l.add(new IdSoftRef(e, id, l)); 500 elementsById.put(id, l); 501 return; 502 } 503 504 List l = (List )o; 505 l.add(new IdSoftRef(e, id, l)); 506 } 507 } 508 509 public void updateIdEntry(Element e, String oldId, String newId) { 510 if ((oldId == newId) || 511 ((oldId != null) && (oldId.equals(newId)))) 512 return; 513 514 removeIdEntry(e, oldId); 515 516 addIdEntry(e, newId); 517 } 518 519 520 523 public ElementsByTagName getElementsByTagName(Node n, String ln) { 524 if (elementsByTagNames == null) { 525 return null; 526 } 527 SoftDoublyIndexedTable t; 528 t = (SoftDoublyIndexedTable)elementsByTagNames.get(n); 529 if (t == null) { 530 return null; 531 } 532 return (ElementsByTagName)t.get(null, ln); 533 } 534 535 538 public void putElementsByTagName(Node n, String ln, ElementsByTagName l) { 539 if (elementsByTagNames == null) { 540 elementsByTagNames = new WeakHashMap (11); 541 } 542 SoftDoublyIndexedTable t; 543 t = (SoftDoublyIndexedTable)elementsByTagNames.get(n); 544 if (t == null) { 545 elementsByTagNames.put(n, t = new SoftDoublyIndexedTable()); 546 } 547 t.put(null, ln, l); 548 } 549 550 553 public ElementsByTagNameNS getElementsByTagNameNS(Node n, 554 String ns, 555 String ln) { 556 if (elementsByTagNamesNS == null) { 557 return null; 558 } 559 SoftDoublyIndexedTable t; 560 t = (SoftDoublyIndexedTable)elementsByTagNamesNS.get(n); 561 if (t == null) { 562 return null; 563 } 564 return (ElementsByTagNameNS)t.get(ns, ln); 565 } 566 567 570 public void putElementsByTagNameNS(Node n, String ns, String ln, 571 ElementsByTagNameNS l) { 572 if (elementsByTagNamesNS == null) { 573 elementsByTagNamesNS = new WeakHashMap (11); 574 } 575 SoftDoublyIndexedTable t; 576 t = (SoftDoublyIndexedTable)elementsByTagNamesNS.get(n); 577 if (t == null) { 578 elementsByTagNamesNS.put(n, t = new SoftDoublyIndexedTable()); 579 } 580 t.put(ns, ln, l); 581 } 582 583 585 589 public Event createEvent(String eventType) throws DOMException { 590 if (documentEventSupport == null) { 591 documentEventSupport = 592 ((AbstractDOMImplementation)implementation). 593 createDocumentEventSupport(); 594 } 595 return documentEventSupport.createEvent(eventType); 596 } 597 598 600 604 public NodeIterator createNodeIterator(Node root, 605 int whatToShow, 606 NodeFilter filter, 607 boolean entityReferenceExpansion) 608 throws DOMException { 609 if (traversalSupport == null) { 610 traversalSupport = new TraversalSupport(); 611 } 612 return traversalSupport.createNodeIterator(this, root, whatToShow, 613 filter, 614 entityReferenceExpansion); 615 } 616 617 621 public TreeWalker createTreeWalker(Node root, 622 int whatToShow, 623 NodeFilter filter, 624 boolean entityReferenceExpansion) 625 throws DOMException { 626 return TraversalSupport.createTreeWalker(this, root, whatToShow, 627 filter, 628 entityReferenceExpansion); 629 } 630 631 634 public void detachNodeIterator(NodeIterator it) { 635 traversalSupport.detachNodeIterator(it); 636 } 637 638 641 public void nodeToBeRemoved(Node node) { 642 if (traversalSupport != null) { 643 traversalSupport.nodeToBeRemoved(node); 644 } 645 } 646 647 650 protected AbstractDocument getCurrentDocument() { 651 return this; 652 } 653 654 659 protected Node export(Node n, Document d) { 660 throw createDOMException(DOMException.NOT_SUPPORTED_ERR, 661 "import.document", 662 new Object [] {}); 663 } 664 665 670 protected Node deepExport(Node n, Document d) { 671 throw createDOMException(DOMException.NOT_SUPPORTED_ERR, 672 "import.document", 673 new Object [] {}); 674 } 675 676 680 protected Node copyInto(Node n) { 681 super.copyInto(n); 682 AbstractDocument ad = (AbstractDocument)n; 683 ad.implementation = implementation; 684 ad.localizableSupport = new LocalizableSupport 685 (RESOURCES, getClass().getClassLoader()); 686 return n; 687 } 688 689 693 protected Node deepCopyInto(Node n) { 694 super.deepCopyInto(n); 695 AbstractDocument ad = (AbstractDocument)n; 696 ad.implementation = implementation; 697 ad.localizableSupport = new LocalizableSupport 698 (RESOURCES, getClass().getClassLoader()); 699 return n; 700 } 701 702 705 protected void checkChildType(Node n, boolean replace) { 706 short t = n.getNodeType(); 707 switch (t) { 708 case ELEMENT_NODE: 709 case PROCESSING_INSTRUCTION_NODE: 710 case COMMENT_NODE: 711 case DOCUMENT_TYPE_NODE: 712 case DOCUMENT_FRAGMENT_NODE: 713 break; 714 default: 715 throw createDOMException(DOMException.HIERARCHY_REQUEST_ERR, 716 "child.type", 717 new Object [] { new Integer (getNodeType()), 718 getNodeName(), 719 new Integer (t), 720 n.getNodeName() }); 721 } 722 if (!replace && 723 (t == ELEMENT_NODE && getDocumentElement() != null) || 724 (t == DOCUMENT_TYPE_NODE && getDoctype() != null)) { 725 throw createDOMException(DOMException.HIERARCHY_REQUEST_ERR, 726 "child.type", 727 new Object [] { new Integer (getNodeType()), 728 getNodeName(), 729 new Integer (t), 730 n.getNodeName() }); 731 } 732 } 733 734 736 private void writeObject(ObjectOutputStream s) throws IOException { 737 s.defaultWriteObject(); 738 739 s.writeObject(implementation.getClass().getName()); 740 } 741 742 private void readObject(ObjectInputStream s) 743 throws IOException , ClassNotFoundException { 744 s.defaultReadObject(); 745 746 localizableSupport = new LocalizableSupport 747 (RESOURCES, getClass().getClassLoader()); 748 749 Class c = Class.forName((String )s.readObject()); 750 751 try { 752 Method m = c.getMethod("getDOMImplementation", null); 753 implementation = (DOMImplementation )m.invoke(null, null); 754 } catch (Exception e) { 755 try { 756 implementation = (DOMImplementation )c.newInstance(); 757 } catch (Exception ex) { 758 } 759 } 760 } 761 } 762 | Popular Tags |