garyp 00/10/07 20:33:57
Modified: java/src/org/apache/xalan/extensions ExtensionsTable.java
MethodResolver.java
Log:
Implement new extension handling mechanism
Revision Changes Path
1.7 +111 -86
xml-xalan/java/src/org/apache/xalan/extensions/ExtensionsTable.java
Index: ExtensionsTable.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/extensions/ExtensionsTable.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ExtensionsTable.java 2000/10/04 07:49:52 1.6
+++ ExtensionsTable.java 2000/10/08 03:33:56 1.7
@@ -72,17 +72,42 @@
* @see extensions.html.
*/
public Hashtable m_extensionFunctionNamespaces = new Hashtable();
-
+
+ /**
+ * <meta name="usage" content="internal"/>
+ * Primes the new ExtensionsTable object with built-in namespaces.
+ */
+
+ public ExtensionsTable()
+ {
+ // register the java namespace as being implemented by the
+ // xslt-javaclass engine. Note that there's no real code
+ // per se for this extension as the functions carry the
+ // object on which to call etc. and all the logic of breaking
+ // that up is in the xslt-javaclass engine.
+
+ String uri = "http://xml.apache.org/xslt/java";
+ ExtensionHandler fh = new ExtensionHandlerJavaPackage(uri,
"xslt-javaclass", "");
+ addExtensionNamespace(uri, fh);
+ uri = "http://xsl.lotus.com/java";
+ addExtensionNamespace(uri, fh);
+ uri = "http://xml.apache.org/xalan";
+ fh = new ExtensionHandlerJavaClass(uri, "javaclass",
"org.apache.xalan.lib.Extensions");
+ addExtensionNamespace(uri, fh);
+ }
+
+
/**
- * Get an ExtensionNSHandler object that represents the
+ * Get an ExtensionHandler object that represents the
* given namespace.
* @param extns A valid extension namespace.
*/
- public ExtensionNSHandler get(String extns)
+ public ExtensionHandler get(String extns)
{
- return (ExtensionNSHandler)m_extensionFunctionNamespaces.get(extns);
+ return (ExtensionHandler)m_extensionFunctionNamespaces.get(extns);
}
+
/**
* <meta name="usage" content="advanced"/>
* Register an extension namespace handler. This handler provides
@@ -92,25 +117,13 @@
* @param uri the URI for the extension.
* @param extNS the extension handler.
*/
- public void addExtensionNamespace (String uri,
- ExtensionFunctionHandler extNS) {
- m_extensionFunctionNamespaces.put (uri, extNS);
- }
- /**
- * <meta name="usage" content="advanced"/>
- * Register an element extension namespace handler. This handler provides
- * functions for testing whether a function is known within the
- * namespace and also for invoking the functions.
- *
- * @param uri the URI for the extension.
- * @param extNS the extension handler.
- */
- public void addExtensionElementNamespace (String uri,
- ExtensionFunctionHandler extNS) {
- m_extensionFunctionNamespaces.put (uri, extNS);
+ public void addExtensionNamespace(String uri, ExtensionHandler extNS)
+ {
+ m_extensionFunctionNamespaces.put(uri, extNS);
}
+
/**
* Execute the function-available() function.
* @param ns the URI of namespace in which the function is needed
@@ -118,23 +131,30 @@
*
* @return whether the given function is available or not.
*/
+
public boolean functionAvailable (String ns, String funcName)
+ throws org.xml.sax.SAXException
{
boolean isAvailable = false;
if (null != ns)
{
- ExtensionFunctionHandler extNS =
- (ExtensionFunctionHandler)
m_extensionFunctionNamespaces.get (ns);
+ ExtensionHandler extNS = (ExtensionHandler)
m_extensionFunctionNamespaces.get(ns);
+ if (extNS == null)
+ {
+ extNS = makeJavaNamespace(ns);
+ addExtensionNamespace (ns, extNS);
+ }
if (extNS != null)
{
- isAvailable = extNS.isFunctionAvailable (funcName);
+ isAvailable = extNS.isFunctionAvailable(funcName);
}
}
// System.err.println (">>> functionAvailable (ns=" + ns +
// ", func=" + funcName + ") = " + isAvailable);
return isAvailable;
}
-
+
+
/**
* Execute the element-available() function.
* @param ns the URI of namespace in which the function is needed
@@ -142,95 +162,67 @@
*
* @return whether the given function is available or not.
*/
- public boolean elementAvailable (String ns, String funcName)
+
+ public boolean elementAvailable(String ns, String elemName)
+ throws org.xml.sax.SAXException
{
boolean isAvailable = false;
if (null != ns)
{
- ExtensionFunctionHandler extNS =
- (ExtensionFunctionHandler)
m_extensionFunctionNamespaces.get (ns);
+ ExtensionHandler extNS = (ExtensionHandler)
m_extensionFunctionNamespaces.get(ns);
+ if (extNS == null)
+ {
+ extNS = makeJavaNamespace(ns);
+ addExtensionNamespace (ns, extNS);
+ }
if (extNS != null)
{
- isAvailable = extNS.isElementAvailable (funcName);
+ isAvailable = extNS.isElementAvailable(elemName);
}
}
// System.err.println (">>> elementAvailable (ns=" + ns +
- // ", func=" + funcName + ") = " + isAvailable);
+ // ", elem=" + elemName + ") = " + isAvailable);
return isAvailable;
}
/**
* Handle an extension function.
- * @param ns the URI of namespace in which the function is needed
- * @param funcName the function name being called
- * @param argVec arguments to the function in a vector
+ * @param ns the URI of namespace in which the function is needed
+ * @param funcName the function name being called
+ * @param argVec arguments to the function in a vector
+ * @param methodKey a unique key identifying this function instance in the
+ * stylesheet
+ * @param exprContext a context which may be passed to an extension
function
+ * and provides callback functions to access various
+ * areas in the environment
*
* @return result of executing the function
*/
+
public Object extFunction (String ns, String funcName, Vector argVec,
Object methodKey, ExpressionContext exprContext)
throws org.xml.sax.SAXException
{
- if(null == m_extensionFunctionNamespaces.get
("http://xml.apache.org/xslt/java"))
- {
- // register the java namespace as being implemented by the
- // xslt-javaclass engine. Note that there's no real code
- // per se for this extension as the functions carry the
- // object on which to call etc. and all the logic of breaking
- // that up is in the xslt-javaclass engine.
- String uri = "http://xml.apache.org/xslt/java";
- ExtensionFunctionHandler fh = new ExtensionFunctionHandler (uri, null,
"xslt-javaclass", null, null);
-
- addExtensionNamespace (uri, fh);
- }
- if(null == m_extensionFunctionNamespaces.get
("http://xsl.lotus.com/java"))
- {
- // register the java namespace as being implemented by the
- // xslt-javaclass engine. Note that there's no real code
- // per se for this extension as the functions carry the
- // object on which to call etc. and all the logic of breaking
- // that up is in the xslt-javaclass engine.
- String uri = "http://xsl.lotus.com/java";
- ExtensionFunctionHandler fh = new ExtensionFunctionHandler (uri, null,
"xslt-javaclass", null, null);
-
- addExtensionNamespace (uri, fh);
- }
-
Object result = null;
if (null != ns)
{
- ExtensionFunctionHandler extNS = (ExtensionFunctionHandler)
- m_extensionFunctionNamespaces.get
(ns);
+ ExtensionHandler extNS = (ExtensionHandler)
m_extensionFunctionNamespaces.get(ns);
- // if not found try to auto declare this extension namespace:
- // try treaing the URI of the extension as a fully qualified
- // class name; if it works then go with treating this an extension
- // implemented in "javaclass" for with that class being the srcURL.
- // forget about setting functions in that case - so if u do
- // extension-function-available then u get false, but that's ok.
- if (extNS == null)
+ // If the handler for this extension URI is not found try to auto
declare
+ // this extension namespace:
+
+ if (null == extNS)
{
- try
- {
- // Scott: I don't think this is doing anything for us.
- // String cname = ns.startsWith ("class:") ? ns.substring (6) : ns;
- // Class.forName (cname); // does it load?
- extNS = new ExtensionFunctionHandler (ns, null, "javaclass",
- ns, null);
- addExtensionNamespace (ns, extNS);
- }
- catch (Exception e)
- {
- // oops, it failed .. ok, so this path ain't gonna pan out. shucks.
- }
+ extNS = makeJavaNamespace(ns);
+ addExtensionNamespace (ns, extNS);
}
- if (extNS != null)
+ if (null != extNS)
{
try
{
- result = extNS.callFunction (funcName, argVec, methodKey, null,
exprContext);
+ result = extNS.callFunction(funcName, argVec, methodKey,
exprContext);
}
catch (Exception e)
{
@@ -259,10 +251,43 @@
}
return result;
}
-
+
+
/**
- * The table of extension namespaces.
- * @serial
- */
- // public Hashtable m_extensionNamespaces = new Hashtable();
+ * Declare the appropriate java extension handler.
+ * @param ns the URI of namespace in which the function is needed
+ * @return an ExtensionHandler for this namespace
+ */
+
+ public ExtensionHandler makeJavaNamespace(String ns)
+ throws org.xml.sax.SAXException
+ {
+
+ // First, prepare the name of the actual class or package. We strip
+ // out any leading "class:". Next, we see if there is a /. If so,
+ // only look at anything to the right of the rightmost /.
+ // In the documentation, we state that any classes or packages
+ // declared using this technique must start with xalan://. However,
+ // in this version, we don't enforce that.
+
+ String className = ns;
+ if (className.startsWith("class:"))
+ {
+ className = className.substring(6);
+ }
+
+ int lastSlash = className.lastIndexOf("/");
+ if (-1 != lastSlash)
+ className = className.substring(lastSlash + 1);
+
+ try
+ {
+ Class.forName(className);
+ return new ExtensionHandlerJavaClass(ns, "javaclass", className);
+ }
+ catch (ClassNotFoundException e)
+ {
+ return new ExtensionHandlerJavaPackage(ns, "javapackage", className +
".");
+ }
+ }
}
1.10 +183 -35
xml-xalan/java/src/org/apache/xalan/extensions/MethodResolver.java
Index: MethodResolver.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/extensions/MethodResolver.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- MethodResolver.java 2000/10/04 07:49:53 1.9
+++ MethodResolver.java 2000/10/08 03:33:56 1.10
@@ -2,6 +2,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -11,6 +12,7 @@
import org.apache.xpath.objects.XString;
import org.w3c.xslt.ExpressionContext;
+import org.xml.sax.SAXException;
/**
* Utility class to help resolve method overloading with Xalan XSLT
@@ -18,7 +20,31 @@
*/
public class MethodResolver
{
+
+ /**
+ * Specifies a search for static methods only.
+ */
+ public static final int STATIC_ONLY = 1;
+
+ /**
+ * Specifies a search for instance methods only.
+ */
+ public static final int INSTANCE_ONLY = 2;
+
+ /**
+ * Specifies a search for both static and instance methods.
+ */
+ public static final int STATIC_AND_INSTANCE = 3;
+
/**
+ * Specifies a Dynamic method search. If the method being
+ * evaluated is a static method, all arguments are used.
+ * Otherwise, it is an instance method and only arguments
+ * beginning with the second argument are used.
+ */
+ public static final int DYNAMIC = 4;
+
+ /**
* Given a class, figure out the resolution of
* the Java Constructor from the XSLT argument types, and perform the
* conversion of the arguments.
@@ -36,13 +62,14 @@
ExpressionContext exprContext)
throws NoSuchMethodException,
SecurityException,
- org.xml.sax.SAXException
+ SAXException
{
Constructor bestConstructor = null;
Class[] bestParamTypes = null;
Constructor[] constructors = classObj.getConstructors();
int nMethods = constructors.length;
int bestScore = Integer.MAX_VALUE;
+ int bestScoreCount = 0;
for(int i = 0; i < nMethods; i++)
{
Constructor ctor = constructors[i];
@@ -66,7 +93,7 @@
// System.out.println("Incrementing paramStart: "+paramStart);
}
else
- scoreStart = 100;
+ continue;
}
else
scoreStart = 100;
@@ -76,7 +103,7 @@
// then we have our candidate.
int score = scoreMatch(paramTypes, paramStart, argsIn, scoreStart);
// System.out.println("score: "+score);
- if(-1 == score)
+ if(-1 == score)
continue;
if(score < bestScore)
{
@@ -84,12 +111,20 @@
bestConstructor = ctor;
bestParamTypes = paramTypes;
bestScore = score;
+ bestScoreCount = 1;
}
+ else if (score == bestScore)
+ bestScoreCount++;
}
}
if(null == bestConstructor)
throw new NoSuchMethodException(classObj.getName()); // Should give
more info...
+ /*** This is commented out until we can do a better object -> object
scoring
+ else if (bestScoreCount > 1)
+ throw new SAXException("More than one best match for constructor for "
+ +
classObj.getName());
+ ***/
else
convertParams(argsIn, argsOut, bestParamTypes, exprContext);
@@ -110,13 +145,15 @@
* @exception SAXException may be thrown for Xalan conversion
* exceptions.
*/
- public static Method getMethod(Class classObj, String name,
+ public static Method getMethod(Class classObj,
+ String name,
Object[] argsIn,
Object[][] argsOut,
- ExpressionContext exprContext)
+ ExpressionContext exprContext,
+ int searchMethod)
throws NoSuchMethodException,
SecurityException,
- org.xml.sax.SAXException
+ SAXException
{
// System.out.println("---> Looking for method: "+name);
// System.out.println("---> classObj: "+classObj);
@@ -125,42 +162,69 @@
Method[] methods = classObj.getMethods();
int nMethods = methods.length;
int bestScore = Integer.MAX_VALUE;
+ int bestScoreCount = 0;
+ boolean isStatic;
for(int i = 0; i < nMethods; i++)
{
Method method = methods[i];
// System.out.println("looking at method: "+method);
+ int xsltParamStart = 0;
if(method.getName().equals(name))
{
+ isStatic = Modifier.isStatic(method.getModifiers());
+ switch(searchMethod)
+ {
+ case STATIC_ONLY:
+ if (!isStatic)
+ {
+ continue;
+ }
+ break;
+
+ case INSTANCE_ONLY:
+ if (isStatic)
+ {
+ continue;
+ }
+ break;
+
+ case STATIC_AND_INSTANCE:
+ break;
+
+ case DYNAMIC:
+ if (!isStatic)
+ xsltParamStart = 1;
+ }
+ int javaParamStart = 0;
Class[] paramTypes = method.getParameterTypes();
int numberMethodParams = paramTypes.length;
- int paramStart = 0;
boolean isFirstExpressionContext = false;
int scoreStart;
// System.out.println("numberMethodParams: "+numberMethodParams);
// System.out.println("argsIn.length: "+argsIn.length);
// System.out.println("exprContext: "+exprContext);
int argsLen = (null != argsIn) ? argsIn.length : 0;
- if(numberMethodParams == (argsLen+1))
+ if(numberMethodParams == (argsLen-xsltParamStart+1))
{
Class javaClass = paramTypes[0];
if(org.w3c.xslt.ExpressionContext.class.isAssignableFrom(javaClass))
{
isFirstExpressionContext = true;
scoreStart = 0;
- paramStart++;
+ javaParamStart++;
}
else
{
- scoreStart = 100;
+ continue;
}
}
else
scoreStart = 100;
- if(argsLen == (numberMethodParams - paramStart))
+ if((argsLen - xsltParamStart) == (numberMethodParams -
javaParamStart))
{
// then we have our candidate.
- int score = scoreMatch(paramTypes, paramStart, argsIn, scoreStart);
+ int score = scoreMatch(paramTypes, javaParamStart, argsIn,
scoreStart);
// System.out.println("score: "+score);
if(-1 == score)
continue;
@@ -170,20 +234,98 @@
bestMethod = method;
bestParamTypes = paramTypes;
bestScore = score;
+ bestScoreCount = 1;
}
+ else if (score == bestScore)
+ bestScoreCount++;
}
}
}
- if(null == bestMethod)
+ if (null == bestMethod)
throw new NoSuchMethodException(name); // Should give more info...
+ /*** This is commented out until we can do a better object -> object
scoring
+ else if (bestScoreCount > 1)
+ throw new SAXException("More than one best match for method " + name);
+ ***/
else
convertParams(argsIn, argsOut, bestParamTypes, exprContext);
return bestMethod;
}
+
/**
+ * Given the name of a method, figure out the resolution of
+ * the Java Method
+ * @param classObj The Class of the object that should have the method.
+ * @param name The name of the method to be invoked.
+ * @return A method that will work to be called as an element.
+ * @exception SAXException may be thrown for Xalan conversion
+ * exceptions.
+ */
+ public static Method getElementMethod(Class classObj,
+ String name)
+ throws NoSuchMethodException,
+ SecurityException,
+ SAXException
+ {
+ // System.out.println("---> Looking for element method: "+name);
+ // System.out.println("---> classObj: "+classObj);
+ Method bestMethod = null;
+ Method[] methods = classObj.getMethods();
+ int nMethods = methods.length;
+ int bestScore = Integer.MAX_VALUE;
+ int bestScoreCount = 0;
+ for(int i = 0; i < nMethods; i++)
+ {
+ Method method = methods[i];
+ // System.out.println("looking at method: "+method);
+ if(method.getName().equals(name))
+ {
+ Class[] paramTypes = method.getParameterTypes();
+ if ( (paramTypes.length == 2)
+ && org.w3c.dom.Element.class.isAssignableFrom(paramTypes[1]) )
+ {
+ int score = -1;
+ if (paramTypes[0].isAssignableFrom(
+
org.apache.xalan.extensions.XSLProcessorContext.class))
+ {
+ score = 10;
+ }
+ /*******
+ else if (paramTypes[0].isAssignableFrom(
+
org.apace.xalan.xslt.XSLProcessorContext.class))
+ {
+ score = 5;
+ }
+ ********/
+ else
+ continue;
+
+ if (score < bestScore)
+ {
+ // System.out.println("Assigning best method: "+method);
+ bestMethod = method;
+ bestScore = score;
+ bestScoreCount = 1;
+ }
+ else if (score == bestScore)
+ bestScoreCount++;
+ }
+ }
+ }
+
+ if (null == bestMethod)
+ throw new NoSuchMethodException(name); // Should give more info...
+ else if (bestScoreCount > 1)
+ throw new SAXException("More than one best match for element method "
+ name);
+
+ return bestMethod;
+ }
+
+
+ /**
* Convert a set of parameters based on a set of paramTypes.
* @param argsIn An array of XSLT/XPath arguments.
* @param argsOut An array of the exact size as argsIn, which will be
@@ -199,25 +341,29 @@
throws org.xml.sax.SAXException
{
// System.out.println("In convertParams");
- int nMethods = (null != argsIn) ? argsIn.length : 0;
- int paramIndex = 0;
- if((paramTypes.length > 0)
- &&
org.w3c.xslt.ExpressionContext.class.isAssignableFrom(paramTypes[0]))
- {
- argsOut[0] = new Object[nMethods+1];
- argsOut[0][0] = exprContext;
- // System.out.println("Incrementing paramIndex in convertParams:
"+paramIndex);
- paramIndex++;
- }
+ if (paramTypes == null)
+ argsOut[0] = null;
else
{
- argsOut[0] = (nMethods > 0) ? new Object[nMethods] : null;
- }
+ int nParams = paramTypes.length;
+ argsOut[0] = new Object[nParams];
+ int paramIndex = 0;
+ if((nParams > 0)
+ &&
org.w3c.xslt.ExpressionContext.class.isAssignableFrom(paramTypes[0]))
+ {
+ argsOut[0][0] = exprContext;
+ // System.out.println("Incrementing paramIndex in convertParams:
"+paramIndex);
+ paramIndex++;
+ }
- for(int i = 0; i < nMethods; i++, paramIndex++)
- {
- // System.out.println("paramTypes[i]: "+paramTypes[i]);
- argsOut[0][paramIndex] = convert(argsIn[i], paramTypes[paramIndex]);
+ if (argsIn != null)
+ {
+ for(int i = argsIn.length - nParams + paramIndex ; paramIndex <
nParams; i++, paramIndex++)
+ {
+ // System.out.println("paramTypes[i]: "+paramTypes[i]);
+ argsOut[0][paramIndex] = convert(argsIn[i],
paramTypes[paramIndex]);
+ }
+ }
}
}
@@ -363,7 +509,7 @@
* If any invocations of this function for a method with
* the same name return the same positive value, then a conflict
* has occured, and an error should be signaled.
- * @param javeParamTypes Must be filled with valid class names, and
+ * @param javaParamTypes Must be filled with valid class names, and
* of the same length as xsltArgs.
* @param xsltArgs Must be filled with valid object instances, and
* of the same length as javeParamTypes.
@@ -371,19 +517,21 @@
* that is closer to zero for more preferred, or further from
* zero for less preferred.
*/
- public static int scoreMatch(Class[] javeParamTypes, int paramTypesStart,
+ public static int scoreMatch(Class[] javaParamTypes, int javaParamsStart,
Object[] xsltArgs, int score)
{
- int nParams = (null != xsltArgs) ? xsltArgs.length : 0;
- for(int i = 0, paramTypesIndex = paramTypesStart;
+ if ((xsltArgs == null) || (javaParamTypes == null))
+ return score;
+ int nParams = xsltArgs.length;
+ for(int i = nParams - javaParamTypes.length + javaParamsStart,
javaParamTypesIndex = javaParamsStart;
i < nParams;
- i++, paramTypesIndex++)
+ i++, javaParamTypesIndex++)
{
Object xsltObj = xsltArgs[i];
int xsltClassType = (xsltObj instanceof XObject)
? ((XObject)xsltObj).getType()
: XObject.CLASS_UNKNOWN;
- Class javaClass = javeParamTypes[paramTypesIndex];
+ Class javaClass = javaParamTypes[javaParamTypesIndex];
// System.out.println("Checking xslt: "+xsltObj.getClass().getName()+
// " against java: "+javaClass.getName());