mmidy       00/09/25 13:31:30

  Modified:    src/org/apache/xalan/xpath ExtensionFunctionHandler.java
                        XSLTJavaClassEngine.java
               src/org/apache/xalan/xslt ExtensionNSHandler.java
  Log:
  Patch from Costin Manolache: Isolate BSF specific code to XSLTJavaClassEngine
  
  Revision  Changes    Path
  1.14      +118 -424  
xml-xalan/src/org/apache/xalan/xpath/ExtensionFunctionHandler.java
  
  Index: ExtensionFunctionHandler.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/src/org/apache/xalan/xpath/ExtensionFunctionHandler.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- ExtensionFunctionHandler.java     2000/07/23 17:57:06     1.13
  +++ ExtensionFunctionHandler.java     2000/09/25 20:31:28     1.14
  @@ -63,11 +63,6 @@
   import org.w3c.dom.*;
   import org.xml.sax.*;
   
  -import com.ibm.bsf.BSFException;
  -import java.lang.reflect.*;
  -import com.ibm.cs.util.ReflectionUtils;
  -
  -
   /**
    * <meta name="usage" content="internal"/>
    * Class handling an extension namespace for XPath. Provides functions
  @@ -77,19 +72,25 @@
    */
   public class ExtensionFunctionHandler 
   {
  -  public String namespaceUri;  // uri of the extension namespace
  -  public String scriptLang = "javaclass";    // scripting language of 
implementation
  +     /**
  +      * Patch from Costin Manolache
  +      * Remove BSF Specific code, create new Interface ExtensionLiaison
  +      * and move BSF Specific code to XSLTJavaClassEngine
  +   */        
  +  protected ExtensionLiaison extensionLiaison;
  +     public String namespaceUri;  // uri of the extension namespace
  +     // scripting language of implementation
  +  public String scriptLang = "javaclass";    
     public String scriptSrc;     // script source to run (if any)
     public String scriptSrcURL;  // URL of source of script (if any)
  -  public Object javaObject = null;    // object for javaclass engine
  -  protected boolean hasCalledCTor = false;  // we'll be nice and call a ctor 
if they haven't
  -  public Class classObject = null;  // class object for javaclass engine
     protected Hashtable functions = new Hashtable (); // functions of namespace
     protected Hashtable elements = new Hashtable (); // elements of namespace
  -  protected com.ibm.bsf.BSFManager mgr = null; // mgr used to run scripts
     protected boolean componentStarted; // true when the scripts in a
     // component description (if any) have
     // been run
  +     
  +     public static final String DEFAULT_EXTENSION_LIAISON =
  +    "org.apache.xalan.xpath.XSLTJavaClassEngine";
   
     /////////////////////////////////////////////////////////////////////////
     // Constructors
  @@ -101,10 +102,19 @@
      * 
      * @param namespaceUri the extension namespace URI that I'm implementing
      */
  -  public ExtensionFunctionHandler (String namespaceUri) 
  -  {
  -    this.namespaceUri = namespaceUri;
  -  }
  +     public ExtensionFunctionHandler (String namespaceUri) 
  +     {
  +             this.namespaceUri = namespaceUri;
  +             try 
  +             {
  +                     Class c=Class.forName(DEFAULT_EXTENSION_LIAISON);
  +                     extensionLiaison=(ExtensionLiaison)c.newInstance();
  +             } 
  +             catch( Exception ex ) 
  +             {
  +                     extensionLiaison=null;
  +             }
  +     }
   
     /////////////////////////////////////////////////////////////////////////
   
  @@ -125,7 +135,8 @@
     {
       this (namespaceUri);
       setFunctions (funcNames);
  -    setScript (lang, srcURL, src);
  +    if( extensionLiaison!=null)
  +      extensionLiaison.setScript (lang, srcURL, src);
     }
   
     /////////////////////////////////////////////////////////////////////////
  @@ -191,9 +202,8 @@
      */
     public void setScript (String lang, String srcURL, String scriptSrc) 
     {
  -    this.scriptLang = lang;
  -    this.scriptSrcURL = srcURL;
  -    this.scriptSrc = scriptSrc;
  +    if (extensionLiaison != null)
  +                     extensionLiaison.setScript(lang, srcURL, scriptSrc);  
     }
   
     /////////////////////////////////////////////////////////////////////////
  @@ -223,7 +233,7 @@
     }
   
   
  -  Hashtable m_cachedMethods = null;
  +  //Hashtable m_cachedMethods = null;
     
     /**
      * call the named method on the object that was loaded by eval. 
  @@ -234,227 +244,11 @@
      */
     public Object callJava (Object object, String method, Object[] args, 
                             Object methodKey) 
  -    throws BSFException
  -  {
  -    // if the function name has a "." in it, then its a static
  -    // call with the args being arguments to the call. If it 
  -    // does not, then its a method call on args[0] with the rest
  -    // of the args as the arguments to the call
  -    int dotPos = method.lastIndexOf (".");
  -    Object[] methodArgs = null;
  -    boolean isNew = false;
  -    if (dotPos == -1) 
  -    {
  -      methodArgs = args;
  -      object = args[0];
  -      if (args.length > 1) 
  -      {
  -        methodArgs = new Object[args.length-1];
  -        System.arraycopy (args, 1, methodArgs, 0, args.length - 1);
  -      }
  -      else
  -        methodArgs = null;
  -    }
  -    else 
  -    {
  -      String className = method.substring (0, dotPos);
  -      method = method.substring (dotPos+1);
  -      methodArgs = args;
  -      isNew = method.equals ("new");
  -      try 
  -      {
  -        if(null == object)
  -          object = Class.forName (className);
  -      }
  -      catch (ClassNotFoundException e) 
  -      {
  -        throw new BSFException(1, "unable to load class '" + 
  -          className + "'", e);
  -      }
  -    }
  -    
  -    if((null != m_cachedMethods) && !isNew && (null != object))
  -    {
  -      try
  -      {
  -        Method thisMethod = (Method)m_cachedMethods.get(methodKey);
  -        if(null != thisMethod)
  -        {
  -          return thisMethod.invoke (object, methodArgs);
  -        }
  -      }
  -      catch(Exception e)
  -      {
  -        // try again below...
  -      }
  -    
  -    }
  -
  -    // determine the argument types as they are given
  -    Class[] argTypes = null;
  -    if (methodArgs != null) 
  -    {
  -      argTypes = new Class[methodArgs.length];
  -      for (int i = 0; i < argTypes.length; i++) 
  -      {
  -        argTypes[i] = (methodArgs[i]!=null) ? methodArgs[i].getClass() : 
null;
  -      }
  -    }
  -
  -    // try to find the method and run it, taking into account the special
  -    // type conversions we want. If an arg is a Double, we first try with
  -    // double and then with Double. Same for Boolean/boolean. This is done
  -    // wholesale tho - that is, if there are two Double args both are
  -    // tried double first and then Double.
  -    boolean done = false;
  -    boolean toggled = false;
  -    try 
  -    {
  -      while (!done) 
  -      {
  -        if (methodArgs == null) 
  -        {
  -          done = true; // nothing to retry - do as-is or give up
  -        }
  -        else 
  -        {
  -          if (!toggled) 
  -          {
  -            for (int i = 0; i < argTypes.length; i++) 
  -            {
  -              Class cl = argTypes[i];
  -              if (cl != null) 
  -              {
  -                if (cl == Double.class) 
  -                {
  -                  cl = double.class;
  -                }
  -                if (cl == Float.class) 
  -                {
  -                  cl = float.class;
  -                }
  -                else if (cl == Boolean.class) 
  -                {
  -                  cl = boolean.class;
  -                }
  -                else if (cl == Byte.class) 
  -                {
  -                  cl = byte.class;
  -                }
  -                else if (cl == Character.class) 
  -                {
  -                  cl = char.class;
  -                }
  -                else if (cl == Short.class) 
  -                {
  -                  cl = short.class;
  -                }
  -                else if (cl == Integer.class) 
  -                {
  -                  cl = int.class;
  -                }
  -                else if (cl == Long.class) 
  -                {
  -                  cl = long.class;
  -                }
  -                argTypes[i] = cl;
  -              }
  -            }
  -            toggled = true;
  -          }
  -          else 
  -          {
  -            for (int i = 0; i < argTypes.length; i++) 
  -            {
  -              Class cl = argTypes[i];
  -              if (cl != null) 
  -              {
  -                if (cl == double.class) 
  -                {
  -                  cl = Double.class;
  -                }
  -                if (cl == float.class) 
  -                {
  -                  cl = Float.class;
  -                }
  -                else if (cl == boolean.class) 
  -                {
  -                  cl = Boolean.class;
  -                }
  -                else if (cl == byte.class) 
  -                {
  -                  cl = Byte.class;
  -                }
  -                else if (cl == char.class) 
  -                {
  -                  cl = Character.class;
  -                }
  -                else if (cl == short.class) 
  -                {
  -                  cl = Short.class;
  -                }
  -                else if (cl == int.class) 
  -                {
  -                  cl = Integer.class;
  -                }
  -                else if (cl == long.class) 
  -                {
  -                  cl = Long.class;
  -                }
  -                argTypes[i] = cl;
  -              }
  -            }
  -            done = true;
  -          }
  -        }
  -        
  -        // now find method with the right signature, call it and return 
result.
  -        try 
  -        {
  -          if (isNew) 
  -          {
  -            // if its a "new" call then need to find and invoke a constructor
  -            // otherwise find and invoke the appropriate method. The method
  -            // searching logic is the same of course.
  -            Constructor c =
  -                           ReflectionUtils.getConstructor ((Class) object, 
argTypes);
  -            Object obj = c.newInstance (methodArgs);
  -            return obj;
  -          }
  -          else 
  -          {
  -            Method m = ReflectionUtils.getMethod (object, method, argTypes);
  -            Object returnObj = m.invoke (object, methodArgs);
  -            if(!isNew)
  -            {
  -              if(null == m_cachedMethods)
  -                m_cachedMethods = new Hashtable();
  -              m_cachedMethods.put(methodKey, m);
  -            }
  -            return returnObj;
  -          }
  -        }
  -        catch (NoSuchMethodException e) 
  -        {
  -          // ignore if not done looking
  -          if (done) 
  -          {
  -            throw e;
  -          }
  -        }
  -      }
  -    }
  -    catch (Exception e) 
  -    {
  -      Throwable t = (e instanceof InvocationTargetException) ?
  -                    ((InvocationTargetException)e).getTargetException () :
  -                    null;
  -      throw new BSFException (BSFException.REASON_OTHER_ERROR,
  -        "method call/new failed: " + e +
  -        ((t==null)?"":(" target exception: "+t)), t);
  -    }
  -    // should not get here
  -    return null;
  +    throws XPathException //BSFException
  +  {    
  +             if( extensionLiaison==null)
  +      return null;
  +    return extensionLiaison.callJava( object, method, args, methodKey );
     }
   
     /////////////////////////////////////////////////////////////////////////
  @@ -481,109 +275,13 @@
       {
         startupComponent (javaClass);
       }
  -
  -    boolean isJava = false;
  -    try 
  -    {
  -      com.ibm.bsf.BSFEngine e;
  -      Object[] argArray;
  -      int argStart;
  -      
  -      if(null == mgr)
  -      {
  -        mgr = new com.ibm.bsf.BSFManager ();
  -      }
  -
  -      // we want to use the xslt-javaclass engine to handle the javaclass
  -      // case 'cause of the funky method selection rules. That engine 
  -      // expects the first arg to be the object on which to make the call.
  -      boolean isCTorCall = false;
  -      if (scriptLang.equals ("javaclass")) 
  -      {
  -        isJava = true;
  -        isCTorCall = funcName.equals("new");
  -        e = mgr.loadScriptingEngine ("xslt-javaclass");
  -        if(isCTorCall)
  -        {
  -          argArray = new Object[args.size ()];
  -          argStart = 0;
  -          funcName = this.classObject.getName()+".new";
  -          javaObject = null;
  -          hasCalledCTor = true;
  -        }
  -        else
  -        {
  -          if(!hasCalledCTor)
  -          {
  -            if(null == javaObject)
  -            {
  -              javaObject = this.classObject.newInstance();
  -            }
  -            
  -            argArray = new Object[args.size () + 1];
  -            
  -            argArray[0] = javaObject;
  -            argStart = 1;
  -            // argArray = new Object[args.size ()];
  -            // argStart = 0;
  -          }
  -          else
  -          {
  -            argArray = new Object[args.size ()];
  -            argStart = 0;
  -          }
  -        }
  -      }
  -      else 
  -      {
  -        e = ((com.ibm.bsf.BSFManager)mgr).loadScriptingEngine (scriptLang);
  -        argArray = new Object[args.size ()];
  -        argStart = 0;
  -      }
  -
  -      // convert the xobject args to their object forms
  -      for (int i = 0; i < args.size (); i++) 
  -      {
  -        Object o = args.elementAt (i);
  -        argArray[i+argStart] = 
  -                              (o instanceof XObject) ? ((XObject)o).object 
() : o;
  -      }
  -      
  -      if(isJava)
  -        return callJava(javaObject, funcName, argArray, methodKey);
  -      else
  -        return e.call (null, funcName, argArray);
  -    }
  -    catch (Exception e) 
  -    {
  -      // throw new XPathException ("Error with extension in callFunction.", 
e);
  -      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);
  -      }
  -      else
  -      {
  -        throw new XPathProcessorException ("Extension not found");
  -      }
  -    }
  -    return new XNull();
  -  }
  -
  -  /////////////////////////////////////////////////////////////////////////
  -  // Private/Protected Functions
  -  /////////////////////////////////////////////////////////////////////////
     
  -  /**
  -   * Tell if we've already initialized the bsf engine.
  -   */
  -  protected static boolean bsfInitialized = false;
  -  
  -  protected static Boolean m_bsfInitSynch = new Boolean(true);
  +             if( extensionLiaison==null)
  +      return null;
  +             
  +    return  extensionLiaison.callFunction( funcName, args,
  +                                                                             
       methodKey, javaClass );
  +  }
   
     /**
      * Start the component up by executing any script that needs to run
  @@ -593,89 +291,85 @@
      * @exception XPathProcessorException if something bad happens.
      */
     protected void startupComponent (Class classObj) throws  
XPathProcessorException 
  +  {   
  +             if( extensionLiaison == null)
  +      return;  
  +             
  +             extensionLiaison.checkInit();
  +    extensionLiaison.startupComponent( classObj );
  +    componentStarted=true;
  +  } 
  +     
  +     /**
  +   * Interface for connecting extension functions to xalan.
  +   * Based on ExtensionFunctionHandler
  +   *
  +   * @author Sanjiva Weerawarana ([EMAIL PROTECTED])
  +   * @author [EMAIL PROTECTED]
  +   */
  +  public static interface  ExtensionLiaison
     {
  -    if(!bsfInitialized)
  -    {
  -      synchronized(m_bsfInitSynch)
  -      {
  -        bsfInitialized = true;
  -        com.ibm.bsf.BSFManager.registerScriptingEngine ("xslt-javaclass",
  -                                                        
"org.apache.xalan.xpath.XSLTJavaClassEngine",
  -                                                        new String[0]);
  -      }
  -    }
  -
  -    // special case the javaclass engine - the scriptSrcURL is 
  -    // the class name to run. If it starts with class: then use the
  -    // class object with that name instead of init'ing it as the
  -    // target of the calls later
  -    if(null != classObj)
  -    {
  -      classObject = classObj;
  -      if (scriptSrcURL.startsWith ("class:")) 
  -      {
  -        javaObject = classObj;
  -      }
  -      return;
  -    }
  -    else
  -    {
  -      if (scriptLang.equals ("javaclass") && (scriptSrcURL != null)) 
  -      {
  -        try 
  -        {
  -          String cname = scriptSrcURL;
  -          boolean isClass = false;
  -          if (scriptSrcURL.startsWith ("class:")) 
  -          {
  -            cname = scriptSrcURL.substring (6);
  -            isClass = true;
  -          }
  -          classObject = Class.forName (cname);
  -          if (isClass) 
  -          {
  -            javaObject = classObject;
  -          }
  -          else
  -          {
  -            // We'll only do this if they haven't called a ctor.
  -            // javaObject = classObject.newInstance ();
  -          }
  -          componentStarted = true;
  -          return;
  -        }
  -        catch (Exception e) 
  -        {
  -          // System.out.println("Extension error: "+e.getMessage ());
  -          throw new XPathProcessorException (e.getMessage (), e);
  -        }
  -      }
  -    }
  +    /** Make sure the component is initialized
  +     */
  +    public void checkInit()
  +      throws  XPathProcessorException;
  +             
  +    /**
  +     * Start the component up by executing any script that needs to run
  +     * at startup time. This needs to happen before any functions can be
  +     * called on the component. 
  +     * 
  +     * @exception XPathProcessorException if something bad happens.
  +     */
  +    public void startupComponent (Class classObj)
  +      throws  XPathProcessorException;
  +
  +    /**
  +     * 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,
  +                                                              Class 
javaClass)
  +      throws  XPathException;
  +    
  +    /**
  +     * call the named method on the object that was loaded by eval. 
  +     * The method selection stuff is very XSLT-specific, hence the
  +     * custom engine.
  +     *
  +     * @param object ignored - should always be null
  +     */
  +    public Object callJava (Object object, String method, Object[] args, 
  +                                                  Object methodKey) 
  +      throws XPathException;
  +             
  +             /**
  +     * Set the script data for this extension NS. If srcURL is !null then
  +     * the script body is read from that URL. If not the scriptSrc is used
  +     * as the src. This method does not actually execute anything - that's
  +     * done when the component is first hit by the user by an element or 
  +     * a function call.
  +     *
  +     * @param lang      language of the script.
  +     * @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 void setScript (String lang, String srcURL, String scriptSrc);
   
  -    // if scriptSrcURL is specified read it off
  -    if (scriptSrcURL != null) 
  -    {
  -      throw new XPathProcessorException ("src attr not supported (yet)");
  -    }
  +   }
   
  -    if (scriptSrc == null) 
  -    {
  -      return;
  -    }
  -    
  -    if(null == mgr)
  -      mgr = new com.ibm.bsf.BSFManager ();
   
  -    // evaluate the src to load whatever content is in that string to 
  -    // the engines
  -    try 
  -    {
  -      ((com.ibm.bsf.BSFManager)mgr).exec (scriptLang, "LotusXSLScript", -1, 
-1, scriptSrc);
  -    }
  -    catch (com.ibm.bsf.BSFException bsfe) 
  -    {
  -      throw new XPathProcessorException (bsfe.getMessage (), bsfe);
  -    }
  -    componentStarted = true;
  -  }
   }
  
  
  
  1.8       +504 -2    
xml-xalan/src/org/apache/xalan/xpath/XSLTJavaClassEngine.java
  
  Index: XSLTJavaClassEngine.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/src/org/apache/xalan/xpath/XSLTJavaClassEngine.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- XSLTJavaClassEngine.java  2000/03/06 20:13:30     1.7
  +++ XSLTJavaClassEngine.java  2000/09/25 20:31:28     1.8
  @@ -61,12 +61,21 @@
   import java.io.*;
   import java.lang.reflect.*;
   
  +import org.w3c.dom.*;
  +import org.xml.sax.*;
  +
   import com.ibm.bsf.*;
   import com.ibm.bsf.util.BSFEngineImpl;
   
   import com.ibm.cs.util.ReflectionUtils;
   
   /**
  + * Patch from Costin Manolache 
  + * This class acts as the "Adapter" between BSF scripting engine and
  + * Xalan
  + */
  +
  +/**
    * <meta name="usage" content="internal"/>
    * This is a custom scripting engine for the XSLT processor's needs of 
calling
    * into Java objects. 
  @@ -74,7 +83,8 @@
    * @author   Sanjiva Weerawarana ([EMAIL PROTECTED])
    */
   
  -public class XSLTJavaClassEngine extends BSFEngineImpl 
  +public class XSLTJavaClassEngine extends BSFEngineImpl
  +     implements ExtensionFunctionHandler.ExtensionLiaison
   {
     /**
      * This is used by an application to evaluate an object containing
  @@ -259,11 +269,12 @@
               Constructor c =
                              ReflectionUtils.getConstructor ((Class) object, 
argTypes);
               Object obj = c.newInstance (methodArgs);
  +            
               return obj;
             }
             else 
             {
  -            Method m = ReflectionUtils.getMethod (object, method, argTypes);
  +                                             Method m = 
ReflectionUtils.getMethod (object, method, argTypes);
               return m.invoke (object, methodArgs);
             }
           }
  @@ -289,5 +300,496 @@
       // should not get here
       return null;
     }
  +
  +  // -------------------- ExtensionLiaison implementation 
--------------------
  +  public String scriptLang = "javaclass";    // scripting language of 
implementation
  +  public String scriptSrcURL;  // URL of source of script (if any)
  +  public String scriptSrc;     // script source to run (if any)
  +
  +    
  +  protected boolean hasCalledCTor = false;  // we'll be nice and call a ctor 
if they haven't
  +  public Object javaObject = null;    // object for javaclass engine
  +  public Class classObject = null;  // class object for javaclass engine
  +  Hashtable m_cachedMethods = null;
  +  protected com.ibm.bsf.BSFManager mgr = null; // mgr used to run scripts
  +  protected boolean componentStarted; // true when the scripts in a
  +    
  +  /////////////////////////////////////////////////////////////////////////
  +
  +  /**
  +   * Set the script data for this extension NS. If srcURL is !null then
  +   * the script body is read from that URL. If not the scriptSrc is used
  +   * as the src. This method does not actually execute anything - that's
  +   * done when the component is first hit by the user by an element or 
  +   * a function call.
  +   *
  +   * @param lang      language of the script.
  +   * @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 void setScript (String lang, String srcURL, String scriptSrc) 
  +  {
  +    this.scriptLang = lang;
  +    this.scriptSrcURL = srcURL;
  +    this.scriptSrc = scriptSrc;
  +  }
  +
  +  /**
  +   * call the named method on the object that was loaded by eval. 
  +   * The method selection stuff is very XSLT-specific, hence the
  +   * custom engine.
  +   *
  +   * @param object ignored - should always be null
  +   */
  +  public Object callJava (Object object, String method, Object[] args, 
  +                          Object methodKey) 
  +    throws XPathException
  +  {
  +    // if the function name has a "." in it, then its a static
  +    // call with the args being arguments to the call. If it 
  +    // does not, then its a method call on args[0] with the rest
  +    // of the args as the arguments to the call
  +    int dotPos = method.lastIndexOf (".");
  +    Object[] methodArgs = null;
  +    boolean isNew = false;
  +    if (dotPos == -1) 
  +    {
  +      methodArgs = args;
  +      object = args[0];
  +      if (args.length > 1) 
  +      {
  +        methodArgs = new Object[args.length-1];
  +        System.arraycopy (args, 1, methodArgs, 0, args.length - 1);
  +      }
  +      else
  +        methodArgs = null;
  +    }
  +    else 
  +    {
  +      String className = method.substring (0, dotPos);
  +      method = method.substring (dotPos+1);
  +      methodArgs = args;
  +      isNew = method.equals ("new");
  +      try 
  +      {
  +        if(null == object)
  +          object = Class.forName (className);
  +      }
  +      catch (ClassNotFoundException e) 
  +      {
  +              // used to be BSFException (1, .. )
  +        throw new XPathException( "unable to load class '" + 
  +          className + "'", e);
  +      }
  +    }
  +    
  +    if((null != m_cachedMethods) && !isNew && (null != object))
  +    {
  +      try
  +      {
  +        Method thisMethod = (Method)m_cachedMethods.get(methodKey);
  +        if(null != thisMethod)
  +        {
  +          return thisMethod.invoke (object, methodArgs);
  +        }
  +      }
  +      catch(Exception e)
  +      {
  +        // try again below...
  +      }
  +    
  +    }
  +
  +    // determine the argument types as they are given
  +    Class[] argTypes = null;
  +    if (methodArgs != null) 
  +    {
  +      argTypes = new Class[methodArgs.length];
  +      for (int i = 0; i < argTypes.length; i++) 
  +      {
  +        argTypes[i] = (methodArgs[i]!=null) ? methodArgs[i].getClass() : 
null;
  +      }
  +    }
  +
  +    // try to find the method and run it, taking into account the special
  +    // type conversions we want. If an arg is a Double, we first try with
  +    // double and then with Double. Same for Boolean/boolean. This is done
  +    // wholesale tho - that is, if there are two Double args both are
  +    // tried double first and then Double.
  +    boolean done = false;
  +    boolean toggled = false;
  +    try 
  +    {
  +      while (!done) 
  +      {
  +        if (methodArgs == null) 
  +        {
  +          done = true; // nothing to retry - do as-is or give up
  +        }
  +        else 
  +        {
  +          if (!toggled) 
  +          {
  +            for (int i = 0; i < argTypes.length; i++) 
  +            {
  +              Class cl = argTypes[i];
  +              if (cl != null) 
  +              {
  +                if (cl == Double.class) 
  +                {
  +                  cl = double.class;
  +                }
  +                if (cl == Float.class) 
  +                {
  +                  cl = float.class;
  +                }
  +                else if (cl == Boolean.class) 
  +                {
  +                  cl = boolean.class;
  +                }
  +                else if (cl == Byte.class) 
  +                {
  +                  cl = byte.class;
  +                }
  +                else if (cl == Character.class) 
  +                {
  +                  cl = char.class;
  +                }
  +                else if (cl == Short.class) 
  +                {
  +                  cl = short.class;
  +                }
  +                else if (cl == Integer.class) 
  +                {
  +                  cl = int.class;
  +                }
  +                else if (cl == Long.class) 
  +                {
  +                  cl = long.class;
  +                }
  +                argTypes[i] = cl;
  +              }
  +            }
  +            toggled = true;
  +          }
  +          else 
  +          {
  +            for (int i = 0; i < argTypes.length; i++) 
  +            {
  +              Class cl = argTypes[i];
  +              if (cl != null) 
  +              {
  +                if (cl == double.class) 
  +                {
  +                  cl = Double.class;
  +                }
  +                if (cl == float.class) 
  +                {
  +                  cl = Float.class;
  +                }
  +                else if (cl == boolean.class) 
  +                {
  +                  cl = Boolean.class;
  +                }
  +                else if (cl == byte.class) 
  +                {
  +                  cl = Byte.class;
  +                }
  +                else if (cl == char.class) 
  +                {
  +                  cl = Character.class;
  +                }
  +                else if (cl == short.class) 
  +                {
  +                  cl = Short.class;
  +                }
  +                else if (cl == int.class) 
  +                {
  +                  cl = Integer.class;
  +                }
  +                else if (cl == long.class) 
  +                {
  +                  cl = Long.class;
  +                }
  +                argTypes[i] = cl;
  +              }
  +            }
  +            done = true;
  +          }
  +        }
  +        
  +        // now find method with the right signature, call it and return 
result.
  +        try 
  +        {
  +          if (isNew) 
  +          {
  +            // if its a "new" call then need to find and invoke a constructor
  +            // otherwise find and invoke the appropriate method. The method
  +            // searching logic is the same of course.
  +            Constructor c =
  +                           ReflectionUtils.getConstructor ((Class) object, 
argTypes);
  +            Object obj = c.newInstance (methodArgs);
  +            return obj;
  +          }
  +          else 
  +          {
  +            Method m = ReflectionUtils.getMethod (object, method, argTypes);
  +            Object returnObj = m.invoke (object, methodArgs);
  +            if(!isNew)
  +            {
  +              if(null == m_cachedMethods)
  +                m_cachedMethods = new Hashtable();
  +              m_cachedMethods.put(methodKey, m);
  +            }
  +            return returnObj;
  +          }
  +        }
  +        catch (NoSuchMethodException e) 
  +        {
  +          // ignore if not done looking
  +          if (done) 
  +          {
  +            throw e;
  +          }
  +        }
  +      }
  +    }
  +    catch (Exception e) 
  +    {
  +      Throwable t = (e instanceof InvocationTargetException) ?
  +                    ((InvocationTargetException)e).getTargetException () :
  +                    null;
  +      throw new XPathException (// BSFException.REASON_OTHER_ERROR,
  +        "method call/new failed: " + e +
  +        ((t==null)?"":(" target exception: "+t)), t);
  +    }
  +    // should not get here
  +    return 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, Class javaClass)
  +    throws XPathException 
  +  {
  +    if (!componentStarted) 
  +    {
  +      startupComponent (javaClass);
  +    }
  +
  +    boolean isJava = false;
  +    try 
  +    {
  +      com.ibm.bsf.BSFEngine e;
  +      Object[] argArray;
  +      int argStart;
  +      
  +      if(null == mgr)
  +      {
  +        mgr = new com.ibm.bsf.BSFManager ();
  +      }
  +
  +      // we want to use the xslt-javaclass engine to handle the javaclass
  +      // case 'cause of the funky method selection rules. That engine 
  +      // expects the first arg to be the object on which to make the call.
  +      boolean isCTorCall = false;
  +      if (scriptLang.equals ("javaclass")) 
  +      {
  +        isJava = true;
  +        isCTorCall = funcName.equals("new");
  +        e = mgr.loadScriptingEngine ("xslt-javaclass");
  +        if(isCTorCall)
  +        {
  +          argArray = new Object[args.size ()];
  +          argStart = 0;
  +          funcName = this.classObject.getName()+".new";
  +          javaObject = null;
  +          hasCalledCTor = true;
  +        }
  +        else
  +        {
  +          if(!hasCalledCTor)
  +          {
  +            if(null == javaObject)
  +            {
  +              javaObject = this.classObject.newInstance();
  +            }
  +            
  +            argArray = new Object[args.size () + 1];
  +            
  +            argArray[0] = javaObject;
  +            argStart = 1;
  +            // argArray = new Object[args.size ()];
  +            // argStart = 0;
  +          }
  +          else
  +          {
  +            argArray = new Object[args.size ()];
  +            argStart = 0;
  +          }
  +        }
  +      }
  +      else 
  +      {
  +        e = ((com.ibm.bsf.BSFManager)mgr).loadScriptingEngine (scriptLang);
  +        argArray = new Object[args.size ()];
  +        argStart = 0;
  +      }
  +
  +      // convert the xobject args to their object forms
  +      for (int i = 0; i < args.size (); i++) 
  +      {
  +        Object o = args.elementAt (i);
  +        argArray[i+argStart] = 
  +                              (o instanceof XObject) ? ((XObject)o).object 
() : o;
  +      }
  +      
  +      if(isJava)
  +        return callJava(javaObject, funcName, argArray, methodKey);
  +      else
  +        return e.call (null, funcName, argArray);
  +    }
  +    catch (Exception e) 
  +    {
  +      // throw new XPathException ("Error with extension in callFunction.", 
e);
  +      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);
  +      }
  +      else
  +      {
  +        throw new XPathProcessorException ("Extension not found");
  +      }
  +    }
  +    return new XNull();
  +  }
  +
  +
  +  /**
  +   * Tell if we've already initialized the bsf engine.
  +   */
  +  protected static boolean bsfInitialized = false;
  +  
  +  protected static Boolean m_bsfInitSynch = new Boolean(true);
  +
  +  public void checkInit()
  +    throws  XPathProcessorException 
  +  {
  +    if( !bsfInitialized ) {
  +      synchronized(m_bsfInitSynch)
  +              {
  +                bsfInitialized = true;
  +                BSFManager.registerScriptingEngine ("xslt-javaclass",
  +                                                                             
       "org.apache.xalan.xpath.XSLTJavaClassEngine",
  +                                                                             
       new String[0]);
  +              }
  +    }
  +  }
  +
  +  /**
  +   * Start the component up by executing any script that needs to run
  +   * at startup time. This needs to happen before any functions can be
  +   * called on the component. 
  +   * 
  +   * @exception XPathProcessorException if something bad happens.
  +   */
  +  public void startupComponent (Class classObj)
  +    throws  XPathProcessorException 
  +  {
  +    // special case the javaclass engine - the scriptSrcURL is 
  +    // the class name to run. If it starts with class: then use the
  +    // class object with that name instead of init'ing it as the
  +    // target of the calls later
  +    if(null != classObj)
  +    {
  +      classObject = classObj;
  +      if (scriptSrcURL.startsWith ("class:")) 
  +      {
  +        javaObject = classObj;
  +      }
  +      return;
  +    }
  +    else
  +    {
  +      if (scriptLang.equals ("javaclass") && (scriptSrcURL != null)) 
  +      {
  +        try 
  +        {
  +          String cname = scriptSrcURL;
  +          boolean isClass = false;
  +          if (scriptSrcURL.startsWith ("class:")) 
  +          {
  +            cname = scriptSrcURL.substring (6);
  +            isClass = true;
  +          }
  +          classObject = Class.forName (cname);
  +          if (isClass) 
  +          {
  +            javaObject = classObject;
  +          }
  +          else
  +          {
  +            // We'll only do this if they haven't called a ctor.
  +            // javaObject = classObject.newInstance ();
  +          }
  +          componentStarted = true;
  +          return;
  +        }
  +        catch (Exception e) 
  +        {
  +          // System.out.println("Extension error: "+e.getMessage ());
  +          throw new XPathProcessorException (e.getMessage (), e);
  +        }
  +      }
  +    }
  +
  +    // if scriptSrcURL is specified read it off
  +    if (scriptSrcURL != null) 
  +    {
  +      throw new XPathProcessorException ("src attr not supported (yet)");
  +    }
  +
  +    if (scriptSrc == null) 
  +    {
  +      return;
  +    }
  +    
  +    if(null == mgr)
  +      mgr = new BSFManager ();
  +
  +    // evaluate the src to load whatever content is in that string to 
  +    // the engines
  +    try 
  +    {
  +      ((BSFManager)mgr).exec (scriptLang, "LotusXSLScript", -1, -1, 
scriptSrc);
  +    }
  +    catch (BSFException bsfe) 
  +    {
  +      throw new XPathProcessorException (bsfe.getMessage (), bsfe);
  +    }
  +             componentStarted = true;
  +  }
  +
   }
   
  
  
  
  1.11      +5 -1      
xml-xalan/src/org/apache/xalan/xslt/ExtensionNSHandler.java
  
  Index: ExtensionNSHandler.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/src/org/apache/xalan/xslt/ExtensionNSHandler.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- ExtensionNSHandler.java   2000/09/07 22:21:10     1.10
  +++ ExtensionNSHandler.java   2000/09/25 20:31:29     1.11
  @@ -286,6 +286,9 @@
      */
     protected void startupComponent (Class classObj) throws  
XPathProcessorException
     {
  +             /**
  +        * Patch from Costin Manolache
  +        *
       if(!bsfInitialized)
       {
         synchronized(m_bsfInitSynch)
  @@ -295,7 +298,8 @@
                                                           
"org.apache.xalan.xpath.XSLTJavaClassEngine",
                                                           new String[0]);
         }
  -    }
  +    }*/
  +             extensionLiaison.checkInit();
   
       if (!componentDescLoaded)
       {
  
  
  

Reply via email to