|
Hi there, enclosed you'll find a diff ("svn diff" was run off the "org.apache.bsf" directory), which contains the following changes:
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 "relaxed" 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]
