--- old/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java Fri Jan 16 18:28:42 2015 +++ new/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java Fri Jan 16 18:28:41 2015 @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -28,55 +27,37 @@ import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import javax.xml.xpath.XPathExpression; - -import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xpath.internal.*; import com.sun.org.apache.xpath.internal.objects.XObject; -import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.utils.FactoryImpl; import com.sun.org.apache.xalan.internal.utils.FeatureManager; - -import org.w3c.dom.Node; import org.w3c.dom.Document; -import org.w3c.dom.traversal.NodeIterator; - import org.xml.sax.InputSource; -import org.xml.sax.SAXException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathEvaluationResult; -import javax.xml.parsers.*; - -import java.io.IOException; - /** * The XPathImpl class provides implementation for the methods defined in - * javax.xml.xpath.XPath interface. This provide simple access to the results + * javax.xml.xpath.XPath interface. This provides simple access to the results * of an XPath expression. * - * * @author Ramesh Mandava + * + * Updated 12/04/2014: + * New methods: evaluateExpression + * Refactored to share code with XPathExpressionImpl. */ -public class XPathImpl implements javax.xml.xpath.XPath { +public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { // Private variables - private XPathVariableResolver variableResolver; - private XPathFunctionResolver functionResolver; private XPathVariableResolver origVariableResolver; private XPathFunctionResolver origFunctionResolver; private NamespaceContext namespaceContext=null; - private JAXPPrefixResolver prefixResolver; - // By default Extension Functions are allowed in XPath Expressions. If - // Secure Processing Feature is set on XPathFactory then the invocation of - // extensions function need to throw XPathFunctionException - private boolean featureSecureProcessing = false; - private boolean useServiceMechanism = true; - private final FeatureManager featureManager; - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr ) { + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr) { this(vr, fr, false, true, new FeatureManager()); } - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr, + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr, boolean featureSecureProcessing, boolean useServiceMechanism, FeatureManager featureManager) { this.origVariableResolver = this.variableResolver = vr; @@ -86,447 +67,134 @@ this.featureManager = featureManager; } - /** - *

Establishes a variable resolver.

- * - * @param resolver Variable Resolver - */ + @Override public void setXPathVariableResolver(XPathVariableResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathVariableResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathVariableResolver"); this.variableResolver = resolver; } - /** - *

Returns the current variable resolver.

- * - * @return Current variable resolver - */ + @Override public XPathVariableResolver getXPathVariableResolver() { return variableResolver; } - /** - *

Establishes a function resolver.

- * - * @param resolver XPath function resolver - */ + @Override public void setXPathFunctionResolver(XPathFunctionResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathFunctionResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathFunctionResolver"); this.functionResolver = resolver; } - /** - *

Returns the current function resolver.

- * - * @return Current function resolver - */ + @Override public XPathFunctionResolver getXPathFunctionResolver() { return functionResolver; } - /** - *

Establishes a namespace context.

- * - * @param nsContext Namespace context to use - */ + @Override public void setNamespaceContext(NamespaceContext nsContext) { - if ( nsContext == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"NamespaceContext"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(nsContext, "NamespaceContext"); this.namespaceContext = nsContext; - this.prefixResolver = new JAXPPrefixResolver ( nsContext ); + this.prefixResolver = new JAXPPrefixResolver (nsContext); } - /** - *

Returns the current namespace context.

- * - * @return Current Namespace context - */ + @Override public NamespaceContext getNamespaceContext() { return namespaceContext; } - private static Document d = null; - - private DocumentBuilder getParser() { - try { - // we'd really like to cache those DocumentBuilders, but we can't because: - // 1. thread safety. parsers are not thread-safe, so at least - // we need one instance per a thread. - // 2. parsers are non-reentrant, so now we are looking at having a - // pool of parsers. - // 3. then the class loading issue. The look-up procedure of - // DocumentBuilderFactory.newInstance() depends on context class loader - // and system properties, which may change during the execution of JVM. - // - // so we really have to create a fresh DocumentBuilder every time we need one - // - KK - DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(useServiceMechanism); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); - return dbf.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - // this should never happen with a well-behaving JAXP implementation. - throw new Error(e); - } - } - - + /** + * Evaluate an {@code XPath} expression in the specified context. + * @param expression The XPath expression. + * @param contextItem The starting context. + * @return an XObject as the result of evaluating the expression + * @throws TransformerException if evaluating fails + */ private XObject eval(String expression, Object contextItem) - throws javax.xml.transform.TransformerException { - com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath( expression, - null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); - com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; - if ( functionResolver != null ) { - JAXPExtensionsProvider jep = new JAXPExtensionsProvider( - functionResolver, featureSecureProcessing, featureManager ); - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); - } else { - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); - } + throws TransformerException { + requireNonNull(expression, "XPath expression"); + com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath(expression, + null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); - XObject xobj = null; - - xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); - - // If item is null, then we will create a a Dummy contextNode - if ( contextItem instanceof Node ) { - xobj = xpath.execute (xpathSupport, (Node)contextItem, - prefixResolver ); - } else { - xobj = xpath.execute ( xpathSupport, DTM.NULL, prefixResolver ); - } - - return xobj; + return eval(contextItem, xpath); } - /** - *

Evaluate an XPath expression in the specified context and return the result as the specified type.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in {@link XPathConstants} ( - * {@link XPathConstants#NUMBER NUMBER}, - * {@link XPathConstants#STRING STRING}, - * {@link XPathConstants#BOOLEAN BOOLEAN}, - * {@link XPathConstants#NODE NODE} or - * {@link XPathConstants#NODESET NODESET}) - * then an IllegalArgumentException is thrown.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression or returnType is null, then a - * NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * @param returnType The desired return type. - * - * @return Result of evaluating an XPath expression as an Object of returnType. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression or returnType is null. - */ + @Override public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } - // Checking if requested returnType is supported. returnType need to - // be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + //this check is necessary before calling eval to maintain binary compatibility + requireNonNull(expression, "XPath expression"); + isSupported(returnType); try { - XObject resultObject = eval( expression, item ); - return getResultAsType( resultObject, returnType ); - } catch ( java.lang.NullPointerException npe ) { + XObject resultObject = eval(expression, item); + return getResultAsType(resultObject, returnType); + } catch (java.lang.NullPointerException npe) { // If VariableResolver returns null Or if we get // NullPointerException at this stage for some other reason // then we have to reurn XPathException - throw new XPathExpressionException ( npe ); - } catch ( javax.xml.transform.TransformerException te ) { + throw new XPathExpressionException (npe); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { // For any other exceptions we need to throw - // XPathExpressionException ( as per spec ) - throw new XPathExpressionException ( te ); + // XPathExpressionException (as per spec) + throw new XPathExpressionException (te); } } } - private boolean isSupported( QName returnType ) { - if ( ( returnType.equals( XPathConstants.STRING ) ) || - ( returnType.equals( XPathConstants.NUMBER ) ) || - ( returnType.equals( XPathConstants.BOOLEAN ) ) || - ( returnType.equals( XPathConstants.NODE ) ) || - ( returnType.equals( XPathConstants.NODESET ) ) ) { - - return true; - } - return false; - } - - private Object getResultAsType( XObject resultObject, QName returnType ) - throws javax.xml.transform.TransformerException { - // XPathConstants.STRING - if ( returnType.equals( XPathConstants.STRING ) ) { - return resultObject.str(); - } - // XPathConstants.NUMBER - if ( returnType.equals( XPathConstants.NUMBER ) ) { - return new Double ( resultObject.num()); - } - // XPathConstants.BOOLEAN - if ( returnType.equals( XPathConstants.BOOLEAN ) ) { - return new Boolean( resultObject.bool()); - } - // XPathConstants.NODESET ---ORdered, UNOrdered??? - if ( returnType.equals( XPathConstants.NODESET ) ) { - return resultObject.nodelist(); - } - // XPathConstants.NODE - if ( returnType.equals( XPathConstants.NODE ) ) { - NodeIterator ni = resultObject.nodeset(); - //Return the first node, or null - return ni.nextNode(); - } - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString()}); - throw new IllegalArgumentException( fmsg ); - } - - - - /** - *

Evaluate an XPath expression in the specified context and return the result as a String.

- * - *

This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a returnType of - * {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression is null, then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression is null. - */ + @Override public String evaluate(String expression, Object item) throws XPathExpressionException { - return (String)this.evaluate( expression, item, XPathConstants.STRING ); + return (String)this.evaluate(expression, item, XPathConstants.STRING); } - /** - *

Compile an XPath expression for later evaluation.

- * - *

If expression contains any {@link XPathFunction}s, - * they must be available via the {@link XPathFunctionResolver}. - * An {@link XPathExpressionException} will be thrown if the XPathFunction - * cannot be resovled with the XPathFunctionResolver.

- * - *

If expression is null, a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * - * @return Compiled XPath expression. - - * @throws XPathExpressionException If expression cannot be compiled. - * @throws NullPointerException If expression is null. - */ + @Override public XPathExpression compile(String expression) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } + requireNonNull(expression, "XPath expression"); try { com.sun.org.apache.xpath.internal.XPath xpath = new XPath (expression, null, - prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); + prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath, prefixResolver, functionResolver, variableResolver, - featureSecureProcessing, useServiceMechanism, featureManager ); + featureSecureProcessing, useServiceMechanism, featureManager); return ximpl; - } catch ( javax.xml.transform.TransformerException te ) { - throw new XPathExpressionException ( te ) ; + } catch (TransformerException te) { + throw new XPathExpressionException (te) ; } } - - /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as the specified type.

- * - *

This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If expression, source or returnType is null, - * then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param source The input source of the document to evaluate over. - * @param returnType The desired return type. - * - * @return The Object that encapsulates the result of evaluating the expression. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression, source or returnType - * is null. - */ + @Override public Object evaluate(String expression, InputSource source, QName returnType) throws XPathExpressionException { - // Checking validity of different parameters - if( source== null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"source"} ); - throw new NullPointerException ( fmsg ); - } - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } + isSupported(returnType); - //Checking if requested returnType is supported. - //returnType need to be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } - try { - - Document document = getParser().parse( source ); - - XObject resultObject = eval( expression, document ); - return getResultAsType( resultObject, returnType ); - } catch ( SAXException e ) { - throw new XPathExpressionException ( e ); - } catch( IOException e ) { - throw new XPathExpressionException ( e ); - } catch ( javax.xml.transform.TransformerException te ) { + Document document = getDocument(source); + XObject resultObject = eval(expression, document); + return getResultAsType(resultObject, returnType); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { - throw new XPathExpressionException ( te ); + throw new XPathExpressionException (te); } } - } - - - - /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as a String.

- * - *

This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a - * returnType of {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If expression or source is null, - * then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param source The InputSource of the document to evaluate over. - * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression or source is null. - */ + @Override public String evaluate(String expression, InputSource source) throws XPathExpressionException { - return (String)this.evaluate( expression, source, XPathConstants.STRING ); + return (String)this.evaluate(expression, source, XPathConstants.STRING); } - /** - *

Reset this XPath to its original configuration.

- * - *

XPath is reset to the same state as when it was created with - * {@link XPathFactory#newXPath()}. - * reset() is designed to allow the reuse of existing XPaths - * thus saving resources associated with the creation of new XPaths.

- * - *

The reset XPath is not guaranteed to have the same - * {@link XPathFunctionResolver}, {@link XPathVariableResolver} - * or {@link NamespaceContext} Objects, e.g. {@link Object#equals(Object obj)}. - * It is guaranteed to have a functionally equal XPathFunctionResolver, - * XPathVariableResolver - * and NamespaceContext.

- */ + @Override public void reset() { this.variableResolver = this.origVariableResolver; this.functionResolver = this.origFunctionResolver; @@ -533,4 +201,40 @@ this.namespaceContext = null; } + @Override + public T evaluateExpression(String expression, Object item, Class type) + throws XPathExpressionException { + isSupportedClassType(type); + try { + XObject resultObject = eval(expression, item); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + XPathEvaluationResult x = getXPathResult(resultObject); + + return (T)x; + } else { + return XPathResultImpl.getValue(resultObject, type); + } + } catch (TransformerException te) { + throw new XPathExpressionException (te); + } + } + + @Override + public XPathEvaluationResult evaluateExpression(String expression, Object item) + throws XPathExpressionException { + return evaluateExpression(expression, item, XPathEvaluationResult.class); + } + + @Override + public T evaluateExpression(String expression, InputSource source, Class type) + throws XPathExpressionException { + Document document = getDocument(source); + return evaluateExpression(expression, document, type); + } + + @Override + public XPathEvaluationResult evaluateExpression(String expression, InputSource source) + throws XPathExpressionException { + return evaluateExpression(expression, source, XPathEvaluationResult.class); + } }