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 */ 017package org.apache.commons.jxpath.ri; 018 019import java.lang.ref.SoftReference; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.Collections; 023import java.util.Comparator; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.Map; 027import java.util.Vector; 028import java.util.Map.Entry; 029 030import org.apache.commons.jxpath.CompiledExpression; 031import org.apache.commons.jxpath.ExceptionHandler; 032import org.apache.commons.jxpath.Function; 033import org.apache.commons.jxpath.Functions; 034import org.apache.commons.jxpath.JXPathContext; 035import org.apache.commons.jxpath.JXPathException; 036import org.apache.commons.jxpath.JXPathFunctionNotFoundException; 037import org.apache.commons.jxpath.JXPathInvalidSyntaxException; 038import org.apache.commons.jxpath.JXPathNotFoundException; 039import org.apache.commons.jxpath.JXPathTypeConversionException; 040import org.apache.commons.jxpath.Pointer; 041import org.apache.commons.jxpath.ri.axes.InitialContext; 042import org.apache.commons.jxpath.ri.axes.RootContext; 043import org.apache.commons.jxpath.ri.compiler.Expression; 044import org.apache.commons.jxpath.ri.compiler.LocationPath; 045import org.apache.commons.jxpath.ri.compiler.Path; 046import org.apache.commons.jxpath.ri.compiler.TreeCompiler; 047import org.apache.commons.jxpath.ri.model.NodePointer; 048import org.apache.commons.jxpath.ri.model.NodePointerFactory; 049import org.apache.commons.jxpath.ri.model.VariablePointerFactory; 050import org.apache.commons.jxpath.ri.model.beans.BeanPointerFactory; 051import org.apache.commons.jxpath.ri.model.beans.CollectionPointerFactory; 052import org.apache.commons.jxpath.ri.model.container.ContainerPointerFactory; 053import org.apache.commons.jxpath.ri.model.dynamic.DynamicPointerFactory; 054import org.apache.commons.jxpath.util.ReverseComparator; 055import org.apache.commons.jxpath.util.ClassLoaderUtil; 056import org.apache.commons.jxpath.util.TypeUtils; 057 058/** 059 * The reference implementation of JXPathContext. 060 * 061 * @author Dmitri Plotnikov 062 * @version $Revision: 1523199 $ $Date: 2013-09-14 11:45:47 +0200 (Sa, 14 Sep 2013) $ 063 */ 064public class JXPathContextReferenceImpl extends JXPathContext { 065 066 /** 067 * Change this to <code>false</code> to disable soft caching of 068 * CompiledExpressions. 069 */ 070 public static final boolean USE_SOFT_CACHE = true; 071 072 private static final Compiler COMPILER = new TreeCompiler(); 073 private static Map compiled = new HashMap(); 074 private static int cleanupCount = 0; 075 076 private static NodePointerFactory[] nodeFactoryArray = null; 077 // The frequency of the cache cleanup 078 private static final int CLEANUP_THRESHOLD = 500; 079 private static final Vector nodeFactories = new Vector(); 080 081 static { 082 nodeFactories.add(new CollectionPointerFactory()); 083 nodeFactories.add(new BeanPointerFactory()); 084 nodeFactories.add(new DynamicPointerFactory()); 085 nodeFactories.add(new VariablePointerFactory()); 086 087 // DOM factory is only registered if DOM support is on the classpath 088 Object domFactory = allocateConditionally( 089 "org.apache.commons.jxpath.ri.model.dom.DOMPointerFactory", 090 "org.w3c.dom.Node"); 091 if (domFactory != null) { 092 nodeFactories.add(domFactory); 093 } 094 095 // JDOM factory is only registered if JDOM is on the classpath 096 Object jdomFactory = allocateConditionally( 097 "org.apache.commons.jxpath.ri.model.jdom.JDOMPointerFactory", 098 "org.jdom.Document"); 099 if (jdomFactory != null) { 100 nodeFactories.add(jdomFactory); 101 } 102 103 // DynaBean factory is only registered if BeanUtils are on the classpath 104 Object dynaBeanFactory = 105 allocateConditionally( 106 "org.apache.commons.jxpath.ri.model.dynabeans." 107 + "DynaBeanPointerFactory", 108 "org.apache.commons.beanutils.DynaBean"); 109 if (dynaBeanFactory != null) { 110 nodeFactories.add(dynaBeanFactory); 111 } 112 113 nodeFactories.add(new ContainerPointerFactory()); 114 createNodeFactoryArray(); 115 } 116 117 /** 118 * Create the default node factory array. 119 */ 120 private static synchronized void createNodeFactoryArray() { 121 if (nodeFactoryArray == null) { 122 nodeFactoryArray = 123 (NodePointerFactory[]) nodeFactories. 124 toArray(new NodePointerFactory[nodeFactories.size()]); 125 Arrays.sort(nodeFactoryArray, new Comparator() { 126 public int compare(Object a, Object b) { 127 int orderA = ((NodePointerFactory) a).getOrder(); 128 int orderB = ((NodePointerFactory) b).getOrder(); 129 return orderA - orderB; 130 } 131 }); 132 } 133 } 134 135 /** 136 * Call this with a custom NodePointerFactory to add support for 137 * additional types of objects. Make sure the factory returns 138 * a name that puts it in the right position on the list of factories. 139 * @param factory NodePointerFactory to add 140 */ 141 public static void addNodePointerFactory(NodePointerFactory factory) { 142 synchronized (nodeFactories) { 143 nodeFactories.add(factory); 144 nodeFactoryArray = null; 145 } 146 } 147 148 /** 149 * Get the registered NodePointerFactories. 150 * @return NodePointerFactory[] 151 */ 152 public static NodePointerFactory[] getNodePointerFactories() { 153 return nodeFactoryArray; 154 } 155 156 /** Namespace resolver */ 157 protected NamespaceResolver namespaceResolver; 158 159 private Pointer rootPointer; 160 private Pointer contextPointer; 161 162 /** 163 * Create a new JXPathContextReferenceImpl. 164 * @param parentContext parent context 165 * @param contextBean Object 166 */ 167 protected JXPathContextReferenceImpl(JXPathContext parentContext, 168 Object contextBean) { 169 this(parentContext, contextBean, null); 170 } 171 172 /** 173 * Create a new JXPathContextReferenceImpl. 174 * @param parentContext parent context 175 * @param contextBean Object 176 * @param contextPointer context pointer 177 */ 178 public JXPathContextReferenceImpl(JXPathContext parentContext, 179 Object contextBean, Pointer contextPointer) { 180 super(parentContext, contextBean); 181 182 synchronized (nodeFactories) { 183 createNodeFactoryArray(); 184 } 185 186 if (contextPointer != null) { 187 this.contextPointer = contextPointer; 188 this.rootPointer = 189 NodePointer.newNodePointer( 190 new QName(null, "root"), 191 contextPointer.getRootNode(), 192 getLocale()); 193 } 194 else { 195 this.contextPointer = 196 NodePointer.newNodePointer( 197 new QName(null, "root"), 198 contextBean, 199 getLocale()); 200 this.rootPointer = this.contextPointer; 201 } 202 203 NamespaceResolver parentNR = null; 204 if (parentContext instanceof JXPathContextReferenceImpl) { 205 parentNR = ((JXPathContextReferenceImpl) parentContext).getNamespaceResolver(); 206 } 207 namespaceResolver = new NamespaceResolver(parentNR); 208 namespaceResolver 209 .setNamespaceContextPointer((NodePointer) this.contextPointer); 210 } 211 212 /** 213 * Returns a static instance of TreeCompiler. 214 * 215 * Override this to return an alternate compiler. 216 * @return Compiler 217 */ 218 protected Compiler getCompiler() { 219 return COMPILER; 220 } 221 222 protected CompiledExpression compilePath(String xpath) { 223 return new JXPathCompiledExpression(xpath, compileExpression(xpath)); 224 } 225 226 /** 227 * Compile the given expression. 228 * @param xpath to compile 229 * @return Expression 230 */ 231 private Expression compileExpression(String xpath) { 232 Expression expr; 233 234 synchronized (compiled) { 235 if (USE_SOFT_CACHE) { 236 expr = null; 237 SoftReference ref = (SoftReference) compiled.get(xpath); 238 if (ref != null) { 239 expr = (Expression) ref.get(); 240 } 241 } 242 else { 243 expr = (Expression) compiled.get(xpath); 244 } 245 } 246 247 if (expr != null) { 248 return expr; 249 } 250 251 expr = (Expression) Parser.parseExpression(xpath, getCompiler()); 252 253 synchronized (compiled) { 254 if (USE_SOFT_CACHE) { 255 if (cleanupCount++ >= CLEANUP_THRESHOLD) { 256 Iterator it = compiled.entrySet().iterator(); 257 while (it.hasNext()) { 258 Entry me = (Entry) it.next(); 259 if (((SoftReference) me.getValue()).get() == null) { 260 it.remove(); 261 } 262 } 263 cleanupCount = 0; 264 } 265 compiled.put(xpath, new SoftReference(expr)); 266 } 267 else { 268 compiled.put(xpath, expr); 269 } 270 } 271 272 return expr; 273 } 274 275 /** 276 * Traverses the xpath and returns the resulting object. Primitive 277 * types are wrapped into objects. 278 * @param xpath expression 279 * @return Object found 280 */ 281 public Object getValue(String xpath) { 282 Expression expression = compileExpression(xpath); 283// TODO: (work in progress) - trying to integrate with Xalan 284// Object ctxNode = getNativeContextNode(expression); 285// if (ctxNode != null) { 286// System.err.println("WILL USE XALAN: " + xpath); 287// CachedXPathAPI api = new CachedXPathAPI(); 288// try { 289// if (expression instanceof Path) { 290// Node node = api.selectSingleNode((Node)ctxNode, xpath); 291// System.err.println("NODE: " + node); 292// if (node == null) { 293// return null; 294// } 295// return new DOMNodePointer(node, null).getValue(); 296// } 297// else { 298// XObject object = api.eval((Node)ctxNode, xpath); 299// switch (object.getType()) { 300// case XObject.CLASS_STRING: return object.str(); 301// case XObject.CLASS_NUMBER: return new Double(object.num()); 302// case XObject.CLASS_BOOLEAN: return new Boolean(object.bool()); 303// default: 304// System.err.println("OTHER TYPE: " + object.getTypeString()); 305// } 306// } 307// } 308// catch (TransformerException e) { 309// // TODO Auto-generated catch block 310// e.printStackTrace(); 311// } 312// return 313// } 314 315 return getValue(xpath, expression); 316 } 317 318// private Object getNativeContextNode(Expression expression) { 319// Object node = getNativeContextNode(getContextBean()); 320// if (node == null) { 321// return null; 322// } 323// 324// List vars = expression.getUsedVariables(); 325// if (vars != null) { 326// return null; 327// } 328// 329// return node; 330// } 331 332// private Object getNativeContextNode(Object bean) { 333// if (bean instanceof Number || bean instanceof String || bean instanceof Boolean) { 334// return bean; 335// } 336// if (bean instanceof Node) { 337// return (Node)bean; 338// } 339// 340// if (bean instanceof Container) { 341// bean = ((Container)bean).getValue(); 342// return getNativeContextNode(bean); 343// } 344// 345// return null; 346// } 347 348 /** 349 * Get the value indicated. 350 * @param xpath String 351 * @param expr Expression 352 * @return Object 353 */ 354 public Object getValue(String xpath, Expression expr) { 355 Object result = expr.computeValue(getEvalContext()); 356 if (result == null) { 357 if (expr instanceof Path && !isLenient()) { 358 throw new JXPathNotFoundException("No value for xpath: " 359 + xpath); 360 } 361 return null; 362 } 363 if (result instanceof EvalContext) { 364 EvalContext ctx = (EvalContext) result; 365 result = ctx.getSingleNodePointer(); 366 if (!isLenient() && result == null) { 367 throw new JXPathNotFoundException("No value for xpath: " 368 + xpath); 369 } 370 } 371 if (result instanceof NodePointer) { 372 result = ((NodePointer) result).getValuePointer(); 373 if (!isLenient()) { 374 NodePointer.verify((NodePointer) result); 375 } 376 result = ((NodePointer) result).getValue(); 377 } 378 return result; 379 } 380 381 /** 382 * Calls getValue(xpath), converts the result to the required type 383 * and returns the result of the conversion. 384 * @param xpath expression 385 * @param requiredType Class 386 * @return Object 387 */ 388 public Object getValue(String xpath, Class requiredType) { 389 Expression expr = compileExpression(xpath); 390 return getValue(xpath, expr, requiredType); 391 } 392 393 /** 394 * Get the value indicated. 395 * @param xpath expression 396 * @param expr compiled Expression 397 * @param requiredType Class 398 * @return Object 399 */ 400 public Object getValue(String xpath, Expression expr, Class requiredType) { 401 Object value = getValue(xpath, expr); 402 if (value != null && requiredType != null) { 403 if (!TypeUtils.canConvert(value, requiredType)) { 404 throw new JXPathTypeConversionException( 405 "Invalid expression type. '" 406 + xpath 407 + "' returns " 408 + value.getClass().getName() 409 + ". It cannot be converted to " 410 + requiredType.getName()); 411 } 412 value = TypeUtils.convert(value, requiredType); 413 } 414 return value; 415 } 416 417 /** 418 * Traverses the xpath and returns a Iterator of all results found 419 * for the path. If the xpath matches no properties 420 * in the graph, the Iterator will not be null. 421 * @param xpath expression 422 * @return Iterator 423 */ 424 public Iterator iterate(String xpath) { 425 return iterate(xpath, compileExpression(xpath)); 426 } 427 428 /** 429 * Traverses the xpath and returns a Iterator of all results found 430 * for the path. If the xpath matches no properties 431 * in the graph, the Iterator will not be null. 432 * @param xpath expression 433 * @param expr compiled Expression 434 * @return Iterator 435 */ 436 public Iterator iterate(String xpath, Expression expr) { 437 return expr.iterate(getEvalContext()); 438 } 439 440 public Pointer getPointer(String xpath) { 441 return getPointer(xpath, compileExpression(xpath)); 442 } 443 444 /** 445 * Get a pointer to the specified path/expression. 446 * @param xpath String 447 * @param expr compiled Expression 448 * @return Pointer 449 */ 450 public Pointer getPointer(String xpath, Expression expr) { 451 Object result = expr.computeValue(getEvalContext()); 452 if (result instanceof EvalContext) { 453 result = ((EvalContext) result).getSingleNodePointer(); 454 } 455 if (result instanceof Pointer) { 456 if (!isLenient() && !((NodePointer) result).isActual()) { 457 throw new JXPathNotFoundException("No pointer for xpath: " 458 + xpath); 459 } 460 return (Pointer) result; 461 } 462 return NodePointer.newNodePointer(null, result, getLocale()); 463 } 464 465 public void setValue(String xpath, Object value) { 466 setValue(xpath, compileExpression(xpath), value); 467 } 468 469 /** 470 * Set the value of xpath to value. 471 * @param xpath path 472 * @param expr compiled Expression 473 * @param value Object 474 */ 475 public void setValue(String xpath, Expression expr, Object value) { 476 try { 477 setValue(xpath, expr, value, false); 478 } 479 catch (Throwable ex) { 480 throw new JXPathException( 481 "Exception trying to set value with xpath " + xpath, ex); 482 } 483 } 484 485 public Pointer createPath(String xpath) { 486 return createPath(xpath, compileExpression(xpath)); 487 } 488 489 /** 490 * Create the given path. 491 * @param xpath String 492 * @param expr compiled Expression 493 * @return resulting Pointer 494 */ 495 public Pointer createPath(String xpath, Expression expr) { 496 try { 497 Object result = expr.computeValue(getEvalContext()); 498 Pointer pointer = null; 499 500 if (result instanceof Pointer) { 501 pointer = (Pointer) result; 502 } 503 else if (result instanceof EvalContext) { 504 EvalContext ctx = (EvalContext) result; 505 pointer = ctx.getSingleNodePointer(); 506 } 507 else { 508 checkSimplePath(expr); 509 // This should never happen 510 throw new JXPathException("Cannot create path:" + xpath); 511 } 512 return ((NodePointer) pointer).createPath(this); 513 } 514 catch (Throwable ex) { 515 throw new JXPathException( 516 "Exception trying to create xpath " + xpath, 517 ex); 518 } 519 } 520 521 public Pointer createPathAndSetValue(String xpath, Object value) { 522 return createPathAndSetValue(xpath, compileExpression(xpath), value); 523 } 524 525 /** 526 * Create the given path setting its value to value. 527 * @param xpath String 528 * @param expr compiled Expression 529 * @param value Object 530 * @return resulting Pointer 531 */ 532 public Pointer createPathAndSetValue(String xpath, Expression expr, 533 Object value) { 534 try { 535 return setValue(xpath, expr, value, true); 536 } 537 catch (Throwable ex) { 538 throw new JXPathException( 539 "Exception trying to create xpath " + xpath, 540 ex); 541 } 542 } 543 544 /** 545 * Set the specified value. 546 * @param xpath path 547 * @param expr compiled Expression 548 * @param value destination value 549 * @param create whether to create missing node(s) 550 * @return Pointer created 551 */ 552 private Pointer setValue(String xpath, Expression expr, Object value, 553 boolean create) { 554 Object result = expr.computeValue(getEvalContext()); 555 Pointer pointer = null; 556 557 if (result instanceof Pointer) { 558 pointer = (Pointer) result; 559 } 560 else if (result instanceof EvalContext) { 561 EvalContext ctx = (EvalContext) result; 562 pointer = ctx.getSingleNodePointer(); 563 } 564 else { 565 if (create) { 566 checkSimplePath(expr); 567 } 568 569 // This should never happen 570 throw new JXPathException("Cannot set value for xpath: " + xpath); 571 } 572 if (create) { 573 pointer = ((NodePointer) pointer).createPath(this, value); 574 } 575 else { 576 pointer.setValue(value); 577 } 578 return pointer; 579 } 580 581 /** 582 * Checks if the path follows the JXPath restrictions on the type 583 * of path that can be passed to create... methods. 584 * @param expr Expression to check 585 */ 586 private void checkSimplePath(Expression expr) { 587 if (!(expr instanceof LocationPath) 588 || !((LocationPath) expr).isSimplePath()) { 589 throw new JXPathInvalidSyntaxException( 590 "JXPath can only create a path if it uses exclusively " 591 + "the child:: and attribute:: axes and has " 592 + "no context-dependent predicates"); 593 } 594 } 595 596 /** 597 * Traverses the xpath and returns an Iterator of Pointers. 598 * A Pointer provides easy access to a property. 599 * If the xpath matches no properties 600 * in the graph, the Iterator be empty, but not null. 601 * @param xpath expression 602 * @return Iterator 603 */ 604 public Iterator iteratePointers(String xpath) { 605 return iteratePointers(xpath, compileExpression(xpath)); 606 } 607 608 /** 609 * Traverses the xpath and returns an Iterator of Pointers. 610 * A Pointer provides easy access to a property. 611 * If the xpath matches no properties 612 * in the graph, the Iterator be empty, but not null. 613 * @param xpath expression 614 * @param expr compiled Expression 615 * @return Iterator 616 */ 617 public Iterator iteratePointers(String xpath, Expression expr) { 618 return expr.iteratePointers(getEvalContext()); 619 } 620 621 public void removePath(String xpath) { 622 removePath(xpath, compileExpression(xpath)); 623 } 624 625 /** 626 * Remove the specified path. 627 * @param xpath expression 628 * @param expr compiled Expression 629 */ 630 public void removePath(String xpath, Expression expr) { 631 try { 632 NodePointer pointer = (NodePointer) getPointer(xpath, expr); 633 if (pointer != null) { 634 pointer.remove(); 635 } 636 } 637 catch (Throwable ex) { 638 throw new JXPathException( 639 "Exception trying to remove xpath " + xpath, 640 ex); 641 } 642 } 643 644 public void removeAll(String xpath) { 645 removeAll(xpath, compileExpression(xpath)); 646 } 647 648 /** 649 * Remove all matching nodes. 650 * @param xpath expression 651 * @param expr compiled Expression 652 */ 653 public void removeAll(String xpath, Expression expr) { 654 try { 655 ArrayList list = new ArrayList(); 656 Iterator it = expr.iteratePointers(getEvalContext()); 657 while (it.hasNext()) { 658 list.add(it.next()); 659 } 660 Collections.sort(list, ReverseComparator.INSTANCE); 661 it = list.iterator(); 662 if (it.hasNext()) { 663 NodePointer pointer = (NodePointer) it.next(); 664 pointer.remove(); 665 while (it.hasNext()) { 666 removePath(((NodePointer) it.next()).asPath()); 667 } 668 } 669 } 670 catch (Throwable ex) { 671 throw new JXPathException( 672 "Exception trying to remove all for xpath " + xpath, 673 ex); 674 } 675 } 676 677 public JXPathContext getRelativeContext(Pointer pointer) { 678 Object contextBean = pointer.getNode(); 679 if (contextBean == null) { 680 throw new JXPathException( 681 "Cannot create a relative context for a non-existent node: " 682 + pointer); 683 } 684 return new JXPathContextReferenceImpl(this, contextBean, pointer); 685 } 686 687 public Pointer getContextPointer() { 688 return contextPointer; 689 } 690 691 /** 692 * Get absolute root pointer. 693 * @return NodePointer 694 */ 695 private NodePointer getAbsoluteRootPointer() { 696 return (NodePointer) rootPointer; 697 } 698 699 /** 700 * Get the evaluation context. 701 * @return EvalContext 702 */ 703 private EvalContext getEvalContext() { 704 return new InitialContext(new RootContext(this, 705 (NodePointer) getContextPointer())); 706 } 707 708 /** 709 * Get the absolute root context. 710 * @return EvalContext 711 */ 712 public EvalContext getAbsoluteRootContext() { 713 return new InitialContext(new RootContext(this, 714 getAbsoluteRootPointer())); 715 } 716 717 /** 718 * Get a VariablePointer for the given variable name. 719 * @param name variable name 720 * @return NodePointer 721 */ 722 public NodePointer getVariablePointer(QName name) { 723 return NodePointer.newNodePointer(name, VariablePointerFactory 724 .contextWrapper(this), getLocale()); 725 } 726 727 /** 728 * Get the named Function. 729 * @param functionName name 730 * @param parameters function args 731 * @return Function 732 */ 733 public Function getFunction(QName functionName, Object[] parameters) { 734 String namespace = functionName.getPrefix(); 735 String name = functionName.getName(); 736 JXPathContext funcCtx = this; 737 Function func = null; 738 Functions funcs; 739 while (funcCtx != null) { 740 funcs = funcCtx.getFunctions(); 741 if (funcs != null) { 742 func = funcs.getFunction(namespace, name, parameters); 743 if (func != null) { 744 return func; 745 } 746 } 747 funcCtx = funcCtx.getParentContext(); 748 } 749 throw new JXPathFunctionNotFoundException( 750 "Undefined function: " + functionName.toString()); 751 } 752 753 public void registerNamespace(String prefix, String namespaceURI) { 754 if (namespaceResolver.isSealed()) { 755 namespaceResolver = (NamespaceResolver) namespaceResolver.clone(); 756 } 757 namespaceResolver.registerNamespace(prefix, namespaceURI); 758 } 759 760 public String getNamespaceURI(String prefix) { 761 return namespaceResolver.getNamespaceURI(prefix); 762 } 763 764 /** 765 * {@inheritDoc} 766 * @see org.apache.commons.jxpath.JXPathContext#getPrefix(java.lang.String) 767 */ 768 public String getPrefix(String namespaceURI) { 769 return namespaceResolver.getPrefix(namespaceURI); 770 } 771 772 public void setNamespaceContextPointer(Pointer pointer) { 773 if (namespaceResolver.isSealed()) { 774 namespaceResolver = (NamespaceResolver) namespaceResolver.clone(); 775 } 776 namespaceResolver.setNamespaceContextPointer((NodePointer) pointer); 777 } 778 779 public Pointer getNamespaceContextPointer() { 780 return namespaceResolver.getNamespaceContextPointer(); 781 } 782 783 /** 784 * Get the namespace resolver. 785 * @return NamespaceResolver 786 */ 787 public NamespaceResolver getNamespaceResolver() { 788 namespaceResolver.seal(); 789 return namespaceResolver; 790 } 791 792 /** 793 * {@inheritDoc} 794 */ 795 public void setExceptionHandler(ExceptionHandler exceptionHandler) { 796 if (rootPointer instanceof NodePointer) { 797 ((NodePointer) rootPointer).setExceptionHandler(exceptionHandler); 798 } 799 } 800 801 /** 802 * Checks if existenceCheckClass exists on the class path. If so, allocates 803 * an instance of the specified class, otherwise returns null. 804 * @param className to instantiate 805 * @param existenceCheckClassName guard class 806 * @return className instance 807 */ 808 public static Object allocateConditionally(String className, 809 String existenceCheckClassName) { 810 try { 811 try { 812 ClassLoaderUtil.getClass(existenceCheckClassName, true); 813 } 814 catch (ClassNotFoundException ex) { 815 return null; 816 } 817 Class cls = ClassLoaderUtil.getClass(className, true); 818 return cls.newInstance(); 819 } 820 catch (Exception ex) { 821 throw new JXPathException("Cannot allocate " + className, ex); 822 } 823 } 824}