You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by cj...@apache.org on 2003/08/14 11:32:30 UTC
cvs commit: xml-batik/sources/org/apache/batik/script/rhino EventTargetWrapper.java
cjolif 2003/08/14 02:32:30
Modified: sources/org/apache/batik/script/rhino
EventTargetWrapper.java
Log:
1/ remove usage of JavaNativeMethod to avoid problems with current Rhino
CVS modifications.
2/ fix a bug that was preventing in some cases the listeners to be removed
because the listenerMap was not shared among all the pointers on some
EventTarget
Revision Changes Path
1.13 +140 -49 xml-batik/sources/org/apache/batik/script/rhino/EventTargetWrapper.java
Index: EventTargetWrapper.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/script/rhino/EventTargetWrapper.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- EventTargetWrapper.java 9 Aug 2003 16:58:40 -0000 1.12
+++ EventTargetWrapper.java 14 Aug 2003 09:32:29 -0000 1.13
@@ -53,11 +53,11 @@
import java.lang.reflect.Method;
import java.util.Map;
import java.util.HashMap;
+import java.util.WeakHashMap;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.JavaScriptException;
-import org.mozilla.javascript.NativeJavaMethod;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
@@ -105,7 +105,7 @@
}
}
- class HandleEventListener implements EventListener {
+ static class HandleEventListener implements EventListener {
private final static String HANDLE_EVENT = "handleEvent";
private Scriptable scriptable;
@@ -133,11 +133,98 @@
}
}
- class RhinoNativeJavaAddMethod extends NativeJavaMethod {
- Map listenerMap;
- RhinoNativeJavaAddMethod(Method method, String name,
- Map listenerMap) {
- super(method, name);
+ static abstract class FunctionProxy implements Function {
+ protected Function delegate;
+
+ public FunctionProxy(Function delegate) {
+ this.delegate = delegate;
+ }
+
+ public Scriptable construct(Context cx,
+ Scriptable scope, Object[] args)
+ throws JavaScriptException {
+ return this.delegate.construct(cx, scope, args);
+ }
+
+ public String getClassName() {
+ return this.delegate.getClassName();
+ }
+
+ public Object get(String name, Scriptable start) {
+ return this.delegate.get(name, start);
+ }
+
+ public Object get(int index, Scriptable start) {
+ return this.delegate.get(index, start);
+ }
+
+ public boolean has(String name, Scriptable start) {
+ return this.delegate.has(name, start);
+ }
+
+ public boolean has(int index, Scriptable start) {
+ return this.delegate.has(index, start);
+ }
+
+ public void put(String name, Scriptable start, Object value) {
+ this.delegate.put(name, start, value);
+ }
+
+ public void put(int index, Scriptable start, Object value) {
+ this.delegate.put(index, start, value);
+ }
+
+ public void delete(String name) {
+ this.delegate.delete(name);
+ }
+
+ public void delete(int index) {
+ this.delegate.delete(index);
+ }
+
+ public Scriptable getPrototype() {
+ return this.delegate.getPrototype();
+ }
+
+ public void setPrototype(Scriptable prototype) {
+ this.delegate.setPrototype(prototype);
+ }
+
+ public Scriptable getParentScope() {
+ return this.delegate.getParentScope();
+ }
+
+ public void setParentScope(Scriptable parent) {
+ this.delegate.setParentScope(parent);
+ }
+
+ public Object[] getIds() {
+ return this.delegate.getIds();
+ }
+
+ public Object getDefaultValue(Class hint) {
+ return this.delegate.getDefaultValue(hint);
+ }
+
+ public boolean hasInstance(Scriptable instance) {
+ return this.delegate.hasInstance(instance);
+ }
+ }
+
+ /**
+ * This function proxy is delegating most of the job
+ * to the underlying NativeJavaMethod object through
+ * the FunctionProxy. However to allow user to specify
+ * "Function" or objects with an "handleEvent" method
+ * as parameter of "addEventListener"
+ * it redefines the call method to deal with these
+ * cases.
+ */
+ static class FunctionAddProxy extends FunctionProxy {
+ private Map listenerMap;
+
+ FunctionAddProxy(Function delegate, Map listenerMap) {
+ super(delegate);
this.listenerMap = listenerMap;
}
@@ -146,7 +233,6 @@
throws JavaScriptException {
NativeJavaObject njo = (NativeJavaObject)thisObj;
if (args[1] instanceof Function) {
-
EventListener evtListener = new FunctionEventListener
((Function)args[1],
((RhinoInterpreter.ExtendedContext)ctx).getInterpreter());
@@ -156,41 +242,39 @@
Boolean.TYPE };
for (int i = 0; i < args.length; i++)
args[i] = Context.toType(args[i], paramTypes[i]);
-
-
((EventTarget)njo.unwrap()).addEventListener
((String)args[0], evtListener,
((Boolean)args[2]).booleanValue());
return Undefined.instance;
- }
+ }
if (args[1] instanceof NativeObject) {
EventListener evtListener =
- new HandleEventListener((Scriptable)args[1],
- ((RhinoInterpreter.ExtendedContext)ctx).getInterpreter());
+ new HandleEventListener((Scriptable)args[1],
+ ((RhinoInterpreter.ExtendedContext)
+ ctx).getInterpreter());
listenerMap.put(args[1], evtListener);
// we need to marshall args
Class[] paramTypes = { String.class, Scriptable.class,
Boolean.TYPE };
for (int i = 0; i < args.length; i++)
args[i] = Context.toType(args[i], paramTypes[i]);
-
((EventTarget)njo.unwrap()).addEventListener
((String)args[0], evtListener,
((Boolean)args[2]).booleanValue());
return Undefined.instance;
}
-
- return super.call(ctx, scope, thisObj, args);
+ return delegate.call(ctx, scope, thisObj, args);
}
}
- static class RhinoNativeJavaRemoveMethod extends NativeJavaMethod {
- Map listenerMap;
- RhinoNativeJavaRemoveMethod(Method method, String name,
- Map listenerMap) {
- super(method, name);
+ static class FunctionRemoveProxy extends FunctionProxy {
+ private Map listenerMap;
+
+ FunctionRemoveProxy(Function delegate, Map listenerMap) {
+ super(delegate);
this.listenerMap = listenerMap;
}
+
public Object call(Context ctx, Scriptable scope,
Scriptable thisObj, Object[] args)
throws JavaScriptException {
@@ -198,26 +282,22 @@
if (args[1] instanceof Function) {
EventListener el;
el = (EventListener)listenerMap.remove(args[1]);
- if (el == null)
+ if (el == null)
return Undefined.instance;
-
// we need to marshall args
Class[] paramTypes = { String.class, Function.class,
Boolean.TYPE };
for (int i = 0; i < args.length; i++)
args[i] = Context.toType(args[i], paramTypes[i]);
-
((EventTarget)njo.unwrap()).removeEventListener
((String)args[0], el, ((Boolean)args[2]).booleanValue());
return Undefined.instance;
}
-
if (args[1] instanceof NativeObject) {
EventListener el;
el = (EventListener)listenerMap.remove(args[1]);
- if (el == null)
+ if (el == null)
return Undefined.instance;
-
// we need to marshall args
Class[] paramTypes = { String.class, Scriptable.class,
Boolean.TYPE };
@@ -228,12 +308,15 @@
((String)args[0], el, ((Boolean)args[2]).booleanValue());
return Undefined.instance;
}
- return super.call(ctx, scope, thisObj, args);
+ return delegate.call(ctx, scope, thisObj, args);
}
}
- private NativeJavaMethod methodadd;
- private NativeJavaMethod methodremove;
+ // the keys are the underlying Java object, in order
+ // to remove potential memory leaks use a WeakHashMap to allow
+ // to collect entries as soon as the underlying Java object is
+ // not anymore available.
+ private static WeakHashMap mapOfListenerMap;
private final static String ADD_NAME = "addEventListener";
private final static String REMOVE_NAME = "removeEventListener";
@@ -244,29 +327,37 @@
EventTargetWrapper(Scriptable scope, EventTarget object) {
super(scope, object, null);
- try {
- HashMap listenerMap = new HashMap(2);
- methodadd = new RhinoNativeJavaAddMethod
- (object.getClass().getMethod(ADD_NAME,ARGS_TYPE),
- ADD_NAME, listenerMap);
- methodremove = new RhinoNativeJavaRemoveMethod
- (object.getClass().getMethod(REMOVE_NAME,ARGS_TYPE),
- REMOVE_NAME, listenerMap);
- } catch (NoSuchMethodException e) {
- // should not happened
- // we are sure the method are there as we
- // have an EventTarget in parameter
- }
}
/**
* Overriden Rhino method.
*/
public Object get(String name, Scriptable start) {
- if (name.equals(ADD_NAME))
- return methodadd;
- if (name.equals(REMOVE_NAME))
- return methodremove;
- return super.get(name, start);
+ Object method = super.get(name, start);
+ if (name.equals(ADD_NAME)) {
+ // prevent creating a Map for all JavaScript objects
+ // when we need it only from time to time...
+ method = new FunctionAddProxy((Function)method, initMap());
+ }
+ if (name.equals(REMOVE_NAME)) {
+ // prevent creating a Map for all JavaScript objects
+ // when we need it only from time to time...
+ Map listenerMap = initMap();
+ method = new FunctionRemoveProxy((Function)method, initMap());
+ }
+ return method;
+ }
+
+ // we have to store the listenerMap in a Map because
+ // several EventTargetWrapper may be created for the exact
+ // same underlying Java object.
+ public Map initMap() {
+ Map map = null;
+ if (mapOfListenerMap == null)
+ mapOfListenerMap = new WeakHashMap(10);
+ if ((map = (Map)mapOfListenerMap.get(unwrap())) == null) {
+ mapOfListenerMap.put(unwrap(), map = new HashMap(2));
+ }
+ return map;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org