From 7e7ab30808c2f756fdfae0c224491bb3ceab1a1e Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Mon, 30 Apr 2012 17:45:24 +0930 Subject: [PATCH] Refactor JNI command-line interface Does not depend on ServalDResult class - appends output fields to a supplied list instead, and returns the integer status Does not depend on ServalDReentranceError class - uses java.lang.IllegalStateException instead --- commandline.c | 76 +++++++------------ java/org/servalproject/servald/ServalD.java | 22 ++++-- .../servald/ServalDReentranceError.java | 5 -- .../servalproject/servald/ServalDResult.java | 14 ---- .../servalproject/servald/ServalDTests.java | 11 +-- tests/dna_jni | 2 - 6 files changed, 51 insertions(+), 79 deletions(-) delete mode 100644 java/org/servalproject/servald/ServalDReentranceError.java delete mode 100644 java/org/servalproject/servald/ServalDResult.java diff --git a/commandline.c b/commandline.c index 46cee061..7af3ab83 100644 --- a/commandline.c +++ b/commandline.c @@ -95,19 +95,13 @@ int cli_usage() { #ifdef HAVE_JNI_H -struct outv_field { - jstring jstr; -}; - -#define OUTV_BUFFER_ATOM (8192) -#define OUTC_INCREMENT (256) +#define OUTV_BUFFER_ALLOCSIZE (8192) JNIEnv *jni_env = NULL; int jni_exception = 0; -struct outv_field *outv = NULL; -size_t outc = 0; -size_t outc_limit = 0; +jobject outv_list = NULL; +jmethodID listAddMethodId = NULL; char *outv_buffer = NULL; char *outv_current = NULL; @@ -117,8 +111,8 @@ static int outv_growbuf(size_t needed) { size_t newsize = (outv_limit - outv_current < needed) ? (outv_limit - outv_buffer) + needed : 0; if (newsize) { - // Round up to nearest multiple of OUTV_BUFFER_ATOM. - newsize = newsize + OUTV_BUFFER_ATOM - ((newsize - 1) % OUTV_BUFFER_ATOM + 1); + // Round up to nearest multiple of OUTV_BUFFER_ALLOCSIZE. + newsize = newsize + OUTV_BUFFER_ALLOCSIZE - ((newsize - 1) % OUTV_BUFFER_ALLOCSIZE + 1); size_t length = outv_current - outv_buffer; outv_buffer = realloc(outv_buffer, newsize); if (outv_buffer == NULL) @@ -133,57 +127,52 @@ static int outv_end_field() { outv_growbuf(1); *outv_current++ = '\0'; - if (outc == outc_limit) { - outc_limit += OUTC_INCREMENT; - size_t newsize = outc_limit * sizeof(struct outv_field); - outv = realloc(outv, newsize); - } - struct outv_field *f = &outv[outc]; - f->jstr = (jstring)(*jni_env)->NewStringUTF(jni_env, outv_buffer); + jstring str = (jstring)(*jni_env)->NewStringUTF(jni_env, outv_buffer); outv_current = outv_buffer; - if (f->jstr == NULL) { + if (str == NULL) { jni_exception = 1; return WHY("Exception thrown from NewStringUTF()"); } - ++outc; + (*jni_env)->CallBooleanMethod(jni_env, outv_list, listAddMethodId, str); + if ((*jni_env)->ExceptionOccurred(jni_env)) { + jni_exception = 1; + return WHY("Exception thrown from CallBooleanMethod()"); + } return 0; } /* JNI entry point to command line. See org.servalproject.servald.ServalD class for the Java side. - JNI method descriptor: "([Ljava/lang/String;)Lorg/servalproject/servald/ServalDResult;" + JNI method descriptor: "(Ljava/util/List;[Ljava/lang/String;)I" */ -JNIEXPORT jobject JNICALL Java_org_servalproject_servald_ServalD_command(JNIEnv *env, jobject this, jobjectArray args) +JNIEXPORT jint JNICALL Java_org_servalproject_servald_ServalD_rawCommand(JNIEnv *env, jobject this, jobject outv, jobjectArray args) { - jclass resultClass = NULL; jclass stringClass = NULL; - jmethodID resultConstructorId = NULL; - jobjectArray outArray = NULL; + jclass listClass = NULL; jint status = 0; // Enforce non re-entrancy. if (jni_env) { jclass exceptionClass = NULL; - if ((exceptionClass = (*env)->FindClass(env, "org/servalproject/servald/ServalDReentranceError")) == NULL) - return NULL; // exception + if ((exceptionClass = (*env)->FindClass(env, "java/lang/IllegalStateException")) == NULL) + return -1; // exception (*env)->ThrowNew(env, exceptionClass, "re-entrancy not supported"); - return NULL; + return -1; } - // Get some handles to some classes and methods that we use later on. - if ((resultClass = (*env)->FindClass(env, "org/servalproject/servald/ServalDResult")) == NULL) - return NULL; // exception - if ((resultConstructorId = (*env)->GetMethodID(env, resultClass, "", "(I[Ljava/lang/String;)V")) == NULL) - return NULL; // exception if ((stringClass = (*env)->FindClass(env, "java/lang/String")) == NULL) - return NULL; // exception + return -1; // exception + if ((listClass = (*env)->FindClass(env, "java/util/List")) == NULL) + return -1; // exception + if ((listAddMethodId = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z")) == NULL) + return -1; // exception // Construct argv, argc from this method's arguments. jsize len = (*env)->GetArrayLength(env, args); const char **argv = malloc(sizeof(char*) * (len + 1)); if (argv == NULL) { jclass exceptionClass = NULL; if ((exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError")) == NULL) - return NULL; // exception + return -1; // exception (*env)->ThrowNew(env, exceptionClass, "malloc returned NULL"); - return NULL; + return -1; } jsize i; for (i = 0; i <= len; ++i) @@ -206,7 +195,7 @@ JNIEXPORT jobject JNICALL Java_org_servalproject_servald_ServalD_command(JNIEnv } if (!jni_exception) { // Set up the output buffer. - outc = 0; + outv_list = outv; outv_current = outv_buffer; // Execute the command. jni_env = env; @@ -223,15 +212,8 @@ JNIEXPORT jobject JNICALL Java_org_servalproject_servald_ServalD_command(JNIEnv free(argv); // Deal with Java exceptions: NewStringUTF out of memory in outv_end_field(). if (jni_exception || (outv_current != outv_buffer && outv_end_field() == -1)) - return NULL; - // Pack the output fields into a Java array of strings. - if ((outArray = (*env)->NewObjectArray(env, outc, stringClass, NULL)) == NULL) - return NULL; // out of memory exception - for (i = 0; i != outc; ++i) - (*env)->SetObjectArrayElement(env, outArray, i, outv[i].jstr); - // Return the ResultD object constructed with the status integer and the array of output field - // strings. - return (*env)->NewObject(env, resultClass, resultConstructorId, status, outArray); + return -1; + return status; } #endif /* HAVE_JNI_H */ @@ -422,7 +404,7 @@ int cli_delim(const char *opt) { #ifdef HAVE_JNI_H if (jni_env) { - outv_end_field(); + return outv_end_field(); } else #endif { diff --git a/java/org/servalproject/servald/ServalD.java b/java/org/servalproject/servald/ServalD.java index 2d27e2ff..5bfee5bd 100644 --- a/java/org/servalproject/servald/ServalD.java +++ b/java/org/servalproject/servald/ServalD.java @@ -1,23 +1,33 @@ package org.servalproject.servald; -import org.servalproject.servald.ServalDResult; +import java.util.List; +import java.util.LinkedList; class ServalD { + int status; + List outv; + public ServalD() { System.loadLibrary("servald"); } - public native ServalDResult command(String... args); + public native int rawCommand(List outv, String... args); + + public void command(String... args) + { + this.outv = new LinkedList(); + this.status = this.rawCommand(this.outv, args); + } public static void main(String[] args) { - ServalD sdi = new ServalD(); - ServalDResult res = sdi.command(args); - for (String s: res.outv) { + ServalD servald = new ServalD(); + servald.command(args); + for (String s: servald.outv) { System.out.println(s); } - System.exit(res.status); + System.exit(servald.status); } } diff --git a/java/org/servalproject/servald/ServalDReentranceError.java b/java/org/servalproject/servald/ServalDReentranceError.java deleted file mode 100644 index 0f66d701..00000000 --- a/java/org/servalproject/servald/ServalDReentranceError.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.servalproject.servald; - -class ServalDReentranceError extends RuntimeException -{ -} diff --git a/java/org/servalproject/servald/ServalDResult.java b/java/org/servalproject/servald/ServalDResult.java deleted file mode 100644 index c6ef10a0..00000000 --- a/java/org/servalproject/servald/ServalDResult.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.servalproject.servald; - -class ServalDResult -{ - public int status; - public String[] outv; - - public ServalDResult(int status, String[] outv) - { - this.status = status; - this.outv = outv; - } - -} diff --git a/java/org/servalproject/servald/ServalDTests.java b/java/org/servalproject/servald/ServalDTests.java index 43380862..4546196f 100644 --- a/java/org/servalproject/servald/ServalDTests.java +++ b/java/org/servalproject/servald/ServalDTests.java @@ -2,8 +2,9 @@ package org.servalproject.servald; import java.lang.reflect.*; import java.util.Arrays; +import java.util.List; +import java.util.LinkedList; import org.servalproject.servald.ServalD; -import org.servalproject.servald.ServalDResult; class ServalDTests { @@ -24,11 +25,11 @@ class ServalDTests public static void repeat(String[] args) { int repeat = Integer.decode(args[0]); - ServalD sdi = new ServalD(); + ServalD servald = new ServalD(); for (int i = 0; i != repeat; ++i) { - ServalDResult res = sdi.command(Arrays.copyOfRange(args, 1, args.length)); - System.out.print(res.status); - for (String s: res.outv) { + servald.command(Arrays.copyOfRange(args, 1, args.length)); + System.out.print(servald.status); + for (String s: servald.outv) { System.out.print(":"); System.out.print(s); } diff --git a/tests/dna_jni b/tests/dna_jni index 59861778..49385883 100755 --- a/tests/dna_jni +++ b/tests/dna_jni @@ -34,8 +34,6 @@ compile_java_classes() { mkdir classes assert $JAVAC -d classes "$dna_source_root"/java/org/servalproject/servald/*.java assert [ -r classes/org/servalproject/servald/ServalD.class ] - assert [ -r classes/org/servalproject/servald/ServalDResult.class ] - assert [ -r classes/org/servalproject/servald/ServalDReentranceError.class ] assert [ -r classes/org/servalproject/servald/ServalDTests.class ] }