# HG changeset patch # User John W. Eaton # Date 1354944193 18000 # Node ID f96faf028d90ffb6fb84f1145ffb6dc749456e0b # Parent 72968fb32c82b3f093408220a09f8f9cdd9f70ad make java functions part of core octave_value classes * run-octave.in: Set OCTAVE_JAVA_DIR. * octave-value/ov-java.cc: Rename from dldfcn/__java__.cc. (get_module_path): Delete. (initial_java_dir): Don't set architecture dependent directory. Check environment or use Vfcn_file_dir to set default directory. (initial_class_path): Don't search load path for octave.jar. (initialize_jvm): Don't add -Doctave.java.path=DIR to vm_args. Use DEFUN, not DEFUN_DLD. (F__java__): Delete. * octave-value/ov-java.h: Rename from dldfcn/__java__.h. * dldfcn/module-files: Delete entry for __java__.cc. * libinterp/Makefile.am (octinclude_HEADERS): Delete $(DLDFCN_INC) from the list. * octave-value/module.mk (OCTAVE_VALUE_INC): Add ov-java.h to the list. (OCTAVE_VALUE_SRC) Add ov-java.cc to the list. (octave_value_liboctave_value_la_LIBADD): New variable. (octave_value_liboctave_value_la_CPPFLAGS): Add $(JAVA_CPPFLAGS) to the list. * dldfcn/config-module.awk: Don't print DLDFCN_INC variable. * Octave.java, OctaveReference.java: Don't grab a reference to __java__.oct. diff -r 72968fb32c82 -r f96faf028d90 libinterp/Makefile.am --- a/libinterp/Makefile.am Fri Dec 07 19:34:19 2012 -0500 +++ b/libinterp/Makefile.am Sat Dec 08 00:23:13 2012 -0500 @@ -107,8 +107,7 @@ $(PARSE_TREE_INC) \ $(OPERATORS_INC) \ $(INTERP_CORE_INC) \ - $(INTERPFCN_INC) \ - $(DLDFCN_INC) + $(INTERPFCN_INC) nodist_octinclude_HEADERS = \ interp-core/mxarray.h \ diff -r 72968fb32c82 -r f96faf028d90 libinterp/dldfcn/__java__.cc --- a/libinterp/dldfcn/__java__.cc Fri Dec 07 19:34:19 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2242 +0,0 @@ -/* - -Copyright (C) 2007 Michael Goffioul - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if defined HAVE_JAVA - -#if defined (HAVE_WINDWOS_H) -#include -#endif - -#include -#include -#include -#include - -#include - -#include "Cell.h" -#include "__java__.h" -#include "cmd-edit.h" -#include "defun-dld.h" -#include "file-ops.h" -#include "file-stat.h" -#include "load-path.h" -#include "oct-env.h" -#include "oct-shlib.h" -#include "parse.h" -#include "variables.h" - -typedef jint (JNICALL *JNI_CreateJavaVM_t) (JavaVM **pvm, JNIEnv **penv, void *args); -typedef jint (JNICALL *JNI_GetCreatedJavaVMs_t) (JavaVM **pvm, jsize bufLen, jsize *nVMs); - -extern "C" -{ - JNIEXPORT jboolean JNICALL - Java_org_octave_Octave_call (JNIEnv *, jclass, jstring, jobjectArray, - jobjectArray); - JNIEXPORT void JNICALL - Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint); - - JNIEXPORT void JNICALL - Java_org_octave_Octave_doInvoke (JNIEnv *, jclass, jint, jobjectArray); - - JNIEXPORT void JNICALL - Java_org_octave_Octave_doEvalString (JNIEnv *, jclass, jstring); - - JNIEXPORT jboolean JNICALL - Java_org_octave_Octave_needThreadedInvokation (JNIEnv *, jclass); -} - -static octave_value _java_new (const octave_value_list& args); -static octave_value _java_invoke (const octave_value_list& args); - -static JavaVM *jvm = 0; -static bool jvm_attached = false; - -// Need to keep hold of the shared library handle until exit. -static octave_shlib jvm_lib; - -static std::map listener_map; -static std::map octave_ref_map; -static int octave_java_refcount = 0; -static long octave_thread_ID = -1; - -bool Vjava_convert_matrix = false; -bool Vjava_unsigned_conversion = true; -bool Vjava_debug = false; - -class JVMArgs -{ -public: - - JVMArgs (void) - { - vm_args.version = JNI_VERSION_1_2; - vm_args.nOptions = 0; - vm_args.options = 0; - vm_args.ignoreUnrecognized = false; - } - - ~JVMArgs (void) - { - clean (); - } - - JavaVMInitArgs* to_args () - { - update (); - return &vm_args; - } - - void add (const std::string& opt) - { - java_opts.push_back (opt); - } - - void read_java_opts (const std::string& filename) - { - std::ifstream js (filename.c_str ()); - - if (! js.bad () && ! js.fail ()) - { - std::string line; - - while (! js.eof () && ! js.fail ()) - { - std::getline (js, line); - if (line.length () > 2 - && (line.find ("-D") == 0 || line.find ("-X") == 0)) - java_opts.push_back (line); - else if (line.length () > 0 && Vjava_debug) - std::cerr << "invalid JVM option, skipping: " << line << std::endl; - } - } - } - -private: - - void clean (void) - { - if (vm_args.options != 0) - { - for (int i = 0; i < vm_args.nOptions; i++) - delete [] vm_args.options[i].optionString; - delete [] vm_args.options; - - vm_args.options = 0; - vm_args.nOptions = 0; - } - } - - void update (void) - { - clean (); - - if (java_opts.size () > 0) - { - int index = 0; - - vm_args.nOptions = java_opts.size (); - vm_args.options = new JavaVMOption [vm_args.nOptions]; - for (std::list::const_iterator it = java_opts.begin (); it != java_opts.end (); ++it) - { - if (Vjava_debug) - std::cout << *it << std::endl; - vm_args.options[index++].optionString = strsave ((*it).c_str ()); - } - java_opts.clear (); - } - } - -private: - - JavaVMInitArgs vm_args; - - std::list java_opts; -}; - -static dim_vector compute_array_dimensions (JNIEnv* jni_env, jobject obj); - -#ifdef __WIN32__ -static std::string -read_registry_string (const std::string& key, const std::string& value) -{ - HKEY hkey; - DWORD len; - - std::string retval; - - if (! RegOpenKeyEx (HKEY_LOCAL_MACHINE, key.c_str (), 0, KEY_READ, &hkey)) - { - if (! RegQueryValueEx (hkey, value.c_str (), 0, 0, 0, &len)) - { - retval.resize (len); - if (RegQueryValueEx (hkey, value.c_str (), 0, 0, (LPBYTE)&retval[0], &len)) - retval = ""; - else if (retval[len-1] == '\0') - retval.resize (--len); - } - RegCloseKey (hkey); - } - - return retval; -} - -static std::string -get_module_filename (HMODULE hMod) -{ - int n = 1024; - std::string retval (n, '\0'); - bool found = false; - - while (n < 65536) - { - int status = GetModuleFileName(hMod, &retval[0], n); - - if (status < n) - { - retval.resize(n); - found = true; - break; - } - else - { - n *= 2; - retval.resize(n); - } - } - return (found ? retval : ""); -} - -static void -set_dll_directory (const std::string& dir = "") -{ - typedef BOOL (WINAPI *dllfcn_t) (LPCTSTR path); - - static dllfcn_t dllfcn = NULL; - static bool first = true; - - if (! dllfcn && first) - { - HINSTANCE hKernel32 = GetModuleHandle ("kernel32"); - dllfcn = reinterpret_cast (GetProcAddress (hKernel32, "SetDllDirectoryA")); - first = false; - } - - if (dllfcn) - dllfcn (dir.empty () ? NULL : dir.c_str ()); -} -#endif - -static std::string -get_module_path (const std::string& name, bool strip_name = true) -{ - std::string retval; - - retval = octave_env::make_absolute (load_path::find_file (name), - octave_env::get_current_directory ()); - - if (! retval.empty ()) - { - if (strip_name) - { - size_t pos = retval.rfind (file_ops::dir_sep_str () + name); - - if (pos != std::string::npos) - retval.resize (pos); - else - throw std::string ("No module path in ") + retval; - } - } - else - throw std::string ("Could not find file ") + name; - - return retval; -} - -static std::string -initial_java_dir (bool arch_dependent = false) -{ - static std::string path1; - static std::string path2; - - if (arch_dependent) - { - if (path1.empty ()) - path1 = get_module_path ("__java__.oct", true); - - return path1; - } - else - { - if (path2.empty ()) - path2 = get_module_path ("javaclasspath.m", true); - - return path2; - } -} - -// Read the content of a file filename (usually "classpath.txt") -// -// Returns a string with all lines concatenated and separated -// by the path separator character. -// The return string also starts with a path separator so that -// it can be appended easily to a base classpath. -// -// The file "classpath.txt" must contain single lines, each -// with a classpath. -// Comment lines starting with a '#' or a '%' in column 1 are allowed. - -static std::string -read_classpath_txt (const std::string& filepath) -{ - std::string classpath; - - std::ifstream fs (filepath.c_str ()); - - if (! fs.bad () && ! fs.fail ()) - { - std::string line; - - while (! fs.eof () && ! fs.fail ()) - { - std::getline (fs, line); - - if (line.length () > 1) - { - if (line.at(0) == '#' || line.at(0) == '%') - ; // skip comments - else - { - // prepend separator character - classpath.append (dir_path::path_sep_str ()); - - // append content of line without trailing blanks - int iLast = line.find_last_not_of (' '); - - classpath.append (file_ops::tilde_expand (line.substr (0, iLast+1))); - } - } - } - } - - return (classpath); -} - - -static std::string -initial_class_path (void) -{ - std::string retval = initial_java_dir (); - - // find octave.jar file - if (! retval.empty ()) - { - std::string jar_file = get_module_path ("octave.jar", false); - file_stat jar_exists (jar_file); - - if (jar_exists) - { - // initialize static classpath to octave.jar - retval = jar_file; - - - // The base classpath has been set. Try to find the optional - // file "classpath.txt" in two places. The users classes will - // take precedence over the settings defined in the package - // directory - - std::string str_filename = "classpath.txt"; - std::string cp_file; - file_stat cp_exists; - - // Try to read the file "classpath.txt" in the user's home - // directory. - - cp_file = file_ops::tilde_expand ("~" + file_ops::dir_sep_str () + str_filename); - cp_exists = file_stat (cp_file); - if (cp_exists) - { - // The file "classpath.txt" has been found: add its - // contents to the static classpath. - - std::string theClassPath = read_classpath_txt (cp_file); - retval.append (theClassPath); - } - - // Try to read a file "classpath.txt" in the package directory. - - cp_file = initial_java_dir () + file_ops::dir_sep_str () + str_filename; - cp_exists = file_stat (cp_file); - if (cp_exists) - { - // The file "classpath.txt" has been found: add its - // contents to the static classpath. - - std::string theClassPath = read_classpath_txt (cp_file); - retval.append (theClassPath); - } - } - else - throw std::string ("octave jar does not exist: ") + jar_file; - } - else - throw std::string ("initial java dir is empty"); - - return retval; -} - -static void -initialize_jvm (void) -{ - JNIEnv *current_env; - - if (jvm) - return; - - const char *static_locale = setlocale (LC_ALL, NULL); - const std::string locale (static_locale); - -#if defined (__WIN32__) - - HMODULE hMod = GetModuleHandle ("jvm.dll"); - std::string jvm_lib_path; - std::string old_cwd; - - if (hMod == NULL) - { - // In windows, find the location of the JRE from the registry - // and load the symbol from the dll. - std::string key, value; - - key = "software\\javasoft\\java runtime environment"; - - value = octave_env::getenv ("JAVA_VERSION"); - if (value.empty ()) - { - value = "Currentversion"; - std::string regval = read_registry_string (key,value); - - if (regval.empty ()) - throw std::string ("unable to find Java Runtime Environment: ") + key + "::" + value; - value = regval; - } - - key = key + "\\" + value; - value = "RuntimeLib"; - jvm_lib_path = read_registry_string (key, value); - if (jvm_lib_path.empty ()) - throw std::string ("unable to find Java Runtime Environment: ") + key + "::" + value; - - std::string jvm_bin_path; - - value = "JavaHome"; - jvm_bin_path = read_registry_string (key, value); - if (! jvm_bin_path.empty ()) - { - jvm_bin_path = (jvm_bin_path + std::string ("\\bin")); - - old_cwd = octave_env::get_current_directory (); - - set_dll_directory (jvm_bin_path); - octave_env::chdir (jvm_bin_path); - } - } - else - { - // JVM seems to be already loaded, better to use that DLL instead - // of looking in the registry, to avoid opening a different JVM. - jvm_lib_path = get_module_filename (hMod); - - if (jvm_lib_path.empty ()) - throw std::string ("unable to find Java Runtime Environment"); - } - -#else - - std::string jvm_lib_path = JAVA_HOME + std::string ("/jre/lib/") + JAVA_ARCH + "/server/libjvm.so"; - -#endif - - jsize nVMs = 0; - -# if !defined (__APPLE__) && !defined (__MACH__) - - octave_shlib lib (jvm_lib_path); - - if (!lib) - throw std::string ("unable to load Java Runtime Environment from ") + jvm_lib_path; - -#if defined (__WIN32__) - - set_dll_directory (); - - if (! old_cwd.empty ()) - octave_env::chdir (old_cwd); - -#endif - - JNI_CreateJavaVM_t create_vm = reinterpret_cast (lib.search ("JNI_CreateJavaVM")); - JNI_GetCreatedJavaVMs_t get_vm = reinterpret_cast (lib.search ("JNI_GetCreatedJavaVMs")); - - if (!create_vm) - throw std::string ("unable to find JNI_CreateJavaVM in ") + jvm_lib_path; - - if (!get_vm) - throw std::string ("unable to find JNI_GetCreatedJavaVMs in ") + jvm_lib_path; - - if (get_vm (&jvm, 1, &nVMs) == 0 && nVMs > 0) - -#else - - // FIXME: There exists a problem on the Mac platform that - // octave_shlib lib (jvm_lib_path) - // doesn't work with 'not-bundled' *.oct files. - - if (JNI_GetCreatedJavaVMs (&jvm, 1, &nVMs) == 0 && nVMs > 0) - -#endif - - { - // At least one JVM exists, try to attach to it - - switch (jvm->GetEnv (reinterpret_cast (¤t_env), JNI_VERSION_1_2)) - { - case JNI_EDETACHED: - // Attach the current thread - JavaVMAttachArgs vm_args; - vm_args.version = JNI_VERSION_1_2; - vm_args.name = const_cast ("octave"); - vm_args.group = NULL; - if (jvm->AttachCurrentThread (reinterpret_cast (¤t_env), &vm_args) < 0) - throw std::string ("JVM internal error, unable to attach octave to existing JVM"); - break; - - case JNI_EVERSION: - throw std::string ("JVM internal error, the required JNI version is not supported"); - break; - - case JNI_OK: - // Don't do anything, the current thread is already attached to JVM - break; - } - - jvm_attached = true; - //printf ("JVM attached\n"); - } - else - { - // No JVM exists, create one - - JVMArgs vm_args; - - vm_args.add ("-Djava.class.path=" + initial_class_path ()); - vm_args.add ("-Doctave.java.path=" + initial_java_dir (true)); - vm_args.add ("-Xrs"); - vm_args.add ("-Djava.system.class.loader=org.octave.OctClassLoader"); - vm_args.read_java_opts (initial_java_dir (false) + file_ops::dir_sep_str () + "java.opts"); - -# if !defined (__APPLE__) && !defined (__MACH__) - - if (create_vm (&jvm, ¤t_env, vm_args.to_args ()) != JNI_OK) - throw std::string ("unable to start Java VM in ")+jvm_lib_path; - //printf ("JVM created\n"); - } - - jvm_lib = lib; - -#else - - if (JNI_CreateJavaVM (&jvm, reinterpret_cast (¤t_env), - vm_args.to_args ()) != JNI_OK) - throw std::string ("unable to start Java VM in ")+jvm_lib_path; - - } - -#endif - - setlocale (LC_ALL, locale.c_str ()); -} - -static void -terminate_jvm (void) -{ - if (jvm) - { - if (jvm_attached) - jvm->DetachCurrentThread (); - else - jvm->DestroyJavaVM (); - - jvm = 0; - jvm_attached = false; - - if (jvm_lib) - jvm_lib.close (); - } -} - -std::string -jstring_to_string (JNIEnv* jni_env, jstring s) -{ - std::string retval; - - if (jni_env) - { - const char *cstr = jni_env->GetStringUTFChars (s, 0); - retval = cstr; - jni_env->ReleaseStringUTFChars (s, cstr); - } - - return retval; -} - -std::string -jstring_to_string (JNIEnv* jni_env, jobject obj) -{ - std::string retval; - - if (jni_env && obj) - { - jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String")); - if (cls) - { - if (jni_env->IsInstanceOf (obj, cls)) - retval = jstring_to_string (jni_env, reinterpret_cast (obj)); - } - } - - return retval; -} - -static octave_value -check_exception (JNIEnv* jni_env) -{ - octave_value retval; - - jthrowable_ref ex (jni_env, jni_env->ExceptionOccurred ()); - - if (ex) - { - if (Vjava_debug) - jni_env->ExceptionDescribe (); - - jni_env->ExceptionClear (); - - jclass_ref jcls (jni_env, jni_env->GetObjectClass (ex)); - jmethodID mID = jni_env->GetMethodID (jcls, "toString", "()Ljava/lang/String;"); - jstring_ref js (jni_env, reinterpret_cast (jni_env->CallObjectMethod (ex, mID))); - std::string msg = jstring_to_string (jni_env, js); - - error ("[java] %s", msg.c_str ()); - } - else - retval = Matrix (); - - return retval; -} - -static jclass -find_octave_class (JNIEnv *jni_env, const char *name) -{ - static std::string class_loader; - static jclass uiClass = 0; - - jclass jcls = jni_env->FindClass (name); - - if (jcls == 0) - { - jni_env->ExceptionClear (); - - if (! uiClass) - { - if (class_loader.empty ()) - { - jclass_ref syscls (jni_env, jni_env->FindClass ("java/lang/System")); - jmethodID mID = jni_env->GetStaticMethodID (syscls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); - jstring_ref js (jni_env, jni_env->NewStringUTF ("octave.class.loader")); - js = reinterpret_cast (jni_env->CallStaticObjectMethod (syscls, mID, jstring (js))); - class_loader = jstring_to_string (jni_env, jstring (js)); - std::replace (class_loader.begin (), class_loader.end (), '.', '/'); - } - - jclass_ref uicls (jni_env, jni_env->FindClass (class_loader.c_str ())); - - if (! uicls) - { - jni_env->ExceptionClear (); - - /* Try the netbeans way */ - std::replace (class_loader.begin (), class_loader.end (), '/', '.'); - jclass_ref jcls2 (jni_env, jni_env->FindClass ("org/openide/util/Lookup")); - jmethodID mID = jni_env->GetStaticMethodID (jcls2, "getDefault", "()Lorg/openide/util/Lookup;"); - jobject_ref lObj (jni_env, jni_env->CallStaticObjectMethod (jcls2, mID)); - mID = jni_env->GetMethodID (jcls2, "lookup", "(Ljava/lang/Class;)Ljava/lang/Object;"); - jclass_ref cLoaderCls (jni_env, jni_env->FindClass ("java/lang/ClassLoader")); - jobject_ref cLoader (jni_env, jni_env->CallObjectMethod (lObj, mID, jclass (cLoaderCls))); - mID = jni_env->GetMethodID (cLoaderCls, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - jstring_ref js (jni_env, jni_env->NewStringUTF (class_loader.c_str ())); - uicls = reinterpret_cast (jni_env->CallObjectMethod (cLoader, mID, jstring (js))); - } - - if (uicls) - uiClass = reinterpret_cast (jni_env->NewGlobalRef (jclass (uicls))); - } - - if (uiClass) - { - jmethodID mID = jni_env->GetStaticMethodID (uiClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - jstring_ref js (jni_env, jni_env->NewStringUTF (name)); - jcls = reinterpret_cast (jni_env->CallStaticObjectMethod (uiClass, mID, jstring (js))); - } - } - - return jcls; -} - -static dim_vector -compute_array_dimensions (JNIEnv* jni_env, jobject obj) -{ - jobjectArray_ref jobj (jni_env, reinterpret_cast (obj)); - jclass_ref jcls (jni_env, jni_env->GetObjectClass (obj)); - jclass_ref ccls (jni_env, jni_env->GetObjectClass (jcls)); - jmethodID isArray_ID = jni_env->GetMethodID (ccls, "isArray", "()Z"), - getComponentType_ID = jni_env->GetMethodID (ccls, "getComponentType", "()Ljava/lang/Class;"); - - dim_vector dv (1, 1); - int idx = 0; - - jobj.detach (); - while (jcls && jni_env->CallBooleanMethod (jcls, isArray_ID)) - { - int len = (jobj ? jni_env->GetArrayLength (jobj) : 0); - if (idx >= dv.length ()) - dv.resize (idx+1); - dv(idx) = len; - jcls = reinterpret_cast (jni_env->CallObjectMethod (jcls, getComponentType_ID)); - jobj = (len > 0 ? reinterpret_cast (jni_env->GetObjectArrayElement (jobj, 0)) : 0); - idx++; - } - - return dv; -} - -static jobject -make_java_index (JNIEnv* jni_env, const octave_value_list& idx) -{ - jclass_ref ocls (jni_env, jni_env->FindClass ("[I")); - jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, 0); - - for (int i = 0; i < idx.length (); i++) - { - idx_vector v = idx(i).index_vector (); - - if (! error_state) - { - jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ())); - jint *buf = jni_env->GetIntArrayElements (i_array, 0); - - for (int k = 0; k < v.length (); k++) - buf[k] = v(k); - - jni_env->ReleaseIntArrayElements (i_array, buf, 0); - jni_env->SetObjectArrayElement (retval, i, i_array); - - check_exception (jni_env); - - if (error_state) - break; - } - else - break; - } - - return retval; -} - -static octave_value -get_array_elements (JNIEnv* jni_env, jobject jobj, - const octave_value_list& idx) -{ - octave_value retval; - jobject_ref resObj (jni_env); - jobject_ref java_idx (jni_env, make_java_index (jni_env, idx)); - - if (! error_state) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsref", "(Ljava/lang/Object;[[I)Ljava/lang/Object;"); - resObj = jni_env->CallStaticObjectMethod (helperClass, mID, jobj, jobject (java_idx)); - } - - if (resObj) - retval = box (jni_env, resObj); - else - retval = check_exception (jni_env); - - return retval; -} - -static octave_value -set_array_elements (JNIEnv* jni_env, jobject jobj, - const octave_value_list& idx, const octave_value& rhs) -{ - octave_value retval; - - jclass_ref rhsCls (jni_env); - jobject_ref resObj (jni_env), rhsObj (jni_env); - jobject_ref java_idx (jni_env, make_java_index (jni_env, idx)); - - if (! error_state && unbox (jni_env, rhs, rhsObj, rhsCls)) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsasgn", - "(Ljava/lang/Object;[[ILjava/lang/Object;)Ljava/lang/Object;"); - resObj = jni_env->CallStaticObjectMethod (helperClass, mID, - jobj, jobject (java_idx), jobject (rhsObj)); - } - - if (resObj) - retval = box (jni_env, resObj); - else - retval = check_exception (jni_env); - - return retval; -} - -static string_vector -get_invoke_list (JNIEnv* jni_env, jobject jobj) -{ - std::list name_list; - - if (jni_env) - { - jclass_ref cls (jni_env, jni_env->GetObjectClass (jobj)); - jclass_ref ccls (jni_env, jni_env->GetObjectClass (cls)); - jmethodID getMethods_ID = jni_env->GetMethodID (ccls, "getMethods", "()[Ljava/lang/reflect/Method;"), - getFields_ID = jni_env->GetMethodID (ccls, "getFields", "()[Ljava/lang/reflect/Field;"); - jobjectArray_ref mList (jni_env, reinterpret_cast (jni_env->CallObjectMethod (cls, getMethods_ID))), - fList (jni_env, reinterpret_cast (jni_env->CallObjectMethod (cls, getFields_ID))); - int mLen = jni_env->GetArrayLength (mList), fLen = jni_env->GetArrayLength (fList); - jclass_ref mCls (jni_env, jni_env->FindClass ("java/lang/reflect/Method")), - fCls (jni_env, jni_env->FindClass ("java/lang/reflect/Field")); - jmethodID m_getName_ID = jni_env->GetMethodID (mCls, "getName", "()Ljava/lang/String;"), - f_getName_ID = jni_env->GetMethodID (fCls, "getName", "()Ljava/lang/String;"); - - for (int i = 0; i < mLen; i++) - { - jobject_ref meth (jni_env, jni_env->GetObjectArrayElement (mList, i)); - jstring_ref methName (jni_env, reinterpret_cast (jni_env->CallObjectMethod (meth, m_getName_ID))); - name_list.push_back (jstring_to_string (jni_env, methName)); - } - - for (int i = 0; i < fLen; i++) - { - jobject_ref field (jni_env, jni_env->GetObjectArrayElement (fList, i)); - jstring_ref fieldName (jni_env, reinterpret_cast (jni_env->CallObjectMethod (field, f_getName_ID))); - name_list.push_back (jstring_to_string (jni_env, fieldName)); - } - } - - string_vector v (name_list); - - return v.sort (true); -} - -static octave_value -convert_to_string (JNIEnv *jni_env, jobject java_object, bool force, char type) -{ - octave_value retval; - - if (jni_env && java_object) - { - jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String")); - - if (jni_env->IsInstanceOf (java_object, cls)) - retval = octave_value (jstring_to_string (jni_env, java_object), type); - else if (force) - { - cls = jni_env->FindClass ("[Ljava/lang/String;"); - - if (jni_env->IsInstanceOf (java_object, cls)) - { - jobjectArray array = reinterpret_cast (java_object); - int len = jni_env->GetArrayLength (array); - Cell c (len, 1); - - for (int i = 0; i < len; i++) - { - jstring_ref js (jni_env, reinterpret_cast (jni_env->GetObjectArrayElement (array, i))); - - if (js) - c(i) = octave_value (jstring_to_string (jni_env, js), type); - else - { - c(i) = check_exception (jni_env); - - if (error_state) - break; - } - } - - retval = octave_value (c); - } - else - { - cls = jni_env->FindClass ("java/lang/Object"); - jmethodID mID = jni_env->GetMethodID (cls, "toString", "()Ljava/lang/String;"); - jstring_ref js (jni_env, reinterpret_cast (jni_env->CallObjectMethod (java_object, mID))); - - if (js) - retval = octave_value (jstring_to_string (jni_env, js), type); - else - retval = check_exception (jni_env); - } - } - else - error ("unable to convert Java object to string"); - } - - return retval; -} - -#define TO_JAVA(obj) dynamic_cast ((obj).internal_rep ()) - -octave_value -box (JNIEnv* jni_env, jobject jobj, jclass jcls) -{ - octave_value retval; - jclass_ref cls (jni_env); - - if (! jobj) - retval = Matrix (); - - if (retval.is_undefined ()) - { - cls = jni_env->FindClass ("java/lang/Integer"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jmethodID m = jni_env->GetMethodID (cls, "intValue", "()I"); - retval = jni_env->CallIntMethod (jobj, m); - } - } - - if (retval.is_undefined ()) - { - cls = jni_env->FindClass ("java/lang/Double"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jmethodID m = jni_env->GetMethodID (cls, "doubleValue", "()D"); - retval = jni_env->CallDoubleMethod (jobj, m); - } - } - - if (retval.is_undefined ()) - { - cls = jni_env->FindClass ("java/lang/Boolean"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jmethodID m = jni_env->GetMethodID (cls, "booleanValue", "()Z"); - // MH retval = jni_env->CallBooleanMethod (jobj, m); - retval = (jni_env->CallBooleanMethod (jobj, m) ? true : false); - } - } - - if (retval.is_undefined ()) - { - cls = jni_env->FindClass ("java/lang/String"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - retval = jstring_to_string (jni_env, jobj); - } - } - - if (retval.is_undefined () && Vjava_convert_matrix) - { - cls = find_octave_class (jni_env, "org/octave/Matrix"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jmethodID mID = jni_env->GetMethodID (cls, "getDims", "()[I"); - jintArray_ref iv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); - jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0); - dim_vector dims; - dims.resize (jni_env->GetArrayLength (jintArray (iv))); - - for (int i = 0; i < dims.length (); i++) - dims(i) = iv_data[i]; - - jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0); - mID = jni_env->GetMethodID (cls, "getClassName", "()Ljava/lang/String;"); - jstring_ref js (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); - - std::string s = jstring_to_string (jni_env, js); - - if (s == "double") - { - NDArray m (dims); - mID = jni_env->GetMethodID (cls, "toDouble", "()[D"); - jdoubleArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); - jni_env->GetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ()); - retval = m; - } - else if (s == "byte") - { - if (Vjava_unsigned_conversion) - { - uint8NDArray m (dims); - mID = jni_env->GetMethodID (cls, "toByte", "()[B"); - jbyteArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); - jni_env->GetByteArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); - retval = m; - } - else - { - int8NDArray m (dims); - mID = jni_env->GetMethodID (cls, "toByte", "()[B"); - jbyteArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); - jni_env->GetByteArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); - retval = m; - } - } - else if (s == "integer") - { - if (Vjava_unsigned_conversion) - { - uint32NDArray m (dims); - mID = jni_env->GetMethodID (cls, "toInt", "()[I"); - jintArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); - jni_env->GetIntArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); - retval = m; - } - else - { - int32NDArray m (dims); - mID = jni_env->GetMethodID (cls, "toInt", "()[I"); - jintArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); - jni_env->GetIntArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); - retval = m; - } - } - } - } - - if (retval.is_undefined ()) - { - cls = find_octave_class (jni_env, "org/octave/OctaveReference"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jmethodID mID = jni_env->GetMethodID (cls, "getID", "()I"); - int ID = jni_env->CallIntMethod (jobj, mID); - std::map::iterator it = octave_ref_map.find (ID); - - if (it != octave_ref_map.end ()) - retval = it->second; - } - } - - if (retval.is_undefined ()) - retval = octave_value (new octave_java (jobj, jcls)); - - return retval; -} - -octave_value -box_more (JNIEnv* jni_env, jobject jobj, jclass jcls) -{ - octave_value retval = box (jni_env, jobj, jcls); - - if (retval.class_name () == "octave_java") - { - retval = octave_value (); - - jclass_ref cls (jni_env); - - if (retval.is_undefined ()) - { - cls = jni_env->FindClass ("[D"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jdoubleArray jarr = reinterpret_cast (jobj); - int len = jni_env->GetArrayLength (jarr); - - if (len > 0) - { - Matrix m (1, len); - jni_env->GetDoubleArrayRegion (jarr, 0, len, m.fortran_vec ()); - retval = m; - } - else - retval = Matrix (); - } - } - - if (retval.is_undefined ()) - { - cls = jni_env->FindClass ("[[D"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jobjectArray jarr = reinterpret_cast (jobj); - int rows = jni_env->GetArrayLength (jarr), cols = 0; - - if (rows > 0) - { - Matrix m; - - for (int r = 0; r < rows; r++) - { - jdoubleArray_ref row (jni_env, reinterpret_cast (jni_env->GetObjectArrayElement (jarr, r))); - - if (m.length () == 0) - { - cols = jni_env->GetArrayLength (row); - m.resize (cols, rows); - } - jni_env->GetDoubleArrayRegion (row, 0, cols, m.fortran_vec () + r * cols); - } - retval = m.transpose (); - } - else - retval = Matrix (); - } - } - - if (retval.is_undefined ()) - { - cls = jni_env->FindClass ("[Ljava/lang/String;"); - - if (jni_env->IsInstanceOf (jobj, cls)) - { - jobjectArray jarr = reinterpret_cast (jobj); - int len = jni_env->GetArrayLength (jarr); - Cell m (len, 1); - - for (int i = 0; i < len; i++) - { - jstring_ref js (jni_env, reinterpret_cast (jni_env->GetObjectArrayElement (jarr, i))); - m(i) = jstring_to_string (jni_env, js); - } - - retval = m; - } - } - } - - if (retval.is_undefined ()) - retval = octave_value (new octave_java (jobj, jcls)); - - return retval; -} - -int -unbox (JNIEnv* jni_env, const octave_value& val, jobject_ref& jobj, - jclass_ref& jcls) -{ - int found = 1; - - if (val.class_name () == "octave_java") - { - octave_java *ovj = TO_JAVA (val); - jobj = ovj->to_java (); - jobj.detach (); - jcls = jni_env->GetObjectClass (jobj); - } - else if (val.is_string ()) - { - std::string s = val.string_value (); - - jobj = jni_env->NewStringUTF (s.c_str ()); - jcls = jni_env->GetObjectClass (jobj); - } - else if (val.is_bool_scalar ()) - { - bool bval = val.bool_value (); - jclass_ref bcls (jni_env, jni_env->FindClass ("java/lang/Boolean")); - jfieldID fid = jni_env->GetStaticFieldID (bcls, "TYPE", "Ljava/lang/Class;"); - jmethodID mid = jni_env->GetMethodID (bcls, "", "(Z)V"); - jcls = reinterpret_cast (jni_env->GetStaticObjectField (bcls, fid)); - jobj = jni_env->NewObject (bcls, mid, bval); - } - else if (val.is_real_scalar ()) - { - double dval = val.double_value (); - jclass_ref dcls (jni_env, jni_env->FindClass ("java/lang/Double")); - jfieldID fid = jni_env->GetStaticFieldID (dcls, "TYPE", "Ljava/lang/Class;"); - jmethodID mid = jni_env->GetMethodID (dcls, "", "(D)V"); - jcls = reinterpret_cast (jni_env->GetStaticObjectField (dcls, fid)); - jobj = jni_env->NewObject (dcls, mid, dval); - } - else if (val.is_empty ()) - { - jobj = 0; - //jcls = jni_env->FindClass ("java/lang/Object"); - jcls = 0; - } - else if (!Vjava_convert_matrix - && ((val.is_real_matrix () - && (val.rows () == 1 || val.columns () == 1)) - || val.is_range ())) - { - Matrix m = val.matrix_value (); - jdoubleArray dv = jni_env->NewDoubleArray (m.length ()); - //for (int i = 0; i < m.length (); i++) - jni_env->SetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ()); - jobj = dv; - jcls = jni_env->GetObjectClass (jobj); - } - else if (Vjava_convert_matrix - && (val.is_matrix_type () || val.is_range ()) && val.is_real_type ()) - { - jclass_ref mcls (jni_env, find_octave_class (jni_env, "org/octave/Matrix")); - dim_vector dims = val.dims (); - jintArray_ref iv (jni_env, jni_env->NewIntArray (dims.length ())); - jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0); - - for (int i = 0; i < dims.length (); i++) - iv_data[i] = dims(i); - - jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0); - - if (val.is_double_type ()) - { - NDArray m = val.array_value (); - jdoubleArray_ref dv (jni_env, jni_env->NewDoubleArray (m.length ())); - jni_env->SetDoubleArrayRegion (jdoubleArray (dv), 0, m.length (), m.fortran_vec ()); - jmethodID mID = jni_env->GetMethodID (mcls, "", "([D[I)V"); - jobj = jni_env->NewObject (jclass (mcls), mID, jdoubleArray (dv), jintArray (iv)); - jcls = jni_env->GetObjectClass (jobj); - } - else if (val.is_int8_type ()) - { - int8NDArray m = val.int8_array_value (); - jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ())); - jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (), reinterpret_cast (m.fortran_vec ())); - jmethodID mID = jni_env->GetMethodID (mcls, "", "([B[I)V"); - jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv)); - jcls = jni_env->GetObjectClass (jobj); - } - else if (val.is_uint8_type ()) - { - uint8NDArray m = val.uint8_array_value (); - jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ())); - jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (), reinterpret_cast (m.fortran_vec ())); - jmethodID mID = jni_env->GetMethodID (mcls, "", "([B[I)V"); - jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv)); - jcls = jni_env->GetObjectClass (jobj); - } - else if (val.is_int32_type ()) - { - int32NDArray m = val.int32_array_value (); - jintArray_ref v (jni_env, jni_env->NewIntArray (m.length ())); - jni_env->SetIntArrayRegion (jintArray (v), 0, m.length (), reinterpret_cast (m.fortran_vec ())); - jmethodID mID = jni_env->GetMethodID (mcls, "", "([I[I)V"); - jobj = jni_env->NewObject (jclass (mcls), mID, jintArray (v), jintArray (iv)); - jcls = jni_env->GetObjectClass (jobj); - } - else - { - found = 0; - error ("cannot convert matrix of type `%s'", val.class_name ().c_str ()); - } - } - else if (val.is_cellstr ()) - { - Cell cellStr = val.cell_value (); - jclass_ref scls (jni_env, jni_env->FindClass ("java/lang/String")); - jobjectArray array = jni_env->NewObjectArray (cellStr.length (), scls, 0); - for (int i = 0; i < cellStr.length (); i++) - { - jstring_ref jstr (jni_env, jni_env->NewStringUTF (cellStr(i).string_value().c_str ())); - jni_env->SetObjectArrayElement (array, i, jstr); - } - jobj = array; - jcls = jni_env->GetObjectClass (jobj); - } - else - { - jclass rcls = find_octave_class (jni_env, "org/octave/OctaveReference"); - jmethodID mID = jni_env->GetMethodID (rcls, "", "(I)V"); - int ID = octave_java_refcount++; - - jobj = jni_env->NewObject (rcls, mID, ID); - jcls = rcls; - octave_ref_map[ID] = val; - } - - return found; -} - -int -unbox (JNIEnv* jni_env, const octave_value_list& args, - jobjectArray_ref& jobjs, jobjectArray_ref& jclss) -{ - int found = 1; - - jclass_ref ocls (jni_env, jni_env->FindClass ("java/lang/Object")); - jclass_ref ccls (jni_env, jni_env->FindClass ("java/lang/Class")); - - if (! jobjs) - jobjs = jni_env->NewObjectArray (args.length (), ocls, 0); - - if (! jclss) - jclss = jni_env->NewObjectArray (args.length (), ccls, 0); - - for (int i = 0; i < args.length (); i++) - { - jobject_ref jobj (jni_env); - jclass_ref jcls (jni_env); - - if (! unbox (jni_env, args(i), jobj, jcls)) - { - found = 0; - break; - } - - jni_env->SetObjectArrayElement (jobjs, i, jobj); - jni_env->SetObjectArrayElement (jclss, i, jcls); - } - - return found; -} - - -static long -get_current_thread_ID (JNIEnv *jni_env) -{ - if (jni_env) - { - jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/Thread")); - jmethodID mID = jni_env->GetStaticMethodID (cls, "currentThread", "()Ljava/lang/Thread;"); - jobject_ref jthread (jni_env, jni_env->CallStaticObjectMethod (cls, mID)); - - if (jthread) - { - jclass_ref jth_cls (jni_env, jni_env->GetObjectClass (jthread)); - mID = jni_env->GetMethodID (jth_cls, "getId", "()J"); - long result = jni_env->CallLongMethod (jthread, mID); - //printf ("current java thread ID = %ld\n", result); - return result; - } - } - - return -1; -} - -static int -java_event_hook (void) -{ - JNIEnv *current_env = octave_java::thread_jni_env (); - - if (current_env) - { - jclass_ref cls (current_env, find_octave_class (current_env, "org/octave/Octave")); - jmethodID mID = current_env->GetStaticMethodID (cls, "checkPendingAction", "()V"); - current_env->CallStaticVoidMethod (cls, mID); - } - - return 0; -} - -static void -initialize_java (void) -{ - if (! jvm) - { - try - { - initialize_jvm (); - - JNIEnv *current_env = octave_java::thread_jni_env (); - - octave_java::register_type (); - command_editor::add_event_hook (java_event_hook); - octave_thread_ID = get_current_thread_ID (current_env); - //printf ("octave thread ID=%ld\n", octave_thread_ID); - } - catch (std::string msg) - { - error (msg.c_str ()); - } - } -} - -DEFUN_DLD (java_init, , , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} java_init ()\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - octave_value retval; - - retval = 0; - initialize_java (); - if (! error_state) - retval = 1; - - return retval; -} - -DEFUN_DLD (java_exit, , , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} java_exit ()\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - octave_value retval; - - terminate_jvm (); - - return retval; -} - -DEFUN_DLD (java_new, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{obj} =} java_new (@var{name}, @var{arg1}, ...)\n\ -Create a Java object of class @var{name}, by calling the class constructor with the\n\ -arguments @var{arg1}, ...\n\ -\n\ -@example\n\ - x = java_new (\"java.lang.StringBuffer\", \"Initial string\")\n\ -@end example\n\ -\n\ -@seealso{java_invoke, java_get, java_set}\n\ -@end deftypefn") -{ - return _java_new (args); -} - -DEFUN_DLD (javaObject, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{obj} =} javaObject (@var{name}, @var{arg1}, ...)\n\ -Create a Java object of class @var{name}, by calling the class constructor with the\n\ -arguments @var{arg1}, ...\n\ -The first example creates an unitialized object, \ -while the second example supplies an initializer argument.\n\ -\n\ -@example\n\ - x = javaObject (\"java.lang.StringBuffer\")\n\ - x = javaObject (\"java.lang.StringBuffer\", \"Initial string\")\n\ -@end example\n\ -\n\ -@seealso{java_invoke, java_new, java_get, java_set}\n\ -@end deftypefn") -{ - return _java_new (args); -} - -// internally called from java_new and javaObject for backward compatibility -static octave_value _java_new (const octave_value_list& args) -{ - octave_value retval; - - initialize_java (); - if (! error_state) - { - JNIEnv *current_env = octave_java::thread_jni_env (); - - if (args.length () > 0) - { - std::string name = args(0).string_value (); - if (! error_state) - { - octave_value_list tmp; - for (int i=1; i 1) - { - // swap first two arguments - octave_value_list tmp; - tmp(0) = args(1); - tmp(1) = args(0); - - // copy remaining arguments - for (int i=2; i 1) - { - std::string name = args(1).string_value (); - if (! error_state) - { - octave_value_list tmp; - for (int i=2; ido_java_invoke (current_env, name, tmp); - } - else if (args(0).is_string ()) - { - std::string cls = args(0).string_value (); - retval = octave_java::do_java_invoke (current_env, cls, name, tmp); - } - else - error ("java_invoke: first argument must be a Java object or a string"); - } - else - error ("java_invoke: second argument must be a string"); - } - else - print_usage (); - } - - return retval; -} - -DEFUN_DLD (java_get, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{val} =} java_get (@var{obj}, @var{name})\n\ -Get the value of the field @var{name} of the Java object @var{obj}. For\n\ -static fields, @var{obj} can be a string representing the fully qualified\n\ -name of the corresponding class.\n\ -\n\ -When @var{obj} is a regular Java object, the structure-like indexing can be used\n\ -as a shortcut syntax. For instance, the two following statements are equivalent\n\ -\n\ -@example\n\ - java_get (x, \"field1\")\n\ - x.field1\n\ -@end example\n\ -\n\ -@seealso{java_set, java_invoke, java_new}\n\ -@end deftypefn") -{ - octave_value retval; - - initialize_java (); - - if (! error_state) - { - JNIEnv *current_env = octave_java::thread_jni_env (); - - if (args.length () == 2) - { - std::string name = args(1).string_value (); - if (! error_state) - { - if (args(0).class_name () == "octave_java") - { - octave_java *jobj = TO_JAVA (args(0)); - retval = jobj->do_java_get (current_env, name); - } - else if (args(0).is_string ()) - { - std::string cls = args(0).string_value (); - retval = octave_java::do_java_get (current_env, cls, name); - } - else - error ("java_get: first argument must be a Java object or a string"); - } - else - error ("java_get: second argument must be a string"); - } - else - print_usage (); - } - - return retval; -} - -DEFUN_DLD (java_set, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{obj} =} java_set (@var{obj}, @var{name}, @var{val})\n\ -Set the value of the field @var{name} of the Java object @var{obj} to @var{val}.\n\ -For static fields, @var{obj} can be a string representing the fully qualified named\n\ -of the corresponding Java class.\n\ -\n\ -When @var{obj} is a regular Java object, the structure-like indexing can be used as\n\ -a shortcut syntax. For instance, the two following statements are equivalent\n\ -\n\ -@example\n\ - java_set (x, \"field1\", val)\n\ - x.field1 = val\n\ -@end example\n\ -\n\ -@seealso{java_get, java_invoke, java_new}\n\ -@end deftypefn") -{ - octave_value retval; - - initialize_java (); - - if (! error_state) - { - JNIEnv *current_env = octave_java::thread_jni_env (); - - if (args.length () == 3) - { - std::string name = args(1).string_value (); - if (! error_state) - { - if (args(0).class_name () == "octave_java") - { - octave_java *jobj = TO_JAVA (args(0)); - retval = jobj->do_java_set (current_env, name, args(2)); - } - else if (args(0).is_string ()) - { - std::string cls = args(0).string_value (); - retval = octave_java::do_java_set (current_env, cls, name, args(2)); - } - else - error ("java_set: first argument must be a Java object or a string"); - } - else - error ("java_set: second argument must be a string"); - } - else - print_usage (); - } - - return retval; -} - -DEFUN_DLD (java2mat, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} java2mat (@var{obj})\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - octave_value_list retval; - - initialize_java (); - - if (! error_state) - { - JNIEnv *current_env = octave_java::thread_jni_env (); - - if (args.length () == 1) - { - if (args(0).class_name () == "octave_java") - { - octave_java *jobj = TO_JAVA (args(0)); - retval(0) = box_more (current_env, jobj->to_java (), 0); - } - else - retval(0) = args(0); - } - else - print_usage (); - } - - return retval; -} - -DEFUN_DLD (__java__, , , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __java__ ()\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - return octave_value (); -} - -DEFUN_DLD (java_convert_matrix, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} java_convert_matrix ()\n\ -Query or set the internal variable that determines FIXME.\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (java_convert_matrix); -} - -DEFUN_DLD (java_unsigned_conversion, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} java_unsigned_conversion ()\n\ -Query or set the internal variable that determines FIXME.\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (java_unsigned_conversion); -} - -DEFUN_DLD (java_debug, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} java_debug ()\n\ -Query or set the internal variable that determines FIXME.\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (java_debug); -} - -JNIEXPORT jboolean JNICALL -Java_org_octave_Octave_call (JNIEnv *env, jclass, jstring funcName, - jobjectArray argin, jobjectArray argout) -{ - std::string fname = jstring_to_string (env, funcName); - - int nargout = env->GetArrayLength (argout); - int nargin = env->GetArrayLength (argin); - - octave_value_list varargin, varargout; - - for (int i = 0; i < nargin; i++) - varargin(i) = box (env, env->GetObjectArrayElement (argin, i), 0); - - varargout = feval (fname, varargin, nargout); - - if (! error_state) - { - jobjectArray_ref out_objs (env, argout), out_clss (env); - - out_objs.detach (); - - if (unbox (env, varargout, out_objs, out_clss)) - return true; - } - - return false; -} - -JNIEXPORT void JNICALL -Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint ID) -{ - octave_ref_map.erase (ID); -} - -JNIEXPORT void JNICALL -Java_org_octave_Octave_doInvoke (JNIEnv *env, jclass, jint ID, - jobjectArray args) -{ - std::map::iterator it = octave_ref_map.find (ID); - - if (it != octave_ref_map.end ()) - { - octave_value val = it->second; - int len = env->GetArrayLength (args); - octave_value_list oct_args; - - for (int i = 0; i < len; i++) - { - jobject_ref jobj (env, env->GetObjectArrayElement (args, i)); - oct_args(i) = box (env, jobj, 0); - - if (error_state) - break; - } - - if (! error_state) - { - BEGIN_INTERRUPT_WITH_EXCEPTIONS; - - if (val.is_function_handle ()) - { - octave_function *fcn = val.function_value (); - feval (fcn, oct_args); - } - else if (val.is_cell () && val.length () > 0 - && (val.rows () == 1 || val.columns () == 1) - && val.cell_value()(0).is_function_handle ()) - { - Cell c = val.cell_value (); - octave_function *fcn = c(0).function_value (); - - for (int i=1; iGetEnv (reinterpret_cast (&env), JNI_VERSION_1_2); - - return env; -} - -octave_value_list -octave_java::subsref (const std::string& type, - const std::list& idx, int nargout) -{ - octave_value_list retval; - int skip = 1; - - JNIEnv *current_env = thread_jni_env (); - - switch (type[0]) - { - case '.': - if (type.length () > 1 && type[1] == '(') - { - octave_value_list ovl; - count++; - ovl(0) = octave_value (this); - ovl(1) = (idx.front ())(0); - std::list::const_iterator it = idx.begin (); - ovl.append (*++it); - retval = feval (std::string ("java_invoke"), ovl, 1); - skip++; - } - else - { - octave_value_list ovl; - count++; - ovl(0) = octave_value (this); - ovl(1) = (idx.front ())(0); - retval = feval (std::string ("java_get"), ovl, 1); - } - break; - - case '(': - if (current_env) - retval = get_array_elements (current_env, to_java (), idx.front ()); - break; - - default: - error ("subsref: Java object cannot be indexed with %c", type[0]); - break; - } - - if (idx.size () > 1 && type.length () > 1) - retval = retval(0).next_subsref (nargout, type, idx, skip); - - return retval; -} - -octave_value -octave_java::subsasgn (const std::string& type, - const std::list&idx, - const octave_value &rhs) -{ - octave_value retval; - - JNIEnv *current_env = thread_jni_env (); - - switch (type[0]) - { - case '.': - if (type.length () == 1) - { - // field assignment - octave_value_list ovl; - count++; - ovl(0) = octave_value (this); - ovl(1) = (idx.front ())(0); - ovl(2) = rhs; - feval ("java_set", ovl, 0); - if (! error_state) - { - count++; - retval = octave_value (this); - } - } - else if (type.length () > 2 && type[1] == '(') - { - std::list new_idx; - std::list::const_iterator it = idx.begin (); - new_idx.push_back (*it++); - new_idx.push_back (*it++); - octave_value_list u = subsref (type.substr (0, 2), new_idx, 1); - if (! error_state) - { - std::list next_idx (idx); - next_idx.erase (next_idx.begin ()); - next_idx.erase (next_idx.begin ()); - u(0).subsasgn (type.substr (2), next_idx, rhs); - if (! error_state) - { - count++; - retval = octave_value (this); - } - } - } - else if (type[1] == '.') - { - octave_value_list u = subsref (type.substr (0, 1), idx, 1); - if (! error_state) - { - std::list next_idx (idx); - next_idx.erase (next_idx.begin ()); - u(0).subsasgn (type.substr (1), next_idx, rhs); - if (! error_state) - { - count++; - retval = octave_value (this); - } - } - } - else - error ("invalid indexing/assignment on Java object"); - break; - - case '(': - if (current_env) - { - set_array_elements (current_env, to_java (), idx.front (), rhs); - if (! error_state) - { - count++; - retval = octave_value (this); - } - } - break; - - default: - error ("Java object cannot be indexed with %c", type[0]); - break; - } - - return retval; -} - -string_vector -octave_java::map_keys (void) const -{ - JNIEnv *current_env = thread_jni_env (); - - if (current_env) - return get_invoke_list (current_env, to_java ()); - else - return string_vector (); -} - -octave_value -octave_java::convert_to_str_internal (bool, bool force, char type) const -{ - JNIEnv *current_env = thread_jni_env (); - - if (current_env) - return convert_to_string (current_env, to_java (), force, type); - else - return octave_value (""); -} - -octave_value -octave_java::do_java_invoke (JNIEnv* jni_env, const std::string& name, - const octave_value_list& args) -{ - octave_value retval; - - if (jni_env) - { - jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); - if (unbox (jni_env, args, arg_objs, arg_types)) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeMethod", - "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); - jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ())); - jobjectArray_ref resObj (jni_env, reinterpret_cast (jni_env->CallStaticObjectMethod (helperClass, mID, - to_java (), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types)))); - if (resObj) - retval = box (jni_env, resObj); - else - retval = check_exception (jni_env); - } - } - - return retval; -} - -octave_value -octave_java:: do_java_invoke (JNIEnv* jni_env, - const std::string& class_name, - const std::string& name, - const octave_value_list& args) -{ - octave_value retval; - - if (jni_env) - { - jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); - if (unbox (jni_env, args, arg_objs, arg_types)) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeStaticMethod", - "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); - jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ())); - jstring_ref clsName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); - jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, - jstring (clsName), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types))); - if (resObj) - retval = box (jni_env, resObj); - else - retval = check_exception (jni_env); - } - } - - return retval; -} - -octave_value -octave_java::do_java_create (JNIEnv* jni_env, const std::string& name, - const octave_value_list& args) -{ - octave_value retval; - - if (jni_env) - { - jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); - - if (unbox (jni_env, args, arg_objs, arg_types)) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeConstructor", - "(Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); - jstring_ref clsName (jni_env, jni_env->NewStringUTF (name.c_str ())); - jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, - jstring (clsName), jobjectArray (arg_objs), jobjectArray (arg_types))); - - if (resObj) - retval = box (jni_env, resObj); - else - check_exception (jni_env); - } - } - - return retval; -} - -octave_value -octave_java::do_java_get (JNIEnv* jni_env, const std::string& name) -{ - octave_value retval; - - if (jni_env) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getField", - "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;"); - jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); - jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, - to_java (), jstring (fName))); - - if (resObj) - retval = box (jni_env, resObj); - else - retval = check_exception (jni_env); - } - - return retval; -} - -octave_value -octave_java::do_java_get (JNIEnv* jni_env, const std::string& class_name, - const std::string& name) -{ - octave_value retval; - - if (jni_env) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getStaticField", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); - jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); - jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); - jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, - jstring (cName), jstring (fName))); - if (resObj) - retval = box (jni_env, resObj); - else - retval = check_exception (jni_env); - } - - return retval; -} - -octave_value -octave_java::do_java_set (JNIEnv* jni_env, const std::string& name, - const octave_value& val) -{ - octave_value retval; - - if (jni_env) - { - jobject_ref jobj (jni_env); - jclass_ref jcls (jni_env); - - if (unbox (jni_env, val, jobj, jcls)) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setField", - "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V"); - jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); - jni_env->CallStaticObjectMethod (helperClass, mID, to_java (), jstring (fName), jobject (jobj)); - check_exception (jni_env); - } - } - - return retval; -} - -octave_value -octave_java::do_java_set (JNIEnv* jni_env, const std::string& class_name, - const std::string& name, const octave_value& val) -{ - octave_value retval; - - if (jni_env) - { - jobject_ref jobj (jni_env); - jclass_ref jcls (jni_env); - - if (unbox (jni_env, val, jobj, jcls)) - { - jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); - jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setStaticField", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"); - jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); - jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); - jni_env->CallStaticObjectMethod (helperClass, mID, jstring (cName), jstring (fName), jobject (jobj)); - check_exception (jni_env); - } - } - - return retval; -} - -#endif - diff -r 72968fb32c82 -r f96faf028d90 libinterp/dldfcn/__java__.h --- a/libinterp/dldfcn/__java__.h Fri Dec 07 19:34:19 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,324 +0,0 @@ -/* - -Copyright (C) 2007 Michael Goffioul - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave___java__h) -#define octave___java__h 1 - -#include - -#include -#include - -#ifdef JAVAPKG_BUILD -# define JAVAPKG_API OCTAVE_EXPORT -#else -# define JAVAPKG_API OCTAVE_IMPORT -#endif - -template -class java_local_ref -{ -public: - - java_local_ref (JNIEnv *_env) - : jobj (0), detached (false), env (_env) { } - - java_local_ref (JNIEnv *_env, T obj) - : jobj (obj), detached (false), env (_env) { } - - ~java_local_ref (void) { release (); } - - T& operator= (T obj) - { - release (); - jobj = obj; - detached = false; - return jobj; - } - - operator bool () const { return (jobj != 0); } - operator T () { return jobj; } - - void detach (void) { detached = true; } - -private: - - void release (void) - { - if (env && jobj && ! detached) - env->DeleteLocalRef (jobj); - - jobj = 0; - } - - java_local_ref (void) - : jobj (0), detached (false), env (0) - { } - -protected: - T jobj; - bool detached; - JNIEnv *env; -}; - -typedef java_local_ref jobject_ref; -typedef java_local_ref jclass_ref; -typedef java_local_ref jstring_ref; -typedef java_local_ref jobjectArray_ref; -typedef java_local_ref jintArray_ref; -typedef java_local_ref jbyteArray_ref; -typedef java_local_ref jdoubleArray_ref; -typedef java_local_ref jthrowable_ref; - -extern JAVAPKG_API std::string -jstring_to_string (JNIEnv* jni_env, jstring s); - -extern JAVAPKG_API std::string -jstring_to_string (JNIEnv* jni_env, jobject obj); - -extern JAVAPKG_API octave_value -box (JNIEnv* jni_env, jobject jobj, jclass jcls = 0); - -extern JAVAPKG_API octave_value -box_more (JNIEnv* jni_env, jobject jobj, jclass jcls = 0); - -extern JAVAPKG_API int -unbox (JNIEnv* jni_env, const octave_value& val, jobject_ref& jobj, - jclass_ref& jcls); - -extern JAVAPKG_API int -unbox (JNIEnv* jni_env, const octave_value_list& args, - jobjectArray_ref& jobjs, jobjectArray_ref& jclss); - -extern JAVAPKG_API bool Vjava_convert_matrix; - -extern JAVAPKG_API bool Vjava_unsigned_conversion; - -extern JAVAPKG_API bool Vjava_debug; - -class JAVAPKG_API octave_java : public octave_base_value -{ -public: - - octave_java (void) - : octave_base_value (), java_object (0), java_class (0) - { } - - octave_java (const octave_java& jobj) - : octave_base_value (jobj), java_object (0), java_class (0) - { - init (jobj.java_object, jobj.java_class); - } - - octave_java (const jobject& obj, jclass cls = 0) - : octave_base_value (), java_object (0) - { - init (obj, cls); - } - - ~octave_java (void) { release (); } - - jobject to_java (void) const { return java_object; } - jclass to_class (void) const { return java_class; } - - std::string java_class_name (void) const { return java_type; } - - octave_base_value* clone (void) const { return new octave_java (*this); } - octave_base_value* empty_clone (void) const { return new octave_java (); } - - bool is_defined (void) const { return true; } - - bool is_map (void) const { return true; } - - string_vector map_keys (void) const; - - dim_vector dims (void) const; - - void print (std::ostream& os, bool pr_as_read_syntax = false) const - { - os << ""; - newline(os); - } - - void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const - { - print(os, pr_as_read_syntax); - } - - octave_value_list - subsref (const std::string& type, - const std::list& idx, int nargout); - - octave_value - subsref (const std::string& type, const std::list& idx) - { - octave_value_list retval = subsref (type, idx, 1); - return (retval.length () > 0 ? retval(0) : octave_value ()); - } - - octave_value subsasgn (const std::string& type, - const std::list& idx, - const octave_value& rhs); - - octave_value convert_to_str_internal (bool pad, bool force, char type) const; - - bool is_string (void) const - { - JNIEnv *current_env = thread_jni_env (); - - if (current_env && java_object) - { - jclass_ref cls (current_env, current_env->FindClass ("java/lang/String")); - return current_env->IsInstanceOf (java_object, cls); - } - - return false; - } - - static JNIEnv* thread_jni_env (void); - - octave_value do_java_invoke (JNIEnv* jni_env, const std::string& name, - const octave_value_list& args); - - octave_value - do_java_invoke (const std::string& name, const octave_value_list& args) - { - return do_java_invoke(thread_jni_env (), name, args); - } - - static octave_value - do_java_invoke (JNIEnv* jni_env, const std::string& class_name, - const std::string& name, const octave_value_list& args); - - static octave_value - do_java_invoke (const std::string& class_name, const std::string& name, - const octave_value_list& args) - { - return do_java_invoke(thread_jni_env (), class_name, name, args); - } - - static octave_value - do_java_create (JNIEnv* jni_env, const std::string& name, - const octave_value_list& args); - - static octave_value - do_java_create (const std::string& name, const octave_value_list& args) - { - return do_java_create (thread_jni_env (), name, args); - } - - octave_value do_java_get (JNIEnv* jni_env, const std::string& name); - - octave_value do_java_get (const std::string& name) - { - return do_java_get (thread_jni_env (), name); - } - - static octave_value - do_java_get (JNIEnv* jni_env, const std::string& class_name, - const std::string& name); - - static octave_value - do_java_get (const std::string& class_name, const std::string& name) - { - return do_java_get (thread_jni_env (), class_name, name); - } - - octave_value do_java_set (JNIEnv* jni_env, const std::string& name, - const octave_value& val); - - octave_value do_java_set (const std::string& name, const octave_value& val) - { - return do_java_set (thread_jni_env (), name, val); - } - - static octave_value - do_java_set (JNIEnv* jni_env, const std::string& class_name, - const std::string& name, const octave_value& val); - - static octave_value - do_java_set (const std::string& class_name, const std::string& name, - const octave_value& val) - { - return do_java_set (thread_jni_env (), class_name, name, val); - } - -private: - - void init (jobject jobj, jclass jcls) - { - JNIEnv *current_env = thread_jni_env (); - - if (current_env) - { - if (jobj) - java_object = current_env->NewGlobalRef (jobj); - - if (jcls) - java_class = reinterpret_cast (current_env->NewGlobalRef (jcls)); - else if (java_object) - { - jclass_ref ocls (current_env, current_env->GetObjectClass (java_object)); - java_class = reinterpret_cast (current_env->NewGlobalRef (jclass (ocls))); - } - - if (java_class) - { - jclass_ref clsCls (current_env, current_env->GetObjectClass (java_class)); - jmethodID mID = current_env->GetMethodID (clsCls, "getCanonicalName", "()Ljava/lang/String;"); - jobject_ref resObj (current_env, current_env->CallObjectMethod (java_class, mID)); - java_type = jstring_to_string (current_env, resObj); - } - } - } - - void release (void) - { - JNIEnv *current_env = thread_jni_env (); - - if (current_env) - { - if (java_object) - current_env->DeleteGlobalRef (java_object); - - if (java_class) - current_env->DeleteGlobalRef (java_class); - - java_object = 0; - java_class = 0; - } - } - -private: - - DECLARE_OCTAVE_ALLOCATOR - - DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA - - jobject java_object; - - jclass java_class; - - std::string java_type; -}; - -#endif /* __JAVA__H__ */ diff -r 72968fb32c82 -r f96faf028d90 libinterp/dldfcn/config-module.awk --- a/libinterp/dldfcn/config-module.awk Fri Dec 07 19:34:19 2012 -0500 +++ b/libinterp/dldfcn/config-module.awk Sat Dec 08 00:23:13 2012 -0500 @@ -10,10 +10,6 @@ print " dldfcn/module-files \\" print " dldfcn/oct-qhull.h" print "" -## Kluge... - print "DLDFCN_INC = \\" - print " dldfcn/__java__.h" - print "" } /^#.*/ { next; } { diff -r 72968fb32c82 -r f96faf028d90 libinterp/dldfcn/module-files --- a/libinterp/dldfcn/module-files Fri Dec 07 19:34:19 2012 -0500 +++ b/libinterp/dldfcn/module-files Sat Dec 08 00:23:13 2012 -0500 @@ -5,7 +5,6 @@ __glpk__.cc|$(GLPK_CPPFLAGS)|$(GLPK_LDFLAGS)|$(GLPK_LIBS) __init_fltk__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) __init_gnuplot__.cc -__java__.cc|$(JAVA_CPPFLAGS)||$(JAVA_LIBS) __magick_read__.cc|$(MAGICK_CPPFLAGS)|$(MAGICK_LDFLAGS)|$(MAGICK_LIBS) __voronoi__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) amd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) diff -r 72968fb32c82 -r f96faf028d90 libinterp/octave-value/module.mk --- a/libinterp/octave-value/module.mk Fri Dec 07 19:34:19 2012 -0500 +++ b/libinterp/octave-value/module.mk Sat Dec 08 00:23:13 2012 -0500 @@ -51,6 +51,7 @@ octave-value/ov-flt-cx-mat.h \ octave-value/ov-flt-re-diag.h \ octave-value/ov-flt-re-mat.h \ + octave-value/ov-java.h \ octave-value/ov-lazy-idx.h \ octave-value/ov-mex-fcn.h \ octave-value/ov-null-mat.h \ @@ -108,6 +109,7 @@ octave-value/ov-flt-cx-mat.cc \ octave-value/ov-flt-re-diag.cc \ octave-value/ov-flt-re-mat.cc \ + octave-value/ov-java.cc \ octave-value/ov-lazy-idx.cc \ octave-value/ov-mex-fcn.cc \ octave-value/ov-null-mat.cc \ @@ -128,4 +130,14 @@ noinst_LTLIBRARIES += octave-value/liboctave-value.la octave_value_liboctave_value_la_SOURCES = $(OCTAVE_VALUE_SRC) -octave_value_liboctave_value_la_CPPFLAGS = $(liboctinterp_la_CPPFLAGS) + +## FIXME -- maybe it would be better to limit the JAVA flags to +## the compile commands for ov-java.cc? Does JAVA_LIBS need to be +## added to LIBOCTINTERP_LINK_DEPS (see libinterp/link-deps.mk)? +## Should we have a separate set of JAVA_LDFLAGS? + +octave_value_liboctave_value_la_CPPFLAGS = \ + $(liboctinterp_la_CPPFLAGS) \ + $(JAVA_CPPFLAGS) + +octave_value_liboctave_value_la_LIBADD = $(JAVA_LIBS) diff -r 72968fb32c82 -r f96faf028d90 libinterp/octave-value/ov-java.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-java.cc Sat Dec 08 00:23:13 2012 -0500 @@ -0,0 +1,2206 @@ +/* + +Copyright (C) 2007 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined HAVE_JAVA + +#if defined (HAVE_WINDWOS_H) +#include +#endif + +#include +#include +#include +#include + +#include + +#include "Cell.h" +#include "cmd-edit.h" +#include "defaults.h" +#include "defun.h" +#include "file-ops.h" +#include "file-stat.h" +#include "load-path.h" +#include "oct-env.h" +#include "oct-shlib.h" +#include "ov-java.h" +#include "parse.h" +#include "variables.h" + +typedef jint (JNICALL *JNI_CreateJavaVM_t) (JavaVM **pvm, JNIEnv **penv, void *args); +typedef jint (JNICALL *JNI_GetCreatedJavaVMs_t) (JavaVM **pvm, jsize bufLen, jsize *nVMs); + +extern "C" +{ + JNIEXPORT jboolean JNICALL + Java_org_octave_Octave_call (JNIEnv *, jclass, jstring, jobjectArray, + jobjectArray); + JNIEXPORT void JNICALL + Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint); + + JNIEXPORT void JNICALL + Java_org_octave_Octave_doInvoke (JNIEnv *, jclass, jint, jobjectArray); + + JNIEXPORT void JNICALL + Java_org_octave_Octave_doEvalString (JNIEnv *, jclass, jstring); + + JNIEXPORT jboolean JNICALL + Java_org_octave_Octave_needThreadedInvokation (JNIEnv *, jclass); +} + +static octave_value _java_new (const octave_value_list& args); +static octave_value _java_invoke (const octave_value_list& args); + +static JavaVM *jvm = 0; +static bool jvm_attached = false; + +// Need to keep hold of the shared library handle until exit. +static octave_shlib jvm_lib; + +static std::map listener_map; +static std::map octave_ref_map; +static int octave_java_refcount = 0; +static long octave_thread_ID = -1; + +bool Vjava_convert_matrix = false; +bool Vjava_unsigned_conversion = true; +bool Vjava_debug = false; + +class JVMArgs +{ +public: + + JVMArgs (void) + { + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 0; + vm_args.options = 0; + vm_args.ignoreUnrecognized = false; + } + + ~JVMArgs (void) + { + clean (); + } + + JavaVMInitArgs* to_args () + { + update (); + return &vm_args; + } + + void add (const std::string& opt) + { + java_opts.push_back (opt); + } + + void read_java_opts (const std::string& filename) + { + std::ifstream js (filename.c_str ()); + + if (! js.bad () && ! js.fail ()) + { + std::string line; + + while (! js.eof () && ! js.fail ()) + { + std::getline (js, line); + if (line.length () > 2 + && (line.find ("-D") == 0 || line.find ("-X") == 0)) + java_opts.push_back (line); + else if (line.length () > 0 && Vjava_debug) + std::cerr << "invalid JVM option, skipping: " << line << std::endl; + } + } + } + +private: + + void clean (void) + { + if (vm_args.options != 0) + { + for (int i = 0; i < vm_args.nOptions; i++) + delete [] vm_args.options[i].optionString; + delete [] vm_args.options; + + vm_args.options = 0; + vm_args.nOptions = 0; + } + } + + void update (void) + { + clean (); + + if (java_opts.size () > 0) + { + int index = 0; + + vm_args.nOptions = java_opts.size (); + vm_args.options = new JavaVMOption [vm_args.nOptions]; + for (std::list::const_iterator it = java_opts.begin (); it != java_opts.end (); ++it) + { + if (Vjava_debug) + std::cout << *it << std::endl; + vm_args.options[index++].optionString = strsave ((*it).c_str ()); + } + java_opts.clear (); + } + } + +private: + + JavaVMInitArgs vm_args; + + std::list java_opts; +}; + +static dim_vector compute_array_dimensions (JNIEnv* jni_env, jobject obj); + +#ifdef __WIN32__ +static std::string +read_registry_string (const std::string& key, const std::string& value) +{ + HKEY hkey; + DWORD len; + + std::string retval; + + if (! RegOpenKeyEx (HKEY_LOCAL_MACHINE, key.c_str (), 0, KEY_READ, &hkey)) + { + if (! RegQueryValueEx (hkey, value.c_str (), 0, 0, 0, &len)) + { + retval.resize (len); + if (RegQueryValueEx (hkey, value.c_str (), 0, 0, (LPBYTE)&retval[0], &len)) + retval = ""; + else if (retval[len-1] == '\0') + retval.resize (--len); + } + RegCloseKey (hkey); + } + + return retval; +} + +static std::string +get_module_filename (HMODULE hMod) +{ + int n = 1024; + std::string retval (n, '\0'); + bool found = false; + + while (n < 65536) + { + int status = GetModuleFileName(hMod, &retval[0], n); + + if (status < n) + { + retval.resize(n); + found = true; + break; + } + else + { + n *= 2; + retval.resize(n); + } + } + return (found ? retval : ""); +} + +static void +set_dll_directory (const std::string& dir = "") +{ + typedef BOOL (WINAPI *dllfcn_t) (LPCTSTR path); + + static dllfcn_t dllfcn = NULL; + static bool first = true; + + if (! dllfcn && first) + { + HINSTANCE hKernel32 = GetModuleHandle ("kernel32"); + dllfcn = reinterpret_cast (GetProcAddress (hKernel32, "SetDllDirectoryA")); + first = false; + } + + if (dllfcn) + dllfcn (dir.empty () ? NULL : dir.c_str ()); +} +#endif + +static std::string +initial_java_dir (void) +{ + static std::string java_dir; + + if (java_dir.empty ()) + { + java_dir = octave_env::getenv ("OCTAVE_JAVA_DIR"); + + if (java_dir.empty ()) + java_dir = Vfcn_file_dir + file_ops::dir_sep_str () + "java"; + } + + return java_dir; +} + +// Read the content of a file filename (usually "classpath.txt") +// +// Returns a string with all lines concatenated and separated +// by the path separator character. +// The return string also starts with a path separator so that +// it can be appended easily to a base classpath. +// +// The file "classpath.txt" must contain single lines, each +// with a classpath. +// Comment lines starting with a '#' or a '%' in column 1 are allowed. + +static std::string +read_classpath_txt (const std::string& filepath) +{ + std::string classpath; + + std::ifstream fs (filepath.c_str ()); + + if (! fs.bad () && ! fs.fail ()) + { + std::string line; + + while (! fs.eof () && ! fs.fail ()) + { + std::getline (fs, line); + + if (line.length () > 1) + { + if (line.at(0) == '#' || line.at(0) == '%') + ; // skip comments + else + { + // prepend separator character + classpath.append (dir_path::path_sep_str ()); + + // append content of line without trailing blanks + int iLast = line.find_last_not_of (' '); + + classpath.append (file_ops::tilde_expand (line.substr (0, iLast+1))); + } + } + } + } + + return (classpath); +} + + +static std::string +initial_class_path (void) +{ + std::string java_dir = initial_java_dir (); + + std::string retval = java_dir; + + // find octave.jar file + if (! retval.empty ()) + { + std::string sep = file_ops::dir_sep_str (); + + std::string jar_file = java_dir + sep + "octave.jar"; + + file_stat jar_exists (jar_file); + + if (jar_exists) + { + // initialize static classpath to octave.jar + retval = jar_file; + + // The base classpath has been set. Try to find the optional + // file "classpath.txt" in two places. The users classes will + // take precedence over the settings defined in the package + // directory + + std::string str_filename = "classpath.txt"; + std::string cp_file; + file_stat cp_exists; + + // Try to read the file "classpath.txt" in the user's home + // directory. + + std::string home_dir = "~" + sep + str_filename; + cp_file = file_ops::tilde_expand (home_dir); + cp_exists = file_stat (cp_file); + if (cp_exists) + { + // The file "classpath.txt" has been found: add its + // contents to the static classpath. + + std::string theClassPath = read_classpath_txt (cp_file); + retval.append (theClassPath); + } + + // Try to read a file "classpath.txt" in the package directory. + + cp_file = java_dir + sep + str_filename; + cp_exists = file_stat (cp_file); + if (cp_exists) + { + // The file "classpath.txt" has been found: add its + // contents to the static classpath. + + std::string theClassPath = read_classpath_txt (cp_file); + retval.append (theClassPath); + } + } + else + throw std::string ("octave jar does not exist: ") + jar_file; + } + else + throw std::string ("initial java dir is empty"); + + return retval; +} + +static void +initialize_jvm (void) +{ + JNIEnv *current_env; + + if (jvm) + return; + + const char *static_locale = setlocale (LC_ALL, NULL); + const std::string locale (static_locale); + +#if defined (__WIN32__) + + HMODULE hMod = GetModuleHandle ("jvm.dll"); + std::string jvm_lib_path; + std::string old_cwd; + + if (hMod == NULL) + { + // In windows, find the location of the JRE from the registry + // and load the symbol from the dll. + std::string key, value; + + key = "software\\javasoft\\java runtime environment"; + + value = octave_env::getenv ("JAVA_VERSION"); + if (value.empty ()) + { + value = "Currentversion"; + std::string regval = read_registry_string (key,value); + + if (regval.empty ()) + throw std::string ("unable to find Java Runtime Environment: ") + key + "::" + value; + value = regval; + } + + key = key + "\\" + value; + value = "RuntimeLib"; + jvm_lib_path = read_registry_string (key, value); + if (jvm_lib_path.empty ()) + throw std::string ("unable to find Java Runtime Environment: ") + key + "::" + value; + + std::string jvm_bin_path; + + value = "JavaHome"; + jvm_bin_path = read_registry_string (key, value); + if (! jvm_bin_path.empty ()) + { + jvm_bin_path = (jvm_bin_path + std::string ("\\bin")); + + old_cwd = octave_env::get_current_directory (); + + set_dll_directory (jvm_bin_path); + octave_env::chdir (jvm_bin_path); + } + } + else + { + // JVM seems to be already loaded, better to use that DLL instead + // of looking in the registry, to avoid opening a different JVM. + jvm_lib_path = get_module_filename (hMod); + + if (jvm_lib_path.empty ()) + throw std::string ("unable to find Java Runtime Environment"); + } + +#else + + std::string jvm_lib_path = JAVA_HOME + std::string ("/jre/lib/") + JAVA_ARCH + "/server/libjvm.so"; + +#endif + + jsize nVMs = 0; + +# if !defined (__APPLE__) && !defined (__MACH__) + + octave_shlib lib (jvm_lib_path); + + if (!lib) + throw std::string ("unable to load Java Runtime Environment from ") + jvm_lib_path; + +#if defined (__WIN32__) + + set_dll_directory (); + + if (! old_cwd.empty ()) + octave_env::chdir (old_cwd); + +#endif + + JNI_CreateJavaVM_t create_vm = reinterpret_cast (lib.search ("JNI_CreateJavaVM")); + JNI_GetCreatedJavaVMs_t get_vm = reinterpret_cast (lib.search ("JNI_GetCreatedJavaVMs")); + + if (!create_vm) + throw std::string ("unable to find JNI_CreateJavaVM in ") + jvm_lib_path; + + if (!get_vm) + throw std::string ("unable to find JNI_GetCreatedJavaVMs in ") + jvm_lib_path; + + if (get_vm (&jvm, 1, &nVMs) == 0 && nVMs > 0) + +#else + + // FIXME: There exists a problem on the Mac platform that + // octave_shlib lib (jvm_lib_path) + // doesn't work with 'not-bundled' *.oct files. + + if (JNI_GetCreatedJavaVMs (&jvm, 1, &nVMs) == 0 && nVMs > 0) + +#endif + + { + // At least one JVM exists, try to attach to it + + switch (jvm->GetEnv (reinterpret_cast (¤t_env), JNI_VERSION_1_2)) + { + case JNI_EDETACHED: + // Attach the current thread + JavaVMAttachArgs vm_args; + vm_args.version = JNI_VERSION_1_2; + vm_args.name = const_cast ("octave"); + vm_args.group = NULL; + if (jvm->AttachCurrentThread (reinterpret_cast (¤t_env), &vm_args) < 0) + throw std::string ("JVM internal error, unable to attach octave to existing JVM"); + break; + + case JNI_EVERSION: + throw std::string ("JVM internal error, the required JNI version is not supported"); + break; + + case JNI_OK: + // Don't do anything, the current thread is already attached to JVM + break; + } + + jvm_attached = true; + //printf ("JVM attached\n"); + } + else + { + // No JVM exists, create one + + JVMArgs vm_args; + + vm_args.add ("-Djava.class.path=" + initial_class_path ()); + vm_args.add ("-Xrs"); + vm_args.add ("-Djava.system.class.loader=org.octave.OctClassLoader"); + vm_args.read_java_opts (initial_java_dir () + file_ops::dir_sep_str () + "java.opts"); + +# if !defined (__APPLE__) && !defined (__MACH__) + + if (create_vm (&jvm, ¤t_env, vm_args.to_args ()) != JNI_OK) + throw std::string ("unable to start Java VM in ")+jvm_lib_path; + //printf ("JVM created\n"); + } + + jvm_lib = lib; + +#else + + if (JNI_CreateJavaVM (&jvm, reinterpret_cast (¤t_env), + vm_args.to_args ()) != JNI_OK) + throw std::string ("unable to start Java VM in ")+jvm_lib_path; + + } + +#endif + + setlocale (LC_ALL, locale.c_str ()); +} + +static void +terminate_jvm (void) +{ + if (jvm) + { + if (jvm_attached) + jvm->DetachCurrentThread (); + else + jvm->DestroyJavaVM (); + + jvm = 0; + jvm_attached = false; + + if (jvm_lib) + jvm_lib.close (); + } +} + +std::string +jstring_to_string (JNIEnv* jni_env, jstring s) +{ + std::string retval; + + if (jni_env) + { + const char *cstr = jni_env->GetStringUTFChars (s, 0); + retval = cstr; + jni_env->ReleaseStringUTFChars (s, cstr); + } + + return retval; +} + +std::string +jstring_to_string (JNIEnv* jni_env, jobject obj) +{ + std::string retval; + + if (jni_env && obj) + { + jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String")); + if (cls) + { + if (jni_env->IsInstanceOf (obj, cls)) + retval = jstring_to_string (jni_env, reinterpret_cast (obj)); + } + } + + return retval; +} + +static octave_value +check_exception (JNIEnv* jni_env) +{ + octave_value retval; + + jthrowable_ref ex (jni_env, jni_env->ExceptionOccurred ()); + + if (ex) + { + if (Vjava_debug) + jni_env->ExceptionDescribe (); + + jni_env->ExceptionClear (); + + jclass_ref jcls (jni_env, jni_env->GetObjectClass (ex)); + jmethodID mID = jni_env->GetMethodID (jcls, "toString", "()Ljava/lang/String;"); + jstring_ref js (jni_env, reinterpret_cast (jni_env->CallObjectMethod (ex, mID))); + std::string msg = jstring_to_string (jni_env, js); + + error ("[java] %s", msg.c_str ()); + } + else + retval = Matrix (); + + return retval; +} + +static jclass +find_octave_class (JNIEnv *jni_env, const char *name) +{ + static std::string class_loader; + static jclass uiClass = 0; + + jclass jcls = jni_env->FindClass (name); + + if (jcls == 0) + { + jni_env->ExceptionClear (); + + if (! uiClass) + { + if (class_loader.empty ()) + { + jclass_ref syscls (jni_env, jni_env->FindClass ("java/lang/System")); + jmethodID mID = jni_env->GetStaticMethodID (syscls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); + jstring_ref js (jni_env, jni_env->NewStringUTF ("octave.class.loader")); + js = reinterpret_cast (jni_env->CallStaticObjectMethod (syscls, mID, jstring (js))); + class_loader = jstring_to_string (jni_env, jstring (js)); + std::replace (class_loader.begin (), class_loader.end (), '.', '/'); + } + + jclass_ref uicls (jni_env, jni_env->FindClass (class_loader.c_str ())); + + if (! uicls) + { + jni_env->ExceptionClear (); + + /* Try the netbeans way */ + std::replace (class_loader.begin (), class_loader.end (), '/', '.'); + jclass_ref jcls2 (jni_env, jni_env->FindClass ("org/openide/util/Lookup")); + jmethodID mID = jni_env->GetStaticMethodID (jcls2, "getDefault", "()Lorg/openide/util/Lookup;"); + jobject_ref lObj (jni_env, jni_env->CallStaticObjectMethod (jcls2, mID)); + mID = jni_env->GetMethodID (jcls2, "lookup", "(Ljava/lang/Class;)Ljava/lang/Object;"); + jclass_ref cLoaderCls (jni_env, jni_env->FindClass ("java/lang/ClassLoader")); + jobject_ref cLoader (jni_env, jni_env->CallObjectMethod (lObj, mID, jclass (cLoaderCls))); + mID = jni_env->GetMethodID (cLoaderCls, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + jstring_ref js (jni_env, jni_env->NewStringUTF (class_loader.c_str ())); + uicls = reinterpret_cast (jni_env->CallObjectMethod (cLoader, mID, jstring (js))); + } + + if (uicls) + uiClass = reinterpret_cast (jni_env->NewGlobalRef (jclass (uicls))); + } + + if (uiClass) + { + jmethodID mID = jni_env->GetStaticMethodID (uiClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + jstring_ref js (jni_env, jni_env->NewStringUTF (name)); + jcls = reinterpret_cast (jni_env->CallStaticObjectMethod (uiClass, mID, jstring (js))); + } + } + + return jcls; +} + +static dim_vector +compute_array_dimensions (JNIEnv* jni_env, jobject obj) +{ + jobjectArray_ref jobj (jni_env, reinterpret_cast (obj)); + jclass_ref jcls (jni_env, jni_env->GetObjectClass (obj)); + jclass_ref ccls (jni_env, jni_env->GetObjectClass (jcls)); + jmethodID isArray_ID = jni_env->GetMethodID (ccls, "isArray", "()Z"), + getComponentType_ID = jni_env->GetMethodID (ccls, "getComponentType", "()Ljava/lang/Class;"); + + dim_vector dv (1, 1); + int idx = 0; + + jobj.detach (); + while (jcls && jni_env->CallBooleanMethod (jcls, isArray_ID)) + { + int len = (jobj ? jni_env->GetArrayLength (jobj) : 0); + if (idx >= dv.length ()) + dv.resize (idx+1); + dv(idx) = len; + jcls = reinterpret_cast (jni_env->CallObjectMethod (jcls, getComponentType_ID)); + jobj = (len > 0 ? reinterpret_cast (jni_env->GetObjectArrayElement (jobj, 0)) : 0); + idx++; + } + + return dv; +} + +static jobject +make_java_index (JNIEnv* jni_env, const octave_value_list& idx) +{ + jclass_ref ocls (jni_env, jni_env->FindClass ("[I")); + jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, 0); + + for (int i = 0; i < idx.length (); i++) + { + idx_vector v = idx(i).index_vector (); + + if (! error_state) + { + jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ())); + jint *buf = jni_env->GetIntArrayElements (i_array, 0); + + for (int k = 0; k < v.length (); k++) + buf[k] = v(k); + + jni_env->ReleaseIntArrayElements (i_array, buf, 0); + jni_env->SetObjectArrayElement (retval, i, i_array); + + check_exception (jni_env); + + if (error_state) + break; + } + else + break; + } + + return retval; +} + +static octave_value +get_array_elements (JNIEnv* jni_env, jobject jobj, + const octave_value_list& idx) +{ + octave_value retval; + jobject_ref resObj (jni_env); + jobject_ref java_idx (jni_env, make_java_index (jni_env, idx)); + + if (! error_state) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsref", "(Ljava/lang/Object;[[I)Ljava/lang/Object;"); + resObj = jni_env->CallStaticObjectMethod (helperClass, mID, jobj, jobject (java_idx)); + } + + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + + return retval; +} + +static octave_value +set_array_elements (JNIEnv* jni_env, jobject jobj, + const octave_value_list& idx, const octave_value& rhs) +{ + octave_value retval; + + jclass_ref rhsCls (jni_env); + jobject_ref resObj (jni_env), rhsObj (jni_env); + jobject_ref java_idx (jni_env, make_java_index (jni_env, idx)); + + if (! error_state && unbox (jni_env, rhs, rhsObj, rhsCls)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsasgn", + "(Ljava/lang/Object;[[ILjava/lang/Object;)Ljava/lang/Object;"); + resObj = jni_env->CallStaticObjectMethod (helperClass, mID, + jobj, jobject (java_idx), jobject (rhsObj)); + } + + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + + return retval; +} + +static string_vector +get_invoke_list (JNIEnv* jni_env, jobject jobj) +{ + std::list name_list; + + if (jni_env) + { + jclass_ref cls (jni_env, jni_env->GetObjectClass (jobj)); + jclass_ref ccls (jni_env, jni_env->GetObjectClass (cls)); + jmethodID getMethods_ID = jni_env->GetMethodID (ccls, "getMethods", "()[Ljava/lang/reflect/Method;"), + getFields_ID = jni_env->GetMethodID (ccls, "getFields", "()[Ljava/lang/reflect/Field;"); + jobjectArray_ref mList (jni_env, reinterpret_cast (jni_env->CallObjectMethod (cls, getMethods_ID))), + fList (jni_env, reinterpret_cast (jni_env->CallObjectMethod (cls, getFields_ID))); + int mLen = jni_env->GetArrayLength (mList), fLen = jni_env->GetArrayLength (fList); + jclass_ref mCls (jni_env, jni_env->FindClass ("java/lang/reflect/Method")), + fCls (jni_env, jni_env->FindClass ("java/lang/reflect/Field")); + jmethodID m_getName_ID = jni_env->GetMethodID (mCls, "getName", "()Ljava/lang/String;"), + f_getName_ID = jni_env->GetMethodID (fCls, "getName", "()Ljava/lang/String;"); + + for (int i = 0; i < mLen; i++) + { + jobject_ref meth (jni_env, jni_env->GetObjectArrayElement (mList, i)); + jstring_ref methName (jni_env, reinterpret_cast (jni_env->CallObjectMethod (meth, m_getName_ID))); + name_list.push_back (jstring_to_string (jni_env, methName)); + } + + for (int i = 0; i < fLen; i++) + { + jobject_ref field (jni_env, jni_env->GetObjectArrayElement (fList, i)); + jstring_ref fieldName (jni_env, reinterpret_cast (jni_env->CallObjectMethod (field, f_getName_ID))); + name_list.push_back (jstring_to_string (jni_env, fieldName)); + } + } + + string_vector v (name_list); + + return v.sort (true); +} + +static octave_value +convert_to_string (JNIEnv *jni_env, jobject java_object, bool force, char type) +{ + octave_value retval; + + if (jni_env && java_object) + { + jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String")); + + if (jni_env->IsInstanceOf (java_object, cls)) + retval = octave_value (jstring_to_string (jni_env, java_object), type); + else if (force) + { + cls = jni_env->FindClass ("[Ljava/lang/String;"); + + if (jni_env->IsInstanceOf (java_object, cls)) + { + jobjectArray array = reinterpret_cast (java_object); + int len = jni_env->GetArrayLength (array); + Cell c (len, 1); + + for (int i = 0; i < len; i++) + { + jstring_ref js (jni_env, reinterpret_cast (jni_env->GetObjectArrayElement (array, i))); + + if (js) + c(i) = octave_value (jstring_to_string (jni_env, js), type); + else + { + c(i) = check_exception (jni_env); + + if (error_state) + break; + } + } + + retval = octave_value (c); + } + else + { + cls = jni_env->FindClass ("java/lang/Object"); + jmethodID mID = jni_env->GetMethodID (cls, "toString", "()Ljava/lang/String;"); + jstring_ref js (jni_env, reinterpret_cast (jni_env->CallObjectMethod (java_object, mID))); + + if (js) + retval = octave_value (jstring_to_string (jni_env, js), type); + else + retval = check_exception (jni_env); + } + } + else + error ("unable to convert Java object to string"); + } + + return retval; +} + +#define TO_JAVA(obj) dynamic_cast ((obj).internal_rep ()) + +octave_value +box (JNIEnv* jni_env, jobject jobj, jclass jcls) +{ + octave_value retval; + jclass_ref cls (jni_env); + + if (! jobj) + retval = Matrix (); + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/Integer"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID m = jni_env->GetMethodID (cls, "intValue", "()I"); + retval = jni_env->CallIntMethod (jobj, m); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/Double"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID m = jni_env->GetMethodID (cls, "doubleValue", "()D"); + retval = jni_env->CallDoubleMethod (jobj, m); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/Boolean"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID m = jni_env->GetMethodID (cls, "booleanValue", "()Z"); + // MH retval = jni_env->CallBooleanMethod (jobj, m); + retval = (jni_env->CallBooleanMethod (jobj, m) ? true : false); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/String"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + retval = jstring_to_string (jni_env, jobj); + } + } + + if (retval.is_undefined () && Vjava_convert_matrix) + { + cls = find_octave_class (jni_env, "org/octave/Matrix"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID mID = jni_env->GetMethodID (cls, "getDims", "()[I"); + jintArray_ref iv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); + jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0); + dim_vector dims; + dims.resize (jni_env->GetArrayLength (jintArray (iv))); + + for (int i = 0; i < dims.length (); i++) + dims(i) = iv_data[i]; + + jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0); + mID = jni_env->GetMethodID (cls, "getClassName", "()Ljava/lang/String;"); + jstring_ref js (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); + + std::string s = jstring_to_string (jni_env, js); + + if (s == "double") + { + NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toDouble", "()[D"); + jdoubleArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ()); + retval = m; + } + else if (s == "byte") + { + if (Vjava_unsigned_conversion) + { + uint8NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toByte", "()[B"); + jbyteArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetByteArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); + retval = m; + } + else + { + int8NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toByte", "()[B"); + jbyteArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetByteArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); + retval = m; + } + } + else if (s == "integer") + { + if (Vjava_unsigned_conversion) + { + uint32NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toInt", "()[I"); + jintArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetIntArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); + retval = m; + } + else + { + int32NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toInt", "()[I"); + jintArray_ref dv (jni_env, reinterpret_cast (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetIntArrayRegion (dv, 0, m.length (), reinterpret_cast (m.fortran_vec ())); + retval = m; + } + } + } + } + + if (retval.is_undefined ()) + { + cls = find_octave_class (jni_env, "org/octave/OctaveReference"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID mID = jni_env->GetMethodID (cls, "getID", "()I"); + int ID = jni_env->CallIntMethod (jobj, mID); + std::map::iterator it = octave_ref_map.find (ID); + + if (it != octave_ref_map.end ()) + retval = it->second; + } + } + + if (retval.is_undefined ()) + retval = octave_value (new octave_java (jobj, jcls)); + + return retval; +} + +octave_value +box_more (JNIEnv* jni_env, jobject jobj, jclass jcls) +{ + octave_value retval = box (jni_env, jobj, jcls); + + if (retval.class_name () == "octave_java") + { + retval = octave_value (); + + jclass_ref cls (jni_env); + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("[D"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jdoubleArray jarr = reinterpret_cast (jobj); + int len = jni_env->GetArrayLength (jarr); + + if (len > 0) + { + Matrix m (1, len); + jni_env->GetDoubleArrayRegion (jarr, 0, len, m.fortran_vec ()); + retval = m; + } + else + retval = Matrix (); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("[[D"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jobjectArray jarr = reinterpret_cast (jobj); + int rows = jni_env->GetArrayLength (jarr), cols = 0; + + if (rows > 0) + { + Matrix m; + + for (int r = 0; r < rows; r++) + { + jdoubleArray_ref row (jni_env, reinterpret_cast (jni_env->GetObjectArrayElement (jarr, r))); + + if (m.length () == 0) + { + cols = jni_env->GetArrayLength (row); + m.resize (cols, rows); + } + jni_env->GetDoubleArrayRegion (row, 0, cols, m.fortran_vec () + r * cols); + } + retval = m.transpose (); + } + else + retval = Matrix (); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("[Ljava/lang/String;"); + + if (jni_env->IsInstanceOf (jobj, cls)) + { + jobjectArray jarr = reinterpret_cast (jobj); + int len = jni_env->GetArrayLength (jarr); + Cell m (len, 1); + + for (int i = 0; i < len; i++) + { + jstring_ref js (jni_env, reinterpret_cast (jni_env->GetObjectArrayElement (jarr, i))); + m(i) = jstring_to_string (jni_env, js); + } + + retval = m; + } + } + } + + if (retval.is_undefined ()) + retval = octave_value (new octave_java (jobj, jcls)); + + return retval; +} + +int +unbox (JNIEnv* jni_env, const octave_value& val, jobject_ref& jobj, + jclass_ref& jcls) +{ + int found = 1; + + if (val.class_name () == "octave_java") + { + octave_java *ovj = TO_JAVA (val); + jobj = ovj->to_java (); + jobj.detach (); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_string ()) + { + std::string s = val.string_value (); + + jobj = jni_env->NewStringUTF (s.c_str ()); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_bool_scalar ()) + { + bool bval = val.bool_value (); + jclass_ref bcls (jni_env, jni_env->FindClass ("java/lang/Boolean")); + jfieldID fid = jni_env->GetStaticFieldID (bcls, "TYPE", "Ljava/lang/Class;"); + jmethodID mid = jni_env->GetMethodID (bcls, "", "(Z)V"); + jcls = reinterpret_cast (jni_env->GetStaticObjectField (bcls, fid)); + jobj = jni_env->NewObject (bcls, mid, bval); + } + else if (val.is_real_scalar ()) + { + double dval = val.double_value (); + jclass_ref dcls (jni_env, jni_env->FindClass ("java/lang/Double")); + jfieldID fid = jni_env->GetStaticFieldID (dcls, "TYPE", "Ljava/lang/Class;"); + jmethodID mid = jni_env->GetMethodID (dcls, "", "(D)V"); + jcls = reinterpret_cast (jni_env->GetStaticObjectField (dcls, fid)); + jobj = jni_env->NewObject (dcls, mid, dval); + } + else if (val.is_empty ()) + { + jobj = 0; + //jcls = jni_env->FindClass ("java/lang/Object"); + jcls = 0; + } + else if (!Vjava_convert_matrix + && ((val.is_real_matrix () + && (val.rows () == 1 || val.columns () == 1)) + || val.is_range ())) + { + Matrix m = val.matrix_value (); + jdoubleArray dv = jni_env->NewDoubleArray (m.length ()); + //for (int i = 0; i < m.length (); i++) + jni_env->SetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ()); + jobj = dv; + jcls = jni_env->GetObjectClass (jobj); + } + else if (Vjava_convert_matrix + && (val.is_matrix_type () || val.is_range ()) && val.is_real_type ()) + { + jclass_ref mcls (jni_env, find_octave_class (jni_env, "org/octave/Matrix")); + dim_vector dims = val.dims (); + jintArray_ref iv (jni_env, jni_env->NewIntArray (dims.length ())); + jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0); + + for (int i = 0; i < dims.length (); i++) + iv_data[i] = dims(i); + + jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0); + + if (val.is_double_type ()) + { + NDArray m = val.array_value (); + jdoubleArray_ref dv (jni_env, jni_env->NewDoubleArray (m.length ())); + jni_env->SetDoubleArrayRegion (jdoubleArray (dv), 0, m.length (), m.fortran_vec ()); + jmethodID mID = jni_env->GetMethodID (mcls, "", "([D[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jdoubleArray (dv), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_int8_type ()) + { + int8NDArray m = val.int8_array_value (); + jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ())); + jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (), reinterpret_cast (m.fortran_vec ())); + jmethodID mID = jni_env->GetMethodID (mcls, "", "([B[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_uint8_type ()) + { + uint8NDArray m = val.uint8_array_value (); + jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ())); + jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (), reinterpret_cast (m.fortran_vec ())); + jmethodID mID = jni_env->GetMethodID (mcls, "", "([B[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_int32_type ()) + { + int32NDArray m = val.int32_array_value (); + jintArray_ref v (jni_env, jni_env->NewIntArray (m.length ())); + jni_env->SetIntArrayRegion (jintArray (v), 0, m.length (), reinterpret_cast (m.fortran_vec ())); + jmethodID mID = jni_env->GetMethodID (mcls, "", "([I[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jintArray (v), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else + { + found = 0; + error ("cannot convert matrix of type `%s'", val.class_name ().c_str ()); + } + } + else if (val.is_cellstr ()) + { + Cell cellStr = val.cell_value (); + jclass_ref scls (jni_env, jni_env->FindClass ("java/lang/String")); + jobjectArray array = jni_env->NewObjectArray (cellStr.length (), scls, 0); + for (int i = 0; i < cellStr.length (); i++) + { + jstring_ref jstr (jni_env, jni_env->NewStringUTF (cellStr(i).string_value().c_str ())); + jni_env->SetObjectArrayElement (array, i, jstr); + } + jobj = array; + jcls = jni_env->GetObjectClass (jobj); + } + else + { + jclass rcls = find_octave_class (jni_env, "org/octave/OctaveReference"); + jmethodID mID = jni_env->GetMethodID (rcls, "", "(I)V"); + int ID = octave_java_refcount++; + + jobj = jni_env->NewObject (rcls, mID, ID); + jcls = rcls; + octave_ref_map[ID] = val; + } + + return found; +} + +int +unbox (JNIEnv* jni_env, const octave_value_list& args, + jobjectArray_ref& jobjs, jobjectArray_ref& jclss) +{ + int found = 1; + + jclass_ref ocls (jni_env, jni_env->FindClass ("java/lang/Object")); + jclass_ref ccls (jni_env, jni_env->FindClass ("java/lang/Class")); + + if (! jobjs) + jobjs = jni_env->NewObjectArray (args.length (), ocls, 0); + + if (! jclss) + jclss = jni_env->NewObjectArray (args.length (), ccls, 0); + + for (int i = 0; i < args.length (); i++) + { + jobject_ref jobj (jni_env); + jclass_ref jcls (jni_env); + + if (! unbox (jni_env, args(i), jobj, jcls)) + { + found = 0; + break; + } + + jni_env->SetObjectArrayElement (jobjs, i, jobj); + jni_env->SetObjectArrayElement (jclss, i, jcls); + } + + return found; +} + + +static long +get_current_thread_ID (JNIEnv *jni_env) +{ + if (jni_env) + { + jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/Thread")); + jmethodID mID = jni_env->GetStaticMethodID (cls, "currentThread", "()Ljava/lang/Thread;"); + jobject_ref jthread (jni_env, jni_env->CallStaticObjectMethod (cls, mID)); + + if (jthread) + { + jclass_ref jth_cls (jni_env, jni_env->GetObjectClass (jthread)); + mID = jni_env->GetMethodID (jth_cls, "getId", "()J"); + long result = jni_env->CallLongMethod (jthread, mID); + //printf ("current java thread ID = %ld\n", result); + return result; + } + } + + return -1; +} + +static int +java_event_hook (void) +{ + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (current_env) + { + jclass_ref cls (current_env, find_octave_class (current_env, "org/octave/Octave")); + jmethodID mID = current_env->GetStaticMethodID (cls, "checkPendingAction", "()V"); + current_env->CallStaticVoidMethod (cls, mID); + } + + return 0; +} + +static void +initialize_java (void) +{ + if (! jvm) + { + try + { + initialize_jvm (); + + JNIEnv *current_env = octave_java::thread_jni_env (); + + octave_java::register_type (); + command_editor::add_event_hook (java_event_hook); + octave_thread_ID = get_current_thread_ID (current_env); + //printf ("octave thread ID=%ld\n", octave_thread_ID); + } + catch (std::string msg) + { + error (msg.c_str ()); + } + } +} + +DEFUN (java_init, , , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} java_init ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + retval = 0; + initialize_java (); + if (! error_state) + retval = 1; + + return retval; +} + +DEFUN (java_exit, , , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} java_exit ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + terminate_jvm (); + + return retval; +} + +DEFUN (java_new, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{obj} =} java_new (@var{name}, @var{arg1}, ...)\n\ +Create a Java object of class @var{name}, by calling the class constructor with the\n\ +arguments @var{arg1}, ...\n\ +\n\ +@example\n\ + x = java_new (\"java.lang.StringBuffer\", \"Initial string\")\n\ +@end example\n\ +\n\ +@seealso{java_invoke, java_get, java_set}\n\ +@end deftypefn") +{ + return _java_new (args); +} + +DEFUN (javaObject, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{obj} =} javaObject (@var{name}, @var{arg1}, ...)\n\ +Create a Java object of class @var{name}, by calling the class constructor with the\n\ +arguments @var{arg1}, ...\n\ +The first example creates an unitialized object, \ +while the second example supplies an initializer argument.\n\ +\n\ +@example\n\ + x = javaObject (\"java.lang.StringBuffer\")\n\ + x = javaObject (\"java.lang.StringBuffer\", \"Initial string\")\n\ +@end example\n\ +\n\ +@seealso{java_invoke, java_new, java_get, java_set}\n\ +@end deftypefn") +{ + return _java_new (args); +} + +// internally called from java_new and javaObject for backward compatibility +static octave_value _java_new (const octave_value_list& args) +{ + octave_value retval; + + initialize_java (); + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () > 0) + { + std::string name = args(0).string_value (); + if (! error_state) + { + octave_value_list tmp; + for (int i=1; i 1) + { + // swap first two arguments + octave_value_list tmp; + tmp(0) = args(1); + tmp(1) = args(0); + + // copy remaining arguments + for (int i=2; i 1) + { + std::string name = args(1).string_value (); + if (! error_state) + { + octave_value_list tmp; + for (int i=2; ido_java_invoke (current_env, name, tmp); + } + else if (args(0).is_string ()) + { + std::string cls = args(0).string_value (); + retval = octave_java::do_java_invoke (current_env, cls, name, tmp); + } + else + error ("java_invoke: first argument must be a Java object or a string"); + } + else + error ("java_invoke: second argument must be a string"); + } + else + print_usage (); + } + + return retval; +} + +DEFUN (java_get, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{val} =} java_get (@var{obj}, @var{name})\n\ +Get the value of the field @var{name} of the Java object @var{obj}. For\n\ +static fields, @var{obj} can be a string representing the fully qualified\n\ +name of the corresponding class.\n\ +\n\ +When @var{obj} is a regular Java object, the structure-like indexing can be used\n\ +as a shortcut syntax. For instance, the two following statements are equivalent\n\ +\n\ +@example\n\ + java_get (x, \"field1\")\n\ + x.field1\n\ +@end example\n\ +\n\ +@seealso{java_set, java_invoke, java_new}\n\ +@end deftypefn") +{ + octave_value retval; + + initialize_java (); + + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () == 2) + { + std::string name = args(1).string_value (); + if (! error_state) + { + if (args(0).class_name () == "octave_java") + { + octave_java *jobj = TO_JAVA (args(0)); + retval = jobj->do_java_get (current_env, name); + } + else if (args(0).is_string ()) + { + std::string cls = args(0).string_value (); + retval = octave_java::do_java_get (current_env, cls, name); + } + else + error ("java_get: first argument must be a Java object or a string"); + } + else + error ("java_get: second argument must be a string"); + } + else + print_usage (); + } + + return retval; +} + +DEFUN (java_set, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{obj} =} java_set (@var{obj}, @var{name}, @var{val})\n\ +Set the value of the field @var{name} of the Java object @var{obj} to @var{val}.\n\ +For static fields, @var{obj} can be a string representing the fully qualified named\n\ +of the corresponding Java class.\n\ +\n\ +When @var{obj} is a regular Java object, the structure-like indexing can be used as\n\ +a shortcut syntax. For instance, the two following statements are equivalent\n\ +\n\ +@example\n\ + java_set (x, \"field1\", val)\n\ + x.field1 = val\n\ +@end example\n\ +\n\ +@seealso{java_get, java_invoke, java_new}\n\ +@end deftypefn") +{ + octave_value retval; + + initialize_java (); + + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () == 3) + { + std::string name = args(1).string_value (); + if (! error_state) + { + if (args(0).class_name () == "octave_java") + { + octave_java *jobj = TO_JAVA (args(0)); + retval = jobj->do_java_set (current_env, name, args(2)); + } + else if (args(0).is_string ()) + { + std::string cls = args(0).string_value (); + retval = octave_java::do_java_set (current_env, cls, name, args(2)); + } + else + error ("java_set: first argument must be a Java object or a string"); + } + else + error ("java_set: second argument must be a string"); + } + else + print_usage (); + } + + return retval; +} + +DEFUN (java2mat, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} java2mat (@var{obj})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value_list retval; + + initialize_java (); + + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () == 1) + { + if (args(0).class_name () == "octave_java") + { + octave_java *jobj = TO_JAVA (args(0)); + retval(0) = box_more (current_env, jobj->to_java (), 0); + } + else + retval(0) = args(0); + } + else + print_usage (); + } + + return retval; +} + +DEFUN (java_convert_matrix, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} java_convert_matrix ()\n\ +Query or set the internal variable that determines FIXME.\n\ +@end deftypefn") +{ + return SET_INTERNAL_VARIABLE (java_convert_matrix); +} + +DEFUN (java_unsigned_conversion, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} java_unsigned_conversion ()\n\ +Query or set the internal variable that determines FIXME.\n\ +@end deftypefn") +{ + return SET_INTERNAL_VARIABLE (java_unsigned_conversion); +} + +DEFUN (java_debug, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} java_debug ()\n\ +Query or set the internal variable that determines FIXME.\n\ +@end deftypefn") +{ + return SET_INTERNAL_VARIABLE (java_debug); +} + +JNIEXPORT jboolean JNICALL +Java_org_octave_Octave_call (JNIEnv *env, jclass, jstring funcName, + jobjectArray argin, jobjectArray argout) +{ + std::string fname = jstring_to_string (env, funcName); + + int nargout = env->GetArrayLength (argout); + int nargin = env->GetArrayLength (argin); + + octave_value_list varargin, varargout; + + for (int i = 0; i < nargin; i++) + varargin(i) = box (env, env->GetObjectArrayElement (argin, i), 0); + + varargout = feval (fname, varargin, nargout); + + if (! error_state) + { + jobjectArray_ref out_objs (env, argout), out_clss (env); + + out_objs.detach (); + + if (unbox (env, varargout, out_objs, out_clss)) + return true; + } + + return false; +} + +JNIEXPORT void JNICALL +Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint ID) +{ + octave_ref_map.erase (ID); +} + +JNIEXPORT void JNICALL +Java_org_octave_Octave_doInvoke (JNIEnv *env, jclass, jint ID, + jobjectArray args) +{ + std::map::iterator it = octave_ref_map.find (ID); + + if (it != octave_ref_map.end ()) + { + octave_value val = it->second; + int len = env->GetArrayLength (args); + octave_value_list oct_args; + + for (int i = 0; i < len; i++) + { + jobject_ref jobj (env, env->GetObjectArrayElement (args, i)); + oct_args(i) = box (env, jobj, 0); + + if (error_state) + break; + } + + if (! error_state) + { + BEGIN_INTERRUPT_WITH_EXCEPTIONS; + + if (val.is_function_handle ()) + { + octave_function *fcn = val.function_value (); + feval (fcn, oct_args); + } + else if (val.is_cell () && val.length () > 0 + && (val.rows () == 1 || val.columns () == 1) + && val.cell_value()(0).is_function_handle ()) + { + Cell c = val.cell_value (); + octave_function *fcn = c(0).function_value (); + + for (int i=1; iGetEnv (reinterpret_cast (&env), JNI_VERSION_1_2); + + return env; +} + +octave_value_list +octave_java::subsref (const std::string& type, + const std::list& idx, int nargout) +{ + octave_value_list retval; + int skip = 1; + + JNIEnv *current_env = thread_jni_env (); + + switch (type[0]) + { + case '.': + if (type.length () > 1 && type[1] == '(') + { + octave_value_list ovl; + count++; + ovl(0) = octave_value (this); + ovl(1) = (idx.front ())(0); + std::list::const_iterator it = idx.begin (); + ovl.append (*++it); + retval = feval (std::string ("java_invoke"), ovl, 1); + skip++; + } + else + { + octave_value_list ovl; + count++; + ovl(0) = octave_value (this); + ovl(1) = (idx.front ())(0); + retval = feval (std::string ("java_get"), ovl, 1); + } + break; + + case '(': + if (current_env) + retval = get_array_elements (current_env, to_java (), idx.front ()); + break; + + default: + error ("subsref: Java object cannot be indexed with %c", type[0]); + break; + } + + if (idx.size () > 1 && type.length () > 1) + retval = retval(0).next_subsref (nargout, type, idx, skip); + + return retval; +} + +octave_value +octave_java::subsasgn (const std::string& type, + const std::list&idx, + const octave_value &rhs) +{ + octave_value retval; + + JNIEnv *current_env = thread_jni_env (); + + switch (type[0]) + { + case '.': + if (type.length () == 1) + { + // field assignment + octave_value_list ovl; + count++; + ovl(0) = octave_value (this); + ovl(1) = (idx.front ())(0); + ovl(2) = rhs; + feval ("java_set", ovl, 0); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + else if (type.length () > 2 && type[1] == '(') + { + std::list new_idx; + std::list::const_iterator it = idx.begin (); + new_idx.push_back (*it++); + new_idx.push_back (*it++); + octave_value_list u = subsref (type.substr (0, 2), new_idx, 1); + if (! error_state) + { + std::list next_idx (idx); + next_idx.erase (next_idx.begin ()); + next_idx.erase (next_idx.begin ()); + u(0).subsasgn (type.substr (2), next_idx, rhs); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + } + else if (type[1] == '.') + { + octave_value_list u = subsref (type.substr (0, 1), idx, 1); + if (! error_state) + { + std::list next_idx (idx); + next_idx.erase (next_idx.begin ()); + u(0).subsasgn (type.substr (1), next_idx, rhs); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + } + else + error ("invalid indexing/assignment on Java object"); + break; + + case '(': + if (current_env) + { + set_array_elements (current_env, to_java (), idx.front (), rhs); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + break; + + default: + error ("Java object cannot be indexed with %c", type[0]); + break; + } + + return retval; +} + +string_vector +octave_java::map_keys (void) const +{ + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + return get_invoke_list (current_env, to_java ()); + else + return string_vector (); +} + +octave_value +octave_java::convert_to_str_internal (bool, bool force, char type) const +{ + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + return convert_to_string (current_env, to_java (), force, type); + else + return octave_value (""); +} + +octave_value +octave_java::do_java_invoke (JNIEnv* jni_env, const std::string& name, + const octave_value_list& args) +{ + octave_value retval; + + if (jni_env) + { + jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); + if (unbox (jni_env, args, arg_objs, arg_types)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeMethod", + "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); + jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobjectArray_ref resObj (jni_env, reinterpret_cast (jni_env->CallStaticObjectMethod (helperClass, mID, + to_java (), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types)))); + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + } + + return retval; +} + +octave_value +octave_java:: do_java_invoke (JNIEnv* jni_env, + const std::string& class_name, + const std::string& name, + const octave_value_list& args) +{ + octave_value retval; + + if (jni_env) + { + jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); + if (unbox (jni_env, args, arg_objs, arg_types)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeStaticMethod", + "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); + jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jstring_ref clsName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + jstring (clsName), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types))); + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + } + + return retval; +} + +octave_value +octave_java::do_java_create (JNIEnv* jni_env, const std::string& name, + const octave_value_list& args) +{ + octave_value retval; + + if (jni_env) + { + jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); + + if (unbox (jni_env, args, arg_objs, arg_types)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeConstructor", + "(Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); + jstring_ref clsName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + jstring (clsName), jobjectArray (arg_objs), jobjectArray (arg_types))); + + if (resObj) + retval = box (jni_env, resObj); + else + check_exception (jni_env); + } + } + + return retval; +} + +octave_value +octave_java::do_java_get (JNIEnv* jni_env, const std::string& name) +{ + octave_value retval; + + if (jni_env) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getField", + "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;"); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + to_java (), jstring (fName))); + + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + + return retval; +} + +octave_value +octave_java::do_java_get (JNIEnv* jni_env, const std::string& class_name, + const std::string& name) +{ + octave_value retval; + + if (jni_env) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getStaticField", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); + jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + jstring (cName), jstring (fName))); + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + + return retval; +} + +octave_value +octave_java::do_java_set (JNIEnv* jni_env, const std::string& name, + const octave_value& val) +{ + octave_value retval; + + if (jni_env) + { + jobject_ref jobj (jni_env); + jclass_ref jcls (jni_env); + + if (unbox (jni_env, val, jobj, jcls)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setField", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V"); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jni_env->CallStaticObjectMethod (helperClass, mID, to_java (), jstring (fName), jobject (jobj)); + check_exception (jni_env); + } + } + + return retval; +} + +octave_value +octave_java::do_java_set (JNIEnv* jni_env, const std::string& class_name, + const std::string& name, const octave_value& val) +{ + octave_value retval; + + if (jni_env) + { + jobject_ref jobj (jni_env); + jclass_ref jcls (jni_env); + + if (unbox (jni_env, val, jobj, jcls)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setStaticField", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"); + jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jni_env->CallStaticObjectMethod (helperClass, mID, jstring (cName), jstring (fName), jobject (jobj)); + check_exception (jni_env); + } + } + + return retval; +} + +#endif + diff -r 72968fb32c82 -r f96faf028d90 libinterp/octave-value/ov-java.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-java.h Sat Dec 08 00:23:13 2012 -0500 @@ -0,0 +1,324 @@ +/* + +Copyright (C) 2007 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_java_h) +#define octave_java_h 1 + +#include + +#include +#include + +#ifdef JAVAPKG_BUILD +# define JAVAPKG_API OCTAVE_EXPORT +#else +# define JAVAPKG_API OCTAVE_IMPORT +#endif + +template +class java_local_ref +{ +public: + + java_local_ref (JNIEnv *_env) + : jobj (0), detached (false), env (_env) { } + + java_local_ref (JNIEnv *_env, T obj) + : jobj (obj), detached (false), env (_env) { } + + ~java_local_ref (void) { release (); } + + T& operator= (T obj) + { + release (); + jobj = obj; + detached = false; + return jobj; + } + + operator bool () const { return (jobj != 0); } + operator T () { return jobj; } + + void detach (void) { detached = true; } + +private: + + void release (void) + { + if (env && jobj && ! detached) + env->DeleteLocalRef (jobj); + + jobj = 0; + } + + java_local_ref (void) + : jobj (0), detached (false), env (0) + { } + +protected: + T jobj; + bool detached; + JNIEnv *env; +}; + +typedef java_local_ref jobject_ref; +typedef java_local_ref jclass_ref; +typedef java_local_ref jstring_ref; +typedef java_local_ref jobjectArray_ref; +typedef java_local_ref jintArray_ref; +typedef java_local_ref jbyteArray_ref; +typedef java_local_ref jdoubleArray_ref; +typedef java_local_ref jthrowable_ref; + +extern JAVAPKG_API std::string +jstring_to_string (JNIEnv* jni_env, jstring s); + +extern JAVAPKG_API std::string +jstring_to_string (JNIEnv* jni_env, jobject obj); + +extern JAVAPKG_API octave_value +box (JNIEnv* jni_env, jobject jobj, jclass jcls = 0); + +extern JAVAPKG_API octave_value +box_more (JNIEnv* jni_env, jobject jobj, jclass jcls = 0); + +extern JAVAPKG_API int +unbox (JNIEnv* jni_env, const octave_value& val, jobject_ref& jobj, + jclass_ref& jcls); + +extern JAVAPKG_API int +unbox (JNIEnv* jni_env, const octave_value_list& args, + jobjectArray_ref& jobjs, jobjectArray_ref& jclss); + +extern JAVAPKG_API bool Vjava_convert_matrix; + +extern JAVAPKG_API bool Vjava_unsigned_conversion; + +extern JAVAPKG_API bool Vjava_debug; + +class JAVAPKG_API octave_java : public octave_base_value +{ +public: + + octave_java (void) + : octave_base_value (), java_object (0), java_class (0) + { } + + octave_java (const octave_java& jobj) + : octave_base_value (jobj), java_object (0), java_class (0) + { + init (jobj.java_object, jobj.java_class); + } + + octave_java (const jobject& obj, jclass cls = 0) + : octave_base_value (), java_object (0) + { + init (obj, cls); + } + + ~octave_java (void) { release (); } + + jobject to_java (void) const { return java_object; } + jclass to_class (void) const { return java_class; } + + std::string java_class_name (void) const { return java_type; } + + octave_base_value* clone (void) const { return new octave_java (*this); } + octave_base_value* empty_clone (void) const { return new octave_java (); } + + bool is_defined (void) const { return true; } + + bool is_map (void) const { return true; } + + string_vector map_keys (void) const; + + dim_vector dims (void) const; + + void print (std::ostream& os, bool pr_as_read_syntax = false) const + { + os << ""; + newline(os); + } + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const + { + print(os, pr_as_read_syntax); + } + + octave_value_list + subsref (const std::string& type, + const std::list& idx, int nargout); + + octave_value + subsref (const std::string& type, const std::list& idx) + { + octave_value_list retval = subsref (type, idx, 1); + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs); + + octave_value convert_to_str_internal (bool pad, bool force, char type) const; + + bool is_string (void) const + { + JNIEnv *current_env = thread_jni_env (); + + if (current_env && java_object) + { + jclass_ref cls (current_env, current_env->FindClass ("java/lang/String")); + return current_env->IsInstanceOf (java_object, cls); + } + + return false; + } + + static JNIEnv* thread_jni_env (void); + + octave_value do_java_invoke (JNIEnv* jni_env, const std::string& name, + const octave_value_list& args); + + octave_value + do_java_invoke (const std::string& name, const octave_value_list& args) + { + return do_java_invoke(thread_jni_env (), name, args); + } + + static octave_value + do_java_invoke (JNIEnv* jni_env, const std::string& class_name, + const std::string& name, const octave_value_list& args); + + static octave_value + do_java_invoke (const std::string& class_name, const std::string& name, + const octave_value_list& args) + { + return do_java_invoke(thread_jni_env (), class_name, name, args); + } + + static octave_value + do_java_create (JNIEnv* jni_env, const std::string& name, + const octave_value_list& args); + + static octave_value + do_java_create (const std::string& name, const octave_value_list& args) + { + return do_java_create (thread_jni_env (), name, args); + } + + octave_value do_java_get (JNIEnv* jni_env, const std::string& name); + + octave_value do_java_get (const std::string& name) + { + return do_java_get (thread_jni_env (), name); + } + + static octave_value + do_java_get (JNIEnv* jni_env, const std::string& class_name, + const std::string& name); + + static octave_value + do_java_get (const std::string& class_name, const std::string& name) + { + return do_java_get (thread_jni_env (), class_name, name); + } + + octave_value do_java_set (JNIEnv* jni_env, const std::string& name, + const octave_value& val); + + octave_value do_java_set (const std::string& name, const octave_value& val) + { + return do_java_set (thread_jni_env (), name, val); + } + + static octave_value + do_java_set (JNIEnv* jni_env, const std::string& class_name, + const std::string& name, const octave_value& val); + + static octave_value + do_java_set (const std::string& class_name, const std::string& name, + const octave_value& val) + { + return do_java_set (thread_jni_env (), class_name, name, val); + } + +private: + + void init (jobject jobj, jclass jcls) + { + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + { + if (jobj) + java_object = current_env->NewGlobalRef (jobj); + + if (jcls) + java_class = reinterpret_cast (current_env->NewGlobalRef (jcls)); + else if (java_object) + { + jclass_ref ocls (current_env, current_env->GetObjectClass (java_object)); + java_class = reinterpret_cast (current_env->NewGlobalRef (jclass (ocls))); + } + + if (java_class) + { + jclass_ref clsCls (current_env, current_env->GetObjectClass (java_class)); + jmethodID mID = current_env->GetMethodID (clsCls, "getCanonicalName", "()Ljava/lang/String;"); + jobject_ref resObj (current_env, current_env->CallObjectMethod (java_class, mID)); + java_type = jstring_to_string (current_env, resObj); + } + } + } + + void release (void) + { + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + { + if (java_object) + current_env->DeleteGlobalRef (java_object); + + if (java_class) + current_env->DeleteGlobalRef (java_class); + + java_object = 0; + java_class = 0; + } + } + +private: + + DECLARE_OCTAVE_ALLOCATOR + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA + + jobject java_object; + + jclass java_class; + + std::string java_type; +}; + +#endif diff -r 72968fb32c82 -r f96faf028d90 run-octave.in --- a/run-octave.in Fri Dec 07 19:34:19 2012 -0500 +++ b/run-octave.in Sat Dec 08 00:23:13 2012 -0500 @@ -80,6 +80,7 @@ OCTAVE_SITE_INITFILE="$top_srcdir/scripts/startup/main-rcfile" \ OCTAVE_DEFAULT_QT_SETTINGS="$top_srcdir/libgui/default-qt-settings" \ +OCTAVE_JAVA_DIR="$builddir/scripts/java" \ exec $builddir/libtool --mode=execute $driver \ "$octave_executable" --no-init-path --path="$LOADPATH" \ --image-path="$IMAGEPATH" --doc-cache-file="$DOCFILE" \ diff -r 72968fb32c82 -r f96faf028d90 scripts/java/org/octave/Octave.java --- a/scripts/java/org/octave/Octave.java Fri Dec 07 19:34:19 2012 -0500 +++ b/scripts/java/org/octave/Octave.java Sat Dec 08 00:23:13 2012 -0500 @@ -20,11 +20,6 @@ public class Octave { - static - { - System.load (System.getProperty ("octave.java.path") + java.io.File.separator + "__java__.oct"); - } - private static Object notifyObject = null; private static Object[] args = null; private static LinkedList invokeList = new LinkedList(); diff -r 72968fb32c82 -r f96faf028d90 scripts/java/org/octave/OctaveReference.java --- a/scripts/java/org/octave/OctaveReference.java Fri Dec 07 19:34:19 2012 -0500 +++ b/scripts/java/org/octave/OctaveReference.java Sat Dec 08 00:23:13 2012 -0500 @@ -18,11 +18,6 @@ public class OctaveReference { - static - { - System.load (System.getProperty ("octave.java.path") + java.io.File.separator + "__java__.oct"); - } - private int ID; public OctaveReference(int ID)