You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2011/02/23 19:28:11 UTC
svn commit: r1073874 - in /db/derby/code/trunk:
java/engine/org/apache/derby/iapi/services/loader/
java/engine/org/apache/derby/iapi/types/
java/testing/org/apache/derbyTesting/functionTests/tests/lang/
java/testing/org/apache/derbyTesting/junit/ tools...
Author: kahatlen
Date: Wed Feb 23 18:28:10 2011
New Revision: 1073874
URL: http://svn.apache.org/viewvc?rev=1073874&view=rev
Log:
DERBY-2739: Use DOM interfaces to implement XML operators
Make SqlXmlUtil use JAXP and DOM interfaces and factory classes to
provide support for XML serialization and XPath queries.
Added:
db/derby/code/trunk/tools/java/xml-apis.jar
- copied unchanged from r588374, db/derby/code/trunk/tools/java/xml-apis.jar
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLMissingClassesTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/EnvTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java
db/derby/code/trunk/tools/ant/properties/extrapath.properties
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java Wed Feb 23 18:28:10 2011
@@ -28,11 +28,6 @@ import org.apache.derby.iapi.error.Stand
import org.apache.derby.iapi.reference.SQLState;
import java.lang.reflect.*;
-import java.util.StringTokenizer;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.NoSuchElementException;
-import java.util.Collections;
/**
Methods to find out relationships between classes and methods within a class.
@@ -1062,27 +1057,6 @@ nextMethod: for (int i = 0; i < methods.
}
/**
- * Determine whether or not the received class can be
- * loaded.
- *
- * @param className The name of the class in question
- * @return True if className can be loaded, false otherwise
- */
- public static boolean classIsLoadable(String className)
- {
- try {
-
- Class.forName(className);
- return true;
-
- } catch (ClassNotFoundException ce) {
- return false;
- } catch (LinkageError ce) {
- return false;
- }
- }
-
- /**
* Get the declaring class for a method.
*
* @param method A Member describing a method
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java Wed Feb 23 18:28:10 2011
@@ -29,21 +29,29 @@ import org.apache.derby.iapi.services.sa
import java.util.Properties;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.StringReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+
// -- JDBC 3.0 JAXP API classes.
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
+import org.w3c.dom.xpath.XPathEvaluator;
+import org.w3c.dom.xpath.XPathExpression;
+import org.w3c.dom.xpath.XPathResult;
+
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -53,21 +61,12 @@ import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
-
-// -- Xalan-specific classes.
-
-import org.apache.xpath.XPath;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
-import org.apache.xpath.objects.XNodeSet;
-
-import org.apache.xml.utils.PrefixResolverDefault;
-
-import org.apache.xalan.serialize.DOMSerializer;
-import org.apache.xalan.serialize.Serializer;
-import org.apache.xalan.serialize.SerializerFactory;
-import org.apache.xalan.templates.OutputProperties;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
/**
* This class contains "utility" methods that work with XML-specific
@@ -122,19 +121,52 @@ public class SqlXmlUtil implements Forma
// Used to serialize an XML value according the standard
// XML serialization rules.
- private Serializer serializer;
+ private Transformer serializer;
// Classes used to compile and execute an XPath expression
// against Xalan.
- private XPath query;
- private XPathContext xpContext;
+ private XPathExpression query;
// Used to recompile the XPath expression when this formatable
// object is reconstructed. e.g.: SPS
private String queryExpr;
private String opName;
private boolean recompileQuery;
-
+
+ /**
+ * <p>
+ * An object representing the {@code BigDecimal.toPlainString()} method
+ * if it's available on the platform. If it's not available, this field
+ * will be initialized to {@code null}, and in that case the
+ * {@code BigDecimal.toString()} method should be used instead without
+ * reflection.
+ * </p>
+ *
+ * <p>
+ * The behaviour of the {@code toString()} method changed when
+ * {@code toPlainString()} was introduced in Java SE 5. On older
+ * platforms, it behaves just like {@code toPlainString()} does on
+ * newer platforms. So when {@code toPlainString()} is not
+ * available, it is safe to fall back to {@code toString()}. It
+ * behaves differently on newer platforms, so we need to use
+ * {@code toPlainString()} when it is available in order to get
+ * consistent behaviour across all platforms.
+ * </p>
+ *
+ * @see #numberToString(double)
+ */
+ private static final Method TO_PLAIN_STRING;
+ static {
+ Method m = null;
+ try {
+ m = BigDecimal.class.getMethod("toPlainString", new Class[0]);
+ } catch (NoSuchMethodException nsme) {
+ // Couldn't find the method, so we'll just fall back to toString()
+ // on this platform.
+ }
+ TO_PLAIN_STRING = m;
+ }
+
/**
* Constructor: Initializes objects required for parsing
* and serializing XML values. Since most XML operations
@@ -256,18 +288,17 @@ public class SqlXmlUtil implements Forma
try {
/* The following XPath constructor compiles the expression
- * as part of the construction process. We have to pass
- * in a PrefixResolver object in order to avoid NPEs when
- * invalid/unknown functions are used, so we just create
- * a dummy one, which means prefixes will not be resolved
+ * as part of the construction process. We pass a null
+ * namespace resolver object so that the implementation will
+ * provide one for us, which means prefixes will not be resolved
* in the query (Xalan will just throw an error if a prefix
* is used). In the future we may want to revisit this
* to make it easier for users to query based on namespaces.
*/
- query = new XPath(queryExpr, null,
- new PrefixResolverDefault(dBuilder.newDocument()),
- XPath.SELECT);
-
+ XPathEvaluator eval = (XPathEvaluator)
+ dBuilder.getDOMImplementation().getFeature("+XPath", "3.0");
+ query = eval.createExpression(queryExpr, null);
+
this.queryExpr = queryExpr;
this.opName = opName;
this.recompileQuery = false;
@@ -381,12 +412,13 @@ public class SqlXmlUtil implements Forma
* normalized sequence created from the items in the received
* list.
*/
- protected String serializeToString(ArrayList items,
- XMLDataValue xmlVal) throws java.io.IOException
+ protected String serializeToString(List items,
+ XMLDataValue xmlVal) throws TransformerException
{
- if ((items == null) || (items.size() == 0))
+ if ((items == null) || items.isEmpty()) {
// nothing to do; return empty sequence.
return "";
+ }
java.io.StringWriter sWriter = new java.io.StringWriter();
@@ -397,9 +429,6 @@ public class SqlXmlUtil implements Forma
"Tried to serialize with uninitialized XML serializer.");
}
- serializer.setWriter(sWriter);
- DOMSerializer dSer = serializer.asDOMSerializer();
-
int sz = items.size();
Object obj = null;
@@ -473,7 +502,8 @@ public class SqlXmlUtil implements Forma
*/
if (xmlVal != null)
xmlVal.markAsHavingTopLevelAttr();
- dSer.serialize((Node)obj);
+ serializer.transform(
+ new DOMSource((Node) obj), new StreamResult(sWriter));
lastItemWasString = false;
}
else
@@ -507,7 +537,8 @@ public class SqlXmlUtil implements Forma
* "serialized" as an atomic value, attribute, or
* text node.
*/
- dSer.serialize(n);
+ serializer.transform(
+ new DOMSource(n), new StreamResult(sWriter));
}
lastItemWasString = false;
@@ -555,7 +586,7 @@ public class SqlXmlUtil implements Forma
* @exception Exception thrown on error (and turned into a
* StandardException by the caller).
*/
- protected ArrayList evalXQExpression(XMLDataValue xmlContext,
+ protected List evalXQExpression(XMLDataValue xmlContext,
boolean returnResults, int [] resultXType) throws Exception
{
// if this object is in an SPS, we need to recompile the query
@@ -567,7 +598,7 @@ public class SqlXmlUtil implements Forma
// Make sure we have a compiled query.
if (SanityManager.DEBUG) {
SanityManager.ASSERT(
- (query != null) && (query.getExpression() != null),
+ (query != null),
"Failed to locate compiled XML query expression.");
}
@@ -592,64 +623,74 @@ public class SqlXmlUtil implements Forma
new StringReader(xmlContext.getString())));
// Evaluate the expresion using Xalan.
- getXPathContext();
- xpContext.reset();
- XObject xOb = query.execute(xpContext, docNode, null);
+ XPathResult result = (XPathResult)
+ query.evaluate(docNode, XPathResult.ANY_TYPE, null);
if (!returnResults)
{
// We don't want to return the actual results, we just
// want to know if there was at least one item in the
// result sequence.
- if ((xOb instanceof XNodeSet) &&
- (((XNodeSet)xOb).nodelist().getLength() > 0))
- { // If we have a sequence (XNodeSet) of length greater
- // than zero, then we know that at least one item
- // "exists" in the result so return a non-null list.
- return new ArrayList(0);
- }
- else if (!(xOb instanceof XNodeSet))
- // we have a single atomic value, which means the result is
- // non-empty. So return a non-null list.
- return new ArrayList(0);
- else {
- // return null; caller will take this to mean we have an
- // an empty sequence.
- return null;
+ switch (result.getResultType()) {
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ if (result.iterateNext() == null) {
+ // We have an empty sequence, so return null.
+ return null;
+ } else {
+ // We have a non-empty sequence, so return a non-null
+ // list to indicate that we found at least one item.
+ return Collections.EMPTY_LIST;
+ }
+ default:
+ // We have a single atomic value, which means the result is
+ // non-empty. So return a non-null list.
+ return Collections.EMPTY_LIST;
}
}
// Else process the results.
- NodeList nodeList = null;
- int numItems = 0;
- if (!(xOb instanceof XNodeSet))
- // then we only have a single (probably atomic) item.
- numItems = 1;
- else {
- nodeList = xOb.nodelist();
- numItems = nodeList.getLength();
- }
-
- // Return a list of the items contained in the query results.
- ArrayList itemRefs = new ArrayList();
- if (nodeList == null)
- // result is a single, non-node value (ex. it's an atomic number);
- // in this case, just take the string value.
- itemRefs.add(xOb.str());
- else {
- for (int i = 0; i < numItems; i++)
- itemRefs.add(nodeList.item(i));
+ List itemRefs;
+ switch (result.getResultType()) {
+ case XPathResult.NUMBER_TYPE:
+ // Single atomic number. Get its string value.
+ String val = numberToString(result.getNumberValue());
+ itemRefs = Collections.singletonList(val);
+ break;
+ case XPathResult.STRING_TYPE:
+ // Single atomic string value.
+ itemRefs = Collections.singletonList(result.getStringValue());
+ break;
+ case XPathResult.BOOLEAN_TYPE:
+ // Single atomic boolean. Get its string value.
+ itemRefs = Collections.singletonList(
+ String.valueOf(result.getBooleanValue()));
+ break;
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ // We have a sequence. Get all nodes.
+ itemRefs = new ArrayList();
+ Node node;
+ while ((node = result.iterateNext()) != null) {
+ itemRefs.add(node);
+ }
+ break;
+ default:
+ if (SanityManager.DEBUG) {
+ SanityManager.THROWASSERT(
+ "Don't know how to handle XPath result type " +
+ result.getResultType());
+ }
+ itemRefs = null;
}
- nodeList = null;
-
/* Indicate what kind of XML result value we have. If
* we have a sequence of exactly one Document then it
* is XMLPARSE-able and so we consider it to be of type
* XML_DOC_ANY (which means we can store it in a Derby
* XML column).
*/
- if ((numItems == 1) && (itemRefs.get(0) instanceof Document))
+ if ((itemRefs.size() == 1) && (itemRefs.get(0) instanceof Document))
resultXType[0] = XML.XML_DOC_ANY;
else
resultXType[0] = XML.XML_SEQUENCE;
@@ -662,26 +703,14 @@ public class SqlXmlUtil implements Forma
* */
/**
- * Create and return an instance of Xalan's XPathContext
- * that can be used to compile an XPath expression.
- */
- private XPathContext getXPathContext()
- {
- if (xpContext == null)
- xpContext = new XPathContext();
-
- return xpContext;
- }
-
- /**
* Create an instance of Xalan serializer for the sake of
* serializing an XML value according the SQL/XML specification
* for serialization.
*/
- private void loadSerializer() throws java.io.IOException
+ private void loadSerializer() throws TransformerConfigurationException
{
// Set serialization properties.
- Properties props = OutputProperties.getDefaultMethodProperties("xml");
+ Properties props = new Properties();
// SQL/XML[2006] 10.15:General Rules:6 says method is "xml".
props.setProperty(OutputKeys.METHOD, "xml");
@@ -718,10 +747,62 @@ public class SqlXmlUtil implements Forma
props.setProperty(OutputKeys.ENCODING, "UTF-8");
// Load the serializer with the correct properties.
- serializer = SerializerFactory.getSerializer(props);
+ serializer = TransformerFactory.newInstance().newTransformer();
+ serializer.setOutputProperties(props);
return;
}
+ /**
+ * Convert a number returned by an XPath query to a string, following the
+ * rules for the <a href="http://www.w3.org/TR/xpath/#function-string">
+ * XPath string function</a>.
+ *
+ * @param d {@code double} representation of the number
+ * @return {@code String} representation of the number
+ */
+ private static String numberToString(double d)
+ throws IllegalAccessException, InvocationTargetException {
+ if (Double.isNaN(d) || Double.isInfinite(d)) {
+ // BigDecimal doesn't know how to handle NaN or +/- infinity, so
+ // use Double to handle those cases.
+ return Double.toString(d);
+ } else {
+ // Otherwise, use BigDecimal to format the number the way we want.
+ // Ideally, we'd just return
+ // BigDecimal.valueOf(d).stripTrailingZeros().toPlainString(),
+ // but valueOf(double), stripTrailingZeros() and toPlainString()
+ // were all introduced in Java 5, and we still need to support
+ // older platforms.
+ BigDecimal dec = new BigDecimal(Double.toString(d));
+
+ // See how many trailing zeros we have after the decimal point.
+ long unscaledValue = dec.unscaledValue().longValue();
+ int scale = dec.scale();
+ while (scale > 0 && unscaledValue % 10 == 0) {
+ scale--;
+ unscaledValue /= 10;
+ }
+
+ // If we have trailing zeros after the decimal point, remove them.
+ if (scale != dec.scale()) {
+ dec = BigDecimal.valueOf(unscaledValue, scale);
+ }
+
+ // Finally, convert the value to a string. The method
+ // BigDecimal.toPlainString() formats the number the way we want
+ // it, but it's only available on Java 5 and later. Luckily, on
+ // older platforms, BigDecimal.toString() is defined the same way
+ // as toPlainString(), so we can fall back to that method if
+ // toPlainString() isn't available. toString() was redefined in
+ // Java 5, so we cannot use toString() unconditionally, however.
+ if (TO_PLAIN_STRING == null) {
+ return dec.toString();
+ } else {
+ return (String) TO_PLAIN_STRING.invoke(dec, (Object[]) null);
+ }
+ }
+ }
+
/* ****
* Formatable interface implementation
* */
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java Wed Feb 23 18:28:10 2011
@@ -33,10 +33,6 @@ import org.apache.derby.iapi.services.lo
import org.apache.derby.iapi.services.sanity.SanityManager;
import org.apache.derby.iapi.sql.conn.ConnectionUtil;
-import org.apache.derby.iapi.types.DataValueDescriptor;
-import org.apache.derby.iapi.types.StringDataValue;
-import org.apache.derby.iapi.types.BooleanDataValue;
-
import org.apache.derby.iapi.reference.SQLState;
import java.sql.ResultSet;
@@ -48,9 +44,9 @@ import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectInput;
-import java.io.StringReader;
+import java.lang.reflect.Method;
-import java.util.ArrayList;
+import java.util.List;
/**
* This type implements the XMLDataValue interface and thus is
@@ -867,7 +863,7 @@ public class XML
// Return an XML data value whose contents are the
// serialized version of the query results.
int [] xType = new int[1];
- ArrayList itemRefs = sqlxUtil.evalXQExpression(
+ List itemRefs = sqlxUtil.evalXQExpression(
this, true, xType);
if (result == null)
@@ -995,7 +991,8 @@ public class XML
* provided as part the JVM if it is jdk 1.4 or
* greater.
*/
- if (!ClassInspector.classIsLoadable("org.w3c.dom.Document"))
+ Object docImpl = checkJAXPRequirement();
+ if (docImpl == null)
xmlReqCheck = "JAXP";
/* If the XPath class exists, then we assume that our XML
@@ -1007,8 +1004,8 @@ public class XML
* point in checking for Xalan unless we've already confirmed
* that we have the JAXP interfaces.
*/
- else if (!ClassInspector.classIsLoadable("org.apache.xpath.XPath"))
- xmlReqCheck = "Xalan";
+ else if (!checkXPathRequirement(docImpl))
+ xmlReqCheck = "XPath 3.0";
}
if (xmlReqCheck.length() != 0)
@@ -1020,4 +1017,60 @@ public class XML
return;
}
+ /**
+ * Check if we have a JAXP implementation installed.
+ *
+ * @return a {@code DOMImplementation} object retrieved from the
+ * JAXP implementation, if one is installed, or {@code null} if an
+ * implementation couldn't be found
+ */
+ private static Object checkJAXPRequirement() {
+ try {
+ Class factoryClass =
+ Class.forName("javax.xml.parsers.DocumentBuilderFactory");
+ Method newFactory = factoryClass.getMethod(
+ "newInstance", new Class[0]);
+ Method newBuilder = factoryClass.getMethod(
+ "newDocumentBuilder", new Class[0]);
+
+ Class builderClass =
+ Class.forName("javax.xml.parsers.DocumentBuilder");
+ Method getImpl = builderClass.getMethod(
+ "getDOMImplementation", new Class[0]);
+
+ Object factory = newFactory.invoke(null, new Object[0]);
+ Object builder = newBuilder.invoke(factory, new Object[0]);
+ Object impl = getImpl.invoke(builder, new Object[0]);
+
+ return impl;
+
+ } catch (Throwable t) {
+ // Oops... Couldn't get a DOMImplementation object for
+ // some reason. Assume we don't have JAXP.
+ return null;
+ }
+ }
+
+ /**
+ * Check if the supplied {@code DOMImplementation} object has
+ * support for DOM Level 3 XPath.
+ *
+ * @param domImpl the {@code DOMImplementation} instance to check
+ * @return {@code true} if the required XPath level is supported,
+ * {@code false} otherwise
+ */
+ private static boolean checkXPathRequirement(Object domImpl) {
+ try {
+ Class domImplClass = Class.forName("org.w3c.dom.DOMImplementation");
+ Method getFeature = domImplClass.getMethod(
+ "getFeature", new Class[] {String.class, String.class});
+ Object impl =
+ getFeature.invoke(domImpl, new Object[] {"+XPath", "3.0"});
+ return impl != null;
+ } catch (Throwable t) {
+ // Oops... Something went wrong when checking for XPath
+ // 3.0 support. Assume we don't have it.
+ return false;
+ }
+ }
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml Wed Feb 23 18:28:10 2011
@@ -52,7 +52,7 @@
srcdir="${derby.engine.src.dir}"
destdir="${out.dir}">
<classpath>
- <pathelement path="${java14compile.classpath};${xercesImpl}"/>
+ <pathelement path="${xmlApis};${java14compile.classpath}"/>
</classpath>
<include name="${derby.dir}/iapi/types/SqlXmlUtil.java"/>
</javac>
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLMissingClassesTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLMissingClassesTest.java?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLMissingClassesTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLMissingClassesTest.java Wed Feb 23 18:28:10 2011
@@ -22,7 +22,6 @@ package org.apache.derbyTesting.function
import junit.framework.Test;
import junit.framework.TestSuite;
-import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.XML;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.TestConfiguration;
@@ -73,17 +72,11 @@ public final class XMLMissingClassesTest
* for use of Derby SQL/XML operators, then just return
* an empty suite (the operators are tested in a different
* JUnit test--namely XMLTypeAndOpTests.java).
- *
- * NOTE: We do not want to run this test if it has Xalan
- * but the version of Xalan is not the minimum required.
- * Attempts to do so can lead to unexpected errors (which
- * is why we have a "minimum Xalan version" to begin with;
- * see JDBC.checkXalanVersion()).
*/
public static Test suite()
{
TestSuite suite = new TestSuite("XML Missing Classes Suite");
- if (!XML.classpathHasXalanAndJAXP())
+ if (!XML.classpathMeetsXMLReqs())
{
// Run this test in embedded and client modes.
suite.addTest(TestConfiguration.defaultSuite(
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/EnvTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/EnvTest.java?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/EnvTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/EnvTest.java Wed Feb 23 18:28:10 2011
@@ -68,7 +68,7 @@ public class EnvTest extends TestCase {
** XML related tests
*/
public void testClasspathHasXalanAndJAXP() {
- setName(XML.classpathHasXalanAndJAXP() + "_classpathHasXalanAndJAXP");
+ setName(XML.classpathHasJAXP() + "_classpathHasJAXP");
}
public void testClasspathMeetsXMLReqs() {
setName(XML.classpathMeetsXMLReqs() + "_classpathMeetsXMLReqs");
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java Wed Feb 23 18:28:10 2011
@@ -20,8 +20,6 @@
package org.apache.derbyTesting.junit;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
@@ -31,8 +29,6 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
-import java.util.StringTokenizer;
-
import junit.framework.Assert;
/**
@@ -72,15 +68,6 @@ import junit.framework.Assert;
* </ul>
*/
public class XML {
-
- /**
- * Minimum version of Xalan required to run XML tests under
- * Security Manager. In this case, we're saying that the
- * minimum version is Xalan 2.5.0 (because there's a bug
- * in earlier versions that causes problems with security
- * manager).
- */
- private static int [] MIN_XALAN_VERSION = new int [] { 2, 5, 0 };
/**
* Determine whether or not the classpath with which we're
@@ -92,26 +79,17 @@ public class XML {
/**
* Determine whether or not the classpath with which we're
- * running has a version of Xalan in it. Xalan is required
- * for use of the Derby XML operators. In particular we
- * check for:
- *
- * 1. Xalan classes (version doesn't matter here)
- * 2. The Xalan "EnvironmentCheck" class, which is included
- * as part of Xalan. This allows us to check the specific
- * version of Xalan in use so that we can determine if
- * if we satisfy the minimum requirement.
+ * running has a JAXP implementation.
*/
- private static final boolean HAVE_XALAN =
- JDBC.haveClass("org.apache.xpath.XPath") &&
- JDBC.haveClass("org.apache.xalan.xslt.EnvironmentCheck");
+ private static final boolean HAVE_JAXP_IMPL =
+ HAVE_JAXP && checkJAXPImplementation();
/**
- * Determine if we have the minimum required version of Xalan
+ * Determine if we have support for DOM level 3 XPath, which is required
* for successful use of the XML operators.
*/
- private static final boolean HAVE_MIN_XALAN
- = HAVE_XALAN && checkXalanVersion();
+ private static final boolean HAVE_XPATH_LEVEL_3
+ = HAVE_JAXP_IMPL && checkXPathSupport();
/**
* The filepath for the directory that holds the XML "helper" files
@@ -122,23 +100,24 @@ public class XML {
/**
* Return true if the classpath contains JAXP and
+ * an implementation of the JAXP interfaces, for example the
* Xalan classes (this method doesn't care about
- * the particular version of Xalan).
+ * support for DOM level 3 XPath).
*/
- public static boolean classpathHasXalanAndJAXP()
+ public static boolean classpathHasJAXP()
{
- return HAVE_JAXP && HAVE_XALAN;
+ return HAVE_JAXP_IMPL;
}
/**
* Return true if the classpath meets all of the requirements
* for use of the SQL/XML operators. This means that all
- * required classes exist in the classpath AND the version
- * of Xalan that we found is at least MIN_XALAN_VERSION.
+ * required classes exist in the classpath AND there is support
+ * for DOM level 3 XPath.
*/
public static boolean classpathMeetsXMLReqs()
{
- return HAVE_JAXP && HAVE_MIN_XALAN;
+ return HAVE_XPATH_LEVEL_3;
}
/**
@@ -265,157 +244,79 @@ public class XML {
}
/**
+ * <p>
* Determine whether or not the classpath with which we're
- * running has a version of Xalan that meets the minimum
- * Xalan version requirement. We do that by using a Java
- * utility that ships with Xalan--namely, "EnvironmentCheck"--
- * and by parsing the info gathered by that method to find
- * the Xalan version. We use reflection when doing this
- * so that this file will compile/execute even if XML classes
- * are missing.
+ * running contains a JAXP implementation that supports
+ * DOM level 3 XPath.
+ * </p>
*
+ * <p>
* Assumption is that we only get to this method if we already
- * know that there *is* a version of Xalan in the classpath
- * and that version includes the "EnvironmentCheck" class.
- *
- * Note that this method returns false if the call to Xalan's
- * EnvironmentCheck.checkEnvironment() returns false for any
- * reason. As a specific example, that method will always
- * return false when running with ibm131 because it cannot
- * find the required methods on the SAX 2 classes (apparently
- * the classes in ibm131 jdk don't have all of the methods
- * required by Xalan). Thus this method will always return
- * "false" for ibm131.
+ * know that there *is* an implementation of JAXP in the classpath.
+ * </p>
*/
- private static boolean checkXalanVersion()
+ private static boolean checkXPathSupport()
{
- boolean haveMinXalanVersion = false;
+ boolean supportsXPath;
+
+ // Invoke the following using reflection to see if we have support
+ // for DOM level 3 XPath:
+ //
+ // DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ // .getDOMImplementation().getFeature("+XPath", "3.0");
+ //
try {
+ Class factoryClass =
+ Class.forName("javax.xml.parsers.DocumentBuilderFactory");
- // These io objects allow us to retrieve information generated
- // by the call to EnvironmenCheck.checkEnvironment()
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- PrintWriter pW = new PrintWriter(bos);
-
- // Call the method using reflection.
-
- Class cl = Class.forName("org.apache.xalan.xslt.EnvironmentCheck");
- Method meth = cl.getMethod("checkEnvironment",
- new Class[] { PrintWriter.class });
-
- Boolean boolObj = (Boolean)meth.invoke(
- cl.newInstance(), new Object [] { pW });
-
- pW.flush();
- bos.flush();
-
- cl = null;
- meth = null;
- pW = null;
-
- /* At this point 'bos' holds a list of properties with
- * a bunch of environment information. The specific
- * property we're looking for is "version.xalan2_2",
- * so get that property, parse the value, and see
- * if the version is at least the minimum required.
- */
- if (boolObj.booleanValue())
- {
- /* We wrote the byte array using the platform's default
- * encodinging (that's what we get with the call to
- * "new PrintWriter(bos)" above), so read it in using
- * the default encoding, as well (i.e. don't pass an
- * encoding into toString()).
- */
- String checkEnvOutput = bos.toString();
- bos.close();
-
- /* The property we're looking for is on a single line
- * of the output, and that line starts with the name
- * of the property. So extract that line out now. If
- * we can't find it, just return "false" to say that
- * we could not find the minimum version. Note: it's
- * possible (though admittedly unlikely) that the
- * string "version.xalan2_2" appears in the user's
- * classpath. Adding an equals sign ("=") at the end
- * of our search pattern reduces the chance of the
- * search string appearing in the classpath, but does
- * not eliminate it...
- */
- int pos = checkEnvOutput.indexOf("version.xalan2_2=");
- if (pos < 0)
- return false;
-
- String ver = checkEnvOutput.substring(
- pos, checkEnvOutput.indexOf("\n", pos));
-
- // Now pull out the one we need.
- haveMinXalanVersion = (ver != null);
- if (haveMinXalanVersion)
- {
- /* We found the property, so parse out the necessary
- * piece. The value is of the form:
- *
- * <productName> Major.minor.x
- *
- * Ex:
- *
- * version.xalan2_2=Xalan Java 2.5.1
- * version.xalan2_2=XSLT4J Java 2.6.6
- */
- int i = 0;
- StringTokenizer tok = new StringTokenizer(ver, ". ");
- while (tok.hasMoreTokens())
- {
- String str = tok.nextToken().trim();
- if (Character.isDigit(str.charAt(0)))
- {
- int val = Integer.valueOf(str).intValue();
- if (val < MIN_XALAN_VERSION[i])
- {
- haveMinXalanVersion = false;
- break;
- }
- i++;
- }
-
- /* If we've checked all parts of the min version,
- * then we assume we're okay. Ex. "2.5.0.2"
- * is considered greater than "2.5.0".
- */
- if (i >= MIN_XALAN_VERSION.length)
- break;
- }
-
- /* If the value had fewer parts than the
- * mininum version, then it doesn't meet
- * the requirement. Ex. "2.5" is considered
- * to be a lower version than "2.5.0".
- */
- if (i < MIN_XALAN_VERSION.length)
- haveMinXalanVersion = false;
- }
- }
-
- /* Else the call to checkEnvironment() returned "false",
- * which means it couldn't find all of the classes/methods
- * required for Xalan to function. So in that case we'll
- * fall through and just return false, as well.
- */
+ Method newFactory =
+ factoryClass.getMethod("newInstance", new Class[0]);
- } catch (Throwable t) {
+ Object factory = newFactory.invoke(null, new Object[0]);
+
+ Method newBuilder = factoryClass.getMethod(
+ "newDocumentBuilder", new Class[0]);
+
+ Object builder = newBuilder.invoke(factory, new Object[0]);
+
+ Class builderClass =
+ Class.forName("javax.xml.parsers.DocumentBuilder");
+
+ Method getImpl = builderClass.getMethod(
+ "getDOMImplementation", new Class[0]);
- System.out.println("Unexpected exception while " +
- "trying to find Xalan version:");
- t.printStackTrace(System.err);
+ Object impl = getImpl.invoke(builder, new Object[0]);
+ Class domImplClass = Class.forName("org.w3c.dom.DOMImplementation");
+
+ Method getFeature = domImplClass.getMethod(
+ "getFeature", new Class[] {String.class, String.class});
+
+ Object ret =
+ getFeature.invoke(impl, new Object[] {"+XPath", "3.0"});
+
+ supportsXPath = (ret != null);
+
+ } catch (Throwable t) {
// If something went wrong, assume we don't have the
// necessary classes.
- haveMinXalanVersion = false;
-
+ supportsXPath = false;
}
- return haveMinXalanVersion;
+ return supportsXPath;
+ }
+
+ private static boolean checkJAXPImplementation() {
+ try {
+ Class factoryClass =
+ Class.forName("javax.xml.parsers.DocumentBuilderFactory");
+ Method newFactory =
+ factoryClass.getMethod("newInstance", new Class[0]);
+ Object factory = newFactory.invoke(null, new Object[0]);
+ return factory != null;
+ } catch (Throwable t) {
+ return false;
+ }
}
/**
@@ -436,7 +337,7 @@ public class XML {
* parser in the classpath, the result for J2ME would be
* be a NoClassDefFound error (DERBY-2153).
*/
- if (!classpathHasXalanAndJAXP())
+ if (!classpathHasJAXP())
return null;
return JAXPFinder.getJAXPParserLocation();
Modified: db/derby/code/trunk/tools/ant/properties/extrapath.properties
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/tools/ant/properties/extrapath.properties?rev=1073874&r1=1073873&r2=1073874&view=diff
==============================================================================
--- db/derby/code/trunk/tools/ant/properties/extrapath.properties (original)
+++ db/derby/code/trunk/tools/ant/properties/extrapath.properties Wed Feb 23 18:28:10 2011
@@ -23,6 +23,7 @@ jcc_l=${javatools.dir}/db2jcc_license_c.
osgi=${out.felix.dir}
xercesImpl=${javatools.dir}/xercesImpl.jar
xalan=${javatools.dir}/xalan.jar
+xmlApis=${javatools.dir}/xml-apis.jar
serializer=${javatools.dir}/serializer.jar
javacc=${javatools.dir}/javacc.jar
junit=${javatools.dir}/junit.jar