Hi there,

enclosed you'll find a diff ("svn diff" was run off the "org.apache.bsf" directory), which contains the following changes:
  1. fixed dynamic event handler generating code (e.g. allows creating event handlers for swt),
  2. added an event processor that supplies the arguments sent to the event listener, most notably the event object, cf. <util/EngineUtils.addEventListenerReturningEventInfos(...)> and lookup <util/BSFEventProcessorReturningEventInfos.java>, which processes the events and invokes apply() supplying the received arguments plus the name of the event that had occurred.
Please ignore the references to OpenOffice.org, it should not go into the distribution, as this is a fix for an individual application (the problem: the OOo Java interface does not list the OOo event listeners to implement java.utils.EventListener, so the introspection does not figure out the OOo events). OOo will get changed such that introspection (hence BSF) will be able to detect the OOo event listeners (which is necessary for creating the BSF event listeners on the fly with the correct signatures). I leave the diffs in, such that interested people could pull them off, if a need arises for them to support OOo.

Regards,

---rony



Index: util/event/generator/EventAdapterGenerator.java
===================================================================
--- util/event/generator/EventAdapterGenerator.java     (revision 381339)
+++ util/event/generator/EventAdapterGenerator.java     (working copy)
@@ -53,13 +53,19 @@
  * please see <http://www.apache.org/>.
  */
 
+ /* changes:
+                2006-02-03, Rony G. Flatscher: added OpenOffice.org support 
(versions 1.1.x and 2.0.1)
+                            which need special handling due to their omission 
to tagt heir event
+                            listeners as implementing 
"java.util.EventListener" inhibiting standard
+                            introspection to identify events; therefore a 
"manual" branch got introduced
+                            to identify OpenOffice.org event listeners
+ */
+
 package org.apache.bsf.util.event.generator;
 
 import java.io.*;
@@ -69,6 +75,7 @@
 {
   public static AdapterClassLoader ldr = new AdapterClassLoader();
   static Class  EVENTLISTENER          = null;
+  static Class  OPENOFFICE_XEVENTLISTENER = null;
   static String CLASSPACKAGE           = "org/apache/bsf/util/event/adapters/";
   static String WRITEDIRECTORY         = null;
 
@@ -120,6 +122,18 @@
             ex.printStackTrace();
         }
 
+
+            // try to load the OpenOffice.org (OOo) counterpart of 
EventListener; unfortunately as of 2006
+            // OOo's XEventListener does not report to have 
'java.util.EventListener' implemented, hence
+            // Introspector cannot identify events !
+        try
+        {
+            OPENOFFICE_XEVENTLISTENER = 
Thread.currentThread().getContextClassLoader().loadClass 
("com.sun.star.lang.XEventListener");
+        }
+        catch (Exception e)
+        {
+        }
+
        // start of the Java Class File
        CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(byte)0xCA);  // magic
        CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(byte)0xFE);  // magic
@@ -211,9 +225,13 @@
   /* methods that take an EventListener Class Type to create an 
EventAdapterClass */
   public static Class makeEventAdapterClass(Class listenerType,boolean 
writeClassFile)
   {
-      logger.info("EventAdapterGenerator");
+      DebugLog.stdoutPrintln("EventAdapterGenerator", DebugLog.BSF_LOG_L3);
 
-       if( EVENTLISTENER.isAssignableFrom(listenerType) )
+        if( EVENTLISTENER.isAssignableFrom(listenerType) ||
+                // test explicitly OpenOffice.org listener types; as of 
2006-02-03 neither 1.1.5 nor
+                // OOo 2.0.1 do indicate that they implement 
'java.lang.EventListener'
+            ( OPENOFFICE_XEVENTLISTENER!=null && 
OPENOFFICE_XEVENTLISTENER.isAssignableFrom(listenerType) )
+        )
        {
          boolean exceptionable    = false;
          boolean nonExceptionable = false;
@@ -560,7 +580,8 @@
          {
                try
                {
-                 FileOutputStream fos =  new 
FileOutputStream(WRITEDIRECTORY+finalAdapterClassName+".class");
+                    // removed "WRITEDIRECTORY+", as this path is already part 
of 'finalAdapterClassName'
+                 FileOutputStream fos =  new 
FileOutputStream(finalAdapterClassName+".class");
                  fos.write(newClass);
                  fos.close();
                }
Index: util/event/generator/AdapterClassLoader.java
===================================================================
--- util/event/generator/AdapterClassLoader.java        (revision 381339)
+++ util/event/generator/AdapterClassLoader.java        (working copy)
@@ -53,18 +53,20 @@
  * please see <http://www.apache.org/>.
  */
 
+ /* changes:
+                2006-02-03, Rony G. Flatscher: fixed bug 
(ClassLoader.loadClass(...) needs "/" and not "." as
+                            path separators
+ */
+
 package org.apache.bsf.util.event.generator;
 
 import java.util.*;
@@ -74,13 +76,14 @@
   {
        if ((c = getLoadedClass(name)) == null)
        {
-         c = defineClass(name, b, 0, b.length);
+         c = defineClass(name.replace('/','.'), b, 0, b.length);   // rgf, 
2006-02-03
          put(name, c);
        }
        else
Index: util/event/EventAdapterRegistry.java
===================================================================
--- util/event/EventAdapterRegistry.java        (revision 381339)
+++ util/event/EventAdapterRegistry.java        (working copy)
@@ -99,12 +99,11 @@
                // adapterClass = (cl != null) ? cl.loadClass (cn) : 
Class.forName (cn);
                adapterClass = (cl != null) ? cl.loadClass (cn)
                                             : 
Thread.currentThread().getContextClassLoader().loadClass (cn); // rgf, 
2006-01-05
-
          } catch (ClassNotFoundException e) {
                if (dynamic) {
                  // Unable to resolve one, try to generate one.
-                 adapterClass =
-                       EventAdapterGenerator.makeEventAdapterClass 
(listenerType, false);
+                 adapterClass = // if second argument is set to 'true', then 
the class file will be stored in the filesystem
+                      EventAdapterGenerator.makeEventAdapterClass 
(listenerType, false);
                }
          }
 
Index: util/BSFEventProcessorReturningEventInfos.java
===================================================================
--- util/BSFEventProcessorReturningEventInfos.java      (revision 0)
+++ util/BSFEventProcessorReturningEventInfos.java      (revision 0)
@@ -0,0 +1,146 @@
+/*
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * Sanjiva Weerawarana and others at International Business Machines
+ * Corporation. For more information on the Apache Software Foundation,
+ * please see <http://www.apache.org/>.
+ */
+
+package org.apache.bsf.util;
+
+import org.apache.bsf.util.event.*;
+import org.apache.bsf.*;
+import java.io.PrintStream;
+import java.util.Vector;
+
+/**
+ * This is used to support binding scripts to be run when an event
+ * occurs, forwarding the arguments supplied to the event listener. It is an 
adapted version of
+ * [EMAIL PROTECTED] org.apache.bsf.util.BSFEventProcessor}.
+ *
+ * <pre>------------------------ Apache Version 2.0 license 
-------------------------
+ *    Copyright (C) 2001-2006 Rony G. Flatscher
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        <a 
href="http://www.apache.org/licenses/LICENSE-2.0";>http://www.apache.org/licenses/LICENSE-2.0</a>
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * 
----------------------------------------------------------------------------- 
</pre>
+ *
+ * @author Rony G. Flatscher, but most of the code copied from 
org.apache.bsf.util.BSFEventProcessor by Sanjiva Weerawarana
+ *
+ *
+ * @see [EMAIL PROTECTED] org.apache.bsf.util.BSFEventProcessor}
+ *
+ */
+public class  BSFEventProcessorReturningEventInfos implements EventProcessor {
+  BSFEngine engine;
+  BSFManager manager;
+  String filter;
+  String source;
+  int lineNo;
+  int columnNo;
+  Object script;
+  Object dataFromScriptingEngine; // ---rgf, 2006-02-24: data coming from the 
script engine, could be
+                                  // e.g. an object reference to forward event 
with received arguments to
+
+  /**
+   * Package-protected constructor makes this class unavailable for
+   * public use.
+   *
+   * @param dataFromScriptingEngine this contains any object supplied by the 
scripting engine and gets
+   *        sent back with the supplied script. This could be used e.g. for 
indicating which scripting
+   *        engine object should be ultimately informed of the event 
occurrence.
+   */
+  BSFEventProcessorReturningEventInfos (BSFEngine engine, BSFManager manager, 
String filter,
+                    String source, int lineNo, int columnNo, Object script, 
Object dataFromScriptingEngine)
+          throws BSFException {
+       this.engine = engine;
+       this.manager = manager;
+       this.filter = filter;
+       this.source = source;
+       this.lineNo = lineNo;
+       this.columnNo = columnNo;
+       this.script = script;
+       this.dataFromScriptingEngine = dataFromScriptingEngine;
+  }
+  //////////////////////////////////////////////////////////////////////////
+  //
+  // event is delegated to me by the adapters using this. inFilter is
+  // in general the name of the method via which the event was received
+  // at the adapter. For prop/veto change events, inFilter is the name
+  // of the property. In any case, in the event processor, I only forward
+  // those events if for which the filters match (if one is specified).
+
+
+  public void processEvent (String inFilter, Object[] evtInfo) {
+       try {
+         processExceptionableEvent (inFilter, evtInfo);
+       } catch (RuntimeException re) {
+         // rethrow this .. I don't want to intercept run-time stuff
+         // that can in fact occur legit
+         throw re;
+       } catch (Exception e) {
+         // should not occur
+         System.err.println ("BSFError: non-exceptionable event delivery " +
+                                     "threw exception (that's not nice): " + 
e);
+         e.printStackTrace ();
+       }
+  }
+
+  //////////////////////////////////////////////////////////////////////////
+  //
+  // same as above, but used when the method event method may generate
+  // an exception which must go all the way back to the source (as in
+  // the vetoableChange case)
+
+  public void processExceptionableEvent (String inFilter, Object[] evtInfo) 
throws Exception {
+
+// System.err.println(this+": inFilter=["+inFilter+"], filter=["+filter+"]");
+       if ((filter != null) && !filter.equals (inFilter)) {
+         // ignore this event
+         return;
+       }
+
+       // run the script
+       // engine.exec (source, lineNo, columnNo, script);
+
+            // create the parameter vectors for engine.apply()
+        Vector paramNames  = new Vector(), paramValues = new Vector();
+
+            // parameter # 1
+            // supply the parameters as an array object as sent to the event 
object listener
+            // (usually the first entry is the sent event object)
+        paramNames. add( "eventParameters" );
+        paramValues.add( evtInfo );
+
+            // parameter # 2
+            // supply the data object received from the scripting engine to be 
sent with the event
+        paramNames. add(     "dataFromScriptingEngine" );
+        paramValues.add( this.dataFromScriptingEngine  );       // can be null 
as well
+
+            // parameter # 3
+            // event filter in place
+        paramNames. add( "inFilter" );
+        paramValues.add(  inFilter );           // event name that has occurred
+
+            // parameter # 4
+            // event filter in place
+        paramNames. add( "eventFilter" );
+        paramValues.add(  this.filter );        // can be null as well
+
+            // parameter # 5
+        // BSF manager instance (e.g. allows access to its registry)
+        paramNames. add( "BSFManager" );
+        paramValues.add(  this.manager  );
+
+        engine.apply(source, lineNo, columnNo, this.script, paramNames, 
paramValues);
+  }
+}

Property changes on: util/BSFEventProcessorReturningEventInfos.java
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:keywords
   + Author Date Rev Id URL

Index: util/ReflectionUtils.java
===================================================================
--- util/ReflectionUtils.java   (revision 381339)
+++ util/ReflectionUtils.java   (working copy)
@@ -70,6 +70,7 @@
  *
  * @author   Sanjiva Weerawarana
  * @author   Joseph Kesselman
+ * @author   Rony G. Flatscher (added Proxy-handling needed for OpenOffice.org 
1.1.x and 2.0.x as of 2006-02-03)
  */
 public class ReflectionUtils {
 
@@ -98,25 +99,68 @@
           throws IntrospectionException, IllegalArgumentException,
                          IllegalAccessException, InstantiationException,
                          InvocationTargetException {
+
        // find the event set descriptor for this event
        BeanInfo bi = Introspector.getBeanInfo (source.getClass ());
        EventSetDescriptor esd = (EventSetDescriptor)
          findFeatureByName ("event", eventSetName, bi.getEventSetDescriptors 
());
-       if (esd == null) {
-         throw new IllegalArgumentException ("event set '" + eventSetName +
-                                                                               
  "' unknown for source type '" +
-                                                                               
  source.getClass () + "'");
-       }
 
+
        // get the class object for the event
-       Class listenerType = esd.getListenerType ();
+       Class listenerType = null;
+        int idx2mmm=0;
+        java.lang.reflect.Method mmm[]=null;        // array object to store 
methods from Proxy-class reflected methods
 
+       if (esd == null)        // no events found, maybe a proxy from 
OpenOffice.org?
+        {
+            if (java.lang.reflect.Proxy.class.isInstance(source)==true) // a 
Proxy class, hence reflect "manually"
+            {
+                mmm=source.getClass().getMethods();  // get all methods
+                for (idx2mmm=0; idx2mmm<mmm.length; idx2mmm++)
+                {
+                    String methName=mmm[idx2mmm].getName();
+                        // looking for a method 
"add_XYZ_Listener(someEventClass)
+                    if (methName.endsWith("Listener")==true)
+                    {
+                        String un=getUnqualifiedName(methName);
+
+                        if (un.startsWith("add"))       // get first argument, 
which must be an Event class
+                        {
+                            String tmpName=un.substring(3, un.length()-8);   
// -lengthOf(("add"=3)+("Listener"=8))
+                            if (eventSetName.equalsIgnoreCase(tmpName))
+                            {
+                                java.lang.Class 
params[]=mmm[idx2mmm].getParameterTypes();
+                                if (params.length>0)
+                                {
+                                    listenerType=params[0]; // o.k. found 
ListenerClass
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (listenerType==null)     // o.k. no listenerType found, throw 
up ...
+            {
+                throw new IllegalArgumentException ("event set '" + 
eventSetName +
+                                                    "' unknown for source type 
'" + source.getClass () + "'");
+            }
+
+       }
+        else    // ListenerType from EventSetDescriptor
+        {
+            listenerType=esd.getListenerType(); // get ListenerType class 
object from EventSetDescriptor
+        }
+
+
+
        // find an event adapter class of the right type
        Class adapterClass = EventAdapterRegistry.lookup (listenerType);
        if (adapterClass == null) {
-         throw new IllegalArgumentException ("event adapter for listner type " 
+
-                                                                               
  "'" + listenerType + "' (eventset " +
-                                                                               
  "'" + eventSetName + "') unknown");
+         throw new IllegalArgumentException ("event adapter for listener type 
" +
+                                             "'" + listenerType + "' (eventset 
" +
+                                             "'" + eventSetName + "') 
unknown");
        }
 
        // create the event adapter and give it the event processor
@@ -135,16 +179,77 @@
          // in this case to support the source-side filtering.
          //
          // ** TBD **: the following two lines need to change appropriately
-         addListenerMethod = esd.getAddListenerMethod ();
+          if (mmm==null)
+          {
+              addListenerMethod = esd.getAddListenerMethod ();
+          }
+          else
+          {
+              addListenerMethod = mmm[idx2mmm];
+          }
          args = new Object[] {adapter};
-       } else {
-         addListenerMethod = esd.getAddListenerMethod ();
+       }
+        else
+        {
+          if (mmm==null) {
+              addListenerMethod = esd.getAddListenerMethod ();
+          }
+          else
+          {
+              addListenerMethod = mmm[idx2mmm];
+          }
          args = new Object[] {adapter};
        }
        addListenerMethod.invoke (source, args);
   }
   //////////////////////////////////////////////////////////////////////////
 
+
+  /** Compares two strings in a &quot;relaxed&quot; manner, i.e.
+   *  tests case-insensitively, whether the second argument
+   *  <code>haystack</code> ends with the first argument <code>endName</code>
+   *  string.
+   *
+   * @param endName the string which should end <code>haystack</code>
+   * @param haystack the string to test <code>endName</code> against
+   *
+   * @return <code>true</code>, if <code>haystack</code> ends with the
+   *         string <code>endName</code> (comparison carried out 
case-insensitively),
+   *         <code>false</code> else
+   */
+  static boolean compareRelaxed(String endName, String haystack)
+  {
+      int endNameLength=endName.length(),
+          tmpLength    =haystack.length();
+
+      if (endNameLength>tmpLength)        // interface endName is shorter than 
the sought of one
+      {
+          return false;
+      }
+      else if (endNameLength!=tmpLength)  // cut off haystack from the right 
to match length of received endName
+      {
+          //             012345678
+          //     abc=3   x.y.z.abc=9  9-3=6
+          haystack=haystack.substring(tmpLength-endNameLength);    // cut off 
from the right
+      }
+
+      return endName.equalsIgnoreCase(haystack);
+  }
+  //////////////////////////////////////////////////////////////////////////
+
+  /** Returns unqualified name (string after the last dot) from dotted string 
or string itself, if no dot in string.
+   *
+   * @param s String to extract unqualified name
+   * @return returns unqualified name or s, if no dot in string
+   */
+  static String getUnqualifiedName(String s)
+  {
+      int    lastPos=s.lastIndexOf('.');          // get position of last dot
+      return lastPos==-1 ? s : s.substring(lastPos+1) ;
+  }
+  //////////////////////////////////////////////////////////////////////////
+
+
   /**
    * Create a bean using given class loader and using the appropriate
    * constructor for the given args of the given arg types.
Index: util/EngineUtils.java
===================================================================
--- util/EngineUtils.java       (revision 381339)
+++ util/EngineUtils.java       (working copy)
@@ -69,6 +69,7 @@
  *
  * @author   Sanjiva Weerawarana
  * @author   Sam Ruby
+ * @author   Rony G. Flatscher (added addEventListenerReturningEventInfos)
  */
 public class EngineUtils {
     // the BSF class loader that knows how to load from the a specific
@@ -129,7 +130,65 @@
         }
     }
 
+
     /**
+     * Add a script as a listener to some event coming out of an object. The
+     * first two args identify the src of the event and the event set
+     * and the rest identify the script which should be run when the event
+     * fires. The processing will use the engine's apply() method.
+     *
+     * @param bean         event source
+     * @param eventSetName name of event set from event src to bind to
+     * @param filter       filter for events
+     * @param engine       BSFEngine which can run this script
+     * @param manager      BSFManager of the above engine
+     * @param source       (context info) the source of this expression (e.g., 
filename)
+     * @param lineNo       (context info) the line number in source for expr
+     * @param columnNo     (context info) the column number in source for expr
+     * @param script       the script to execute when the event occurs
+     * @param dataFromScriptingEngine
+     *                     this contains any object supplied by the scripting 
engine and gets sent
+     *                     back with the supplied script, if the event occurs.
+     *                     This could be used e.g. for indicating to the 
scripting engine which
+     *                     scripting engine object/routine/function/procedure
+     *                     should be ultimately informed of the event 
occurrence.
+     *
+     * @exception BSFException if anything goes wrong while running the script
+     */
+    public static void addEventListenerReturningEventInfos ( Object bean,
+                               String eventSetName,
+                               String filter,
+                               BSFEngine engine,
+                               BSFManager manager,
+                               String source,
+                               int lineNo,
+                               int columnNo,
+                               Object script,
+                               Object dataFromScriptingEngine
+                               ) throws BSFException
+    {
+        BSFEventProcessorReturningEventInfos ep =
+        new BSFEventProcessorReturningEventInfos (engine,
+                                                  manager,
+                                                  filter,
+                                                  source,
+                                                  lineNo,
+                                                  columnNo,
+                                                  script,
+                                                  dataFromScriptingEngine
+                                                  );
+
+        try {
+            ReflectionUtils.addEventListener (bean, eventSetName, ep);
+        } catch (Exception e) {
+            e.printStackTrace ();
+            throw new BSFException (BSFException.REASON_OTHER_ERROR,
+                                    "ouch while adding event listener: "
+                                    + e, e);
+        }
+    }
+
+    /**
      * Finds and invokes a method with the given signature on the given
      * bean. The signature of the method that's invoked is first taken
      * as the types of the args, but if that fails, this tries to convert

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to