1 16 package org.apache.commons.jxpath.ri.model; 17 18 import java.util.Locale ; 19 20 import org.apache.commons.jxpath.JXPathContext; 21 import org.apache.commons.jxpath.JXPathException; 22 import org.apache.commons.jxpath.Pointer; 23 import org.apache.commons.jxpath.ri.Compiler; 24 import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl; 25 import org.apache.commons.jxpath.ri.NamespaceResolver; 26 import org.apache.commons.jxpath.ri.QName; 27 import org.apache.commons.jxpath.ri.compiler.NodeNameTest; 28 import org.apache.commons.jxpath.ri.compiler.NodeTest; 29 import org.apache.commons.jxpath.ri.compiler.NodeTypeTest; 30 import org.apache.commons.jxpath.ri.model.beans.NullPointer; 31 32 41 public abstract class NodePointer implements Pointer { 42 43 public static final int WHOLE_COLLECTION = Integer.MIN_VALUE; 44 protected int index = WHOLE_COLLECTION; 45 public static final String UNKNOWN_NAMESPACE = "<<unknown namespace>>"; 46 private boolean attribute = false; 47 private transient Object rootNode; 48 private NamespaceResolver namespaceResolver; 49 50 54 public static NodePointer newNodePointer( 55 QName name, 56 Object bean, 57 Locale locale) 58 { 59 NodePointer pointer = null; 60 if (bean == null) { 61 pointer = new NullPointer(name, locale); 62 return pointer; 63 } 64 65 NodePointerFactory[] factories = 66 JXPathContextReferenceImpl.getNodePointerFactories(); 67 for (int i = 0; i < factories.length; i++) { 68 pointer = factories[i].createNodePointer(name, bean, locale); 69 if (pointer != null) { 70 return pointer; 71 } 72 } 73 throw new JXPathException( 74 "Could not allocate a NodePointer for object of " 75 + bean.getClass()); 76 } 77 78 82 public static NodePointer newChildNodePointer( 83 NodePointer parent, 84 QName name, 85 Object bean) 86 { 87 NodePointerFactory[] factories = 88 JXPathContextReferenceImpl.getNodePointerFactories(); 89 for (int i = 0; i < factories.length; i++) { 90 NodePointer pointer = 91 factories[i].createNodePointer(parent, name, bean); 92 if (pointer != null) { 93 return pointer; 94 } 95 } 96 throw new JXPathException( 97 "Could not allocate a NodePointer for object of " 98 + bean.getClass()); 99 } 100 101 protected NodePointer parent; 102 protected Locale locale; 103 105 protected NodePointer(NodePointer parent) { 106 this.parent = parent; 107 } 108 109 protected NodePointer(NodePointer parent, Locale locale) { 110 this.parent = parent; 111 this.locale = locale; 112 } 113 114 public NamespaceResolver getNamespaceResolver() { 115 if (namespaceResolver == null && parent != null) { 116 namespaceResolver = parent.getNamespaceResolver(); 117 } 118 return namespaceResolver; 119 } 120 121 public void setNamespaceResolver(NamespaceResolver namespaceResolver) { 122 this.namespaceResolver = namespaceResolver; 123 } 124 125 public NodePointer getParent() { 126 NodePointer pointer = parent; 127 while (pointer != null && pointer.isContainer()) { 128 pointer = pointer.getImmediateParentPointer(); 129 } 130 return pointer; 131 } 132 133 public NodePointer getImmediateParentPointer() { 134 return parent; 135 } 136 137 140 public void setAttribute(boolean attribute) { 141 this.attribute = attribute; 142 } 143 144 147 public boolean isAttribute() { 148 return attribute; 149 } 150 151 154 public boolean isRoot() { 155 return parent == null; 156 } 157 158 161 public abstract boolean isLeaf(); 162 163 166 public boolean isNode() { 167 return !isContainer(); 168 } 169 170 174 public boolean isContainer() { 175 return false; 176 } 177 178 185 public int getIndex() { 186 return index; 187 } 188 189 public void setIndex(int index) { 190 this.index = index; 191 } 192 193 197 public abstract boolean isCollection(); 198 199 204 public abstract int getLength(); 205 206 211 public Object getValue() { 212 NodePointer valuePointer = getValuePointer(); 213 if (valuePointer != this) { 214 return valuePointer.getValue(); 215 } 216 return getNode(); 218 } 219 220 237 public NodePointer getValuePointer() { 238 NodePointer ivp = getImmediateValuePointer(); 239 if (ivp != this) { 240 return ivp.getValuePointer(); 241 } 242 return this; 243 } 244 245 251 public NodePointer getImmediateValuePointer() { 252 return this; 253 } 254 255 268 public boolean isActual() { 269 if (index == WHOLE_COLLECTION) { 270 return true; 271 } 272 else { 273 return index >= 0 && index < getLength(); 274 } 275 } 276 277 280 public abstract QName getName(); 281 282 287 public abstract Object getBaseValue(); 288 289 295 public Object getNodeValue() { 296 return getNode(); 297 } 298 299 304 public Object getNode() { 305 return getValuePointer().getImmediateNode(); 306 } 307 308 public Object getRootNode() { 309 if (rootNode == null) { 310 if (parent != null) { 311 rootNode = parent.getRootNode(); 312 } 313 else { 314 rootNode = getImmediateNode(); 315 } 316 } 317 return rootNode; 318 } 319 320 324 public abstract Object getImmediateNode(); 325 326 330 public abstract void setValue(Object value); 331 332 336 public abstract int compareChildNodePointers( 337 NodePointer pointer1, NodePointer pointer2); 338 339 342 public boolean testNode(NodeTest test) { 343 if (test == null) { 344 return true; 345 } 346 else if (test instanceof NodeNameTest) { 347 if (isContainer()) { 348 return false; 349 } 350 NodeNameTest nodeNameTest = (NodeNameTest) test; 351 QName testName = nodeNameTest.getNodeName(); 352 QName nodeName = getName(); 353 if (nodeName == null) { 354 return false; 355 } 356 357 String testPrefix = testName.getPrefix(); 358 String nodePrefix = nodeName.getPrefix(); 359 if (!equalStrings(testPrefix, nodePrefix)) { 360 String testNS = getNamespaceURI(testPrefix); 361 String nodeNS = getNamespaceURI(nodePrefix); 362 if (!equalStrings(testNS, nodeNS)) { 363 return false; 364 } 365 } 366 if (nodeNameTest.isWildcard()) { 367 return true; 368 } 369 return testName.getName().equals(nodeName.getName()); 370 } 371 else if (test instanceof NodeTypeTest) { 372 if (((NodeTypeTest) test).getNodeType() 373 == Compiler.NODE_TYPE_NODE) { 374 return isNode(); 375 } 376 } 377 return false; 378 } 379 380 private static boolean equalStrings(String s1, String s2) { 381 if (s1 == null && s2 != null) { 382 return false; 383 } 384 if (s1 != null && !s1.equals(s2)) { 385 return false; 386 } 387 return true; 388 } 389 390 394 public NodePointer createPath(JXPathContext context, Object value) { 395 setValue(value); 396 return this; 397 } 398 399 402 public void remove() { 403 405 } 408 409 414 public NodePointer createPath(JXPathContext context) { 415 return this; 416 } 417 418 424 public NodePointer createChild( 425 JXPathContext context, 426 QName name, 427 int index, 428 Object value) 429 { 430 throw new JXPathException( 431 "Cannot create an object for path " 432 + asPath() 433 + "/" 434 + name 435 + "[" 436 + (index + 1) 437 + "]" 438 + ", operation is not allowed for this type of node"); 439 } 440 441 447 public NodePointer createChild( 448 JXPathContext context, 449 QName name, 450 int index) 451 { 452 throw new JXPathException( 453 "Cannot create an object for path " 454 + asPath() 455 + "/" 456 + name 457 + "[" 458 + (index + 1) 459 + "]" 460 + ", operation is not allowed for this type of node"); 461 } 462 463 466 public NodePointer createAttribute(JXPathContext context, QName name) { 467 throw new JXPathException( 468 "Cannot create an attribute for path " 469 + asPath() + "/@" + name 470 + ", operation is not allowed for this type of node"); 471 } 472 473 478 public Locale getLocale() { 479 if (locale == null) { 480 if (parent != null) { 481 locale = parent.getLocale(); 482 } 483 } 484 return locale; 485 } 486 487 491 public boolean isLanguage(String lang) { 492 Locale loc = getLocale(); 493 String name = loc.toString().replace('_', '-'); 494 return name.toUpperCase().startsWith(lang.toUpperCase()); 495 } 496 497 522 public NodeIterator childIterator( 523 NodeTest test, 524 boolean reverse, 525 NodePointer startWith) 526 { 527 NodePointer valuePointer = getValuePointer(); 528 if (valuePointer != null && valuePointer != this) { 529 return valuePointer.childIterator(test, reverse, startWith); 530 } 531 return null; 532 } 533 534 539 public NodeIterator attributeIterator(QName qname) { 540 NodePointer valuePointer = getValuePointer(); 541 if (valuePointer != null && valuePointer != this) { 542 return valuePointer.attributeIterator(qname); 543 } 544 return null; 545 } 546 547 552 public NodeIterator namespaceIterator() { 553 return null; 554 } 555 556 561 public NodePointer namespacePointer(String namespace) { 562 return null; 563 } 564 565 568 public String getNamespaceURI(String prefix) { 569 return null; 570 } 571 572 575 public String getNamespaceURI() { 576 return null; 577 } 578 579 583 protected boolean isDefaultNamespace(String prefix) { 584 if (prefix == null) { 585 return true; 586 } 587 588 String namespace = getNamespaceURI(prefix); 589 if (namespace == null) { 590 return false; } 592 593 return namespace.equals(getDefaultNamespaceURI()); 594 } 595 596 protected String getDefaultNamespaceURI() { 597 return null; 598 } 599 600 603 public Pointer getPointerByID(JXPathContext context, String id) { 604 return context.getPointerByID(id); 605 } 606 607 610 public Pointer getPointerByKey( 611 JXPathContext context, 612 String key, 613 String value) 614 { 615 return context.getPointerByKey(key, value); 616 } 617 618 621 public String asPath() { 622 if (parent != null && parent.isContainer()) { 625 return parent.asPath(); 626 } 627 628 StringBuffer buffer = new StringBuffer (); 629 if (parent != null) { 630 buffer.append(parent.asPath()); 631 } 632 633 if (buffer.length() == 0 634 || buffer.charAt(buffer.length() - 1) != '/') { 635 buffer.append('/'); 636 } 637 if (attribute) { 638 buffer.append('@'); 639 } 640 buffer.append(getName()); 641 642 if (index != WHOLE_COLLECTION && isCollection()) { 643 buffer.append('[').append(index + 1).append(']'); 644 } 645 return buffer.toString(); 646 } 647 648 public Object clone() { 649 try { 650 NodePointer ptr = (NodePointer) super.clone(); 651 if (parent != null) { 652 ptr.parent = (NodePointer) parent.clone(); 653 } 654 return ptr; 655 } 656 catch (CloneNotSupportedException ex) { 657 ex.printStackTrace(); 659 } 660 return null; 661 } 662 663 public String toString() { 664 return asPath(); 665 } 666 667 public int compareTo(Object object) { 668 NodePointer pointer = (NodePointer) object; 670 if (parent == pointer.parent) { 671 if (parent == null) { 672 return 0; 673 } 674 return parent.compareChildNodePointers(this, pointer); 675 } 676 677 int depth1 = 0; 679 NodePointer p1 = this; 680 while (p1 != null) { 681 depth1++; 682 p1 = p1.parent; 683 } 684 int depth2 = 0; 685 NodePointer p2 = pointer; 686 while (p2 != null) { 687 depth2++; 688 p2 = p2.parent; 689 } 690 return compareNodePointers(this, depth1, pointer, depth2); 691 } 692 693 private int compareNodePointers( 694 NodePointer p1, 695 int depth1, 696 NodePointer p2, 697 int depth2) 698 { 699 if (depth1 < depth2) { 700 int r = compareNodePointers(p1, depth1, p2.parent, depth2 - 1); 701 if (r != 0) { 702 return r; 703 } 704 return -1; 705 } 706 else if (depth1 > depth2) { 707 int r = compareNodePointers(p1.parent, depth1 - 1, p2, depth2); 708 if (r != 0) { 709 return r; 710 } 711 return 1; 712 } 713 if (p1 == null && p2 == null) { 714 return 0; 715 } 716 717 if (p1 != null && p1.equals(p2)) { 718 return 0; 719 } 720 721 if (depth1 == 1) { 722 throw new JXPathException( 723 "Cannot compare pointers that do not belong to the same tree: '" 724 + p1 725 + "' and '" 726 + p2 727 + "'"); 728 } 729 int r = 730 compareNodePointers(p1.parent, depth1 - 1, p2.parent, depth2 - 1); 731 if (r != 0) { 732 return r; 733 } 734 735 return p1.parent.compareChildNodePointers(p1, p2); 736 } 737 738 741 public void printPointerChain() { 742 printDeep(this, ""); 743 } 744 745 private static void printDeep(NodePointer pointer, String indent) { 746 if (indent.length() == 0) { 747 System.err.println( 748 "POINTER: " 749 + pointer 750 + "(" 751 + pointer.getClass().getName() 752 + ")"); 753 } 754 else { 755 System.err.println( 756 indent 757 + " of " 758 + pointer 759 + "(" 760 + pointer.getClass().getName() 761 + ")"); 762 } 763 if (pointer.getImmediateParentPointer() != null) { 764 printDeep(pointer.getImmediateParentPointer(), indent + " "); 765 } 766 } 767 } | Popular Tags |