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 bp...@apache.org on 2006/08/11 07:06:29 UTC
svn commit: r430670 - in /db/derby/code/trunk/java/engine/org/apache/derby:
iapi/services/loader/ClassInspector.java iapi/types/SqlXmlUtil.java
iapi/types/XML.java impl/sql/compile/sqlgrammar.jj
Author: bpendleton
Date: Thu Aug 10 22:06:29 2006
New Revision: 430670
URL: http://svn.apache.org/viewvc?rev=430670&view=rev
Log:
DERBY-688: Enhancements to XML functionality toward XPath and XQuery support
This revision contains d688_phase5_v1.patch.
This patch was contributed by Army Brown (qozinx@gmail.com).
The phase 5 patch, d688_phase5_v1.patch, adds code to determine whether or
not the user's classpath has the required XML classes and, if not, to throw
a user-friendly(-ier) error message whenver the user attempts to use any of
the XML operators.
I inquired as to the best way to do this in the following thread:
http://thread.gmane.org/gmane.comp.apache.db.derby.devel/25307/focus=25315
Dan suggested a) looking at the Derby code that loads modules, and
b) adding a new utility method to the ClassInspector class.
I looked at the module-loading code and it ultimately just makes a call to
Class.forName() and ignores a module if that call throws a LinkageError or
a ClassNotFoundException; see the getImplementations() method in
BaseMonitor.java. So based on that I added a utility method to ClassInspector
that does the same thing, except that it just returns "true" if the call
to Class.forName() succeeds and "false" otherwise. I made the new method
static because it doesn't rely on any state specific to ClassInspector and
because it would have taken a good deal of searching for me to figure out
how to instantiate an instance of ClassInspector correctly from within
the XML datatype class.
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/impl/sql/compile/sqlgrammar.jj
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=430670&r1=430669&r2=430670&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 Thu Aug 10 22:06:29 2006
@@ -1083,6 +1083,27 @@
}
/**
+ * 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=430670&r1=430669&r2=430670&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 Thu Aug 10 22:06:29 2006
@@ -89,7 +89,8 @@
* this class's constructor, we can detect early on whether
* some classes (ex. Xalan) are missing, and can throw a friendly
* error up front, instead of a ClassNotFoundException somewhere
- * deeper in the execution codepath.
+ * deeper in the execution codepath. The initial check for the
+ * required XML classes can be found in XML.checkXMLRequirements().
*
* Note that we don't want to put references to XML-specific
* objects directly into XML.java because that class (XML.java) is
@@ -154,7 +155,38 @@
* etc--but that's it; no validation errors will be thrown.
*/
- DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance();
+ DocumentBuilderFactory dBF = null;
+ try {
+
+ dBF = DocumentBuilderFactory.newInstance();
+
+ } catch (Throwable e) {
+
+ /* We assume that if we get an error creating the
+ * DocumentBuilderFactory, it's because there's no
+ * JAXP implementation. This can happen in the
+ * (admittedly unlikely) case where the classpath
+ * contains the JAXP _interfaces_ (ex. via xml-apis.jar)
+ * and the Xalan classes but does not actually
+ * contain a JAXP _implementation_. In that case the
+ * check in XML.checkXMLRequirements() will pass
+ * and this class (SqlXmlUtil) will be instantiated
+ * successfully--which is how we get to this constructor.
+ * But then attempts to create a DocumentBuilderFactory
+ * will fail, bringing us here. Note that we can't
+ * check for a valid JAXP implementation in the
+ * XML.checkXMLRequirements() method because we
+ * always want to allow the XML.java class to be
+ * instantiated, even if the required XML classes
+ * are not present--and that means that it (the
+ * XML class) cannot reference DocumentBuilder nor
+ * any of the JAXP classes directly.
+ */
+ throw StandardException.newException(
+ SQLState.LANG_MISSING_XML_CLASSES, "JAXP");
+
+ }
+
dBF.setValidating(false);
dBF.setNamespaceAware(true);
@@ -165,6 +197,11 @@
// Load serializer for serializing XML into string according
// XML serialization rules.
loadSerializer();
+
+ } catch (StandardException se) {
+
+ // Just rethrow it.
+ throw se;
} catch (Exception e) {
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=430670&r1=430669&r2=430670&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 Thu Aug 10 22:06:29 2006
@@ -29,6 +29,7 @@
import org.apache.derby.iapi.services.io.StreamStorable;
import org.apache.derby.iapi.services.io.Storable;
import org.apache.derby.iapi.services.io.TypedFormat;
+import org.apache.derby.iapi.services.loader.ClassInspector;
import org.apache.derby.iapi.services.sanity.SanityManager;
import org.apache.derby.iapi.types.DataValueDescriptor;
@@ -123,17 +124,11 @@
// Derby string types.
private SQLChar xmlStringValue;
- /**
- Loaded at execution time, this holds XML-related objects
- that were created once during compilation but can be re-used
- for each row in the target result set for the current
- SQL statement. In other words, we create the objects
- once per SQL statement, instead of once per row. In the
- case of XMLEXISTS, one of the "objects" is the compiled
- query expression, which means we don't have to compile
- the expression for each row and thus we save some time.
+ /*
+ * Status variable used to verify that user's classpath contains
+ * required classes for accessing/operating on XML data values.
*/
- private SqlXmlUtil sqlxUtil;
+ private static String xmlReqCheck = null;
/**
* Default constructor.
@@ -292,7 +287,7 @@
* brings us to this method).
*/
if (theValue instanceof XMLDataValue)
- setXType(((XMLDataValue)theValue).getXType());
+ setXType(((XMLDataValue)theValue).getXType());
}
/**
@@ -779,6 +774,71 @@
public int getXType()
{
return xType;
+ }
+
+ /**
+ * See if the required JAXP and Xalan classes are in the
+ * user's classpath. Assumption is that we will always
+ * call this method before instantiating an instance of
+ * SqlXmlUtil, and thus we will never get a ClassNotFound
+ * exception caused by missing JAXP/Xalan classes. Instead,
+ * if either is missing we should throw an informative
+ * error indicating what the problem is.
+ *
+ * NOTE: This method only does the checks necessary to
+ * allow successful instantiation of the SqlXmlUtil
+ * class. Further checks (esp. the presence of a JAXP
+ * _implementation_ in addition to the JAXP _interfaces_)
+ * are performed in the SqlXmlUtil constructor.
+ *
+ * @exception StandardException thrown if the required
+ * classes cannot be located in the classpath.
+ */
+ public static void checkXMLRequirements()
+ throws StandardException
+ {
+ // Only check once; after that, just re-use the result.
+ if (xmlReqCheck == null)
+ {
+ xmlReqCheck = "";
+
+ /* If the w3c Document class exists, then we
+ * assume a JAXP implementation is present in
+ * the classpath. If this assumption is incorrect
+ * then we at least know that the JAXP *interface*
+ * exists and thus we'll be able to instantiate
+ * the SqlXmlUtil class. We can then do a check
+ * for an actual JAXP *implementation* from within
+ * the SqlXmlUtil class (see the constructor of
+ * that class).
+ *
+ * Note: The JAXP API and implementation are
+ * provided as part the JVM if it is jdk 1.4 or
+ * greater.
+ */
+ if (!ClassInspector.classIsLoadable("org.w3c.dom.Document"))
+ xmlReqCheck = "JAXP";
+
+ /* If the XPath class exists, then we assume that our XML
+ * query processor (in this case, Xalan), is present in the
+ * classpath. Note: if JAXP API classes aren't present
+ * then the following check will return false even if the
+ * Xalan classes *are* present; this is because the Xalan
+ * XPath class relies on JAXP, as well. Thus there's no
+ * 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";
+ }
+
+ if (xmlReqCheck.length() != 0)
+ {
+ throw StandardException.newException(
+ SQLState.LANG_MISSING_XML_CLASSES, xmlReqCheck);
+ }
+
+ return;
}
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj?rev=430670&r1=430669&r2=430670&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj Thu Aug 10 22:06:29 2006
@@ -6662,6 +6662,10 @@
{
ValueNode value;
checkVersion(DataDictionary.DD_VERSION_DERBY_10_1, "XML");
+
+ // We only allow XML operations if the classpath has all
+ // of the required external classes (namley, JAXP and Xalan).
+ org.apache.derby.iapi.types.XML.checkXMLRequirements();
}
{
<XMLPARSE> <LEFT_PAREN>