Code

Improve exception handling. Handle static method return types.
authorishmal <ishmal@users.sourceforge.net>
Wed, 12 Mar 2008 17:15:41 +0000 (17:15 +0000)
committerishmal <ishmal@users.sourceforge.net>
Wed, 12 Mar 2008 17:15:41 +0000 (17:15 +0000)
src/bind/javabind-private.h
src/bind/javabind.cpp
src/bind/javabind.h

index f76118c282b69e71b9bedfd35c54559918af2a07..9b7b4e9959cafd7b2ed515665ec3e0fdd0476b52 100644 (file)
@@ -63,6 +63,8 @@ public:
  
     virtual bool doBinding();
 
+    virtual String getException();
+
     virtual bool setupScriptRunner();
 
     static JavaBinderyImpl *getInstance();
index 5a870063366a42e387cd8fdc284aebb89211a967..f4905e15349b48a235753a7b92714ede1bdb7860 100644 (file)
 /**
  * Note: We must limit Java or JVM-specific code to this file
  * and to dobinding.cpp.  It should be hidden from javabind.h
+ * 
+ * This file is mostly about getting things up and running, and
+ * providing the basic C-to-Java hooks.
+ *   
+ * dobinding.cpp will have the rote and repetitious
+ * class-by-class binding   
  */  
 
 
@@ -97,22 +103,6 @@ String normalizePath(const String &str)
 }
 
 
-String getException(JNIEnv *env)
-{
-    String buf;
-    jthrowable exc = env->ExceptionOccurred();
-    if (!exc)
-        return buf;
-    jclass cls = env->GetObjectClass(exc);
-    jmethodID mid = env->GetMethodID(cls, "toString", "()Ljava/lang/String;");
-    jstring jstr = (jstring) env->CallObjectMethod(exc, mid);
-    const char *str = env->GetStringUTFChars(jstr, JNI_FALSE);
-    buf.append(str);
-    env->ReleaseStringUTFChars(jstr, str);
-    env->ExceptionClear();
-       return buf;
-}
-
 jint getInt(JNIEnv *env, jobject obj, const char *name)
 {
     jfieldID fid = env->GetFieldID(env->GetObjectClass(obj), name, "I");
@@ -660,9 +650,13 @@ static JNINativeMethod scriptRunnerMethods[] =
 { NULL,  NULL, NULL }
 };
 
+
 /**
  * This sets up the 'ScriptRunner' java class for execution of
- * scripts
+ * scripts.   The class's constructor takes a jlong.  This java long
+ * is used to store the pointer to 'this'.  When ScriptRunner makes
+ * native calls, it passes that jlong back, so that it can call the
+ * methods of this C++ class.  
  */  
 bool JavaBinderyImpl::setupScriptRunner()
 {
@@ -674,21 +668,25 @@ bool JavaBinderyImpl::setupScriptRunner()
     jclass cls = env->FindClass(className.c_str());
     if (!cls)
         {
-        err("setupScriptRunner: cannot find class '%s'", className.c_str());
+        err("setupScriptRunner: cannot find class '%s' : %s",
+                        className.c_str(), getException().c_str());
         return false;
                }
        jmethodID mid = env->GetMethodID(cls, "<init>", "(J)V");
        if (!mid)
         {
-        err("setupScriptRunner: cannot find constructor for '%s'", className.c_str());
+        err("setupScriptRunner: cannot find constructor for '%s' : %s",
+                         className.c_str(), getException().c_str());
         return false;
                }
     jobject obj = env->NewObject(cls, mid, ((jlong)this));
     if (!obj)
         {
-        err("setupScriptRunner: cannot construct '%s'", className.c_str());
+        err("setupScriptRunner: cannot construct '%s' : %s",
+                        className.c_str(), getException().c_str());
         return false;
                }
+
        msg("ScriptRunner ready");
     return true;
 }
@@ -743,16 +741,17 @@ bool JavaBinderyImpl::loadJVM()
     msg("Lib path is: '%s'", libpath.c_str());
 
     JavaVMInitArgs vm_args;
-    JavaVMOption options[4];
-    options[0].optionString    = (char *)classpath.c_str();
-    options[1].optionString    = (char *)libpath.c_str();
-    options[2].optionString    = (char *)"-verbose:jni";
-    options[3].optionString    = (char *)"vfprintf";
-    options[3].extraInfo       = (void *)vfprintfHook;
-    vm_args.version            = JNI_VERSION_1_4;
-    vm_args.options            = options;
-    vm_args.nOptions           = 4;
-    vm_args.ignoreUnrecognized = true;
+    JavaVMOption options[10];//should be enough
+    int nOptions = 0;
+    options[nOptions++].optionString = (char *)classpath.c_str();
+    options[nOptions++].optionString = (char *)libpath.c_str();
+    //options[nOptions++].optionString = (char *)"-verbose:jni";
+    options[nOptions  ].optionString = (char *)"vfprintf";
+    options[nOptions++].extraInfo    = (void *)vfprintfHook;
+    vm_args.version                  = JNI_VERSION_1_4;
+    vm_args.options                  = options;
+    vm_args.nOptions                 = nOptions;
+    vm_args.ignoreUnrecognized       = true;
 
     if (createVM(&jvm, &env, &vm_args) < 0)
         {
@@ -769,7 +768,6 @@ bool JavaBinderyImpl::loadJVM()
     if (!setupScriptRunner())
         return false;
 
-
     return true;
 }
 
@@ -799,15 +797,17 @@ bool JavaBinderyImpl::callStatic(int type,
     jclass cls = env->FindClass(className.c_str());
     if (!cls)
         {
-        err("Could not find class '%s'", className.c_str());
+        err("Could not find class '%s' : %s",
+                      className.c_str(), getException().c_str());
         return false;
         }
     jmethodID mid = env->GetStaticMethodID(cls,
                 methodName.c_str(), signature.c_str());
     if (!mid)
         {
-        err("Could not find method '%s:%s/%s'", className.c_str(),
-                methodName.c_str(), signature.c_str());
+        err("Could not find method '%s:%s/%s' : %s",
+                       className.c_str(), methodName.c_str(),
+                           signature.c_str(), getException().c_str());
         return false;
         }
     /**
@@ -855,22 +855,32 @@ bool JavaBinderyImpl::callStatic(int type,
             }
         case Value::BIND_BOOLEAN:
             {
-            env->CallStaticBooleanMethodA(cls, mid, jvals);
+            jboolean ret = env->CallStaticBooleanMethodA(cls, mid, jvals);
+            if (ret == JNI_TRUE) //remember, don't truncate
+                retval.setBoolean(true);
+            else
+                retval.setBoolean(false);
             break;
             }
         case Value::BIND_INT:
             {
-            env->CallStaticIntMethodA(cls, mid, jvals);
+            jint ret = env->CallStaticIntMethodA(cls, mid, jvals);
+            retval.setInt(ret);
             break;
             }
         case Value::BIND_DOUBLE:
             {
-            env->CallStaticDoubleMethodA(cls, mid, jvals);
+            jdouble ret = env->CallStaticDoubleMethodA(cls, mid, jvals);
+            retval.setDouble(ret);
             break;
             }
         case Value::BIND_STRING:
             {
-            env->CallStaticObjectMethodA(cls, mid, jvals);
+            jobject ret = env->CallStaticObjectMethodA(cls, mid, jvals);
+            jstring jstr = (jstring) ret;
+            const char *str = env->GetStringUTFChars(jstr, JNI_FALSE);
+            retval.setString(str);
+            env->ReleaseStringUTFChars(jstr, str);
             break;
             }
         default:
@@ -880,7 +890,7 @@ bool JavaBinderyImpl::callStatic(int type,
             }
         }
     delete jvals;
-    String errStr = getException(env);
+    String errStr = getException();
     if (errStr.size()>0)
         {
         err("callStatic: %s", errStr.c_str());
@@ -891,6 +901,30 @@ bool JavaBinderyImpl::callStatic(int type,
 
 
 
+/**
+ * Fetch the last exception from the JVM, if any.  Clear it to
+ * continue processing
+ * 
+ * @return the exception's descriptio,if any.  Else ""  
+ */  
+String JavaBinderyImpl::getException()
+{
+    String buf;
+    jthrowable exc = env->ExceptionOccurred();
+    if (!exc)
+        return buf;
+    jclass cls = env->GetObjectClass(exc);
+    jmethodID mid = env->GetMethodID(cls, "toString", "()Ljava/lang/String;");
+    jstring jstr = (jstring) env->CallObjectMethod(exc, mid);
+    const char *str = env->GetStringUTFChars(jstr, JNI_FALSE);
+    buf.append(str);
+    env->ReleaseStringUTFChars(jstr, str);
+    env->ExceptionClear();
+       return buf;
+}
+
+
+
 /**
  * Convenience method to call the static void main(String argv[])
  * method of a given class
@@ -933,13 +967,13 @@ bool JavaBinderyImpl::registerNatives(const String &className,
        if (!mid)
            {
            err("Could not get reflect mid for 'getConstructors' : %s",
-             getException(env).c_str());
+             getException().c_str());
                return false;
                }
        jobject res = env->CallObjectMethod(cls, mid);
        if (!res)
            {
-           err("Could not get constructors");
+           err("Could not get constructors : %s", getException().c_str());
                return false;
                }
        /**
@@ -952,7 +986,7 @@ bool JavaBinderyImpl::registerNatives(const String &className,
     if (ret < 0)
         {
         err("Could not register %d native methods for '%s' : %s",
-                   nrMethods, className.c_str(), getException(env).c_str());
+                   nrMethods, className.c_str(), getException().c_str());
         return false;
         }
     return true;
index b20132d035d360fcf385c04e42dc53206a5c9ec4..cd622960b6824b8129a8c3e528dbd16b41a8e34f 100644 (file)
@@ -262,6 +262,14 @@ public:
         return false;
         }
         
+    /**
+     *
+     */
+    virtual String getException()
+        {
+               return "";
+               }
+        
     virtual String stdOutGet()
         {
         return stdOutBuf;
@@ -307,7 +315,7 @@ public:
         logBuf.push_back((char)ch);
         if (ch == '\n' || ch == '\r')
             {
-            g_message(logBuf.c_str());
+            g_message("%s", logBuf.c_str());
             logBuf.clear();
                        }
         }