Code

Got initial JS execution working
authorishmal <ishmal@users.sourceforge.net>
Tue, 11 Mar 2008 21:13:53 +0000 (21:13 +0000)
committerishmal <ishmal@users.sourceforge.net>
Tue, 11 Mar 2008 21:13:53 +0000 (21:13 +0000)
src/bind/java/org/inkscape/cmn/ScriptRunner.java
src/bind/javabind-private.h
src/bind/javabind.cpp
src/bind/javabind.h
src/extension/script/InkscapeScript.cpp
src/ui/dialog/scriptdialog.cpp

index a128af734ddbe7199806025099bc0c74e4fbc337..d05afd2e3fabe566afbe6645a8d0fc09cd0af4ba 100644 (file)
@@ -25,6 +25,7 @@
 package org.inkscape.cmn;
 
 import javax.script.*;
+import java.util.List;
 import java.io.FileReader;
 import java.io.PrintStream;
 import java.io.OutputStream;
@@ -37,9 +38,40 @@ import javax.swing.JOptionPane;
  */
 public class ScriptRunner
 {
+/**
+ * Pointer back to the BinderyImpl C++ object that launched me
+ */ 
 long backPtr;
 
+/**
+ * The script engine manager that we want to use
+ */ 
+ScriptEngineManager scriptEngineManager;
+
+
+//########################################################################
+//# MESSSAGES
+//########################################################################
+static void err(String message)
+{
+    System.err.println("ScriptRunner err:" + message);
+}
+
+static void msg(String message)
+{
+    System.out.println("ScriptRunner:" + message);
+}
 
+static void trace(String message)
+{
+    log.println("ScriptRunner:" + message);
+}
+
+
+
+//########################################################################
+//# REDIRECT STDERR / STDOUT
+//########################################################################
 /**
  * Redirect stdout
  */
@@ -55,7 +87,6 @@ public void write(int b)
 }
 
 
-
 /**
  * Redirect stderr
  */
@@ -71,14 +102,27 @@ public void write(int b)
 
 }
 
+/**
+ * A logging stream
+ */
+static PrintStream log;
+public native void logWrite(long ptr, int b);
+class LogStream extends OutputStream
+{
 
-static void err(String message)
+public void write(int b)
 {
-    JOptionPane.showMessageDialog(null, message,
-               "Script Error", JOptionPane.ERROR_MESSAGE);
+    logWrite(backPtr, b);
 }
 
 
+}
+
+
+//########################################################################
+//# RUN
+//########################################################################
+
 
 /**
  * Run a script buffer
@@ -87,12 +131,16 @@ static void err(String message)
  * @param str the script buffer to execute
  * @return true if successful, else false
  */
-public boolean run(String lang, String str)
+public boolean doRun(String lang, String str)
 {
-    ScriptEngineManager factory = new ScriptEngineManager();
     // create JavaScript engine
-    ScriptEngine engine = factory.getEngineByName(lang);
-    // evaluate JavaScript code from given file - specified by first argument
+    ScriptEngine engine = scriptEngineManager.getEngineByName(lang);
+    if (engine == null)
+        {
+        err("doRun: cannot find script engine '" + lang + "'");
+        return false;
+               }
+    //execute script from buffer
     try
         {
         engine.eval(str);
@@ -100,10 +148,41 @@ public boolean run(String lang, String str)
     catch (javax.script.ScriptException e)
         {
         err("Executing script: " + e);
+        e.printStackTrace();
         }
     return true;
 }
 
+/**
+ * Run a script buffer
+ *
+ * @param backPtr pointer back to the C context that called this
+ * @param lang the scripting language to run
+ * @param str the script buffer to execute
+ * @return true if successful, else false
+ */
+public static boolean run(String lang, String str)
+{
+    //wrap whole thing in try/catch, since this will
+    //likely be called from C
+    try
+        {
+        ScriptRunner runner = getInstance();
+        if (runner == null)
+            {
+            err("ScriptRunner not initialized");
+            return false;
+                   }
+        return runner.doRun(lang, str);
+        }
+    catch (Exception e)
+        {
+        err("run :" + e);
+        e.printStackTrace();
+        return false;
+               }
+}
+
 
 /**
  * Run a script file
@@ -112,12 +191,16 @@ public boolean run(String lang, String str)
  * @param fname the script file to execute
  * @return true if successful, else false
  */
-public boolean runFile(String lang, String fname)
+public boolean doRunFile(String lang, String fname)
 {
-    ScriptEngineManager factory = new ScriptEngineManager();
     // create JavaScript engine
-    ScriptEngine engine = factory.getEngineByName(lang);
-    // evaluate JavaScript code from given file - specified by first argument
+    ScriptEngine engine = scriptEngineManager.getEngineByName(lang);
+    if (engine == null)
+        {
+        err("doRunFile: cannot find script engine '" + lang + "'");
+        return false;
+               }
+    //try opening file and feeding into engine
     FileReader in = null;
     boolean ret = true;
     try
@@ -152,58 +235,104 @@ public boolean runFile(String lang, String fname)
 
 
 /**
- * Constructor
+ * Run a script file
+ *
  * @param backPtr pointer back to the C context that called this
+ * @param lang the scripting language to run
+ * @param fname the script file to execute
+ * @return true if successful, else false
  */
-public ScriptRunner(long backPtr)
+public static boolean runFile(String lang, String fname)
 {
-    this.backPtr = backPtr;
-    System.setOut(new PrintStream(new StdOutStream()));
-    System.setErr(new PrintStream(new StdErrStream()));
+    //wrap whole thing in try/catch, since this will
+    //likely be called from C
+    try
+        {
+        ScriptRunner runner = getInstance();
+        if (runner == null)
+            {
+            err("ScriptRunner not initialized");
+            return false;
+                   }
+        return runner.doRunFile(lang, fname);
+        }
+    catch (Exception e)
+        {
+        err("run :" + e);
+        return false;
+               }
 }
 
 
 
-private static ScriptRunner _instance = null;
+//########################################################################
+//# CONSTRUCTOR
+//########################################################################
+
 
 
-public static ScriptRunner getInstance(long backPtr)
+private static ScriptRunner _instance = null;
+public static ScriptRunner getInstance()
 {
-    if (_instance == null)
-        _instance = new ScriptRunner(backPtr);
     return _instance;
 }
 
-
-/**
- * Run a script buffer
- *
- * @param backPtr pointer back to the C context that called this
- * @param lang the scripting language to run
- * @param str the script buffer to execute
- * @return true if successful, else false
- */
-public static boolean run(long ptr, String lang, String str)
+private void listFactories()
 {
-    ScriptRunner runner = getInstance(ptr);
-    return runner.run(lang, str);
+    List<ScriptEngineFactory> factories = 
+          scriptEngineManager.getEngineFactories();
+    for (ScriptEngineFactory factory: factories)
+           {
+        log.println("ScriptEngineFactory Info");
+        String engName     = factory.getEngineName();
+        String engVersion  = factory.getEngineVersion();
+        String langName    = factory.getLanguageName();
+        String langVersion = factory.getLanguageVersion();
+        log.printf("\tScript Engine: %s (%s)\n", 
+               engName, engVersion);
+        List<String> engNames = factory.getNames();
+        for(String name: engNames)
+                   {
+            log.printf("\tEngine Alias: %s\n", name);
+            }
+        log.printf("\tLanguage: %s (%s)\n", 
+               langName, langVersion);
+        }
 }
 
 
+   
 /**
- * Run a script file
- *
+ * Constructor
  * @param backPtr pointer back to the C context that called this
- * @param lang the scripting language to run
- * @param fname the script file to execute
- * @return true if successful, else false
  */
-public static boolean runFile(long ptr, String lang, String fname)
+public ScriptRunner(long backPtr)
 {
-    ScriptRunner runner = getInstance(ptr);
-    return runner.runFile(lang, fname);
+    /**
+     * Set up the output, error, and logging stream
+     */             
+    System.setOut(new PrintStream(new StdOutStream()));
+    System.setErr(new PrintStream(new StdErrStream()));
+    log = new PrintStream(new LogStream());
+
+    //Point back to C++ object
+    this.backPtr = backPtr;
+    
+    //Start up the factory
+    scriptEngineManager  = new ScriptEngineManager();
+    listFactories();
+    _instance = this;
 }
 
 
+static
+{
+
+}
 
 }
+//########################################################################
+//# E N D    O F    F I L E
+//########################################################################
+
+
index ce595fa8569f0078daf3dec22ad5ab697629b4ca..f76118c282b69e71b9bedfd35c54559918af2a07 100644 (file)
@@ -63,6 +63,8 @@ public:
  
     virtual bool doBinding();
 
+    virtual bool setupScriptRunner();
+
     static JavaBinderyImpl *getInstance();
 
 
index 3d68bdc15872d36b3f1be50b6c3196fde1ad22eb..5a870063366a42e387cd8fdc284aebb89211a967 100644 (file)
@@ -285,40 +285,115 @@ static bool getRegistryString(HKEY root, const char *keyName,
 }
 
 
+static String cleanPath(const String &s)
+{
+    String buf;
+    for (unsigned int i=0 ; i<s.size() ; i++)
+        {
+        char ch = s[i];
+        if (ch != '"')
+            buf.push_back(ch);
+               }
+       return buf;
+}
+
+
+/**
+ * Common places to find jvm.dll under JAVA_HOME
+ */ 
+static const char *commonJavaPaths[] =
+{
+    "\\jre\\bin\\client\\jvm.dll",
+    "\\bin\\client\\jvm.dll",
+    "\\jvm.dll",
+    NULL
+};
+
 static CreateVMFunc getCreateVMFunc()
 {
-    char verbuf[16];
-    char regpath[80];
-    strcpy(regpath, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
-    bool ret = getRegistryString(HKEY_LOCAL_MACHINE,
-                     regpath, "CurrentVersion", verbuf, 15);
-    if (!ret)
+    bool found = false;
+    String libname;
+
+    /**
+     * First, look for JAVA_HOME.  This will allow the user
+     * to override what's in the registry
+     */                     
+    const char *envStr = getenv("JAVA_HOME");
+    if (envStr)
         {
-        err("JVM CurrentVersion not found in registry\n");
-        return NULL;
+        String javaHome = cleanPath(envStr);
+        msg("JAVA_HOME='%s'", javaHome.c_str());
+        for (const char **path = commonJavaPaths ; *path ; path++)
+            {
+            String jpath = javaHome;
+            jpath.append(*path);
+            //msg("trying '%s'", jpath.c_str());
+            struct stat finfo;
+            if (stat(jpath.c_str(), &finfo)>=0)
+                {
+                //msg("found");
+                libname = jpath;
+                found = true;
+                break;
+                }
+            }
+        }
+
+    //not at JAVA_HOME.  check the registry
+    if (!found)
+        {
+        char verbuf[16];
+        char regpath[80];
+        strcpy(regpath, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
+        bool ret = getRegistryString(HKEY_LOCAL_MACHINE,
+                     regpath, "CurrentVersion", verbuf, 15);
+        if (!ret)
+            {
+            msg("JVM CurrentVersion not found in registry at '%s'", regpath);
+            }
+        else
+            {
+            strcat(regpath, "\\");
+            strcat(regpath, verbuf);
+            //msg("reg path: %s\n", regpath);
+            char valbuf[80];
+            ret = getRegistryString(HKEY_LOCAL_MACHINE,
+                     regpath, "RuntimeLib", valbuf, 79);
+            if (ret)
+                {
+                found = true;
+                libname = valbuf;
+                }
+            else
+                {
+                msg("JVM RuntimeLib not found in registry at '%s'",
+                                         regpath);
+                               }
+                       }
         }
-    strcat(regpath, "\\");
-    strcat(regpath, verbuf);
-    //msg("reg path: %s\n", regpath);
-    char libname[80];
-    ret = getRegistryString(HKEY_LOCAL_MACHINE,
-                     regpath, "RuntimeLib", libname, 79);
-    if (!ret)
+
+    if (!found)
         {
-        err("Current JVM RuntimeLib not found in registry\n");
+        err("JVM not found at JAVA_HOME or in registry");
         return NULL;
         }
-    //msg("jvm path: %s\n", libname);
-    HMODULE lib = LoadLibrary(libname);
+
+    /**
+     * If we are here, then we seem to have a valid path for jvm.dll
+     * Give it a try
+     */                     
+    msg("getCreateVMFunc: Loading JVM: %s", libname.c_str());
+    HMODULE lib = LoadLibrary(libname.c_str());
     if (!lib)
         {
-        err("Java VM not found at '%s'", libname);
+        err("Java VM not found at '%s'", libname.c_str());
         return NULL;
         }
     CreateVMFunc createVM = (CreateVMFunc)GetProcAddress(lib, "JNI_CreateJavaVM");
     if (!createVM)
         {
-        err("Could not find 'JNI_CreateJavaVM' in shared library");
+        err("Could not find 'JNI_CreateJavaVM' in shared library '%s'",
+                                  libname.c_str());
         return NULL;
         }
     return createVM;
@@ -451,6 +526,7 @@ static CreateVMFunc getCreateVMFunc()
         err("No Java VM found. Is JAVA_HOME defined?  Need to find 'libjvm.so'");
         return NULL;
         }
+    msg("getCreateVMFunc: Loading JVM: %s", libname.c_str());
     void *lib = dlopen(libname.c_str(), RTLD_NOW);
     if (!lib)
         {
@@ -547,7 +623,7 @@ static void populateClassPath(const String &javaroot,
 
 
 //========================================================================
-// Native methods
+// SCRIPT RUNNER
 //========================================================================
 /**
  * These methods are used to allow the ScriptRunner class to
@@ -569,14 +645,57 @@ void JNICALL stdErrWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch)
 }
 
 
+void JNICALL logWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch)
+{
+    JavaBinderyImpl *bind = (JavaBinderyImpl *)ptr;
+    bind->log(ch);
+}
+
+
 static JNINativeMethod scriptRunnerMethods[] =
 {
 { (char *)"stdOutWrite", (char *)"(JI)V", (void *)stdOutWrite },
 { (char *)"stdErrWrite", (char *)"(JI)V", (void *)stdErrWrite },
+{ (char *)"logWrite",    (char *)"(JI)V", (void *)logWrite    },
 { NULL,  NULL, NULL }
 };
+
+/**
+ * This sets up the 'ScriptRunner' java class for execution of
+ * scripts
+ */  
+bool JavaBinderyImpl::setupScriptRunner()
+{
+    String className = "org/inkscape/cmn/ScriptRunner";
+    if (!registerNatives(className, scriptRunnerMethods))
+        {
+        return false;
+        }
+    jclass cls = env->FindClass(className.c_str());
+    if (!cls)
+        {
+        err("setupScriptRunner: cannot find class '%s'", className.c_str());
+        return false;
+               }
+       jmethodID mid = env->GetMethodID(cls, "<init>", "(J)V");
+       if (!mid)
+        {
+        err("setupScriptRunner: cannot find constructor for '%s'", className.c_str());
+        return false;
+               }
+    jobject obj = env->NewObject(cls, mid, ((jlong)this));
+    if (!obj)
+        {
+        err("setupScriptRunner: cannot construct '%s'", className.c_str());
+        return false;
+               }
+       msg("ScriptRunner ready");
+    return true;
+}
+
+
 //========================================================================
-// End native methods
+// End SCRIPT RUNNER
 //========================================================================
 
 
@@ -647,16 +766,14 @@ bool JavaBinderyImpl::loadJVM()
     int versionMinor = (vers    ) & 0xffff;
     msg("Loaded JVM version %d.%d", versionMajor, versionMinor);
 
-    if (!registerNatives("org/inkscape/cmn/ScriptRunner",
-             scriptRunnerMethods))
-        {
+    if (!setupScriptRunner())
         return false;
-        }
+
+
     return true;
 }
 
 
-
 /**
  *  This is a difficult method.  What we are doing is trying to
  *  call a static method with a list of arguments.  Similar to 
@@ -763,6 +880,12 @@ bool JavaBinderyImpl::callStatic(int type,
             }
         }
     delete jvals;
+    String errStr = getException(env);
+    if (errStr.size()>0)
+        {
+        err("callStatic: %s", errStr.c_str());
+        return false;
+               }
     return true;
 }
 
@@ -800,7 +923,7 @@ bool JavaBinderyImpl::registerNatives(const String &className,
         err("Could not find class '%s'", className.c_str());
         return false;
         }
-    msg("registerNatives: class '%s' found", className.c_str());
+    //msg("registerNatives: class '%s' found", className.c_str());
     
     /**
      * hack for JDK bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6493522
index 164110ea6c95a8fb730f30e6882c89b68ced9070..b20132d035d360fcf385c04e42dc53206a5c9ec4 100644 (file)
@@ -272,6 +272,11 @@ public:
         stdOutBuf.clear();
         }
 
+    virtual void stdOut(int ch)
+        {
+        stdOutBuf.push_back((char)ch);
+        }
+
     virtual String stdErrGet()
         {
         return stdErrBuf;
@@ -282,14 +287,29 @@ public:
         stdErrBuf.clear();
         }
 
-    virtual void stdOut(int ch)
+    virtual void stdErr(int ch)
         {
-        stdOutBuf.push_back((char)ch);
+        stdErrBuf.push_back((char)ch);
         }
 
-    virtual void stdErr(int ch)
+    virtual String logGet()
         {
-        stdErrBuf.push_back((char)ch);
+        return logBuf;
+        }
+
+    virtual void logClear()
+        {
+        logBuf.clear();
+        }
+
+    virtual void log(int ch)
+        {
+        logBuf.push_back((char)ch);
+        if (ch == '\n' || ch == '\r')
+            {
+            g_message(logBuf.c_str());
+            logBuf.clear();
+                       }
         }
 
 
@@ -303,6 +323,7 @@ protected:
 
     String stdOutBuf;
     String stdErrBuf;
+    String logBuf;
 
 };
 
index 138c8cb7ed9386d833e651c71f52807b5764bca7..1507c63442a9c2cf605b1d00090f32a9a6ea30e2 100644 (file)
@@ -75,15 +75,15 @@ bool InkscapeScript::interpretScript(const Glib::ustring &script,
     //if() instead of switch() lets us scope vars
     if (language == InkscapeScript::JAVASCRIPT)
         {
-        langname="Javascript";
+        langname="javascript";
         }
     else if (language == InkscapeScript::PYTHON)
         {
-        langname="Python";
+        langname="python";
         }
     else if (language == InkscapeScript::RUBY)
         {
-        langname="Ruby";
+        langname="ruby";
         }
     else
         {
index fd0a43851ba011c20f8afddfc78c0cefb02098e6..ff075c1868da82da7d4992a4297423780f6667c5 100644 (file)
@@ -110,31 +110,18 @@ class ScriptDialogImpl : public ScriptDialog
 
 };
 
-static const char *defaultPythonCodeStr =
-#if defined(WITH_PYTHON)
-    "# This is a sample Python script.\n"
-    "# To run it, select 'Execute Python' from the File menu above.\n"
-    "desktop = inkscape.activeDesktop\n"
-    "dialogmanager = desktop.dialogManager\n"
-    "document = inkscape.activeDocument\n"
-    "inkscape.hello()\n"
-    "dialogmanager.showAbout()\n"
-#elif defined(WITH_PERL)
-    "# This is a sample Perl script.\n"
-    "# To run it, select 'Execute Perl' from the File menu above.\n"
-    "my $desktop = $inkscape->getDesktop();\n"
-    "my $dialogmanager = $inkscape->getDialogManager();\n"
-    "my $document = $desktop->getDocument();\n"
-    "$document->hello();\n"
-    "$dialogmanager->showAbout();\n"
-#else
-    "# This is where you could type a script.\n"
-    "# However, no scripting languages have been compiled\n"
-    "# into Inkscape, so this window has no functionality.\n"
-    "# When compiling Inkscape, run \"configure\" with\n"
-    "# \"--with-python\" and/or \"--with-perl\".\n"
-#endif
-    "";
+static const char *defaultCodeStr =
+    "/**\n"
+    " * This is some example Javascript.\n"
+    " * Try 'Execute Javascript'\n"
+    " */\n"
+    "function sayHello() {\n"
+    "  println('Hello, world!');\n"
+    "}\n"
+    "\n"
+    "sayHello();\n"
+    "\n";
+
 
 
 
@@ -229,7 +216,7 @@ ScriptDialogImpl::ScriptDialogImpl() :
 
     //### Set up the script field
     scriptText.set_editable(true);
-    scriptText.get_buffer()->set_text(defaultPythonCodeStr);
+    scriptText.get_buffer()->set_text(defaultCodeStr);
     scriptTextScroll.add(scriptText);
     scriptTextScroll.set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS);
     scriptTextFrame.set_label(_("Script"));