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 ab...@apache.org on 2006/12/07 17:37:59 UTC

svn commit: r483532 - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit: JAXPFinder.java XML.java build.xml

Author: abrown
Date: Thu Dec  7 08:37:58 2006
New Revision: 483532

URL: http://svn.apache.org/viewvc?view=rev&rev=483532
Log:
DERBY-2153:

  1. Create a new JUnit utility file, junit/JAXPFinder.java, that is only
     instantiated when all required XML classes are in the classpath.

  2. Move the import of DocumentBuilderFactory out of junit/XML.java and into
     junit/JAXPFinder.java. This extra level of indirection combined with the
     conditional instantiation of JAXPFinder ensures that we do not attempt to
     instantiate a DocumentBuilderFactory unless we have the necessary JAXP
     classes.

Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JAXPFinder.java   (with props)
Modified:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/build.xml

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JAXPFinder.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JAXPFinder.java?view=auto&rev=483532
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JAXPFinder.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JAXPFinder.java Thu Dec  7 08:37:58 2006
@@ -0,0 +1,122 @@
+/*
+ *
+ * Derby - Class org.apache.derbyTesting.functionTests.util.JAXPFinder
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, 
+ * software distributed under the License is distributed on an 
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
+ * either express or implied. See the License for the specific 
+ * language governing permissions and limitations under the License.
+ */
+package org.apache.derbyTesting.junit;
+
+import java.net.URL;
+import junit.framework.Assert;
+
+/* The following import is of a JAXP API class.  The JAXP API classes
+ * are included within JVMs that are 1.4 and later.  However, 1.3 and
+ * J2ME JVMs do not include the JAXP API classes.  As a result this
+ * file can only be built with 1.4 or later (see build.xml in this
+ * directory).  We have to separate this class out from junit/XML.java
+ * because XML.java will be instantiated for any JUnit test, regardless
+ * of whether or not the the required JAXP classes are in the user's
+ * classpath.  This means that if we imported the JAXP class into
+ * junit/XML.java, a user who tried to run a JUnit test without
+ * the JAXP interface in his/her classpath (which typically means
+ * J2ME is being used) would see a NoClassFoundError. (DERBY-2153).
+ * That's not what we want; instead, all tests that do *not* rely on
+ * JAXP should run as normal and any tests that require JAXP should be
+ * silently skipped.
+ *
+ * To accomplish this goal we import/reference DocumentBuilderFactory 
+ * in *this* class (JAXPFinder). Then we *only* make calls on this
+ * JAXPFinder if we know for certain that all required XML classes
+ * are in the user's classpath.  With this restriction in place we
+ * can ensure that the JAXP class will never be instantiated for
+ * environments which do not have a JAXP parser.  Thus the JUnit
+ * harness will run/skip tests as expected whether or not the user's
+ * classpath includes a JAXP parser.
+ */
+import javax.xml.parsers.DocumentBuilderFactory;
+
+/**
+ * Simple class used for determining the location of the jar 
+ * file (based on the user's classpath) that contains the JAXP
+ * implementation.
+ */
+public class JAXPFinder {
+
+    /**
+     * String form of the URL for the jar file in the user's classpath
+     * that holds the JAXP implementation in use.  If the implementation
+     * is embedded within, or endorsed by, the JVM, then we will set this
+     * field to be an empty string.
+     */
+    private static String jaxpURLString = null;
+    
+    /**
+     * Return the string form of the URL for the jar file that contains
+     * whichever JAXP parser implementation is picked up from the user's
+     * classpath.  If the JAXP parser is not in the user's classpath,
+     * then it must be embedded within the JVM (either implicitly or else
+     * through use of "endorsed standards" jars), in which case we return
+     * null.
+     *
+     * NOTE: Assumption is that we only get here if we know there is in
+     * fact a JAXP parser available to the JVM.  I.e. if a call to
+     * the "classpathHasXalanAndJAXP()" method of junit/XML.java returns
+     * true.
+     */
+    protected static String getJAXPParserLocation()
+    {
+        // Only get the URL if we have not already done it.
+        if (jaxpURLString == null)
+        {
+            /* Figure out which JAXP implementation we have by
+             * instantiating a DocumentBuilderFactory and then getting
+             * the implementation-specific class for that object.
+             * Note that we cannot just use:
+             *
+             *   SecurityManagerSetup.getURL(DocumentBuilderFactory.class)
+             *
+             * because the 1.4, 1.5, and 1.6 JVMs (at least, Sun and IBM)
+             * all embed the JAXP API classes, so any attempts to look
+             * up the URL for DocumentBuilderFactory.class will return
+             * null for those JVMs. But in the case of, say, Sun 1.5, the
+             * JAXP *implementation* classes are not embedded. So if we're
+             * running with Sun 1.5 and we have an external JAXP
+             * implementation (say Xerces) in the classpath, we need to
+             * find the URL for that external jar file. By instantiating
+             * DocumentBuilderFactory and then using the implementation-
+             * specific class name we ensure that, for external (w.r.t the
+             * JVM) JAXP implementations, we can find the implementation
+             * jar file and thus we can assign the correct permissions.
+             */
+            URL jaxpURL = SecurityManagerSetup.getURL(
+                DocumentBuilderFactory.newInstance().getClass());
+
+            /* If we found a URL then the JAXP parser is in the classpath
+             * in some jar external to the JVM; in that case we have the
+             * the jar's location so we use/return that.  Otherwise we
+             * assume that the JAXP parser is either embedded within the
+             * JVM or else "endorsed" by it. In those cases we set our
+             * URL string to be the empty string, which is non-null and
+             * thus we will only execute this try-catch once.
+             */
+            jaxpURLString =
+                (jaxpURL == null) ? "" : jaxpURL.toExternalForm();
+        }
+
+        // If we didn't find the JAXP parser URL, then return null.
+        return ((jaxpURLString.length() == 0) ? null : jaxpURLString);
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JAXPFinder.java
------------------------------------------------------------------------------
    svn:eol-style = native

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?view=diff&rev=483532&r1=483531&r2=483532
==============================================================================
--- 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 Thu Dec  7 08:37:58 2006
@@ -36,14 +36,6 @@
 import java.util.StringTokenizer;
 import java.util.Properties;
 
-/* The following import is for a JDBC 3.0 JAXP class, which means that
- * this file can only be built with 1.4 or later (see build.xml in
- * this directory).  This means that 1.3 JVMs will not be able to
- * instantiate this class--but since 1.3 is deprecated as of 10.3,
- * we do not worry about that here.
- */
-import javax.xml.parsers.DocumentBuilderFactory;
-
 import junit.framework.Assert;
 
 /**
@@ -99,14 +91,6 @@
         "org/apache/derbyTesting/functionTests/tests/lang/xmlTestFiles/";
 
     /**
-     * String form of the URL for the jar file in the user's classpath
-     * that holds the JAXP implementation in use.  If the implementation
-     * is embedded within, or endorsed by, the JVM, then we will set this
-     * field to be an empty string.
-     */
-    private static String jaxpURLString = null;
-
-    /**
      * Return true if the classpath contains JAXP and
      * Xalan classes (this method doesn't care about
      * the particular version of Xalan).
@@ -389,62 +373,20 @@
      * then it must be embedded within the JVM (either implicitly or else
      * through use of "endorsed standards" jars), in which case we return
      * null.
-     *
-     * NOTE: Assumption is that we only get here if we know there is in
-     * fact a JAXP parser available to the JVM.  I.e. if a call to
-     * the "classpathMeetsXMLReqs()" method of this class will return 
-     * true.
      */
     protected static String getJAXPParserLocation()
     {
-        // Only get the URL if we have not already done it.
-        if (jaxpURLString == null)
-        {
-            try {
-
-                /* Figure out which JAXP implementation we have by
-                 * instantiating a DocumentBuilderFactory and then getting
-                 * the implementation-specific class name for that object.
-                 * Note that we cannot just use:
-                 *
-                 *  Class.forName("javax.xml.parsers.DocumentBuilderFactory")
-                 *
-                 * because the constructor for DocumentBuilderFactory (and
-                 * for all JAXP abstract classes) is protected, which means
-                 * Class.forName() cannot instantiate the object.  So we
-                 * explicitly create the object using the JAXP method for
-                 * doing so, and then we pass the object's implementation-
-                 * specific class name to Class.forName() to get the
-                 * appropriate Class.  The Class can then be used for
-                 * retrieval of the URL.
-                 */
-                URL jaxpURL = SecurityManagerSetup.getURL(Class.forName(
-                    DocumentBuilderFactory.newInstance().getClass().getName()));
-
-                /* If we found a URL then the JAXP parser is in the classpath
-                 * in some jar external to the JVM; in that case we have the
-                 * the jar's location so we use/return that.  Otherwise we
-                 * assume that the JAXP parser is either embedded within the
-                 * JVM or else "endorsed" by it. In those cases we set our
-                 * URL string to be the empty string, which is non-null and
-                 * thus we will only execute this try-catch once.
-                 */
-                jaxpURLString =
-                    (jaxpURL == null) ? "" : jaxpURL.toExternalForm();
-
-            } catch (Exception e) {
-
-                /* Probably a ClassNotFoundException.  We assume this
-                 * means that there is no JAXP parser implementation
-                 * in the classpath--but in that case we do not expect
-                 * to get here.
-                 */
-                 Assert.fail("Failed to located JAXP parser.");
-
-            }
-        }
+        /* If the classpath does not have JAXP then we do not want to
+         * instantiate the JAXPFinder class (which happens indirectly
+         * if we call its static methods).  This is because JAXPFinder
+         * references a JAXP class that does not exist for J2ME, so
+         * if we try to call a method on JAXPFinder without a JAXP
+         * parser in the classpath, the result for J2ME would be
+         * be a NoClassDefFound error (DERBY-2153).
+         */
+        if (!classpathHasXalanAndJAXP())
+            return null;
 
-        // If we didn't find the JAXP parser URL, then return null.
-        return ((jaxpURLString.length() == 0) ? null : jaxpURLString);
+        return JAXPFinder.getJAXPParserLocation();
     }
 }

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/build.xml?view=diff&rev=483532&r1=483531&r2=483532
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/build.xml (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/build.xml Thu Dec  7 08:37:58 2006
@@ -55,9 +55,9 @@
  
   <target name="junitcomponents" 
           description="Build Derby JUnit test components">
-    <!-- We only compile junit/XML.java against JDK 1.4 because  -->
-    <!-- it relies on a JAXP class that is part of 1.4 but is    -->
-    <!-- not part of 1.3.                                        -->
+    <!-- We only compile junit/JAXPFinder.java against JDK 1.4   -->
+    <!-- because it relies on a JAXP class that is part of 1.4   -->
+    <!-- but it is not part of 1.3.                              -->
     <javac
       source="1.4"
       target="1.4"
@@ -76,7 +76,7 @@
         <pathelement path="${junit}"/>
         <pathelement path="${xml-apis}"/>
       </classpath>
-	  <include name="${derby.testing.junit.dir}/XML.java"/>
+	  <include name="${derby.testing.junit.dir}/JAXPFinder.java"/>
     </javac>
     <javac
       source="1.3"
@@ -96,7 +96,7 @@
         <pathelement path="${junit}"/>
       </classpath>
       <include name="${derby.testing.junit.dir}/**/*.java"/>
-      <exclude name="${derby.testing.junit.dir}/XML.java"/>
+      <exclude name="${derby.testing.junit.dir}/JAXPFinder.java"/>
     </javac>
   </target>