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