You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by ga...@locus.apache.org on 2000/10/08 05:34:31 UTC

cvs commit: xml-xalan/java/src/org/apache/xalan/extensions ExtensionHandler.java ExtensionHandlerGeneral.java ExtensionHandlerJava.java ExtensionHandlerJavaClass.java ExtensionHandlerJavaPackage.java

garyp       00/10/07 20:34:31

  Added:       java/src/org/apache/xalan/extensions ExtensionHandler.java
                        ExtensionHandlerGeneral.java
                        ExtensionHandlerJava.java
                        ExtensionHandlerJavaClass.java
                        ExtensionHandlerJavaPackage.java
  Log:
  Implement new extension handling mechanism
  
  Revision  Changes    Path
  1.1                  xml-xalan/java/src/org/apache/xalan/extensions/ExtensionHandler.java
  
  Index: ExtensionHandler.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.xalan.extensions;
  
  import java.util.Vector;
  import java.io.IOException;
  
  import org.w3c.xslt.ExpressionContext;
  
  import org.xml.sax.SAXException;
  
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.apache.xalan.templates.Stylesheet;
  import org.apache.xalan.utils.QName;
  
  // Temp??
  import org.apache.xalan.transformer.TransformerImpl;
  
  
  /**
   * <meta name="usage" content="internal"/>
   * Abstract base class for handling an extension namespace for XPath.
   * Provides functions to test a function's existence and call a function.
   * Also provides functions for calling an element and testing for
   * an element's existence.
   *
   * @author Sanjiva Weerawarana (sanjiva@watson.ibm.com)
   */
  
  public abstract class ExtensionHandler 
  {
    protected String m_namespaceUri;  // uri of the extension namespace
    protected String m_scriptLang;    // scripting language of implementation
  
  
    /**
     * Construct a new extension namespace handler given all the information
     * needed.
     * 
     * @param namespaceUri the extension namespace URI that I'm implementing
     * @param scriptLang   language of code implementing the extension
     */
  
    protected ExtensionHandler (String namespaceUri,
                                String scriptLang)
    {
      m_namespaceUri = namespaceUri;
      m_scriptLang   = scriptLang;
    }
  
  
    /**
     * Tests whether a certain function name is known within this namespace.
     * @param function name of the function being tested
     * @return true if its known, false if not.
     */
  
    public abstract boolean isFunctionAvailable (String function);
  
    
    /**
     * Tests whether a certain element name is known within this namespace.
     * @param function name of the function being tested
     * @return true if its known, false if not.
     */
  
    public abstract boolean isElementAvailable (String element);
  
  
    /**
     * Process a call to a function.
     *
     * @param funcName Function name.
     * @param args     The arguments of the function call.
     *
     * @return the return value of the function evaluation.
     *
     * @exception SAXException          if parsing trouble
     */
  
    public abstract Object callFunction (String funcName, 
                                         Vector args, 
                                         Object methodKey, 
                                         ExpressionContext exprContext)
      throws SAXException;
  
  
    /**
     * Process a call to this extension namespace via an element. As a side
     * effect, the results are sent to the TransformerImpl's result tree.
     *
     * @param localPart      Element name's local part.
     * @param element        The extension element being processed.
     * @param transformer      Handle to TransformerImpl.
     * @param stylesheetTree The compiled stylesheet tree.
     * @param mode           The current mode.
     * @param sourceTree     The root of the source tree (but don't assume
     *                       it's a Document).
     * @param sourceNode     The current context node.
     *
     * @exception XSLProcessorException thrown if something goes wrong
     *            while running the extension handler.
     * @exception MalformedURLException if loading trouble
     * @exception FileNotFoundException if loading trouble
     * @exception IOException           if loading trouble
     * @exception SAXException          if parsing trouble
     */
  
    public abstract void processElement(String localPart,
                                        Element element,
                                        TransformerImpl transformer,
                                        Stylesheet stylesheetTree,
                                        Node sourceTree,
                                        Node sourceNode,
                                        QName mode,
                                        Object methodKey)
      throws SAXException, IOException;
  
  }
  
  
  
  1.1                  xml-xalan/java/src/org/apache/xalan/extensions/ExtensionHandlerGeneral.java
  
  Index: ExtensionHandlerGeneral.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.xalan.extensions;
  
  import java.util.Hashtable;
  import java.util.Vector;
  import java.io.IOException;
  
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.apache.xalan.transformer.TransformerImpl;
  import org.apache.xalan.templates.Stylesheet;
  import org.apache.xalan.utils.QName;
  
  import org.w3c.xslt.ExpressionContext;
  
  import org.xml.sax.SAXException;
  
  import com.ibm.bsf.BSFManager;
  import com.ibm.bsf.BSFEngine;
  import com.ibm.bsf.BSFException;
  
  // Temp??
  import org.apache.xalan.transformer.TransformerImpl;
  
  import org.apache.xpath.objects.XObject;
  import org.apache.xpath.XPathProcessorException;
  
  import org.apache.xalan.utils.StringVector;
  
  
  /**
   * <meta name="usage" content="internal"/>
   * Class handling an extension namespace for XPath. Provides functions
   * to test a function's existence and call a function
   *
   * @author Sanjiva Weerawarana (sanjiva@watson.ibm.com)
   */
  
  public class ExtensionHandlerGeneral extends ExtensionHandler
  {
    private String m_scriptSrc;          // script source to run (if any)
    private String m_scriptSrcURL;       // URL of source of script (if any)
    private Hashtable m_functions = new Hashtable ();      // functions of namespace
    private Hashtable m_elements = new Hashtable ();       // elements of namespace
    private BSFManager m_mgr = new BSFManager();    // mgr used to run scripts
    private BSFEngine  m_engine = null;             // engine used 
  
  
    /**
     * Construct a new extension namespace handler given all the information
     * needed. 
     * 
     * @param namespaceUri the extension namespace URI that I'm implementing
     * @param funcNames    string containing list of functions of extension NS
     * @param lang         language of code implementing the extension
     * @param srcURL       value of src attribute (if any) - treated as a URL
     *                     or a classname depending on the value of lang. If
     *                     srcURL is not null, then scriptSrc is ignored.
     * @param scriptSrc    the actual script code (if any)
     */
    public ExtensionHandlerGeneral(String namespaceUri,
                                   StringVector elemNames,
                                   StringVector funcNames, 
                                   String scriptLang,
                                   String scriptSrcURL,
                                   String scriptSrc)
      throws SAXException
    {
      super(namespaceUri, scriptLang);
  
      if (elemNames != null)
      {
        Object junk = new Object();
        int n = elemNames.size();
        for(int i = 0; i < n; i++)
        {
          String tok = elemNames.elementAt(i);
          m_elements.put(tok, junk); // just stick it in there basically
        }
      }
  
      if (funcNames != null)
      {
        Object junk = new Object();
        int n = funcNames.size();
        for(int i = 0; i < n; i++)
        {
          String tok = funcNames.elementAt(i);
          m_functions.put(tok, junk); // just stick it in there basically
        }
      }
  
      m_scriptSrcURL = scriptSrcURL;
      m_scriptSrc = scriptSrc;
  
      if (m_scriptSrcURL != null)
      {
        throw new SAXException("src attribute not yet supported for " + scriptLang);
      }
  
      try
      {
        m_engine = m_mgr.loadScriptingEngine(scriptLang);
        m_engine.exec("XalanScript", -1, -1, m_scriptSrc);	// "Compile" the program
      }
      catch (BSFException e)
      {
        e.printStackTrace();
        throw new SAXException(e);
      }
    }
  
  
    /**
     * Tests whether a certain function name is known within this namespace.
     * @param function name of the function being tested
     * @return true if its known, false if not.
     */
  
    public boolean isFunctionAvailable (String function) 
    {
      return(m_functions.get(function) != null);
    }
  
    
    /**
     * Tests whether a certain element name is known within this namespace.
     * @param function name of the function being tested
     * @return true if its known, false if not.
     */
  
    public boolean isElementAvailable (String element) 
    {
      return(m_elements.get(element) != null);
    }
  
  
    /**
     * Process a call to a function.
     *
     * @param funcName Function name.
     * @param args     The arguments of the function call.
     *
     * @return the return value of the function evaluation.
     *
     * @exception XSLProcessorException thrown if something goes wrong 
     *            while running the extension handler.
     * @exception MalformedURLException if loading trouble
     * @exception FileNotFoundException if loading trouble
     * @exception IOException           if loading trouble
     * @exception SAXException          if parsing trouble
     */
  
    public Object callFunction (String funcName, 
                                Vector args, 
                                Object methodKey, 
                                ExpressionContext exprContext)
      throws SAXException 
    {
  
      Object[] argArray;
  
      try 
      {
         argArray = new Object[args.size()];
  
         for (int i = 0; i < argArray.length; i++) 
         {
            Object o = args.elementAt(i);
            argArray[i] = (o instanceof XObject) ? ((XObject)o).object() : o;
         }
         return m_engine.call (null, funcName, argArray);
      }
      catch (Exception e) 
      {
        e.printStackTrace();
        String msg = e.getMessage();
        if(null != msg)
        {
          if(msg.startsWith("Stopping after fatal error:"))
          {
            msg = msg.substring("Stopping after fatal error:".length());
          }
          // System.out.println("Call to extension function failed: "+msg);
          throw new SAXException (e);
        }
        else
        {
          // Should probably make a TRaX Extension Exception.
          throw new SAXException ("Could not create extension: "+funcName+" because of: "+e);
        }
      }
    }
  
  
    /**
     * Process a call to this extension namespace via an element. As a side
     * effect, the results are sent to the TransformerImpl's result tree.
     *
     * @param localPart      Element name's local part.
     * @param element        The extension element being processed.
     * @param transformer      Handle to TransformerImpl.
     * @param stylesheetTree The compiled stylesheet tree.
     * @param mode           The current mode.
     * @param sourceTree     The root of the source tree (but don't assume
     *                       it's a Document).
     * @param sourceNode     The current context node.
     *
     * @exception XSLProcessorException thrown if something goes wrong
     *            while running the extension handler.
     * @exception MalformedURLException if loading trouble
     * @exception FileNotFoundException if loading trouble
     * @exception IOException           if loading trouble
     * @exception SAXException          if parsing trouble
     */
  
    public void processElement(String localPart,
                               Element element,
                               TransformerImpl transformer,
                               Stylesheet stylesheetTree,
                               Node sourceTree,
                               Node sourceNode,
                               QName mode,
                               Object methodKey)
      throws SAXException, IOException
    {
  
      Object result = null;
      XSLProcessorContext xpc = new XSLProcessorContext (transformer, 
                                                         stylesheetTree,
                                                         sourceTree, 
                                                         sourceNode, 
                                                         mode);
      try
      {
        Vector argv = new Vector(2);
        argv.addElement(xpc);
        argv.addElement(element);
        result = callFunction(localPart,
                              argv,
                              methodKey,
                              transformer.getXPathContext());
      }
      catch (XPathProcessorException e)
      {
        // e.printStackTrace ();
        throw new SAXException (e.getMessage (), e);
      }
  
      if (result != null)
      {
        xpc.outputToResultTree (stylesheetTree, result);
      }
   
   }
  
  }
  
  
  
  1.1                  xml-xalan/java/src/org/apache/xalan/extensions/ExtensionHandlerJava.java
  
  Index: ExtensionHandlerJava.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.xalan.extensions;
  
  import java.util.Hashtable;
  
  /**
   * <meta name="usage" content="internal"/>
   * Abstract base class handling the java language extensions for XPath.
   * This base class provides cache management shared by all of the
   * various java extension handlers.
   *
   */
  
  public abstract class ExtensionHandlerJava extends ExtensionHandler 
  {
  
    protected String m_className = "";
    private Hashtable m_cachedMethods = new Hashtable();
  
  
    /**
     * Construct a new extension handler given all the information
     * needed. 
     * 
     * @param namespaceUri the extension namespace URI that I'm implementing
     * @param funcNames    string containing list of functions of extension NS
     * @param lang         language of code implementing the extension
     * @param srcURL       value of src attribute (if any) - treated as a URL
     *                     or a classname depending on the value of lang. If
     *                     srcURL is not null, then scriptSrc is ignored.
     * @param scriptSrc    the actual script code (if any)
     */
    protected ExtensionHandlerJava(String namespaceUri,
                                   String scriptLang,
                                   String className)
    {
      super(namespaceUri, scriptLang);
      m_className = className;
    }
  
  
    /**
     * Look up the entry in the method cache.
     * @param methodKey   A key that uniquely identifies this invocation in
     *                    the stylesheet.
     * @param objType     A Class object or instance object representing the type
     * @param methodArgs  An array of the XObject arguments to be used for
     *                    function mangling.
     */
  
    public Object getFromCache(Object methodKey,
                               Object objType,
                               Object[] methodArgs)
    {
  
      // Eventually, we want to insert code to mangle the methodKey with methodArgs
  
      return m_cachedMethods.get(methodKey);
    }
  
  
    /**
     * Add a new entry into the method cache.
     * @param methodKey   A key that uniquely identifies this invocation in
     *                    the stylesheet.
     * @param objType     A Class object or instance object representing the type
     * @param methodArgs  An array of the XObject arguments to be used for
     *                    function mangling.
     */
  
    public Object putToCache(Object methodKey,
                           Object objType,
                           Object[] methodArgs,
                           Object methodObj)
    {
  
      // Eventually, we want to insert code to mangle the methodKey with methodArgs
  
      return m_cachedMethods.put(methodKey, methodObj);
    }
  }
  
  
  
  1.1                  xml-xalan/java/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java
  
  Index: ExtensionHandlerJavaClass.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.xalan.extensions;
  
  import java.util.Vector;
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.lang.reflect.Constructor;
  import java.io.IOException;
  
  import org.w3c.xslt.ExpressionContext;
  
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.apache.xalan.transformer.TransformerImpl;
  import org.apache.xalan.templates.Stylesheet;
  import org.apache.xalan.utils.QName;
  
  import org.apache.xpath.objects.XObject;
  import org.xml.sax.SAXException;
  
  /**
   * <meta name="usage" content="internal"/>
   * Class handling the java extension namespace for XPath.
   * This handler is used for namespaces that contain the name of a java class.
   * It is recommended that the class URI be of the form:
   * <pre>
   *   xalan://fully.qualified.class.name
   * </pre>
   * However, we do not enforce this.  If the class name contains a
   * a /, we only use the part to the right of the rightmost slash.
   * In addition, we ignore any "class:" prefix.
   * Provides functions to test a function's existence and call a function.
   *
   */
  
  public class ExtensionHandlerJavaClass extends ExtensionHandlerJava
  {
  
    private Class m_classObj = null;
  
    /**
     * Provides a default Instance for use by elements that need to call 
     * an instance method.
     */
  
    private Object m_defaultInstance = null;
  
  
    /**
     * Construct a new extension namespace handler given all the information
     * needed. 
     * 
     * @param namespaceUri the extension namespace URI that I'm implementing
     * @param scriptLang   language of code implementing the extension
     * @param className    value of src attribute (if any) - treated as a URL
     *                     or a classname depending on the value of lang. If
     *                     srcURL is not null, then scriptSrc is ignored.
     */
    public ExtensionHandlerJavaClass(String namespaceUri,
                                     String scriptLang,
                                     String className)
    {
      super(namespaceUri, scriptLang, className);
      try
      {
        m_classObj = Class.forName(className);
      }
      catch (ClassNotFoundException e)
      {
        // For now, just let this go.  We'll catch it when we try to invoke a method.
      }
    }
  
  
    /**
     * Tests whether a certain function name is known within this namespace.
     * Since this is the generic Java namespace, we simply try to find a
     * method or constructor for the fully qualified class name passed in the
     * argument.  There is no guarantee, of course, that this will actually
     * work at runtime since we may have problems converting the arguments.
     *
     * @param function name of the function being tested
     *
     * @return true if its known, false if not.
     */
  
    public boolean isFunctionAvailable(String function) 
    {
      // TODO:  This function needs to be implemented.
      return true;
    }
  
  
    /**
     * Tests whether a certain element name is known within this namespace.
     * Since this is the generic Java namespace, we simply try to find a
     * method or constructor for the fully qualified class name passed in the
     * argument.  There is no guarantee, of course, that this will actually
     * work at runtime since we may have problems converting the arguments.
     *
     * @param element name of the element being tested
     *
     * @return true if its known, false if not.
     */
  
    public boolean isElementAvailable(String element) 
    {
      // TODO:  This function needs to be implemented.
      return true;
    }
  
  
    /**
     * Process a call to a function in the java class represented by
     * the namespace URI.
     * There are three possible types of calls:
     * <pre>
     *   Constructor:
     *     classns:new(arg1, arg2, ...)
     *
     *   Static method:
     *     classns:method(arg1, arg2, ...)
     *
     *   Instance method:
     *     classns:method(obj, arg1, arg2, ...)
     * </pre>
     * We use the following rules to determine the type of call made:
     * <ol type="1">
     * <li>If the function name is "new", call the best constructor for
     *     class represented by the namespace URI</li>
     * <li>If the first argument to the function is of the class specified
     *     in the namespace or is a subclass of that class, look for the best
     *     method of the class specified in the namespace with the specified
     *     arguments.  Compare all static and instance methods with the correct
     *     method name.  For static methods, use all arguments in the compare.
     *     For instance methods, use all arguments after the first.</li>
     * <li>Otherwise, select the best static or instance method matching
     *     all of the arguments.  If the best method is an instance method,
     *     call the function using a default object, creating it if needed.</li>
     * </ol>
     *
     * @param funcName Function name.
     * @param args     The arguments of the function call.
     *
     * @return the return value of the function evaluation.
     *
     * @exception XSLProcessorException thrown if something goes wrong 
     *            while running the extension handler.
     * @exception MalformedURLException if loading trouble
     * @exception FileNotFoundException if loading trouble
     * @exception IOException           if loading trouble
     * @exception SAXException          if parsing trouble
     */
  
    public Object callFunction (String funcName, 
                                Vector args, 
                                Object methodKey,
                                ExpressionContext exprContext)
      throws SAXException 
    {
  
      Object[] methodArgs;
      Object[][] convertedArgs;
      Class[] paramTypes;
  
      try
      {
        if (funcName.equals("new")) {                   // Handle constructor call
  
          methodArgs = new Object[args.size()];
          convertedArgs = new Object[1][];
          for (int i = 0; i < methodArgs.length; i++)
          {
            methodArgs[i] = args.elementAt(i);
          }
          Constructor c = (Constructor) getFromCache(methodKey, null, methodArgs);
          if (c != null)
          {
            try
            {
              paramTypes = c.getParameterTypes();
              MethodResolver.convertParams(methodArgs, convertedArgs, paramTypes, exprContext);
              return c.newInstance(convertedArgs[0]);
            }
            catch(Exception e)
            {
              // Must not have been the right one
            }
          }
          c = MethodResolver.getConstructor(m_classObj, 
                                            methodArgs,
                                            convertedArgs,
                                            exprContext);
          putToCache(methodKey, null, methodArgs, c);
          return c.newInstance(convertedArgs[0]);
        }
  
        else
        {
  
          int resolveType;
          Object targetObject = null;
          methodArgs = new Object[args.size()];
          convertedArgs = new Object[1][];
          for (int i = 0; i < methodArgs.length; i++)
          {
            methodArgs[i] = args.elementAt(i);
          }
          Method m = (Method) getFromCache(methodKey, null, methodArgs);
          if (m != null)
          {
            try
            {
              paramTypes = m.getParameterTypes();
              MethodResolver.convertParams(methodArgs, convertedArgs, paramTypes, exprContext);
              if (Modifier.isStatic(m.getModifiers()))
                return m.invoke(null, convertedArgs[0]);
              else
              {
                // This is tricky.  We get the actual number of target arguments (excluding any
                //   ExpressionContext).  If we passed in the same number, we need the implied object.
                int nTargetArgs = convertedArgs[0].length;
                if (org.w3c.xslt.ExpressionContext.class.isAssignableFrom(paramTypes[0]))
                  nTargetArgs--;
                if (methodArgs.length <= nTargetArgs)
                  return m.invoke(m_defaultInstance, convertedArgs[0]);
                else  
                  return m.invoke(methodArgs[0], convertedArgs[0]);
              }
            }
            catch(Exception e)
            {
              // Must not have been the right one
            }
          }
  
          if (args.size() > 0)
          {
            targetObject = methodArgs[0];
  
            if (targetObject instanceof XObject)
              targetObject = ((XObject) targetObject).object();
  
            if (m_classObj.isAssignableFrom(targetObject.getClass()))
              resolveType = MethodResolver.DYNAMIC;
            else
              resolveType = MethodResolver.STATIC_AND_INSTANCE;
          }
          else
          {
            targetObject = null;
            resolveType = MethodResolver.STATIC_AND_INSTANCE;
          }
  
          m = MethodResolver.getMethod(m_classObj,
                                       funcName,
                                       methodArgs, 
                                       convertedArgs,
                                       exprContext,
                                       resolveType);
          putToCache(methodKey, null, methodArgs, m);
  
          if (MethodResolver.DYNAMIC == resolveType)          // First argument was object type
            return m.invoke(targetObject, convertedArgs[0]);
          else                                  // First arg was not object.  See if we need the implied object.
          {
            if (Modifier.isStatic(m.getModifiers()))
              return m.invoke(null, convertedArgs[0]);
            else
            {
              if (null == m_defaultInstance)
              {
                m_defaultInstance = m_classObj.newInstance();
              }
              return m.invoke(m_defaultInstance, convertedArgs[0]);
            }  
          }
  
        }
      }
      catch (Exception e)
      {
        e.printStackTrace();
        throw new SAXException(e);
      }
    }
  
  
    /**
     * Process a call to this extension namespace via an element. As a side
     * effect, the results are sent to the TransformerImpl's result tree.
     *
     * @param localPart      Element name's local part.
     * @param element        The extension element being processed.
     * @param transformer      Handle to TransformerImpl.
     * @param stylesheetTree The compiled stylesheet tree.
     * @param mode           The current mode.
     * @param sourceTree     The root of the source tree (but don't assume
     *                       it's a Document).
     * @param sourceNode     The current context node.
     *
     * @exception XSLProcessorException thrown if something goes wrong
     *            while running the extension handler.
     * @exception MalformedURLException if loading trouble
     * @exception FileNotFoundException if loading trouble
     * @exception IOException           if loading trouble
     * @exception SAXException          if parsing trouble
     */
  
    public void processElement(String localPart,
                               Element element,
                               TransformerImpl transformer,
                               Stylesheet stylesheetTree,
                               Node sourceTree,
                               Node sourceNode,
                               QName mode,
                               Object methodKey)
      throws SAXException, IOException
    {
      Object result = null;
  
      Method m = (Method) getFromCache(methodKey, null, null);
      if (null == m)
      {
        try
        {
          m = MethodResolver.getElementMethod(m_classObj, localPart);
          if ( (null == m_defaultInstance) && !Modifier.isStatic(m.getModifiers()) )
            m_defaultInstance = m_classObj.newInstance();
        }
        catch (Exception e)
        {
          // e.printStackTrace ();
          throw new SAXException (e.getMessage (), e);
        }
        putToCache(methodKey, null, null, m);
      }
  
      XSLProcessorContext xpc = new XSLProcessorContext(transformer, 
                                                        stylesheetTree,
                                                        sourceTree, 
                                                        sourceNode, 
                                                        mode);
  
      try
      {
        result = m.invoke(m_defaultInstance, new Object[] {xpc, element});
      }
      catch (Exception e)
      {
        // e.printStackTrace ();
        throw new SAXException (e.getMessage (), e);
      }
  
      if (result != null)
      {
        xpc.outputToResultTree (stylesheetTree, result);
      }
   
    }
   
  }
  
  
  
  1.1                  xml-xalan/java/src/org/apache/xalan/extensions/ExtensionHandlerJavaPackage.java
  
  Index: ExtensionHandlerJavaPackage.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.xalan.extensions;
  
  import java.util.Hashtable;
  import java.util.Vector;
  import java.lang.reflect.Method;
  import java.lang.reflect.Constructor;
  import java.io.IOException;
  
  import org.w3c.xslt.ExpressionContext;
  
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.apache.xalan.transformer.TransformerImpl;
  import org.apache.xalan.templates.Stylesheet;
  import org.apache.xalan.utils.QName;
  
  import org.apache.xpath.objects.XObject;
  import org.xml.sax.SAXException;
  
  /**
   * <meta name="usage" content="internal"/>
   * Class handling the java extension namespaces for XPath that
   * represent packages.  The package namespace should begin with
   * xalan:// but this is not currently enforced.
   * Provides functions to test a function's existence and call a function
   *
   */
  
  public class ExtensionHandlerJavaPackage extends ExtensionHandlerJava
  {
  
  
    /**
     * Construct a new extension namespace handler given all the information
     * needed. 
     * 
     * @param namespaceUri the extension namespace URI that I'm implementing
     * @param funcNames    string containing list of functions of extension NS
     * @param lang         language of code implementing the extension
     * @param srcURL       value of src attribute (if any) - treated as a URL
     *                     or a classname depending on the value of lang. If
     *                     srcURL is not null, then scriptSrc is ignored.
     * @param scriptSrc    the actual script code (if any)
     */
    public ExtensionHandlerJavaPackage(String namespaceUri,
                                       String scriptLang,
                                       String className)
    {
      super(namespaceUri, scriptLang, className);
    }
  
  
    /**
     * Tests whether a certain function name is known within this namespace.
     * Since this is for a package , we simply try to find a
     * method or constructor for the fully qualified class name passed in the
     * argument.  There is no guarantee, of course, that this will actually
     * work at runtime since we may have problems converting the arguments.
     *
     * @param function name of the function being tested
     *
     * @return true if its known, false if not.
     */
    public boolean isFunctionAvailable(String function) 
    {
      // TODO:  This function needs to be implemented.
      return true;
    }
  
  
    /**
     * Tests whether a certain element name is known within this namespace.
     * Since this is for a package , we simply try to find a
     * method or constructor for the fully qualified class name passed in the
     * argument.  There is no guarantee, of course, that this will actually
     * work at runtime since we may have problems converting the arguments.
     *
     * @param function name of the function being tested
     *
     * @return true if its known, false if not.
     */
    public boolean isElementAvailable(String element) 
    {
      // TODO:  This function needs to be implemented.
      return true;
    }
  
  
    /**
     * Process a call to a function in the package java namespace.
     * There are three possible types of calls:
     * <pre>
     *   Constructor:
     *     packagens:class.name.new(arg1, arg2, ...)
     *
     *   Static method:
     *     packagens:class.name.method(arg1, arg2, ...)
     *
     *   Instance method:
     *     packagens:method(obj, arg1, arg2, ...)
     * </pre>
     * We use the following rules to determine the type of call made:
     * <ol type="1">
     * <li>If the function name ends with a ".new", call the best constructor for
     *     class whose name is formed by concatenating the value specified on
     *     the namespace with the value specified in the function invocation
     *     before ".new".</li>
     * <li>If the function name contains a period, call the best static method "method"
     *     in the class whose name is formed by concatenating the value specified on
     *     the namespace with the value specified in the function invocation.</li>
     * <li>Otherwise, call the best instance method "method"
     *     in the class whose name is formed by concatenating the value specified on
     *     the namespace with the value specified in the function invocation.
     *     Note that a static method of the same
     *     name will <i>not</i> be called in the current implementation.  This
     *     module does not verify that the obj argument is a member of the
     *     package namespace.</li>
     * </ol>
     *
     * @param funcName Function name.
     * @param args     The arguments of the function call.
     *
     * @return the return value of the function evaluation.
     *
     * @exception XSLProcessorException thrown if something goes wrong 
     *            while running the extension handler.
     * @exception MalformedURLException if loading trouble
     * @exception FileNotFoundException if loading trouble
     * @exception IOException           if loading trouble
     * @exception SAXException          if parsing trouble
     */
  
    public Object callFunction (String funcName, 
                                Vector args, 
                                Object methodKey,
                                ExpressionContext exprContext)
      throws SAXException 
    {
  
      String className;
      String methodName;
      Class  classObj;
      Object targetObject;
      int lastDot = funcName.lastIndexOf(".");
      Object[] methodArgs;
      Object[][] convertedArgs;
      Class[] paramTypes;
  
      try
      {
  
        if (funcName.endsWith(".new")) {                   // Handle constructor call
  
          methodArgs = new Object[args.size()];
          convertedArgs = new Object[1][];
          for (int i = 0; i < methodArgs.length; i++)
          {
            methodArgs[i] = args.elementAt(i);
          }
          Constructor c = (Constructor) getFromCache(methodKey, null, methodArgs);
          if (c != null)
          {
            try
            {
              paramTypes = c.getParameterTypes();
              MethodResolver.convertParams(methodArgs, convertedArgs, paramTypes, exprContext);
              return c.newInstance(convertedArgs[0]);
            }
            catch(Exception e)
            {
              // Must not have been the right one
            }
          }
          className = m_className + funcName.substring(0, lastDot);
          try
          {
            classObj = Class.forName(className);
          }
          catch (ClassNotFoundException e) 
          {
            throw new SAXException(e);
          }
          c = MethodResolver.getConstructor(classObj, 
                                            methodArgs,
                                            convertedArgs,
                                            exprContext);
          putToCache(methodKey, null, methodArgs, c);
          return c.newInstance(convertedArgs[0]);
        }
  
        else if (-1 != lastDot) {                         // Handle static method call
  
          methodArgs = new Object[args.size()];
          convertedArgs = new Object[1][];
          for (int i = 0; i < methodArgs.length; i++)
          {
            methodArgs[i] = args.elementAt(i);
          }
          Method m = (Method) getFromCache(methodKey, null, methodArgs);
          if (m != null)
          {
            try
            {
              paramTypes = m.getParameterTypes();
              MethodResolver.convertParams(methodArgs, convertedArgs, paramTypes, exprContext);
              return m.invoke(null, convertedArgs[0]);
            }
            catch(Exception e)
            {
              // Must not have been the right one
            }
          }
          className = m_className + funcName.substring(0, lastDot);
          methodName = funcName.substring(lastDot + 1);
          try
          {
            classObj = Class.forName(className);
          }
          catch (ClassNotFoundException e) 
          {
            throw new SAXException(e);
          }
          m = MethodResolver.getMethod(classObj,
                                       methodName,
                                       methodArgs, 
                                       convertedArgs,
                                       exprContext,
                                       MethodResolver.STATIC_ONLY);
          putToCache(methodKey, null, methodArgs, m);
          return m.invoke(null, convertedArgs[0]);
        }
  
        else {                                            // Handle instance method call
  
          if (args.size() < 1)
          {
            throw new SAXException("Instance method call to method " + funcName
                                      + " requires an Object instance as first argument");
          }
          targetObject = args.elementAt(0);
          if (targetObject instanceof XObject)          // Next level down for XObjects
            targetObject = ((XObject) targetObject).object();
          methodArgs = new Object[args.size() - 1];
          convertedArgs = new Object[1][];
          for (int i = 0; i < methodArgs.length; i++)
          {
            methodArgs[i] = args.elementAt(i+1);
          }
          Method m = (Method) getFromCache(methodKey, targetObject, methodArgs);
          if (m != null)
          {
            try
            {
              paramTypes = m.getParameterTypes();
              MethodResolver.convertParams(methodArgs, convertedArgs, paramTypes, exprContext);
              return m.invoke(targetObject, convertedArgs[0]);
            }
            catch(Exception e)
            {
              // Must not have been the right one
            }
          }
          classObj = targetObject.getClass();
          m = MethodResolver.getMethod(classObj,
                                       funcName,
                                       methodArgs, 
                                       convertedArgs,
                                       exprContext,
                                       MethodResolver.INSTANCE_ONLY);
          putToCache(methodKey, targetObject, methodArgs, m);
          return m.invoke(targetObject, convertedArgs[0]);
        }
      }
      catch (Exception e)
      {
        e.printStackTrace();
        throw new SAXException(e);
      }
    }
  
  
    /**
     * Process a call to this extension namespace via an element. As a side
     * effect, the results are sent to the TransformerImpl's result tree.
     *
     * @param localPart      Element name's local part.
     * @param element        The extension element being processed.
     * @param transformer      Handle to TransformerImpl.
     * @param stylesheetTree The compiled stylesheet tree.
     * @param mode           The current mode.
     * @param sourceTree     The root of the source tree (but don't assume
     *                       it's a Document).
     * @param sourceNode     The current context node.
     *
     * @exception XSLProcessorException thrown if something goes wrong
     *            while running the extension handler.
     * @exception MalformedURLException if loading trouble
     * @exception FileNotFoundException if loading trouble
     * @exception IOException           if loading trouble
     * @exception SAXException          if parsing trouble
     */
  
    public void processElement (String localPart,
                                Element element,
                                TransformerImpl transformer,
                                Stylesheet stylesheetTree,
                                Node sourceTree,
                                Node sourceNode,
                                QName mode,
                                Object methodKey)
      throws SAXException, IOException
    {
      throw new SAXException("Extension elements are not yet implemented for "
                                                   + "non-class namespaces: " + localPart);
    }
  
  }