cjolif 01/10/08 08:04:39 Modified: sources/org/apache/batik/script DocumentProxy.java Interpreter.java sources/org/apache/batik/script/jacl JaclInterpreter.java sources/org/apache/batik/script/jpython JPythonInterpreter.java sources/org/apache/batik/script/rhino EventTargetWrapper.java RhinoInterpreter.java Log: Add to the Interpreter interface an evaluate method that take a String in addition to the one that uses a Reader. Implement it, in the different Interpreter concrete classes. This new method allows in the RhinoIntepreter to easily do some cache on the compilation of small pieces of ECMAScript code. This avoid the re-compilation (and thus creation of dynamic Java Classes) at each time an evaluation is performed. The idea and a first draft solution was proposed by George Moudry. Revision Changes Path 1.3 +5 -1 xml-batik/sources/org/apache/batik/script/DocumentProxy.java Index: DocumentProxy.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/script/DocumentProxy.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- DocumentProxy.java 2001/05/14 16:47:47 1.2 +++ DocumentProxy.java 2001/10/08 15:04:39 1.3 @@ -30,9 +30,13 @@ * Proxy to a <code>Document</code> using a <code>WeakReference</code> to * allow the document to be discared when not used outside of the intepreter. * @author <a href="mailto:[EMAIL PROTECTED]">Christophe Jolif</a> - * @version $Id: DocumentProxy.java,v 1.2 2001/05/14 16:47:47 tkormann Exp $ + * @version $Id: DocumentProxy.java,v 1.3 2001/10/08 15:04:39 cjolif Exp $ */ public class DocumentProxy implements Document { + /** + * The <code>WeakReference</code> to the actual + * <code>Document</code>. + */ protected WeakReference ref = null; public DocumentProxy(Document document) 1.4 +11 -1 xml-batik/sources/org/apache/batik/script/Interpreter.java Index: Interpreter.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/script/Interpreter.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Interpreter.java 2001/01/24 13:51:54 1.3 +++ Interpreter.java 2001/10/08 15:04:39 1.4 @@ -16,7 +16,7 @@ * An hight level interface that represents an interpreter engine of * a particular scripting language. * @author <a href="mailto:[EMAIL PROTECTED]">Christophe Jolif</a> - * @version $Id: Interpreter.java,v 1.3 2001/01/24 13:51:54 cjolif Exp $ + * @version $Id: Interpreter.java,v 1.4 2001/10/08 15:04:39 cjolif Exp $ */ public interface Interpreter extends org.apache.batik.i18n.Localizable { /** @@ -27,6 +27,16 @@ */ public Object evaluate(Reader scriptreader) throws InterpreterException, IOException; + /** + * This method should evaluate a piece of script using a <code>String</code> + * instead of a <code>Reader</code>. This usually allows do easily do some + * caching. + * @param script the piece of script + * @return if no exception is thrown during the call, should return the + * value of the last expression evaluated in the script + */ + public Object evaluate(String script) + throws InterpreterException; /** * This method should register a particular Java <code>Object</code> in * the environment of the interpreter. 1.4 +15 -10 xml-batik/sources/org/apache/batik/script/jacl/JaclInterpreter.java Index: JaclInterpreter.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/script/jacl/JaclInterpreter.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- JaclInterpreter.java 2001/01/24 14:50:58 1.3 +++ JaclInterpreter.java 2001/10/08 15:04:39 1.4 @@ -20,7 +20,7 @@ * A simple implementation of <code>Interpreter</code> interface to use * JACL Tcl parser. * @author <a href="mailto:[EMAIL PROTECTED]">Christophe Jolif</a> - * @version $Id: JaclInterpreter.java,v 1.3 2001/01/24 14:50:58 cjolif Exp $ + * @version $Id: JaclInterpreter.java,v 1.4 2001/10/08 15:04:39 cjolif Exp $ */ public class JaclInterpreter implements org.apache.batik.script.Interpreter { private Interp interpreter = null; @@ -37,16 +37,21 @@ public Object evaluate(Reader scriptreader) throws InterpreterException, IOException { + // oups jacl doesn't accept reader in its eval method :-( + StringBuffer sbuffer = new StringBuffer(); + char[] buffer = new char[1024]; + int val = 0; + while ((val = scriptreader.read(buffer)) != -1) { + sbuffer.append(buffer, 0, val); + } + String str = sbuffer.toString(); + return evaluate(str, 0); + } + + public Object evaluate(String script) + throws InterpreterException { try { - // oups jacl doesn't accept reader in its eval method :-( - StringBuffer sbuffer = new StringBuffer(); - char[] buffer = new char[1024]; - int val = 0; - while ((val = scriptreader.read(buffer)) != -1) { - sbuffer.append(buffer, 0, val); - } - String str = sbuffer.toString(); - interpreter.eval(str, 0); + interpreter.eval(script, 0); } catch (TclException e) { throw new InterpreterException(e, e.getMessage(), -1, -1); } catch (RuntimeException re) { 1.4 +15 -9 xml-batik/sources/org/apache/batik/script/jpython/JPythonInterpreter.java Index: JPythonInterpreter.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/script/jpython/JPythonInterpreter.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- JPythonInterpreter.java 2001/01/24 14:51:00 1.3 +++ JPythonInterpreter.java 2001/10/08 15:04:39 1.4 @@ -20,7 +20,7 @@ * A simple implementation of <code>Interpreter</code> interface to use * JPython python parser. * @author <a href="mailto:[EMAIL PROTECTED]">Christophe Jolif</a> - * @version $Id: JPythonInterpreter.java,v 1.3 2001/01/24 14:51:00 cjolif Exp $ + * @version $Id: JPythonInterpreter.java,v 1.4 2001/10/08 15:04:39 cjolif Exp $ */ public class JPythonInterpreter implements org.apache.batik.script.Interpreter { private PythonInterpreter interpreter = null; @@ -33,16 +33,22 @@ public Object evaluate(Reader scriptreader) throws InterpreterException, IOException { + // oups jpython doesn't accept reader in its eval method :-( + StringBuffer sbuffer = new StringBuffer(); + char[] buffer = new char[1024]; + int val = 0; + while ((val = scriptreader.read(buffer)) != -1) { + sbuffer.append(buffer,0, val); + } + String str = sbuffer.toString(); + return evaluate(str); + } + + public Object evaluate(String script) + throws InterpreterException { try { - // oups jpython doesn't accept reader in its eval method :-( - StringBuffer sbuffer = new StringBuffer(); - char[] buffer = new char[1024]; - int val = 0; - while ((val = scriptreader.read(buffer)) != -1) { - sbuffer.append(buffer,0, val); - } String str = sbuffer.toString(); - interpreter.exec(str); + interpreter.exec(script); } catch (org.python.core.PyException e) { throw new InterpreterException(e, e.getMessage(), -1, -1); } catch (RuntimeException re) { 1.5 +2 -2 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.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- EventTargetWrapper.java 2001/06/01 13:54:06 1.4 +++ EventTargetWrapper.java 2001/10/08 15:04:39 1.5 @@ -28,13 +28,13 @@ import org.apache.batik.script.InterpreterException; /** - * A class that wrap an <code>EventTarget</code> instance to expose + * A class that wraps an <code>EventTarget</code> instance to expose * it in the Rhino engine. Then calling <code>addEventListener</code> * with a Rhino function as parameter should redirect the call to * <code>addEventListener</code> with a Java function object calling * the Rhino function. * @author <a href="mailto:[EMAIL PROTECTED]">Christophe Jolif</a> - * @version $Id: EventTargetWrapper.java,v 1.4 2001/06/01 13:54:06 cjolif Exp $ + * @version $Id: EventTargetWrapper.java,v 1.5 2001/10/08 15:04:39 cjolif Exp $ */ class EventTargetWrapper extends NativeJavaObject { 1.7 +101 -5 xml-batik/sources/org/apache/batik/script/rhino/RhinoInterpreter.java Index: RhinoInterpreter.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/script/rhino/RhinoInterpreter.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- RhinoInterpreter.java 2001/06/01 13:54:07 1.6 +++ RhinoInterpreter.java 2001/10/08 15:04:39 1.7 @@ -11,6 +11,9 @@ import java.io.IOException; import java.io.Reader; import java.io.Writer; +import java.io.StringReader; +import java.util.Iterator; +import java.util.LinkedList; import java.util.Locale; import org.w3c.dom.events.EventTarget; @@ -19,10 +22,11 @@ import org.apache.batik.script.InterpreterException; import org.mozilla.javascript.Context; +import org.mozilla.javascript.Function; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.JavaScriptException; -import org.mozilla.javascript.Function; import org.mozilla.javascript.NativeJavaPackage; +import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.WrappedException; @@ -31,7 +35,7 @@ * A simple implementation of <code>Interpreter</code> interface to use * Rhino ECMAScript interpreter. * @author <a href="mailto:[EMAIL PROTECTED]">Christophe Jolif</a> - * @version $Id: RhinoInterpreter.java,v 1.6 2001/06/01 13:54:07 cjolif Exp $ + * @version $Id: RhinoInterpreter.java,v 1.7 2001/10/08 15:04:39 cjolif Exp $ */ public class RhinoInterpreter implements Interpreter { private static String[] TO_BE_IMPORTED = { @@ -45,8 +49,21 @@ "org.w3c.dom.views" }; + private static class Entry { + String str; + Script script; + Entry(String str, Script script) { + this.str = str; + this.script = script; + } + }; + + // store last 32 precompiled objects. + private static final int MAX_CACHED_SCRIPTS = 32; + private Context context = null; private ScriptableObject globalObject = null; + private LinkedList compiledScripts = new LinkedList(); /** * Build a <code>Interpreter</code> for ECMAScript using Rhino. @@ -86,16 +103,18 @@ return context; } + // org.apache.batik.script.Intepreter implementation /** - * This method evaluates a piece of ECMA script. + * This method evaluates a piece of ECMAScript. * @param scriptreader a <code>java.io.Reader</code> on the piece of script * @return if no exception is thrown during the call, should return the - * value of the last expression evaluated in the script + * value of the last expression evaluated in the script. */ public Object evaluate(Reader scriptreader) - throws InterpreterException, IOException { + throws InterpreterException, IOException + { Object rv = null; Context ctx = Context.enter(context); try { @@ -103,6 +122,83 @@ scriptreader, "<SVG>", 1, null); + } catch (JavaScriptException e) { + // exception from JavaScript (possibly wrapping a Java Ex) + if (e.getValue() instanceof Exception) { + Exception ex = (Exception)e.getValue(); + throw new InterpreterException(ex, ex.getMessage(), -1, -1); + } else + throw new InterpreterException(e, e.getMessage(), -1, -1); + } catch (WrappedException we) { + // main Rhino RuntimeException + throw + new InterpreterException((Exception)we.getWrappedException(), + we.getWrappedException().getMessage(), + -1, -1); + } catch (RuntimeException re) { + // other RuntimeExceptions + throw new InterpreterException(re, re.getMessage(), -1, -1); + } finally { + Context.exit(); + } + return rv; + } + + /** + * This method evaluates a piece of ECMA script. + * The first time a String is passed, it is compiled and evaluated. + * At next call, the piece of script will only be evaluated to + * prevent from recompiling it. + * @param scriptstr the piece of script + * @return if no exception is thrown during the call, should return the + * value of the last expression evaluated in the script. + */ + public Object evaluate(String scriptstr) + throws InterpreterException + { + Context ctx = Context.enter(context); + Script script = null; + Entry et = null; + Iterator it = compiledScripts.iterator(); + // between nlog(n) and log(n) because it is + // an AbstractSequentialList + while (it.hasNext()) { + if ((et = (Entry)(it.next())).str == scriptstr) { + // if it is not at the end, remove it because + // it will change from place (it is faster + // to remove it now) + script = et.script; + it.remove(); + break; + } + } + if (script == null) { + // this script has not been compiled yet or has been fogotten + // since the compilation: + // compile it and store it for future use. + try { + script = ctx.compileReader(globalObject, + new StringReader(scriptstr), + "<SVG>", + 1, null); + } catch (IOException io) { + // can't happen because we use a String... + } + if (compiledScripts.size()+1 > MAX_CACHED_SCRIPTS) { + // too many cached items - we should delete the oldest entry. + // all of this is very fast on linkedlist + compiledScripts.removeFirst(); + } + // stroring is done here: + compiledScripts.addLast(new Entry(scriptstr, script)); + } else { + // this script has been compiled before, + // just update it's index so it won't get deleted soon. + compiledScripts.addLast(et); + } + Object rv = null; + try { + rv = script.exec(ctx, globalObject); } catch (JavaScriptException e) { // exception from JavaScript (possibly wrapping a Java Ex) if (e.getValue() instanceof Exception) {
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]