Code

Got initial JS execution working
[inkscape.git] / src / bind / javabind.cpp
1 /**
2  * This is a simple mechanism to bind Inkscape to Java, and thence
3  * to all of the nice things that can be layered upon that.
4  *
5  * Authors:
6  *   Bob Jamison
7  *
8  * Copyright (C) 2007-2008 Bob Jamison
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 3 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  */
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <jni.h>
35 #include <sys/types.h>
36 #include <dirent.h>
39 #ifdef __WIN32__
40 #include <windows.h>
41 #else
42 #include <dlfcn.h>
43 #include <errno.h>
44 #endif
46 #if HAVE_SYS_STAT_H
47 #include <sys/stat.h>
48 #endif
50 #include "javabind.h"
51 #include "javabind-private.h"
52 #include <path-prefix.h>
53 #include <prefix.h>
54 #include <glib/gmessages.h>
57 /**
58  * Note: We must limit Java or JVM-specific code to this file
59  * and to dobinding.cpp.  It should be hidden from javabind.h
60  */  
63 namespace Inkscape
64 {
66 namespace Bind
67 {
70 //########################################################################
71 //# DEFINITIONS
72 //########################################################################
74 typedef jint (*CreateVMFunc)(JavaVM **, JNIEnv **, void *);
78 //########################################################################
79 //# UTILITY
80 //########################################################################
82 /**
83  * Normalize path.  Java wants '/', even on Windows
84  */ 
85 String normalizePath(const String &str)
86 {
87     String buf;
88     for (unsigned int i=0 ; i<str.size() ; i++)
89         {
90         char ch = str[i];
91         if (ch == '\\')
92             buf.push_back('/');
93         else
94             buf.push_back(ch);
95                 }
96         return buf;
97 }
100 String getException(JNIEnv *env)
102     String buf;
103     jthrowable exc = env->ExceptionOccurred();
104     if (!exc)
105         return buf;
106     jclass cls = env->GetObjectClass(exc);
107     jmethodID mid = env->GetMethodID(cls, "toString", "()Ljava/lang/String;");
108     jstring jstr = (jstring) env->CallObjectMethod(exc, mid);
109     const char *str = env->GetStringUTFChars(jstr, JNI_FALSE);
110     buf.append(str);
111     env->ReleaseStringUTFChars(jstr, str);
112     env->ExceptionClear();
113         return buf;
116 jint getInt(JNIEnv *env, jobject obj, const char *name)
118     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "I");
119     return env->GetIntField(obj, fid);
122 void setInt(JNIEnv *env, jobject obj, const char *name, jint val)
124     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "I");
125     env->SetIntField(obj, fid, val);
128 jlong getLong(JNIEnv *env, jobject obj, const char *name)
130     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "J");
131     return env->GetLongField(obj, fid);
134 void setLong(JNIEnv *env, jobject obj, const char *name, jlong val)
136     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "J");
137     env->SetLongField(obj, fid, val);
140 jfloat getFloat(JNIEnv *env, jobject obj, const char *name)
142     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "F");
143     return env->GetFloatField(obj, fid);
146 void setFloat(JNIEnv *env, jobject obj, const char *name, jfloat val)
148     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "F");
149     env->SetFloatField(obj, fid, val);
152 jdouble getDouble(JNIEnv *env, jobject obj, const char *name)
154     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "D");
155     return env->GetDoubleField(obj, fid);
158 void setDouble(JNIEnv *env, jobject obj, const char *name, jdouble val)
160     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "D");
161     env->SetDoubleField(obj, fid, val);
164 String getString(JNIEnv *env, jobject obj, const char *name)
166     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "Ljava/lang/String;");
167     jstring jstr = (jstring)env->GetObjectField(obj, fid);
168     const char *chars = env->GetStringUTFChars(jstr, JNI_FALSE);
169     String str = chars;
170     env->ReleaseStringUTFChars(jstr, chars);
171     return str;
174 void setString(JNIEnv *env, jobject obj, const char *name, const String &val)
176     jstring jstr = env->NewStringUTF(val.c_str());
177     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "Ljava/lang/String;");
178     env->SetObjectField(obj, fid, jstr);
184 //########################################################################
185 //# CONSTRUCTOR/DESTRUCTOR
186 //########################################################################
188 static JavaBinderyImpl *_instance = NULL;
190 JavaBindery *JavaBindery::getInstance()
192     return JavaBinderyImpl::getInstance();
195 JavaBinderyImpl *JavaBinderyImpl::getInstance()
197     if (!_instance)
198         {
199         _instance = new JavaBinderyImpl();
200         }
201     return _instance;
204 JavaBinderyImpl::JavaBinderyImpl()
206     jvm  = NULL;
207     env  = NULL;
210 JavaBinderyImpl::~JavaBinderyImpl()
215 //########################################################################
216 //# MESSAGES
217 //########################################################################
219 void err(const char *fmt, ...)
221 #if 0
222     va_list args;
223     fprintf(stderr, "JavaBinderyImpl err:");
224     va_start(args, fmt);
225     vfprintf(stderr, fmt, args);
226     va_end(args);
227     fprintf(stderr, "\n");
228 #else
229     va_list args;
230     g_warning("JavaBinderyImpl err:");
231     va_start(args, fmt);
232     g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, args);
233     va_end(args);
234     g_warning("\n");
235 #endif
238 void msg(const char *fmt, ...)
240 #if 0
241     va_list args;
242     fprintf(stdout, "JavaBinderyImpl:");
243     va_start(args, fmt);
244     vfprintf(stdout, fmt, args);
245     va_end(args);
246     fprintf(stdout, "\n");
247 #else
248     va_list args;
249     g_message("JavaBinderyImpl:");
250     va_start(args, fmt);
251     g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, args);
252     va_end(args);
253     g_message("\n");
254 #endif
259 //########################################################################
260 //# W I N 3 2      S T Y L E
261 //########################################################################
262 #ifdef __WIN32__
265 #define DIR_SEPARATOR "\\"
266 #define PATH_SEPARATOR ";"
270 static bool getRegistryString(HKEY root, const char *keyName,
271                const char *valName, char *buf, int buflen)
273     HKEY key;
274     DWORD bufsiz  = buflen;
275     RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
276     int ret = RegQueryValueEx(key, TEXT(valName),
277             NULL, NULL, (BYTE *)buf, &bufsiz);
278     if (ret != ERROR_SUCCESS)
279         {
280         err("Key '%s\\%s not found\n", keyName, valName);
281         return false;
282         }
283     RegCloseKey(key);
284     return true;
288 static String cleanPath(const String &s)
290     String buf;
291     for (unsigned int i=0 ; i<s.size() ; i++)
292         {
293         char ch = s[i];
294         if (ch != '"')
295             buf.push_back(ch);
296                 }
297         return buf;
301 /**
302  * Common places to find jvm.dll under JAVA_HOME
303  */ 
304 static const char *commonJavaPaths[] =
306     "\\jre\\bin\\client\\jvm.dll",
307     "\\bin\\client\\jvm.dll",
308     "\\jvm.dll",
309     NULL
310 };
312 static CreateVMFunc getCreateVMFunc()
314     bool found = false;
315     String libname;
317     /**
318      * First, look for JAVA_HOME.  This will allow the user
319      * to override what's in the registry
320      */              
321     const char *envStr = getenv("JAVA_HOME");
322     if (envStr)
323         {
324         String javaHome = cleanPath(envStr);
325         msg("JAVA_HOME='%s'", javaHome.c_str());
326         for (const char **path = commonJavaPaths ; *path ; path++)
327             {
328             String jpath = javaHome;
329             jpath.append(*path);
330             //msg("trying '%s'", jpath.c_str());
331             struct stat finfo;
332             if (stat(jpath.c_str(), &finfo)>=0)
333                 {
334                 //msg("found");
335                 libname = jpath;
336                 found = true;
337                 break;
338                 }
339             }
340         }
342     //not at JAVA_HOME.  check the registry
343     if (!found)
344         {
345         char verbuf[16];
346         char regpath[80];
347         strcpy(regpath, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
348         bool ret = getRegistryString(HKEY_LOCAL_MACHINE,
349                      regpath, "CurrentVersion", verbuf, 15);
350         if (!ret)
351             {
352             msg("JVM CurrentVersion not found in registry at '%s'", regpath);
353             }
354         else
355             {
356             strcat(regpath, "\\");
357             strcat(regpath, verbuf);
358             //msg("reg path: %s\n", regpath);
359             char valbuf[80];
360             ret = getRegistryString(HKEY_LOCAL_MACHINE,
361                      regpath, "RuntimeLib", valbuf, 79);
362             if (ret)
363                 {
364                 found = true;
365                 libname = valbuf;
366                 }
367             else
368                 {
369                 msg("JVM RuntimeLib not found in registry at '%s'",
370                                           regpath);
371                                 }
372                         }
373         }
375     if (!found)
376         {
377         err("JVM not found at JAVA_HOME or in registry");
378         return NULL;
379         }
381     /**
382      * If we are here, then we seem to have a valid path for jvm.dll
383      * Give it a try
384      */              
385     msg("getCreateVMFunc: Loading JVM: %s", libname.c_str());
386     HMODULE lib = LoadLibrary(libname.c_str());
387     if (!lib)
388         {
389         err("Java VM not found at '%s'", libname.c_str());
390         return NULL;
391         }
392     CreateVMFunc createVM = (CreateVMFunc)GetProcAddress(lib, "JNI_CreateJavaVM");
393     if (!createVM)
394         {
395         err("Could not find 'JNI_CreateJavaVM' in shared library '%s'",
396                                    libname.c_str());
397         return NULL;
398         }
399     return createVM;
402 static void getJavaRoot(String &javaroot)
404     char exeName[80];
405     GetModuleFileName(NULL, exeName, 80);
406     char *slashPos = strrchr(exeName, '\\');
407     if (slashPos)
408         *slashPos = '\0';
409     javaroot = exeName;
410     javaroot.append("\\");
411     javaroot.append(INKSCAPE_JAVADIR);
417 //########################################################################
418 //# U N I X    S T Y L E
419 //########################################################################
420 #else /* !__WIN32__ */
423 #define DIR_SEPARATOR "/"
424 #define PATH_SEPARATOR ":"
427 /**
428  * Recursively descend into a directory looking for libjvm.so
429  */
430 static bool findJVMRecursive(const String &dirpath,
431                              std::vector<String> &results)
433     DIR *dir = opendir(dirpath.c_str());
434     if (!dir)
435         return false;
436     bool ret = false;
437     while (true)
438         {
439         struct dirent *de = readdir(dir);
440         if (!de)
441             break;
442         String fname = de->d_name;
443         if (fname == "." || fname == "..")
444             continue;
445         String path = dirpath;
446         path.push_back('/');
447         path.append(fname);
448         if (fname == "libjvm.so")
449             {
450             ret = true;
451             results.push_back(path);
452             continue;
453             }
454         struct stat finfo;
455         if (lstat(path.c_str(), &finfo)<0)
456             {
457             break;
458             }
459         if (finfo.st_mode & S_IFDIR)
460             {
461             ret |= findJVMRecursive(path, results);
462             }
463         }
464     closedir(dir);
465     return ret;
469 static const char *commonJavaPaths[] =
471     "/usr/java",
472     "/usr/local/java",
473     "/usr/lib/jvm",
474     "/usr/local/lib/jvm",
475     NULL
476 };
478 /**
479  * Look for a Java VM (libjvm.so) in several Unix places
480  */
481 static bool findJVM(String &result)
483     std::vector<String> results;
484     int found = false;
486     /* Is there one specified by the user? */
487     const char *javaHome = getenv("JAVA_HOME");
488     if (javaHome && findJVMRecursive(javaHome, results))
489         found = true;
490     else for (const char **path = commonJavaPaths ; *path ; path++)
491         {
492         if (findJVMRecursive(*path, results))
493             {
494             found = true;
495             break;
496             }
497         }
498     if (!found)
499         {
500         return false;
501         }
502     if (results.size() == 0)
503         return false;
504     //Look first for a Client VM
505     for (unsigned int i=0 ; i<results.size() ; i++)
506         {
507         String s = results[i];
508         if (s.find("client") != s.npos)
509             {
510             result = s;
511             return true;
512             }
513         }
514     //else default to the first
515     result = results[0];
516     return true;
521 static CreateVMFunc getCreateVMFunc()
523     String libname;
524     if (!findJVM(libname))
525         {
526         err("No Java VM found. Is JAVA_HOME defined?  Need to find 'libjvm.so'");
527         return NULL;
528         }
529     msg("getCreateVMFunc: Loading JVM: %s", libname.c_str());
530     void *lib = dlopen(libname.c_str(), RTLD_NOW);
531     if (!lib)
532         {
533         err("Java VM not found at '%s' : %s", libname.c_str(), strerror(errno));
534         return NULL;
535         }
536     CreateVMFunc createVM = (CreateVMFunc)dlsym(lib, "JNI_CreateJavaVM");
537     if (!createVM)
538         {
539         err("Could not find 'JNI_CreateJavaVM' in shared library");
540             return NULL;
541         }
542     return createVM;
546 static void getJavaRoot(String &javaroot)
548     javaroot = INKSCAPE_JAVADIR;
551 #endif /* !__WIN32__ */
554 //########################################################################
555 //# COMMON
556 //########################################################################
559 bool JavaBinderyImpl::isLoaded()
561     return (jvm != (void *)0);
566 /**
567  * This will set up the classpath for the launched VM.
568  * We will add two things:
569  *   1.  INKSCAPE_JAVADIR/classes -- path to loose classes
570  *   2.  A concatenation of all jar files in INKSCAPE_JAVADIR/lib
571  *
572  * This will allow people to add classes and jars to the JVM without
573  * needing to state them explicitly.
574  * 
575  * @param javaroot.  Should be INKSCAPE_JAVADIR
576  * @param result a string buffer to hold the result of this method   
577  */        
578 static void populateClassPath(const String &javaroot,
579                               String &result)
581     String classdir = javaroot;
582     classdir.append(DIR_SEPARATOR);
583     classdir.append("classes");
585     String cp = classdir;
587     String libdir = javaroot;
588     libdir.append(DIR_SEPARATOR);
589     libdir.append("lib");
591     DIR *dir = opendir(libdir.c_str());
592     if (!dir)
593         {
594         result = cp;
595         return;
596         }
598     while (true)
599         {
600         struct dirent *de = readdir(dir);
601         if (!de)
602             break;
603         String fname = de->d_name;
604         if (fname == "." || fname == "..")
605             continue;
606         if (fname.size()<5) //x.jar
607             continue;
608         if (fname.compare(fname.size()-4, 4, ".jar") != 0)
609             continue;
611         String path = libdir;
612         path.append(DIR_SEPARATOR);
613         path.append(fname);
615         cp.append(PATH_SEPARATOR);
616         cp.append(path);
617         }
618     closedir(dir);
619     
620     result = cp;
625 //========================================================================
626 // SCRIPT RUNNER
627 //========================================================================
628 /**
629  * These methods are used to allow the ScriptRunner class to
630  * redirect its stderr and stdout streams to here, to be caught
631  * by two string buffers.  We can then use those buffers how we
632  * want.  These native methods are only those needed for running
633  * a script.  For the main C++/Java bindings, see dobinding.cpp 
634  */    
635 void JNICALL stdOutWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch)
637     JavaBinderyImpl *bind = (JavaBinderyImpl *)ptr;
638     bind->stdOut(ch);
641 void JNICALL stdErrWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch)
643     JavaBinderyImpl *bind = (JavaBinderyImpl *)ptr;
644     bind->stdErr(ch);
648 void JNICALL logWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch)
650     JavaBinderyImpl *bind = (JavaBinderyImpl *)ptr;
651     bind->log(ch);
655 static JNINativeMethod scriptRunnerMethods[] =
657 { (char *)"stdOutWrite", (char *)"(JI)V", (void *)stdOutWrite },
658 { (char *)"stdErrWrite", (char *)"(JI)V", (void *)stdErrWrite },
659 { (char *)"logWrite",    (char *)"(JI)V", (void *)logWrite    },
660 { NULL,  NULL, NULL }
661 };
663 /**
664  * This sets up the 'ScriptRunner' java class for execution of
665  * scripts
666  */  
667 bool JavaBinderyImpl::setupScriptRunner()
669     String className = "org/inkscape/cmn/ScriptRunner";
670     if (!registerNatives(className, scriptRunnerMethods))
671         {
672         return false;
673         }
674     jclass cls = env->FindClass(className.c_str());
675     if (!cls)
676         {
677         err("setupScriptRunner: cannot find class '%s'", className.c_str());
678         return false;
679                 }
680         jmethodID mid = env->GetMethodID(cls, "<init>", "(J)V");
681         if (!mid)
682         {
683         err("setupScriptRunner: cannot find constructor for '%s'", className.c_str());
684         return false;
685                 }
686     jobject obj = env->NewObject(cls, mid, ((jlong)this));
687     if (!obj)
688         {
689         err("setupScriptRunner: cannot construct '%s'", className.c_str());
690         return false;
691                 }
692         msg("ScriptRunner ready");
693     return true;
697 //========================================================================
698 // End SCRIPT RUNNER
699 //========================================================================
702 /**
703  * This is used to grab output from the VM itself. See 'options' below.
704  */ 
705 static int JNICALL vfprintfHook(FILE* /*f*/, const char *fmt, va_list args)
707     g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, args);
711 /**
712  * This is the most important part of this class.  Here we
713  * attempt to find, load, and initialize a java (or mlvm?) virtual
714  * machine.
715  * 
716  * @return true if successful, else false    
717  */ 
718 bool JavaBinderyImpl::loadJVM()
720     if (jvm)
721         return true;
723     CreateVMFunc createVM = getCreateVMFunc();
724     if (!createVM)
725         {
726         err("Could not find 'JNI_CreateJavaVM' in shared library");
727         return false;
728         }
730     String javaroot;
731     getJavaRoot(javaroot);
732     String cp;
733     populateClassPath(javaroot, cp);
734     String classpath = "-Djava.class.path=";
735     classpath.append(normalizePath(cp));
736     msg("Class path is: '%s'", classpath.c_str());
738     String libpath = "-Djava.library.path=";
739     libpath.append(javaroot);
740     libpath.append(DIR_SEPARATOR);
741     libpath.append("libm");
742     libpath = normalizePath(libpath);
743     msg("Lib path is: '%s'", libpath.c_str());
745     JavaVMInitArgs vm_args;
746     JavaVMOption options[4];
747     options[0].optionString    = (char *)classpath.c_str();
748     options[1].optionString    = (char *)libpath.c_str();
749     options[2].optionString    = (char *)"-verbose:jni";
750     options[3].optionString    = (char *)"vfprintf";
751     options[3].extraInfo       = (void *)vfprintfHook;
752     vm_args.version            = JNI_VERSION_1_4;
753     vm_args.options            = options;
754     vm_args.nOptions           = 4;
755     vm_args.ignoreUnrecognized = true;
757     if (createVM(&jvm, &env, &vm_args) < 0)
758         {
759         err("JNI_CreateJavaVM() failed");
760         return false;
761         }
763     //get jvm version
764     jint vers = env->GetVersion();
765     int versionMajor = (vers>>16) & 0xffff;
766     int versionMinor = (vers    ) & 0xffff;
767     msg("Loaded JVM version %d.%d", versionMajor, versionMinor);
769     if (!setupScriptRunner())
770         return false;
773     return true;
777 /**
778  *  This is a difficult method.  What we are doing is trying to
779  *  call a static method with a list of arguments.  Similar to 
780  *  a varargs call, we need to marshal the Values into their
781  *  Java equivalents and make the proper call.
782  *  
783  * @param type the return type of the method
784  * @param className the full (package / name) name of the java class
785  * @param methodName the name of the method being invoked
786  * @param signature the method signature (ex: "(Ljava/lang/String;I)V" )
787  *    that describes the param and return types of the method.
788  * @param retval the return value of the java method
789  * @return true if the call was successful, else false.  This is not
790  *    the return value of the method.    
791  */    
792 bool JavaBinderyImpl::callStatic(int type,
793                         const String &className,
794                         const String &methodName,
795                         const String &signature,
796                         const std::vector<Value> &params,
797                         Value &retval)
799     jclass cls = env->FindClass(className.c_str());
800     if (!cls)
801         {
802         err("Could not find class '%s'", className.c_str());
803         return false;
804         }
805     jmethodID mid = env->GetStaticMethodID(cls,
806                 methodName.c_str(), signature.c_str());
807     if (!mid)
808         {
809         err("Could not find method '%s:%s/%s'", className.c_str(),
810                 methodName.c_str(), signature.c_str());
811         return false;
812         }
813     /**
814      * Assemble your parameters into a form usable by JNI
815      */
816     jvalue *jvals = new jvalue[params.size()];
817     for (unsigned int i=0 ; i<params.size() ; i++)
818         {
819         Value v = params[i];
820         switch (v.getType())
821             {
822             case Value::BIND_BOOLEAN:
823                 {
824                 jvals[i].z = (jboolean)v.getBoolean();
825                 break;
826                 }
827             case Value::BIND_INT:
828                 {
829                 jvals[i].i = (jint)v.getInt();
830                 break;
831                 }
832             case Value::BIND_DOUBLE:
833                 {
834                 jvals[i].d = (jdouble)v.getDouble();
835                 break;
836                 }
837             case Value::BIND_STRING:
838                 {
839                 jvals[i].l = (jobject) env->NewStringUTF(v.getString().c_str());
840                 break;
841                 }
842             default:
843                 {
844                 err("Unknown value type: %d", v.getType());
845                 return false;
846                 }
847             }
848         }
849     switch (type)
850         {
851         case Value::BIND_VOID:
852             {
853             env->CallStaticVoidMethodA(cls, mid, jvals);
854             break;
855             }
856         case Value::BIND_BOOLEAN:
857             {
858             env->CallStaticBooleanMethodA(cls, mid, jvals);
859             break;
860             }
861         case Value::BIND_INT:
862             {
863             env->CallStaticIntMethodA(cls, mid, jvals);
864             break;
865             }
866         case Value::BIND_DOUBLE:
867             {
868             env->CallStaticDoubleMethodA(cls, mid, jvals);
869             break;
870             }
871         case Value::BIND_STRING:
872             {
873             env->CallStaticObjectMethodA(cls, mid, jvals);
874             break;
875             }
876         default:
877             {
878             err("Unknown return type: %d", type);
879             return false;
880             }
881         }
882     delete jvals;
883     String errStr = getException(env);
884     if (errStr.size()>0)
885         {
886         err("callStatic: %s", errStr.c_str());
887         return false;
888                 }
889     return true;
894 /**
895  * Convenience method to call the static void main(String argv[])
896  * method of a given class
897  * 
898  * @param className full name of the java class
899  * @return true if successful, else false   
900  */ 
901 bool JavaBinderyImpl::callMain(const String &className)
903     std::vector<Value> parms;
904     Value retval;
905     return callStatic(Value::BIND_VOID, className, "main",
906              "([Ljava/lang/String;)V", parms, retval);
910 /**
911  * Used to register an array of native methods for a named class
912  * 
913  * @param className the full name of the java class
914  * @param the method array
915  * @return true if successful, else false     
916  */ 
917 bool JavaBinderyImpl::registerNatives(const String &className,
918                            const JNINativeMethod *methods)
920     jclass cls = env->FindClass(className.c_str());
921     if (!cls)
922         {
923         err("Could not find class '%s'", className.c_str());
924         return false;
925         }
926     //msg("registerNatives: class '%s' found", className.c_str());
927     
928     /**
929      * hack for JDK bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6493522
930      */
931         jmethodID mid = env->GetMethodID(env->GetObjectClass(cls), "getConstructors",
932                   "()[Ljava/lang/reflect/Constructor;");
933         if (!mid)
934             {
935             err("Could not get reflect mid for 'getConstructors' : %s",
936              getException(env).c_str());
937                 return false;
938                 }
939         jobject res = env->CallObjectMethod(cls, mid);
940         if (!res)
941             {
942             err("Could not get constructors");
943                 return false;
944                 }
945         /**
946          * end hack
947          */             
948     jint nrMethods = 0;
949     for (const JNINativeMethod *m = methods ; m->name ; m++)
950         nrMethods++;
951     jint ret = env->RegisterNatives(cls, methods, nrMethods);
952     if (ret < 0)
953         {
954         err("Could not register %d native methods for '%s' : %s",
955                     nrMethods, className.c_str(), getException(env).c_str());
956         return false;
957         }
958     return true;
964 } // namespace Bind
965 } // namespace Inkscape
967 //########################################################################
968 //# E N D    O F    F I L E
969 //########################################################################