GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ov-java.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2007, 2013 Michael Goffioul
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include "defun.h"
28 #include "error.h"
29 #include "fpucw.h"
30 
31 #if HAVE_FPU_CONTROL_H
32 #include <fpu_control.h>
33 #endif
34 
35 #if defined HAVE_JAVA
36 
37 #if defined (HAVE_WINDOWS_H)
38 #include <windows.h>
39 #endif
40 
41 #include <algorithm>
42 #include <map>
43 #include <iostream>
44 #include <fstream>
45 
46 #include <clocale>
47 
48 #include "Cell.h"
49 #include "cmd-edit.h"
50 #include "defaults.h"
51 #include "file-ops.h"
52 #include "file-stat.h"
53 #include "load-path.h"
54 #include "oct-env.h"
55 #include "oct-shlib.h"
56 #include "ov-java.h"
57 #include "parse.h"
58 #include "variables.h"
59 
60 typedef jint (JNICALL *JNI_CreateJavaVM_t) (JavaVM **pvm, JNIEnv **penv, void *args);
61 typedef jint (JNICALL *JNI_GetCreatedJavaVMs_t) (JavaVM **pvm, jsize bufLen, jsize *nVMs);
62 
63 extern "C"
64 {
65  JNIEXPORT jboolean JNICALL
66  Java_org_octave_Octave_call (JNIEnv *, jclass, jstring, jobjectArray,
67  jobjectArray);
68  JNIEXPORT void JNICALL
69  Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint);
70 
71  JNIEXPORT void JNICALL
72  Java_org_octave_Octave_doInvoke (JNIEnv *, jclass, jint, jobjectArray);
73 
74  JNIEXPORT void JNICALL
75  Java_org_octave_Octave_doEvalString (JNIEnv *, jclass, jstring);
76 
77  JNIEXPORT jboolean JNICALL
78  Java_org_octave_Octave_needThreadedInvokation (JNIEnv *, jclass);
79 }
80 
81 static JavaVM *jvm = 0;
82 static bool jvm_attached = false;
83 
84 // Need to keep hold of the shared library handle until exit.
85 static octave_shlib jvm_lib;
86 
87 static std::map<int,octave_value> listener_map;
88 static std::map<int,octave_value> octave_ref_map;
89 static int octave_java_refcount = 0;
90 static long octave_thread_ID = -1;
91 
92 bool Vjava_matrix_autoconversion = false;
94 bool Vdebug_java = false;
95 
96 class JVMArgs
97 {
98 public:
99 
100  JVMArgs (void)
101  {
102  vm_args.version = JNI_VERSION_1_2;
103  vm_args.nOptions = 0;
104  vm_args.options = 0;
105  vm_args.ignoreUnrecognized = false;
106  }
107 
108  ~JVMArgs (void)
109  {
110  clean ();
111  }
112 
113  JavaVMInitArgs* to_args ()
114  {
115  update ();
116  return &vm_args;
117  }
118 
119  void add (const std::string& opt)
120  {
121  java_opts.push_back (opt);
122  }
123 
124  void read_java_opts (const std::string& filename)
125  {
126  std::ifstream js (filename.c_str ());
127 
128  if (! js.bad () && ! js.fail ())
129  {
130  std::string line;
131 
132  while (! js.eof () && ! js.fail ())
133  {
134  std::getline (js, line);
135  if (line.length () > 2
136  && (line.find ("-D") == 0 || line.find ("-X") == 0))
137  java_opts.push_back (line);
138  else if (line.length () > 0 && Vdebug_java)
139  std::cerr << "invalid JVM option, skipping: " << line << std::endl;
140  }
141  }
142  }
143 
144 private:
145 
146  void clean (void)
147  {
148  if (vm_args.options != 0)
149  {
150  for (int i = 0; i < vm_args.nOptions; i++)
151  delete [] vm_args.options[i].optionString;
152  delete [] vm_args.options;
153 
154  vm_args.options = 0;
155  vm_args.nOptions = 0;
156  }
157  }
158 
159  void update (void)
160  {
161  clean ();
162 
163  if (java_opts.size () > 0)
164  {
165  int index = 0;
166 
167  vm_args.nOptions = java_opts.size ();
168  vm_args.options = new JavaVMOption [vm_args.nOptions];
169  for (std::list<std::string>::const_iterator it = java_opts.begin ();
170  it != java_opts.end (); ++it)
171  {
172  if (Vdebug_java)
173  std::cout << *it << std::endl;
174  vm_args.options[index++].optionString = strsave ((*it).c_str ());
175  }
176  java_opts.clear ();
177  }
178  }
179 
180 private:
181 
182  JavaVMInitArgs vm_args;
183 
184  std::list<std::string> java_opts;
185 };
186 
187 #ifdef __WIN32__
188 static std::string
189 read_registry_string (const std::string& key, const std::string& value)
190 {
191  HKEY hkey;
192  DWORD len;
193 
194  std::string retval;
195 
196  if (! RegOpenKeyEx (HKEY_LOCAL_MACHINE, key.c_str (), 0, KEY_READ, &hkey))
197  {
198  if (! RegQueryValueEx (hkey, value.c_str (), 0, 0, 0, &len))
199  {
200  retval.resize (len);
201  if (RegQueryValueEx (hkey, value.c_str (), 0, 0,
202  (LPBYTE)&retval[0], &len))
203  retval = "";
204  else if (retval[len-1] == '\0')
205  retval.resize (--len);
206  }
207  RegCloseKey (hkey);
208  }
209 
210  return retval;
211 }
212 
213 static std::string
214 get_module_filename (HMODULE hMod)
215 {
216  int n = 1024;
217  std::string retval (n, '\0');
218  bool found = false;
219 
220  while (n < 65536)
221  {
222  int status = GetModuleFileName(hMod, &retval[0], n);
223 
224  if (status < n)
225  {
226  retval.resize (n);
227  found = true;
228  break;
229  }
230  else
231  {
232  n *= 2;
233  retval.resize (n);
234  }
235  }
236  return (found ? retval : "");
237 }
238 
239 static void
240 set_dll_directory (const std::string& dir = "")
241 {
242  typedef BOOL (WINAPI *dllfcn_t) (LPCTSTR path);
243 
244  static dllfcn_t dllfcn = 0;
245  static bool first = true;
246 
247  if (! dllfcn && first)
248  {
249  HINSTANCE hKernel32 = GetModuleHandle ("kernel32");
250  dllfcn = reinterpret_cast<dllfcn_t> (GetProcAddress (hKernel32,
251  "SetDllDirectoryA"));
252  first = false;
253  }
254 
255  if (dllfcn)
256  dllfcn (dir.empty () ? 0 : dir.c_str ());
257 }
258 #endif
259 
260 static std::string
261 initial_java_dir (void)
262 {
263  static std::string java_dir;
264 
265  if (java_dir.empty ())
266  {
267  java_dir = octave_env::getenv ("OCTAVE_JAVA_DIR");
268 
269  if (java_dir.empty ())
270  java_dir = Vfcn_file_dir + file_ops::dir_sep_str () + "java";
271  }
272 
273  return java_dir;
274 }
275 
276 // Read the content of a file filename (usually "classpath.txt")
277 //
278 // Returns a string with all lines concatenated and separated
279 // by the path separator character.
280 // The return string also starts with a path separator so that
281 // it can be appended easily to a base classpath.
282 //
283 // The file "classpath.txt" must contain single lines, each
284 // with a classpath.
285 // Comment lines starting with a '#' or a '%' in column 1 are allowed.
286 
287 static std::string
288 read_classpath_txt (const std::string& filepath)
289 {
290  std::string classpath;
291 
292  std::ifstream fs (filepath.c_str ());
293 
294  if (! fs.bad () && ! fs.fail ())
295  {
296  std::string line;
297 
298  while (! fs.eof () && ! fs.fail ())
299  {
300  std::getline (fs, line);
301 
302  if (line.length () > 0)
303  {
304  if (line[0] == '#' || line[0] == '%')
305  ; // skip comments
306  else
307  {
308  // prepend separator character
309  classpath.append (dir_path::path_sep_str ());
310 
311  // append content of line without whitespace
312  int last = line.find_last_not_of (" \t\f\v\r\n");
313 
314  classpath.append (file_ops::tilde_expand (line.substr (0, last+1)));
315  }
316  }
317  }
318  }
319 
320  return (classpath);
321 }
322 
323 static std::string
324 initial_class_path (void)
325 {
326  std::string java_dir = initial_java_dir ();
327 
328  std::string retval = java_dir;
329 
330  // find octave.jar file
331  if (! retval.empty ())
332  {
333  std::string sep = file_ops::dir_sep_str ();
334 
335  std::string jar_file = java_dir + sep + "octave.jar";
336 
337  file_stat jar_exists (jar_file);
338 
339  if (jar_exists)
340  {
341  // initialize static classpath to octave.jar
342  retval = jar_file;
343 
344  // The base classpath has been set.
345  // Try to find an optional file specifying classpaths in 3 places.
346  // 1) Current directory
347  // 2) User's home directory
348  // 3) Octave installation directory where octave.jar resides
349 
350  // The filename is "javaclasspath.txt", but historically
351  // has been "classpath.txt" so both are supported.
352  std::string cp_list[] = {"javaclasspath.txt", "classpath.txt"};
353 
354  for (int i=0; i<2; i++)
355  {
356  std::string filename = cp_list[i];
357  std::string cp_file = filename;
358  file_stat cp_exists;
359 
360  // Try to find classpath file in the current directory.
361 
362  cp_exists = file_stat (cp_file);
363  if (cp_exists)
364  {
365  // File found. Add its contents to the static classpath.
366  std::string classpath = read_classpath_txt (cp_file);
367  retval.append (classpath);
368  }
369 
370  // Try to find classpath file in the user's home directory.
371 
372  cp_file = "~" + sep + filename;
373  cp_file = file_ops::tilde_expand (cp_file);
374  cp_exists = file_stat (cp_file);
375  if (cp_exists)
376  {
377  // File found. Add its contents to the static classpath.
378  std::string classpath = read_classpath_txt (cp_file);
379  retval.append (classpath);
380  }
381 
382  // Try to find classpath file in the Octave install directory.
383 
384  cp_file = java_dir + sep + filename;
385  cp_exists = file_stat (cp_file);
386  if (cp_exists)
387  {
388  // File found. Add its contents to the static classpath.
389  std::string classpath = read_classpath_txt (cp_file);
390  retval.append (classpath);
391  }
392  }
393  }
394  else
395  throw std::string ("octave.jar does not exist: ") + jar_file;
396  }
397  else
398  throw std::string ("initial java dir is empty");
399 
400  return retval;
401 }
402 
403 #ifndef _FPU_DEFAULT
404 #if defined __i386__ || defined __x86_64__
405 #define _FPU_DEFAULT 0x037f
406 #else
407 #define _FPU_DEFAULT 0
408 #endif
409 #endif
410 
411 static void
412 restore_fpu_state (void)
413 {
414  fpucw_t cw = GET_FPUCW ();
415  if (cw != _FPU_DEFAULT)
416  SET_FPUCW (_FPU_DEFAULT);
417 }
418 
419 static void
420 initialize_jvm (void)
421 {
422  // Most of the time JVM already exists and has been initialized.
423  if (jvm)
424  return;
425 
426  JNIEnv *current_env;
427  const char *static_locale = setlocale (LC_ALL, 0);
428  const std::string locale (static_locale);
429 
430 #if defined (__WIN32__)
431 
432  HMODULE hMod = GetModuleHandle ("jvm.dll");
433  std::string jvm_lib_path;
434  std::string old_cwd;
435 
436  if (hMod)
437  {
438  // JVM seems to be already loaded, better to use that DLL instead
439  // of looking in the registry, to avoid opening a different JVM.
440  jvm_lib_path = get_module_filename (hMod);
441 
442  if (jvm_lib_path.empty ())
443  throw std::string ("unable to find Java Runtime Environment");
444  }
445  else
446  {
447  // In windows, find the location of the JRE from the registry
448  // and load the symbol from the dll.
449  std::string key, value;
450 
451  key = "software\\javasoft\\java runtime environment";
452 
453  value = octave_env::getenv ("JAVA_VERSION");
454  if (value.empty ())
455  {
456  value = "Currentversion";
457  std::string regval = read_registry_string (key,value);
458 
459  if (regval.empty ())
460  throw std::string ("unable to find Java Runtime Environment: ") + key + "::" + value;
461  value = regval;
462  }
463 
464  key = key + "\\" + value;
465  value = "RuntimeLib";
466  jvm_lib_path = read_registry_string (key, value);
467  if (jvm_lib_path.empty ())
468  throw std::string ("unable to find Java Runtime Environment: ") + key + "::" + value;
469 
470  std::string jvm_bin_path;
471 
472  value = "JavaHome";
473  jvm_bin_path = read_registry_string (key, value);
474  if (! jvm_bin_path.empty ())
475  {
476  jvm_bin_path = (jvm_bin_path + std::string ("\\bin"));
477 
479 
480  set_dll_directory (jvm_bin_path);
481  octave_env::chdir (jvm_bin_path);
482  }
483  }
484 
485 #else // Not Win32 system
486 
487  // JAVA_LDPATH determined by configure and set in config.h
488 #if defined (__APPLE__)
489  std::string jvm_lib_path = JAVA_LDPATH + std::string ("/libjvm.dylib");
490 #else
491  std::string jvm_lib_path = JAVA_LDPATH + std::string ("/libjvm.so");
492 #endif
493 
494 #endif
495 
496  jsize nVMs = 0;
497 
498 # if !defined (__APPLE__) && !defined (__MACH__)
499 
500  octave_shlib lib (jvm_lib_path);
501 
502  if (!lib)
503  throw std::string ("unable to load Java Runtime Environment from ") + jvm_lib_path;
504 
505 #if defined (__WIN32__)
506 
507  set_dll_directory ();
508 
509  if (! old_cwd.empty ())
510  octave_env::chdir (old_cwd);
511 
512 #endif
513 
514  JNI_CreateJavaVM_t create_vm =
515  reinterpret_cast<JNI_CreateJavaVM_t> (lib.search ("JNI_CreateJavaVM"));
516  JNI_GetCreatedJavaVMs_t get_vm =
517  reinterpret_cast<JNI_GetCreatedJavaVMs_t> (lib.search ("JNI_GetCreatedJavaVMs"));
518 
519  if (!create_vm)
520  throw std::string ("unable to find JNI_CreateJavaVM in ") + jvm_lib_path;
521 
522  if (!get_vm)
523  throw std::string ("unable to find JNI_GetCreatedJavaVMs in ") + jvm_lib_path;
524 
525  if (get_vm (&jvm, 1, &nVMs) == 0 && nVMs > 0)
526 
527 #else
528 
529  // FIXME: There exists a problem on the Mac platform that
530  // octave_shlib lib (jvm_lib_path)
531  // doesn't work with 'not-bundled' *.oct files.
532 
533  if (JNI_GetCreatedJavaVMs (&jvm, 1, &nVMs) == 0 && nVMs > 0)
534 
535 #endif
536 
537  {
538  // At least one JVM exists, try to attach to it
539 
540  switch (jvm->GetEnv (reinterpret_cast<void **> (&current_env), JNI_VERSION_1_2))
541  {
542  case JNI_EDETACHED:
543  // Attach the current thread
544  JavaVMAttachArgs vm_args;
545  vm_args.version = JNI_VERSION_1_2;
546  vm_args.name = const_cast<char *> ("octave");
547  vm_args.group = 0;
548  if (jvm->AttachCurrentThread (reinterpret_cast<void **> (&current_env),
549  &vm_args) < 0)
550  throw std::string ("JVM internal error, unable to attach octave to existing JVM");
551  break;
552 
553  case JNI_EVERSION:
554  throw std::string ("JVM internal error, the required JNI version is not supported");
555  break;
556 
557  case JNI_OK:
558  // Don't do anything, the current thread is already attached to JVM
559  break;
560  }
561 
562  jvm_attached = true;
563  //printf ("JVM attached\n");
564  }
565  else
566  {
567  // No JVM exists, create one
568 
569  JVMArgs vm_args;
570 
571  vm_args.add ("-Djava.class.path=" + initial_class_path ());
572  vm_args.add ("-Xrs");
573  vm_args.add ("-Djava.system.class.loader=org.octave.OctClassLoader");
574  vm_args.read_java_opts (initial_java_dir () + file_ops::dir_sep_str () + "java.opts");
575 
576 # if !defined (__APPLE__) && !defined (__MACH__)
577 
578  if (create_vm (&jvm, &current_env, vm_args.to_args ()) != JNI_OK)
579  throw std::string ("unable to start Java VM in ")+jvm_lib_path;
580  //printf ("JVM created\n");
581  }
582 
583  jvm_lib = lib;
584 
585 #else
586 
587  if (JNI_CreateJavaVM (&jvm, reinterpret_cast<void **> (&current_env),
588  vm_args.to_args ()) != JNI_OK)
589  throw std::string ("unable to start Java VM in ")+jvm_lib_path;
590 
591  }
592 
593 #endif
594 
595  setlocale (LC_ALL, locale.c_str ());
596 }
597 
598 static void
599 terminate_jvm (void)
600 {
601  if (jvm)
602  {
603  if (jvm_attached)
604  jvm->DetachCurrentThread ();
605  else
606  jvm->DestroyJavaVM ();
607 
608  jvm = 0;
609  jvm_attached = false;
610 
611  if (jvm_lib)
612  jvm_lib.close ();
613 
614  restore_fpu_state ();
615  }
616 }
617 
618 std::string
619 jstring_to_string (JNIEnv* jni_env, jstring s)
620 {
621  std::string retval;
622 
623  if (jni_env)
624  {
625  const char *cstr = jni_env->GetStringUTFChars (s, 0);
626  retval = cstr;
627  jni_env->ReleaseStringUTFChars (s, cstr);
628  }
629 
630  return retval;
631 }
632 
633 std::string
634 jstring_to_string (JNIEnv* jni_env, jobject obj)
635 {
636  std::string retval;
637 
638  if (jni_env && obj)
639  {
640  jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String"));
641  if (cls)
642  {
643  if (jni_env->IsInstanceOf (obj, cls))
644  retval = jstring_to_string (jni_env,
645  reinterpret_cast<jstring> (obj));
646  }
647  }
648 
649  return retval;
650 }
651 
652 bool
653 octave_java::is_java_string (void) const
654 {
655  JNIEnv *current_env = thread_jni_env ();
656 
657  if (current_env && java_object)
658  {
659  jclass_ref cls (current_env, current_env->FindClass ("java/lang/String"));
660  return current_env->IsInstanceOf (java_object, cls);
661  }
662 
663  return false;
664 }
665 
666 static octave_value
667 check_exception (JNIEnv* jni_env)
668 {
669  octave_value retval;
670 
671  jthrowable_ref ex (jni_env, jni_env->ExceptionOccurred ());
672 
673  if (ex)
674  {
675  if (Vdebug_java)
676  jni_env->ExceptionDescribe ();
677 
678  jni_env->ExceptionClear ();
679 
680  jclass_ref jcls (jni_env, jni_env->GetObjectClass (ex));
681  jmethodID mID = jni_env->GetMethodID (jcls, "toString",
682  "()Ljava/lang/String;");
683  jstring_ref js (jni_env,
684  reinterpret_cast<jstring> (jni_env->CallObjectMethod (ex, mID)));
685  std::string msg = jstring_to_string (jni_env, js);
686 
687  error ("[java] %s", msg.c_str ());
688  }
689  else
690  retval = Matrix ();
691 
692  return retval;
693 }
694 
695 static jclass
696 find_octave_class (JNIEnv *jni_env, const char *name)
697 {
698  static std::string class_loader;
699  static jclass uiClass = 0;
700 
701  jclass jcls = jni_env->FindClass (name);
702 
703  if (jcls == 0)
704  {
705  jni_env->ExceptionClear ();
706 
707  if (! uiClass)
708  {
709  if (class_loader.empty ())
710  {
711  jclass_ref syscls (jni_env,
712  jni_env->FindClass ("java/lang/System"));
713  jmethodID mID = jni_env->GetStaticMethodID (syscls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
714  jstring_ref js (jni_env, jni_env->NewStringUTF ("octave.class.loader"));
715  js = reinterpret_cast<jstring> (jni_env->CallStaticObjectMethod (syscls, mID, jstring (js)));
716  class_loader = jstring_to_string (jni_env, jstring (js));
717  std::replace (class_loader.begin (), class_loader.end (), '.', '/');
718  }
719 
720  jclass_ref uicls (jni_env, jni_env->FindClass (class_loader.c_str ()));
721 
722  if (! uicls)
723  {
724  jni_env->ExceptionClear ();
725 
726  /* Try the netbeans way */
727  std::replace (class_loader.begin (), class_loader.end (), '/', '.');
728  jclass_ref jcls2 (jni_env, jni_env->FindClass ("org/openide/util/Lookup"));
729  jmethodID mID = jni_env->GetStaticMethodID (jcls2, "getDefault", "()Lorg/openide/util/Lookup;");
730  jobject_ref lObj (jni_env, jni_env->CallStaticObjectMethod (jcls2, mID));
731  mID = jni_env->GetMethodID (jcls2, "lookup", "(Ljava/lang/Class;)Ljava/lang/Object;");
732  jclass_ref cLoaderCls (jni_env, jni_env->FindClass ("java/lang/ClassLoader"));
733  jobject_ref cLoader (jni_env, jni_env->CallObjectMethod (lObj, mID, jclass (cLoaderCls)));
734  mID = jni_env->GetMethodID (cLoaderCls, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
735  jstring_ref js (jni_env, jni_env->NewStringUTF (class_loader.c_str ()));
736  uicls = reinterpret_cast<jclass> (jni_env->CallObjectMethod (cLoader, mID, jstring (js)));
737  }
738 
739  if (uicls)
740  uiClass = reinterpret_cast<jclass> (jni_env->NewGlobalRef (jclass (uicls)));
741  }
742 
743  if (uiClass)
744  {
745  jmethodID mID = jni_env->GetStaticMethodID (uiClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
746  jstring_ref js (jni_env, jni_env->NewStringUTF (name));
747  jcls = reinterpret_cast<jclass> (jni_env->CallStaticObjectMethod (uiClass, mID, jstring (js)));
748  }
749  }
750 
751  return jcls;
752 }
753 
754 static dim_vector
755 compute_array_dimensions (JNIEnv* jni_env, jobject obj)
756 {
757  jobjectArray_ref jobj (jni_env, reinterpret_cast<jobjectArray> (obj));
758  jclass_ref jcls (jni_env, jni_env->GetObjectClass (obj));
759  jclass_ref ccls (jni_env, jni_env->GetObjectClass (jcls));
760  jmethodID isArray_ID = jni_env->GetMethodID (ccls, "isArray", "()Z");
761  jmethodID getComponentType_ID = jni_env->GetMethodID (ccls, "getComponentType", "()Ljava/lang/Class;");
762 
763  dim_vector dv (1, 1);
764  int idx = 0;
765 
766  jobj.detach ();
767  while (jcls && jni_env->CallBooleanMethod (jcls, isArray_ID))
768  {
769  int len = (jobj ? jni_env->GetArrayLength (jobj) : 0);
770  if (idx >= dv.length ())
771  dv.resize (idx+1);
772  dv(idx) = len;
773  jcls = reinterpret_cast<jclass> (jni_env->CallObjectMethod (jcls, getComponentType_ID));
774  jobj = (len > 0 ? reinterpret_cast<jobjectArray> (jni_env->GetObjectArrayElement (jobj, 0)) : 0);
775  idx++;
776  }
777 
778  restore_fpu_state ();
779 
780  return dv;
781 }
782 
783 static jobject
784 make_java_index (JNIEnv* jni_env, const octave_value_list& idx)
785 {
786  jclass_ref ocls (jni_env, jni_env->FindClass ("[I"));
787  jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, 0);
788 
789  for (int i = 0; i < idx.length (); i++)
790  {
791  idx_vector v = idx(i).index_vector ();
792 
793  if (! error_state)
794  {
795  jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ()));
796  jint *buf = jni_env->GetIntArrayElements (i_array, 0);
797 
798  for (int k = 0; k < v.length (); k++)
799  buf[k] = v(k);
800 
801  jni_env->ReleaseIntArrayElements (i_array, buf, 0);
802  jni_env->SetObjectArrayElement (retval, i, i_array);
803 
804  check_exception (jni_env);
805 
806  if (error_state)
807  break;
808  }
809  else
810  break;
811  }
812 
813  return retval;
814 }
815 
816 static octave_value
817 get_array_elements (JNIEnv* jni_env, jobject jobj,
818  const octave_value_list& idx)
819 {
820  octave_value retval;
821  jobject_ref resObj (jni_env);
822  jobject_ref java_idx (jni_env, make_java_index (jni_env, idx));
823 
824  if (! error_state)
825  {
826  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
827  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsref", "(Ljava/lang/Object;[[I)Ljava/lang/Object;");
828  resObj = jni_env->CallStaticObjectMethod (helperClass, mID, jobj, jobject (java_idx));
829  }
830 
831  if (resObj)
832  retval = box (jni_env, resObj);
833  else
834  retval = check_exception (jni_env);
835 
836  restore_fpu_state ();
837 
838  return retval;
839 }
840 
841 static octave_value
842 set_array_elements (JNIEnv* jni_env, jobject jobj,
843  const octave_value_list& idx, const octave_value& rhs)
844 {
845  octave_value retval;
846 
847  jclass_ref rhsCls (jni_env);
848  jobject_ref resObj (jni_env);
849  jobject_ref rhsObj (jni_env);
850  jobject_ref java_idx (jni_env, make_java_index (jni_env, idx));
851 
852  if (! error_state && unbox (jni_env, rhs, rhsObj, rhsCls))
853  {
854  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
855  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsasgn",
856  "(Ljava/lang/Object;[[ILjava/lang/Object;)Ljava/lang/Object;");
857  resObj = jni_env->CallStaticObjectMethod (helperClass, mID,
858  jobj, jobject (java_idx), jobject (rhsObj));
859  }
860 
861  if (resObj)
862  retval = box (jni_env, resObj);
863  else
864  retval = check_exception (jni_env);
865 
866  restore_fpu_state ();
867 
868  return retval;
869 }
870 
871 static string_vector
872 get_invoke_list (JNIEnv* jni_env, jobject jobj)
873 {
874  std::list<std::string> name_list;
875 
876  if (jni_env)
877  {
878  jclass_ref cls (jni_env, jni_env->GetObjectClass (jobj));
879  jclass_ref ccls (jni_env, jni_env->GetObjectClass (cls));
880  jmethodID getMethods_ID = jni_env->GetMethodID (ccls, "getMethods", "()[Ljava/lang/reflect/Method;");
881  jmethodID getFields_ID = jni_env->GetMethodID (ccls, "getFields", "()[Ljava/lang/reflect/Field;");
882  jobjectArray_ref mList (jni_env, reinterpret_cast<jobjectArray> (jni_env->CallObjectMethod (cls, getMethods_ID)));
883  jobjectArray_ref fList (jni_env, reinterpret_cast<jobjectArray> (jni_env->CallObjectMethod (cls, getFields_ID)));
884  int mLen = jni_env->GetArrayLength (mList);
885  int fLen = jni_env->GetArrayLength (fList);
886  jclass_ref mCls (jni_env, jni_env->FindClass ("java/lang/reflect/Method"));
887  jclass_ref fCls (jni_env, jni_env->FindClass ("java/lang/reflect/Field"));
888  jmethodID m_getName_ID = jni_env->GetMethodID (mCls, "getName", "()Ljava/lang/String;");
889  jmethodID f_getName_ID = jni_env->GetMethodID (fCls, "getName", "()Ljava/lang/String;");
890 
891  for (int i = 0; i < mLen; i++)
892  {
893  jobject_ref meth (jni_env, jni_env->GetObjectArrayElement (mList, i));
894  jstring_ref methName (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (meth, m_getName_ID)));
895  name_list.push_back (jstring_to_string (jni_env, methName));
896  }
897 
898  for (int i = 0; i < fLen; i++)
899  {
900  jobject_ref field (jni_env, jni_env->GetObjectArrayElement (fList, i));
901  jstring_ref fieldName (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (field, f_getName_ID)));
902  name_list.push_back (jstring_to_string (jni_env, fieldName));
903  }
904 
905  restore_fpu_state ();
906  }
907 
908  string_vector v (name_list);
909 
910  return v.sort (true);
911 }
912 
913 static octave_value
914 convert_to_string (JNIEnv *jni_env, jobject java_object, bool force, char type)
915 {
916  octave_value retval;
917 
918  if (jni_env && java_object)
919  {
920  jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String"));
921 
922  if (jni_env->IsInstanceOf (java_object, cls))
923  retval = octave_value (jstring_to_string (jni_env, java_object), type);
924  else if (force)
925  {
926  cls = jni_env->FindClass ("[Ljava/lang/String;");
927 
928  if (jni_env->IsInstanceOf (java_object, cls))
929  {
930  jobjectArray array = reinterpret_cast<jobjectArray> (java_object);
931  int len = jni_env->GetArrayLength (array);
932  Cell c (len, 1);
933 
934  for (int i = 0; i < len; i++)
935  {
936  jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->GetObjectArrayElement (array, i)));
937 
938  if (js)
939  c(i) = octave_value (jstring_to_string (jni_env, js), type);
940  else
941  {
942  c(i) = check_exception (jni_env);
943 
944  if (error_state)
945  break;
946  }
947  }
948 
949  retval = octave_value (c);
950  }
951  else
952  {
953  cls = jni_env->FindClass ("java/lang/Object");
954  jmethodID mID = jni_env->GetMethodID (cls, "toString", "()Ljava/lang/String;");
955  jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (java_object, mID)));
956 
957  if (js)
958  retval = octave_value (jstring_to_string (jni_env, js), type);
959  else
960  retval = check_exception (jni_env);
961  }
962  }
963  else
964  error ("unable to convert Java object to string");
965 
966  restore_fpu_state ();
967  }
968 
969  return retval;
970 }
971 
972 #define TO_JAVA(obj) dynamic_cast<octave_java*> ((obj).internal_rep ())
973 
975 box (JNIEnv* jni_env, jobject jobj, jclass jcls)
976 {
977  octave_value retval;
978  jclass_ref cls (jni_env);
979 
980  if (! jobj)
981  retval = Matrix ();
982 
983  while (retval.is_undefined ())
984  {
985  // Convert a scalar of any numeric class (byte, short, integer, long,
986  // float, double) to a double value. Matlab does the same thing.
987  cls = jni_env->FindClass ("java/lang/Number");
988  if (jni_env->IsInstanceOf (jobj, cls))
989  {
990  jmethodID m = jni_env->GetMethodID (cls, "doubleValue", "()D");
991  retval = jni_env->CallDoubleMethod (jobj, m);
992  break;
993  }
994 
995  cls = jni_env->FindClass ("java/lang/Boolean");
996  if (jni_env->IsInstanceOf (jobj, cls))
997  {
998  jmethodID m = jni_env->GetMethodID (cls, "booleanValue", "()Z");
999  retval = (jni_env->CallBooleanMethod (jobj, m) ? true : false);
1000  break;
1001  }
1002 
1003  cls = jni_env->FindClass ("java/lang/String");
1004  if (jni_env->IsInstanceOf (jobj, cls))
1005  {
1006  retval = jstring_to_string (jni_env, jobj);
1007  break;
1008  }
1009 
1010  cls = jni_env->FindClass ("java/lang/Character");
1011  if (jni_env->IsInstanceOf (jobj, cls))
1012  {
1013  jmethodID m = jni_env->GetMethodID (cls, "charValue", "()C");
1014  retval = jni_env->CallCharMethod (jobj, m);
1015  retval = retval.convert_to_str (false, true);
1016  break;
1017  }
1018 
1019  if (Vjava_matrix_autoconversion)
1020  {
1021  cls = find_octave_class (jni_env, "org/octave/Matrix");
1022 
1023  if (jni_env->IsInstanceOf (jobj, cls))
1024  {
1025  jmethodID mID = jni_env->GetMethodID (cls, "getDims", "()[I");
1026  jintArray_ref iv (jni_env, reinterpret_cast<jintArray> (jni_env->CallObjectMethod (jobj, mID)));
1027  jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0);
1028  dim_vector dims;
1029  dims.resize (jni_env->GetArrayLength (jintArray (iv)));
1030 
1031  for (int i = 0; i < dims.length (); i++)
1032  dims(i) = iv_data[i];
1033 
1034  jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0);
1035  mID = jni_env->GetMethodID (cls, "getClassName", "()Ljava/lang/String;");
1036  jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (jobj, mID)));
1037 
1038  std::string s = jstring_to_string (jni_env, js);
1039 
1040  if (s == "double")
1041  {
1042  NDArray m (dims);
1043  mID = jni_env->GetMethodID (cls, "toDouble", "()[D");
1044  jdoubleArray_ref dv (jni_env, reinterpret_cast<jdoubleArray> (jni_env->CallObjectMethod (jobj, mID)));
1045  jni_env->GetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ());
1046  retval = m;
1047  break;
1048  }
1049  else if (s == "byte")
1050  {
1051  if (Vjava_unsigned_autoconversion)
1052  {
1053  uint8NDArray m (dims);
1054  mID = jni_env->GetMethodID (cls, "toByte", "()[B");
1055  jbyteArray_ref dv (jni_env, reinterpret_cast<jbyteArray> (jni_env->CallObjectMethod (jobj, mID)));
1056  jni_env->GetByteArrayRegion (dv, 0, m.length (), reinterpret_cast<jbyte *> (m.fortran_vec ()));
1057  retval = m;
1058  break;
1059  }
1060  else
1061  {
1062  int8NDArray m (dims);
1063  mID = jni_env->GetMethodID (cls, "toByte", "()[B");
1064  jbyteArray_ref dv (jni_env, reinterpret_cast<jbyteArray> (jni_env->CallObjectMethod (jobj, mID)));
1065  jni_env->GetByteArrayRegion (dv, 0, m.length (), reinterpret_cast<jbyte *> (m.fortran_vec ()));
1066  retval = m;
1067  break;
1068  }
1069  }
1070  else if (s == "integer")
1071  {
1072  if (Vjava_unsigned_autoconversion)
1073  {
1074  uint32NDArray m (dims);
1075  mID = jni_env->GetMethodID (cls, "toInt", "()[I");
1076  jintArray_ref dv (jni_env, reinterpret_cast<jintArray> (jni_env->CallObjectMethod (jobj, mID)));
1077  jni_env->GetIntArrayRegion (dv, 0, m.length (), reinterpret_cast<jint *> (m.fortran_vec ()));
1078  retval = m;
1079  break;
1080  }
1081  else
1082  {
1083  int32NDArray m (dims);
1084  mID = jni_env->GetMethodID (cls, "toInt", "()[I");
1085  jintArray_ref dv (jni_env, reinterpret_cast<jintArray> (jni_env->CallObjectMethod (jobj, mID)));
1086  jni_env->GetIntArrayRegion (dv, 0, m.length (), reinterpret_cast<jint *> (m.fortran_vec ()));
1087  retval = m;
1088  break;
1089  }
1090  }
1091  }
1092  }
1093 
1094  cls = find_octave_class (jni_env, "org/octave/OctaveReference");
1095  if (jni_env->IsInstanceOf (jobj, cls))
1096  {
1097  jmethodID mID = jni_env->GetMethodID (cls, "getID", "()I");
1098  int ID = jni_env->CallIntMethod (jobj, mID);
1099  std::map<int,octave_value>::iterator it = octave_ref_map.find (ID);
1100 
1101  if (it != octave_ref_map.end ())
1102  retval = it->second;
1103 
1104  break;
1105  }
1106 
1107  // No suitable class found. Return a generic octave_java object
1108  retval = octave_value (new octave_java (jobj, jcls));
1109  break;
1110  }
1111 
1112  return retval;
1113 }
1114 
1116 box_more (JNIEnv* jni_env, jobject jobj, jclass jcls)
1117 {
1118  octave_value retval = box (jni_env, jobj, jcls);
1119 
1120  if (retval.is_java ())
1121  {
1122  retval = octave_value ();
1123 
1124  jclass_ref cls (jni_env);
1125 
1126  if (retval.is_undefined ())
1127  {
1128  cls = jni_env->FindClass ("[D");
1129 
1130  if (jni_env->IsInstanceOf (jobj, cls))
1131  {
1132  jdoubleArray jarr = reinterpret_cast<jdoubleArray> (jobj);
1133  int len = jni_env->GetArrayLength (jarr);
1134 
1135  if (len > 0)
1136  {
1137  Matrix m (1, len);
1138  jni_env->GetDoubleArrayRegion (jarr, 0, len, m.fortran_vec ());
1139  retval = m;
1140  }
1141  else
1142  retval = Matrix ();
1143  }
1144  }
1145 
1146  if (retval.is_undefined ())
1147  {
1148  cls = jni_env->FindClass ("[[D");
1149 
1150  if (jni_env->IsInstanceOf (jobj, cls))
1151  {
1152  jobjectArray jarr = reinterpret_cast<jobjectArray> (jobj);
1153  int rows = jni_env->GetArrayLength (jarr), cols = 0;
1154 
1155  if (rows > 0)
1156  {
1157  Matrix m;
1158 
1159  for (int r = 0; r < rows; r++)
1160  {
1161  jdoubleArray_ref row (jni_env,
1162  reinterpret_cast<jdoubleArray> (jni_env->GetObjectArrayElement (jarr, r)));
1163 
1164  if (m.length () == 0)
1165  {
1166  cols = jni_env->GetArrayLength (row);
1167  m.resize (cols, rows);
1168  }
1169  jni_env->GetDoubleArrayRegion (row, 0, cols, m.fortran_vec () + r * cols);
1170  }
1171  retval = m.transpose ();
1172  }
1173  else
1174  retval = Matrix ();
1175  }
1176  }
1177 
1178  if (retval.is_undefined ())
1179  {
1180  cls = jni_env->FindClass ("[Ljava/lang/String;");
1181 
1182  if (jni_env->IsInstanceOf (jobj, cls))
1183  {
1184  jobjectArray jarr = reinterpret_cast<jobjectArray> (jobj);
1185  int len = jni_env->GetArrayLength (jarr);
1186  Cell m (len, 1);
1187 
1188  for (int i = 0; i < len; i++)
1189  {
1190  jstring_ref js (jni_env,
1191  reinterpret_cast<jstring> (jni_env->GetObjectArrayElement (jarr, i)));
1192  m(i) = jstring_to_string (jni_env, js);
1193  }
1194 
1195  retval = m;
1196  }
1197  }
1198  }
1199 
1200  if (retval.is_undefined ())
1201  retval = octave_value (new octave_java (jobj, jcls));
1202 
1203  restore_fpu_state ();
1204 
1205  return retval;
1206 }
1207 
1208 int
1209 unbox (JNIEnv* jni_env, const octave_value& val, jobject_ref& jobj,
1210  jclass_ref& jcls)
1211 {
1212  int found = 1;
1213 
1214  if (val.is_java ())
1215  {
1216  octave_java *ovj = TO_JAVA (val);
1217  jobj = ovj->to_java ();
1218  jobj.detach ();
1219  jcls = jni_env->GetObjectClass (jobj);
1220  }
1221  else if (val.is_string ())
1222  {
1223  std::string s = val.string_value ();
1224 
1225  jobj = jni_env->NewStringUTF (s.c_str ());
1226  jcls = jni_env->GetObjectClass (jobj);
1227  }
1228  else if (val.is_real_scalar ())
1229  {
1230  if (val.is_double_type ())
1231  {
1232  double dval = val.double_value ();
1233  jclass_ref dcls (jni_env, jni_env->FindClass ("java/lang/Double"));
1234  jfieldID fid = jni_env->GetStaticFieldID (dcls, "TYPE", "Ljava/lang/Class;");
1235  jmethodID mid = jni_env->GetMethodID (dcls, "<init>", "(D)V");
1236  jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (dcls, fid));
1237  jobj = jni_env->NewObject (dcls, mid, dval);
1238  }
1239  else if (val.is_bool_type ())
1240  {
1241  bool bval = val.bool_value ();
1242  jclass_ref bcls (jni_env, jni_env->FindClass ("java/lang/Boolean"));
1243  jfieldID fid = jni_env->GetStaticFieldID (bcls, "TYPE", "Ljava/lang/Class;");
1244  jmethodID mid = jni_env->GetMethodID (bcls, "<init>", "(Z)V");
1245  jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (bcls, fid));
1246  jobj = jni_env->NewObject (bcls, mid, bval);
1247  }
1248  else
1249  {
1250  float fval = val.float_scalar_value ();
1251  jclass_ref fcls (jni_env, jni_env->FindClass ("java/lang/Float"));
1252  jfieldID fid = jni_env->GetStaticFieldID (fcls, "TYPE", "Ljava/lang/Class;");
1253  jmethodID mid = jni_env->GetMethodID (fcls, "<init>", "(F)V");
1254  jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (fcls, fid));
1255  jobj = jni_env->NewObject (fcls, mid, fval);
1256  }
1257  }
1258  else if (val.is_integer_type () && val.is_scalar_type ())
1259  {
1260  int32_t ival = val.int32_scalar_value ();
1261  jclass_ref icls (jni_env, jni_env->FindClass ("java/lang/Integer"));
1262  jfieldID fid = jni_env->GetStaticFieldID (icls, "TYPE", "Ljava/lang/Class;");
1263  jmethodID mid = jni_env->GetMethodID (icls, "<init>", "(I)V");
1264  jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (icls, fid));
1265  jobj = jni_env->NewObject (icls, mid, ival);
1266  }
1267  else if (val.is_empty ())
1268  {
1269  jobj = 0;
1270  jcls = 0;
1271  //jcls = jni_env->FindClass ("java/lang/Object");
1272  }
1273  else if (!Vjava_matrix_autoconversion
1274  && ((val.is_real_matrix ()
1275  && (val.rows () == 1 || val.columns () == 1))
1276  || val.is_range ()))
1277  {
1278  Matrix m = val.matrix_value ();
1279  jdoubleArray dv = jni_env->NewDoubleArray (m.length ());
1280  jni_env->SetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ());
1281  jobj = dv;
1282  jcls = jni_env->GetObjectClass (jobj);
1283  }
1284  else if (Vjava_matrix_autoconversion
1285  && (val.is_matrix_type () || val.is_range ()) && val.is_real_type ())
1286  {
1287  jclass_ref mcls (jni_env, find_octave_class (jni_env, "org/octave/Matrix"));
1288  dim_vector dims = val.dims ();
1289  jintArray_ref iv (jni_env, jni_env->NewIntArray (dims.length ()));
1290  jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0);
1291 
1292  for (int i = 0; i < dims.length (); i++)
1293  iv_data[i] = dims(i);
1294 
1295  jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0);
1296 
1297  if (val.is_double_type ())
1298  {
1299  NDArray m = val.array_value ();
1300  jdoubleArray_ref dv (jni_env, jni_env->NewDoubleArray (m.length ()));
1301  jni_env->SetDoubleArrayRegion (jdoubleArray (dv), 0, m.length (),
1302  m.fortran_vec ());
1303  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([D[I)V");
1304  jobj = jni_env->NewObject (jclass (mcls), mID, jdoubleArray (dv),
1305  jintArray (iv));
1306  jcls = jni_env->GetObjectClass (jobj);
1307  }
1308  else if (val.is_int8_type ())
1309  {
1310  int8NDArray m = val.int8_array_value ();
1311  jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ()));
1312  jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (),
1313  reinterpret_cast <jbyte *> (m.fortran_vec ()));
1314  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([B[I)V");
1315  jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv));
1316  jcls = jni_env->GetObjectClass (jobj);
1317  }
1318  else if (val.is_uint8_type ())
1319  {
1320  uint8NDArray m = val.uint8_array_value ();
1321  jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ()));
1322  jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (),
1323  reinterpret_cast<jbyte *> (m.fortran_vec ()));
1324  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([B[I)V");
1325  jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv));
1326  jcls = jni_env->GetObjectClass (jobj);
1327  }
1328  else if (val.is_int32_type ())
1329  {
1330  int32NDArray m = val.int32_array_value ();
1331  jintArray_ref v (jni_env, jni_env->NewIntArray (m.length ()));
1332  jni_env->SetIntArrayRegion (jintArray (v), 0, m.length (),
1333  reinterpret_cast<jint *> (m.fortran_vec ()));
1334  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([I[I)V");
1335  jobj = jni_env->NewObject (jclass (mcls), mID, jintArray (v), jintArray (iv));
1336  jcls = jni_env->GetObjectClass (jobj);
1337  }
1338  else
1339  {
1340  found = 0;
1341  error ("cannot convert matrix of type '%s'", val.class_name ().c_str ());
1342  }
1343  }
1344  else if (val.is_cellstr ())
1345  {
1346  Cell cellStr = val.cell_value ();
1347  jclass_ref scls (jni_env, jni_env->FindClass ("java/lang/String"));
1348  jobjectArray array = jni_env->NewObjectArray (cellStr.length (), scls, 0);
1349  for (int i = 0; i < cellStr.length (); i++)
1350  {
1351  jstring_ref jstr (jni_env,
1352  jni_env->NewStringUTF (cellStr(i).string_value().c_str ()));
1353  jni_env->SetObjectArrayElement (array, i, jstr);
1354  }
1355  jobj = array;
1356  jcls = jni_env->GetObjectClass (jobj);
1357  }
1358  else
1359  {
1360  jclass rcls = find_octave_class (jni_env, "org/octave/OctaveReference");
1361  jmethodID mID = jni_env->GetMethodID (rcls, "<init>", "(I)V");
1362  int ID = octave_java_refcount++;
1363 
1364  jobj = jni_env->NewObject (rcls, mID, ID);
1365  jcls = rcls;
1366  octave_ref_map[ID] = val;
1367  }
1368 
1369  return found;
1370 }
1371 
1372 int
1373 unbox (JNIEnv* jni_env, const octave_value_list& args,
1374  jobjectArray_ref& jobjs, jobjectArray_ref& jclss)
1375 {
1376  int found = 1;
1377 
1378  jclass_ref ocls (jni_env, jni_env->FindClass ("java/lang/Object"));
1379  jclass_ref ccls (jni_env, jni_env->FindClass ("java/lang/Class"));
1380 
1381  if (! jobjs)
1382  jobjs = jni_env->NewObjectArray (args.length (), ocls, 0);
1383 
1384  if (! jclss)
1385  jclss = jni_env->NewObjectArray (args.length (), ccls, 0);
1386 
1387  for (int i = 0; i < args.length (); i++)
1388  {
1389  jobject_ref jobj (jni_env);
1390  jclass_ref jcls (jni_env);
1391 
1392  if (! unbox (jni_env, args(i), jobj, jcls))
1393  {
1394  found = 0;
1395  break;
1396  }
1397 
1398  jni_env->SetObjectArrayElement (jobjs, i, jobj);
1399  jni_env->SetObjectArrayElement (jclss, i, jcls);
1400  }
1401 
1402  return found;
1403 }
1404 
1405 static long
1406 get_current_thread_ID (JNIEnv *jni_env)
1407 {
1408  if (jni_env)
1409  {
1410  jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/Thread"));
1411  jmethodID mID = jni_env->GetStaticMethodID (cls, "currentThread", "()Ljava/lang/Thread;");
1412  jobject_ref jthread (jni_env, jni_env->CallStaticObjectMethod (cls, mID));
1413 
1414  if (jthread)
1415  {
1416  jclass_ref jth_cls (jni_env, jni_env->GetObjectClass (jthread));
1417  mID = jni_env->GetMethodID (jth_cls, "getId", "()J");
1418  long result = jni_env->CallLongMethod (jthread, mID);
1419  //printf ("current java thread ID = %ld\n", result);
1420  return result;
1421  }
1422  }
1423 
1424  return -1;
1425 }
1426 
1427 static int
1428 java_event_hook (void)
1429 {
1430  JNIEnv *current_env = octave_java::thread_jni_env ();
1431 
1432  if (current_env)
1433  {
1434  jclass_ref cls (current_env, find_octave_class (current_env, "org/octave/Octave"));
1435  jmethodID mID = current_env->GetStaticMethodID (cls, "checkPendingAction", "()V");
1436  current_env->CallStaticVoidMethod (cls, mID);
1437 
1438  restore_fpu_state ();
1439  }
1440 
1441  return 0;
1442 }
1443 
1444 static void
1445 initialize_java (void)
1446 {
1447  if (! jvm)
1448  {
1449  try
1450  {
1451  initialize_jvm ();
1452 
1453  JNIEnv *current_env = octave_java::thread_jni_env ();
1454 
1455  command_editor::add_event_hook (java_event_hook);
1456 
1457  octave_thread_ID = get_current_thread_ID (current_env);
1458  //printf ("octave thread ID=%ld\n", octave_thread_ID);
1459  }
1460  catch (std::string msg)
1461  {
1462  error (msg.c_str ());
1463  }
1464 
1465  restore_fpu_state ();
1466  }
1467 }
1468 
1469 JNIEXPORT jboolean JNICALL
1470 Java_org_octave_Octave_call (JNIEnv *env, jclass, jstring funcName,
1471  jobjectArray argin, jobjectArray argout)
1472 {
1473  std::string fname = jstring_to_string (env, funcName);
1474 
1475  int nargout = env->GetArrayLength (argout);
1476  int nargin = env->GetArrayLength (argin);
1477 
1478  octave_value_list varargin, varargout;
1479 
1480  for (int i = 0; i < nargin; i++)
1481  varargin(i) = box (env, env->GetObjectArrayElement (argin, i), 0);
1482 
1483  varargout = feval (fname, varargin, nargout);
1484 
1485  if (! error_state)
1486  {
1487  jobjectArray_ref out_objs (env, argout), out_clss (env);
1488 
1489  out_objs.detach ();
1490 
1491  if (unbox (env, varargout, out_objs, out_clss))
1492  return true;
1493  }
1494 
1495  return false;
1496 }
1497 
1498 JNIEXPORT void JNICALL
1499 Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint ID)
1500 {
1501  octave_ref_map.erase (ID);
1502 }
1503 
1504 JNIEXPORT void JNICALL
1505 Java_org_octave_Octave_doInvoke (JNIEnv *env, jclass, jint ID,
1506  jobjectArray args)
1507 {
1508  std::map<int,octave_value>::iterator it = octave_ref_map.find (ID);
1509 
1510  if (it != octave_ref_map.end ())
1511  {
1512  octave_value val = it->second;
1513  int len = env->GetArrayLength (args);
1514  octave_value_list oct_args;
1515 
1516  for (int i = 0; i < len; i++)
1517  {
1518  jobject_ref jobj (env, env->GetObjectArrayElement (args, i));
1519  oct_args(i) = box (env, jobj, 0);
1520 
1521  if (error_state)
1522  break;
1523  }
1524 
1525  if (! error_state)
1526  {
1527  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
1528 
1529  if (val.is_function_handle ())
1530  {
1531  octave_function *fcn = val.function_value ();
1532  feval (fcn, oct_args);
1533  }
1534  else if (val.is_cell () && val.length () > 0
1535  && (val.rows () == 1 || val.columns () == 1)
1536  && val.cell_value()(0).is_function_handle ())
1537  {
1538  Cell c = val.cell_value ();
1539  octave_function *fcn = c(0).function_value ();
1540 
1541  for (int i=1; i<c.length (); i++)
1542  oct_args(len+i-1) = c(i);
1543 
1544  if (! error_state)
1545  feval (fcn, oct_args);
1546  }
1547  else
1548  error ("trying to invoke non-invocable object");
1549 
1550  END_INTERRUPT_WITH_EXCEPTIONS;
1551  }
1552  }
1553 }
1554 
1555 JNIEXPORT void JNICALL
1556 Java_org_octave_Octave_doEvalString (JNIEnv *env, jclass, jstring cmd)
1557 {
1558  std::string s = jstring_to_string (env, cmd);
1559  int pstatus;
1560  eval_string (s, false, pstatus, 0);
1561 }
1562 
1563 JNIEXPORT jboolean JNICALL
1564 Java_org_octave_Octave_needThreadedInvokation (JNIEnv *env, jclass)
1565 {
1566  return (get_current_thread_ID (env) != octave_thread_ID);
1567 }
1568 
1569 // octave_java class definition
1570 
1572 
1573 int octave_java::t_id (-1);
1574 
1575 const std::string octave_java::t_name ("octave_java");
1576 
1577 void
1579 {
1581  (octave_java::t_name, "<unknown>", octave_value (new octave_java ()));
1582 }
1583 
1584 dim_vector
1585 octave_java::dims (void) const
1586 {
1587  JNIEnv *current_env = thread_jni_env ();
1588 
1589  if (current_env && java_object)
1590  return compute_array_dimensions (current_env, java_object);
1591  else
1592  return dim_vector (1, 1);
1593 }
1594 
1595 JNIEnv *
1597 {
1598  JNIEnv *env = 0;
1599 
1600  if (jvm)
1601  jvm->GetEnv (reinterpret_cast<void **> (&env), JNI_VERSION_1_2);
1602 
1603  return env;
1604 }
1605 
1607 octave_java::subsref (const std::string& type,
1608  const std::list<octave_value_list>& idx, int nargout)
1609 {
1610  octave_value_list retval;
1611  int skip = 1;
1612 
1613  JNIEnv *current_env = thread_jni_env ();
1614 
1615  switch (type[0])
1616  {
1617  case '.':
1618  if (type.length () > 1 && type[1] == '(')
1619  {
1621  count++;
1622  ovl(1) = octave_value (this);
1623  ovl(0) = (idx.front ())(0);
1624  std::list<octave_value_list>::const_iterator it = idx.begin ();
1625  ovl.append (*++it);
1626  retval = feval (std::string ("javaMethod"), ovl, 1);
1627  skip++;
1628  }
1629  else
1630  {
1632  count++;
1633  ovl(0) = octave_value (this);
1634  ovl(1) = (idx.front ())(0);
1635  retval = feval (std::string ("__java_get__"), ovl, 1);
1636  }
1637  break;
1638 
1639  case '(':
1640  if (current_env)
1641  retval = get_array_elements (current_env, to_java (), idx.front ());
1642  break;
1643 
1644  default:
1645  error ("subsref: Java object cannot be indexed with %c", type[0]);
1646  break;
1647  }
1648 
1649  if (idx.size () > 1 && type.length () > 1)
1650  retval = retval(0).next_subsref (nargout, type, idx, skip);
1651 
1652  return retval;
1653 }
1654 
1656 octave_java::subsasgn (const std::string& type,
1657  const std::list<octave_value_list>&idx,
1658  const octave_value &rhs)
1659 {
1660  octave_value retval;
1661 
1662  JNIEnv *current_env = thread_jni_env ();
1663 
1664  switch (type[0])
1665  {
1666  case '.':
1667  if (type.length () == 1)
1668  {
1669  // field assignment
1671  count++;
1672  ovl(0) = octave_value (this);
1673  ovl(1) = (idx.front ())(0);
1674  ovl(2) = rhs;
1675  feval ("__java_set__", ovl, 0);
1676  if (! error_state)
1677  {
1678  count++;
1679  retval = octave_value (this);
1680  }
1681  }
1682  else if (type.length () > 2 && type[1] == '(')
1683  {
1684  std::list<octave_value_list> new_idx;
1685  std::list<octave_value_list>::const_iterator it = idx.begin ();
1686  new_idx.push_back (*it++);
1687  new_idx.push_back (*it++);
1688  octave_value_list u = subsref (type.substr (0, 2), new_idx, 1);
1689  if (! error_state)
1690  {
1691  std::list<octave_value_list> next_idx (idx);
1692  next_idx.erase (next_idx.begin ());
1693  next_idx.erase (next_idx.begin ());
1694  u(0).subsasgn (type.substr (2), next_idx, rhs);
1695  if (! error_state)
1696  {
1697  count++;
1698  retval = octave_value (this);
1699  }
1700  }
1701  }
1702  else if (type[1] == '.')
1703  {
1704  octave_value_list u = subsref (type.substr (0, 1), idx, 1);
1705  if (! error_state)
1706  {
1707  std::list<octave_value_list> next_idx (idx);
1708  next_idx.erase (next_idx.begin ());
1709  u(0).subsasgn (type.substr (1), next_idx, rhs);
1710  if (! error_state)
1711  {
1712  count++;
1713  retval = octave_value (this);
1714  }
1715  }
1716  }
1717  else
1718  error ("invalid indexing/assignment on Java object");
1719  break;
1720 
1721  case '(':
1722  if (current_env)
1723  {
1724  set_array_elements (current_env, to_java (), idx.front (), rhs);
1725  if (! error_state)
1726  {
1727  count++;
1728  retval = octave_value (this);
1729  }
1730  }
1731  break;
1732 
1733  default:
1734  error ("Java object cannot be indexed with %c", type[0]);
1735  break;
1736  }
1737 
1738  return retval;
1739 }
1740 
1742 octave_java::map_keys (void) const
1743 {
1744  JNIEnv *current_env = thread_jni_env ();
1745 
1746  if (current_env)
1747  return get_invoke_list (current_env, to_java ());
1748  else
1749  return string_vector ();
1750 }
1751 
1753 octave_java::convert_to_str_internal (bool, bool force, char type) const
1754 {
1755  JNIEnv *current_env = thread_jni_env ();
1756 
1757  if (current_env)
1758  return convert_to_string (current_env, to_java (), force, type);
1759  else
1760  return octave_value ("");
1761 }
1762 
1763 void
1764 octave_java::print (std::ostream& os, bool) const
1765 {
1766  print_raw (os);
1767  newline (os);
1768 }
1769 
1770 void
1771 octave_java::print_raw (std::ostream& os, bool) const
1772 {
1773  os << "<Java object: " << java_classname << ">";
1774 }
1775 
1777 octave_java::do_javaMethod (JNIEnv* jni_env, const std::string& name,
1778  const octave_value_list& args)
1779 {
1780  octave_value retval;
1781 
1782  if (jni_env)
1783  {
1784  jobjectArray_ref arg_objs (jni_env), arg_types (jni_env);
1785  if (unbox (jni_env, args, arg_objs, arg_types))
1786  {
1787  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
1788  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeMethod",
1789  "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;");
1790  jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ()));
1791  jobjectArray_ref resObj (jni_env, reinterpret_cast<jobjectArray> (jni_env->CallStaticObjectMethod (helperClass, mID,
1792  to_java (), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types))));
1793  if (resObj)
1794  retval = box (jni_env, resObj);
1795  else
1796  retval = check_exception (jni_env);
1797  }
1798 
1799  restore_fpu_state ();
1800  }
1801 
1802  return retval;
1803 }
1804 
1806 octave_java:: do_javaMethod (JNIEnv* jni_env,
1807  const std::string& class_name,
1808  const std::string& name,
1809  const octave_value_list& args)
1810 {
1811  octave_value retval;
1812 
1813  if (jni_env)
1814  {
1815  jobjectArray_ref arg_objs (jni_env), arg_types (jni_env);
1816  if (unbox (jni_env, args, arg_objs, arg_types))
1817  {
1818  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
1819  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeStaticMethod",
1820  "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;");
1821  jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ()));
1822  jstring_ref clsName (jni_env, jni_env->NewStringUTF (class_name.c_str ()));
1823  jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID,
1824  jstring (clsName), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types)));
1825  if (resObj)
1826  retval = box (jni_env, resObj);
1827  else
1828  retval = check_exception (jni_env);
1829  }
1830 
1831  restore_fpu_state ();
1832  }
1833 
1834  return retval;
1835 }
1836 
1838 octave_java::do_javaObject (JNIEnv* jni_env, const std::string& name,
1839  const octave_value_list& args)
1840 {
1841  octave_value retval;
1842 
1843  if (jni_env)
1844  {
1845  jobjectArray_ref arg_objs (jni_env), arg_types (jni_env);
1846 
1847  if (unbox (jni_env, args, arg_objs, arg_types))
1848  {
1849  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
1850  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeConstructor",
1851  "(Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;");
1852  jstring_ref clsName (jni_env, jni_env->NewStringUTF (name.c_str ()));
1853  jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID,
1854  jstring (clsName), jobjectArray (arg_objs), jobjectArray (arg_types)));
1855 
1856  if (resObj)
1857  retval = octave_value (new octave_java (resObj, 0));
1858  else
1859  check_exception (jni_env);
1860  }
1861 
1862  restore_fpu_state ();
1863  }
1864 
1865  return retval;
1866 }
1867 
1869 octave_java::do_java_get (JNIEnv* jni_env, const std::string& name)
1870 {
1871  octave_value retval;
1872 
1873  if (jni_env)
1874  {
1875  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
1876  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getField",
1877  "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");
1878  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
1879  jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID,
1880  to_java (), jstring (fName)));
1881 
1882  if (resObj)
1883  retval = box (jni_env, resObj);
1884  else
1885  retval = check_exception (jni_env);
1886 
1887  restore_fpu_state ();
1888  }
1889 
1890  return retval;
1891 }
1892 
1894 octave_java::do_java_get (JNIEnv* jni_env, const std::string& class_name,
1895  const std::string& name)
1896 {
1897  octave_value retval;
1898 
1899  if (jni_env)
1900  {
1901  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
1902  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getStaticField",
1903  "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
1904  jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ()));
1905  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
1906  jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID,
1907  jstring (cName), jstring (fName)));
1908  if (resObj)
1909  retval = box (jni_env, resObj);
1910  else
1911  retval = check_exception (jni_env);
1912 
1913  restore_fpu_state ();
1914  }
1915 
1916  return retval;
1917 }
1918 
1920 octave_java::do_java_set (JNIEnv* jni_env, const std::string& name,
1921  const octave_value& val)
1922 {
1923  octave_value retval;
1924 
1925  if (jni_env)
1926  {
1927  jobject_ref jobj (jni_env);
1928  jclass_ref jcls (jni_env);
1929 
1930  if (unbox (jni_env, val, jobj, jcls))
1931  {
1932  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
1933  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setField",
1934  "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");
1935  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
1936  jni_env->CallStaticObjectMethod (helperClass, mID, to_java (), jstring (fName), jobject (jobj));
1937  check_exception (jni_env);
1938  }
1939 
1940  restore_fpu_state ();
1941  }
1942 
1943  return retval;
1944 }
1945 
1947 octave_java::do_java_set (JNIEnv* jni_env, const std::string& class_name,
1948  const std::string& name, const octave_value& val)
1949 {
1950  octave_value retval;
1951 
1952  if (jni_env)
1953  {
1954  jobject_ref jobj (jni_env);
1955  jclass_ref jcls (jni_env);
1956 
1957  if (unbox (jni_env, val, jobj, jcls))
1958  {
1959  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
1960  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setStaticField",
1961  "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V");
1962  jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ()));
1963  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
1964  jni_env->CallStaticObjectMethod (helperClass, mID, jstring (cName), jstring (fName), jobject (jobj));
1965  check_exception (jni_env);
1966  }
1967 
1968  restore_fpu_state ();
1969  }
1970 
1971  return retval;
1972 }
1973 
1974 #endif // endif on HAVE_JAVA
1975 
1976 // DEFUN blocks below must be outside of HAVE_JAVA block so that
1977 // documentation strings are always available, even when functions are not.
1978 
1979 DEFUN (__java_init__, , ,
1980  "-*- texinfo -*-\n\
1981 @deftypefn {Built-in Function} {} java_init ()\n\
1982 Internal function used @strong{only} when debugging Java interface.\n\
1983 Function will directly call initialize_java() to create an instance of a JVM.\n\
1984 @end deftypefn")
1985 {
1986 
1987 #ifdef HAVE_JAVA
1988  octave_value retval;
1989 
1990  retval = 0;
1991 
1992  initialize_java ();
1993 
1994  if (! error_state)
1995  retval = 1;
1996 
1997  return retval;
1998 #else
1999  error ("__java_init__: Octave was not compiled with Java interface");
2000  return octave_value ();
2001 #endif
2002 }
2003 
2004 DEFUN (__java_exit__, , ,
2005  "-*- texinfo -*-\n\
2006 @deftypefn {Built-in Function} {} java_exit ()\n\
2007 Internal function used @strong{only} when debugging Java interface.\n\
2008 Function will directly call terminate_jvm() to destroy the current JVM\n\
2009 instance.\n\
2010 @end deftypefn")
2011 {
2012 #ifdef HAVE_JAVA
2013  terminate_jvm ();
2014 #else
2015  error ("__java_init__: Octave was not compiled with Java interface");
2016 #endif
2017 
2018  return octave_value ();
2019 }
2020 
2021 DEFUN (javaObject, args, ,
2022  "-*- texinfo -*-\n\
2023 @deftypefn {Built-in Function} {@var{jobj} =} javaObject (@var{classname})\n\
2024 @deftypefnx {Built-in Function} {@var{jobj} =} javaObject (@var{classname}, @var{arg1}, @dots{})\n\
2025 Create a Java object of class @var{classsname}, by calling the class\n\
2026 constructor with the arguments @var{arg1}, @dots{}\n\
2027 \n\
2028 The first example below creates an uninitialized object,\n\
2029 while the second example supplies an initial argument to the constructor.\n\
2030 \n\
2031 @example\n\
2032 @group\n\
2033 x = javaObject (\"java.lang.StringBuffer\")\n\
2034 x = javaObject (\"java.lang.StringBuffer\", \"Initial string\")\n\
2035 @end group\n\
2036 @end example\n\
2037 \n\
2038 @seealso{javaMethod, javaArray}\n\
2039 @end deftypefn")
2040 {
2041 #ifdef HAVE_JAVA
2042  octave_value retval;
2043 
2044  initialize_java ();
2045 
2046  if (! error_state)
2047  {
2048  JNIEnv *current_env = octave_java::thread_jni_env ();
2049 
2050  if (args.length () > 0)
2051  {
2052  std::string classname = args(0).string_value ();
2053  if (! error_state)
2054  {
2055  octave_value_list tmp;
2056  for (int i=1; i<args.length (); i++)
2057  tmp(i-1) = args(i);
2058  retval = octave_java::do_javaObject (current_env, classname, tmp);
2059  }
2060  else
2061  error ("javaObject: CLASSNAME must be a string");
2062  }
2063  else
2064  print_usage ();
2065  }
2066 
2067  return retval;
2068 #else
2069  error ("javaObject: Octave was not compiled with Java interface");
2070  return octave_value ();
2071 #endif
2072 }
2073 
2074 /*
2075 %!testif HAVE_JAVA
2076 %% The tests below merely check if javaObject works at all. Whether it works
2077 %% properly, i.e. creates the right values, is a matter of Java itself
2078 %% Create a Short and check if it really is a short, i.e. whether it overflows
2079 %! assert (javaObject ("java.lang.Short", 40000).doubleValue < 0);
2080 */
2081 
2082 DEFUN (javaMethod, args, ,
2083  "-*- texinfo -*-\n\
2084 @deftypefn {Built-in Function} {@var{ret} =} javaMethod (@var{methodname}, @var{obj})\n\
2085 @deftypefnx {Built-in Function} {@var{ret} =} javaMethod (@var{methodname}, @var{obj}, @var{arg1}, @dots{})\n\
2086 Invoke the method @var{methodname} on the Java object @var{obj} with the\n\
2087 arguments @var{arg1}, @dots{} For static methods, @var{obj} can be a string\n\
2088 representing the fully qualified name of the corresponding class. The\n\
2089 function returns the result of the method invocation.\n\
2090 \n\
2091 When @var{obj} is a regular Java object, structure-like indexing can be\n\
2092 used as a shortcut syntax. For instance, the two following statements are\n\
2093 equivalent\n\
2094 \n\
2095 @example\n\
2096 @group\n\
2097  ret = javaMethod (\"method1\", x, 1.0, \"a string\")\n\
2098  ret = x.method1 (1.0, \"a string\")\n\
2099 @end group\n\
2100 @end example\n\
2101 \n\
2102 @seealso{methods, javaObject}\n\
2103 @end deftypefn")
2104 {
2105 #ifdef HAVE_JAVA
2106  octave_value retval;
2107 
2108  initialize_java ();
2109 
2110  if (! error_state)
2111  {
2112  JNIEnv *current_env = octave_java::thread_jni_env ();
2113 
2114  if (args.length () > 1)
2115  {
2116  std::string methodname = args(0).string_value ();
2117  if (! error_state)
2118  {
2119  octave_value_list tmp;
2120  for (int i=2; i<args.length (); i++)
2121  tmp(i-2) = args(i);
2122 
2123  if (args(1).is_java ())
2124  {
2125  octave_java *jobj = TO_JAVA (args(1));
2126  retval = jobj->do_javaMethod (current_env, methodname, tmp);
2127  }
2128  else if (args(1).is_string ())
2129  {
2130  std::string cls = args(1).string_value ();
2131  retval = octave_java::do_javaMethod (current_env, cls, methodname, tmp);
2132  }
2133  else
2134  error ("javaMethod: OBJ must be a Java object or a string");
2135  }
2136  else
2137  error ("javaMethod: METHODNAME must be a string");
2138  }
2139  else
2140  print_usage ();
2141  }
2142 
2143  return retval;
2144 #else
2145  error ("javaMethod: Octave was not compiled with Java interface");
2146  return octave_value ();
2147 #endif
2148 }
2149 
2150 /*
2151 %!testif HAVE_JAVA
2152 %% Check for valid first two Java version numbers
2153 %! jver = strsplit (javaMethod ('getProperty', 'java.lang.System', 'java.version'), '.');
2154 %! assert (isfinite (str2double (jver{1})) && isfinite (str2double (jver{2})));
2155 */
2156 
2157 DEFUN (__java_get__, args, ,
2158  "-*- texinfo -*-\n\
2159 @deftypefn {Built-in Function} {@var{val} =} __java_get__ (@var{obj}, @var{name})\n\
2160 Get the value of the field @var{name} of the Java object @var{obj}. For\n\
2161 static fields, @var{obj} can be a string representing the fully qualified\n\
2162 name of the corresponding class.\n\
2163 \n\
2164 When @var{obj} is a regular Java object, structure-like indexing can be\n\
2165 used as a shortcut syntax. For instance, the two following statements are\n\
2166 equivalent\n\
2167 \n\
2168 @example\n\
2169 @group\n\
2170  __java_get__ (x, \"field1\")\n\
2171  x.field1\n\
2172 @end group\n\
2173 @end example\n\
2174 \n\
2175 @seealso{__java_set__, javaMethod, javaObject}\n\
2176 @end deftypefn")
2177 {
2178 #ifdef HAVE_JAVA
2179  octave_value retval;
2180 
2181  initialize_java ();
2182 
2183  if (! error_state)
2184  {
2185  JNIEnv *current_env = octave_java::thread_jni_env ();
2186 
2187  if (args.length () == 2)
2188  {
2189  std::string name = args(1).string_value ();
2190  if (! error_state)
2191  {
2192  if (args(0).is_java ())
2193  {
2194  octave_java *jobj = TO_JAVA (args(0));
2195  retval = jobj->do_java_get (current_env, name);
2196  }
2197  else if (args(0).is_string ())
2198  {
2199  std::string cls = args(0).string_value ();
2200  retval = octave_java::do_java_get (current_env, cls, name);
2201  }
2202  else
2203  error ("__java_get__: OBJ must be a Java object or a string");
2204  }
2205  else
2206  error ("__java_get__: NAME must be a string");
2207  }
2208  else
2209  print_usage ();
2210  }
2211 
2212  return retval;
2213 #else
2214  error ("__java_get__: Octave was not compiled with Java interface");
2215  return octave_value ();
2216 #endif
2217 }
2218 
2219 DEFUN (__java_set__, args, ,
2220  "-*- texinfo -*-\n\
2221 @deftypefn {Built-in Function} {@var{obj} =} __java_set__ (@var{obj}, @var{name}, @var{val})\n\
2222 Set the value of the field @var{name} of the Java object @var{obj} to\n\
2223 @var{val}. For static fields, @var{obj} can be a string representing the\n\
2224 fully qualified named of the corresponding Java class.\n\
2225 \n\
2226 When @var{obj} is a regular Java object, structure-like indexing can be\n\
2227 used as a shortcut syntax. For instance, the two following statements are\n\
2228 equivalent\n\
2229 \n\
2230 @example\n\
2231 @group\n\
2232  __java_set__ (x, \"field1\", val)\n\
2233  x.field1 = val\n\
2234 @end group\n\
2235 @end example\n\
2236 \n\
2237 @seealso{__java_get__, javaMethod, javaObject}\n\
2238 @end deftypefn")
2239 {
2240 #ifdef HAVE_JAVA
2241  octave_value retval;
2242 
2243  initialize_java ();
2244 
2245  if (! error_state)
2246  {
2247  JNIEnv *current_env = octave_java::thread_jni_env ();
2248 
2249  if (args.length () == 3)
2250  {
2251  std::string name = args(1).string_value ();
2252  if (! error_state)
2253  {
2254  if (args(0).is_java ())
2255  {
2256  octave_java *jobj = TO_JAVA (args(0));
2257  retval = jobj->do_java_set (current_env, name, args(2));
2258  }
2259  else if (args(0).is_string ())
2260  {
2261  std::string cls = args(0).string_value ();
2262  retval = octave_java::do_java_set (current_env, cls, name, args(2));
2263  }
2264  else
2265  error ("__java_set__: OBJ must be a Java object or a string");
2266  }
2267  else
2268  error ("__java_set__: NAME must be a string");
2269  }
2270  else
2271  print_usage ();
2272  }
2273 
2274  return retval;
2275 #else
2276  error ("__java_set__: Octave was not compiled with Java interface");
2277  return octave_value ();
2278 #endif
2279 }
2280 
2281 DEFUN (java2mat, args, ,
2282  "-*- texinfo -*-\n\
2283 @deftypefn {Built-in Function} {} java2mat (@var{javaobj})\n\
2284 Undocumented internal function.\n\
2285 @end deftypefn")
2286 {
2287 #ifdef HAVE_JAVA
2288  octave_value_list retval;
2289 
2290  initialize_java ();
2291 
2292  if (! error_state)
2293  {
2294  JNIEnv *current_env = octave_java::thread_jni_env ();
2295 
2296  if (args.length () == 1)
2297  {
2298  if (args(0).is_java ())
2299  {
2300  octave_java *jobj = TO_JAVA (args(0));
2301  retval(0) = box_more (current_env, jobj->to_java (), 0);
2302  }
2303  else
2304  retval(0) = args(0);
2305  }
2306  else
2307  print_usage ();
2308  }
2309 
2310  return retval;
2311 #else
2312  error ("java2mat: Octave was not compiled with Java interface");
2313  return octave_value ();
2314 #endif
2315 }
2316 
2317 DEFUN (java_matrix_autoconversion, args, nargout,
2318  "-*- texinfo -*-\n\
2319 @deftypefn {Built-in Function} {@var{val} =} java_matrix_autoconversion ()\n\
2320 @deftypefnx {Built-in Function} {@var{old_val} =} java_matrix_autoconversion (@var{new_val})\n\
2321 @deftypefnx {Built-in Function} {} java_matrix_autoconversion (@var{new_val}, \"local\")\n\
2322 Query or set the internal variable that controls whether Java arrays are\n\
2323 automatically converted to Octave matrices. The default value is false.\n\
2324 \n\
2325 When called from inside a function with the @qcode{\"local\"} option, the\n\
2326 variable is changed locally for the function and any subroutines it calls. \n\
2327 The original variable value is restored when exiting the function.\n\
2328 @seealso{java_unsigned_autoconversion, debug_java}\n\
2329 @end deftypefn")
2330 {
2331 #ifdef HAVE_JAVA
2332  return SET_INTERNAL_VARIABLE (java_matrix_autoconversion);
2333 #else
2334  error ("java_matrix_autoconversion: Octave was not compiled with Java interface");
2335  return octave_value ();
2336 #endif
2337 }
2338 
2339 DEFUN (java_unsigned_autoconversion, args, nargout,
2340  "-*- texinfo -*-\n\
2341 @deftypefn {Built-in Function} {@var{val} =} java_unsigned_autoconversion ()\n\
2342 @deftypefnx {Built-in Function} {@var{old_val} =} java_unsigned_autoconversion (@var{new_val})\n\
2343 @deftypefnx {Built-in Function} {} java_unsigned_autoconversion (@var{new_val}, \"local\")\n\
2344 Query or set the internal variable that controls how integer classes are\n\
2345 converted when @code{java_matrix_autoconversion} is enabled. When enabled,\n\
2346 Java arrays of class Byte or Integer are converted to matrices of class\n\
2347 uint8 or uint32 respectively. The default value is true.\n\
2348 \n\
2349 When called from inside a function with the @qcode{\"local\"} option, the\n\
2350 variable is changed locally for the function and any subroutines it calls. \n\
2351 The original variable value is restored when exiting the function.\n\
2352 @seealso{java_matrix_autoconversion, debug_java}\n\
2353 @end deftypefn")
2354 {
2355 #ifdef HAVE_JAVA
2356  return SET_INTERNAL_VARIABLE (java_unsigned_autoconversion);
2357 #else
2358  error ("java_unsigned_autoconversion: Octave was not compiled with Java interface");
2359  return octave_value ();
2360 #endif
2361 }
2362 
2363 DEFUN (debug_java, args, nargout,
2364  "-*- texinfo -*-\n\
2365 @deftypefn {Built-in Function} {@var{val} =} debug_java ()\n\
2366 @deftypefnx {Built-in Function} {@var{old_val} =} debug_java (@var{new_val})\n\
2367 @deftypefnx {Built-in Function} {} debug_java (@var{new_val}, \"local\")\n\
2368 Query or set the internal variable that determines whether extra debugging\n\
2369 information regarding the initialization of the JVM and any Java exceptions\n\
2370 is printed.\n\
2371 \n\
2372 When called from inside a function with the @qcode{\"local\"} option, the\n\
2373 variable is changed locally for the function and any subroutines it calls. \n\
2374 The original variable value is restored when exiting the function.\n\
2375 @seealso{java_matrix_autoconversion, java_unsigned_autoconversion}\n\
2376 @end deftypefn")
2377 {
2378 #ifdef HAVE_JAVA
2379  return SET_INTERNAL_VARIABLE (debug_java);
2380 #else
2381  error ("debug_java: Octave was not compiled with Java interface");
2382  return octave_value ();
2383 #endif
2384 }
2385 
2386 // Outside of #ifdef HAVE_JAVA because it is desirable to be able to
2387 // test for the presence of a Java object without having Java installed.
2388 DEFUN (isjava, args, ,
2389  "-*- texinfo -*-\n\
2390 @deftypefn {Built-in Function} {} isjava (@var{x})\n\
2391 Return true if @var{x} is a Java object.\n\
2392 @seealso{class, typeinfo, isa, javaObject}\n\
2393 @end deftypefn")
2394 {
2395  octave_value retval;
2396 
2397  if (args.length () != 1)
2398  print_usage ();
2399  else
2400  retval = args(0).is_java ();
2401 
2402  return retval;
2403 }
2404