GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-java.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2007-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 
24 //! @file ov-java.cc
25 //!
26 //! Provides Octave's Java interface.
27 
28 #if defined (HAVE_CONFIG_H)
29 # include "config.h"
30 #endif
31 
32 #if defined (HAVE_WINDOWS_H)
33 # include <windows.h>
34 #endif
35 
36 #include <algorithm>
37 #include <map>
38 #include <iostream>
39 #include <fstream>
40 #include <string>
41 #include <vector>
42 
43 #include <clocale>
44 
45 #include "Cell.h"
46 #include "builtin-defun-decls.h"
47 #include "cmd-edit.h"
48 #include "defaults.h"
49 #include "defun.h"
50 #include "error.h"
51 #include "errwarn.h"
52 #include "file-ops.h"
53 #include "file-stat.h"
54 #include "fpucw-wrappers.h"
55 #include "load-path.h"
56 #include "oct-env.h"
57 #include "oct-shlib.h"
58 #include "ov-java.h"
59 #include "parse.h"
60 #include "variables.h"
61 
62 #if defined (HAVE_JAVA)
63 #include <jni.h>
64 #endif
65 
66 #if defined (HAVE_JAVA)
67 
68 #define TO_JOBJECT(obj) reinterpret_cast<jobject> (obj)
69 #define TO_JCLASS(obj) reinterpret_cast<jclass> (obj)
70 
71 #define TO_JNIENV(env) reinterpret_cast<JNIEnv *> (env)
72 
73 typedef jint (JNICALL *JNI_CreateJavaVM_t) (JavaVM **pvm, JNIEnv **penv,
74  void *args);
75 
76 typedef jint (JNICALL *JNI_GetCreatedJavaVMs_t) (JavaVM **pvm, jsize bufLen,
77  jsize *nVMs);
78 
79 template <typename T>
81 {
82 public:
83 
84  java_local_ref (JNIEnv *_env)
85  : jobj (nullptr), detached (false), env (_env) { }
86 
87  java_local_ref (JNIEnv *_env, T obj)
88  : jobj (obj), detached (false), env (_env) { }
89 
90  ~java_local_ref (void) { release (); }
91 
92  T& operator = (T obj)
93  {
94  release ();
95 
96  jobj = obj;
97  detached = false;
98 
99  return jobj;
100  }
101 
102  operator bool () const { return (jobj != 0); }
103  operator T () { return jobj; }
104 
105  void detach (void) { detached = true; }
106 
107 private:
108 
109  void release (void)
110  {
111  if (env && jobj && ! detached)
112  env->DeleteLocalRef (jobj);
113 
114  jobj = nullptr;
115  }
116 
118  : jobj (0), detached (false), env (0)
119  { }
120 
121 protected:
122 
123  T jobj;
124  bool detached;
125  JNIEnv *env;
126 };
127 
136 
137 static std::string
138 jstring_to_string (JNIEnv *jni_env, jstring s);
139 
140 static std::string
141 jstring_to_string (JNIEnv *jni_env, jobject obj);
142 
143 static octave_value
144 box (JNIEnv *jni_env, void *jobj, void *jcls_arg = nullptr);
145 
146 static octave_value
147 box_more (JNIEnv *jni_env, void *jobj_arg, void *jcls_arg = nullptr);
148 
149 static bool
150 unbox (JNIEnv *jni_env, const octave_value& val, jobject_ref& jobj,
151  jclass_ref& jcls);
152 
153 static bool
154 unbox (JNIEnv *jni_env, const octave_value_list& args,
155  jobjectArray_ref& jobjs, jobjectArray_ref& jclss);
156 
157 extern "C"
158 {
159  JNIEXPORT jboolean JNICALL
160  Java_org_octave_Octave_call (JNIEnv *, jclass, jstring, jobjectArray,
161  jobjectArray);
162 
163  JNIEXPORT void JNICALL
164  Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint);
165 
166  JNIEXPORT void JNICALL
167  Java_org_octave_Octave_doInvoke (JNIEnv *, jclass, jint, jobjectArray);
168 
169  JNIEXPORT void JNICALL
170  Java_org_octave_Octave_doEvalString (JNIEnv *, jclass, jstring);
171 
172  JNIEXPORT jboolean JNICALL
174 }
175 
176 //! The pointer to a java virtual machine either created in the current thread
177 //! or attached this thread to it.
178 
179 static JavaVM *jvm = nullptr;
180 
181 //! Whether the current thread is attached to the jvm given by #jvm.
182 //! This is @c false also if no jvm exists, i.e. if #jvm is @c nullptr.
183 //! @see #initialize_jvm()
184 //! @see #terminate_jvm()
185 
186 static bool jvm_attached = false;
187 
188 //! Need to keep hold of the shared library handle until exit.
189 //! @see #initialize_jvm()
190 //! @see #terminate_jvm()
191 
193 
194 static std::map<int,octave_value> listener_map;
195 static std::map<int,octave_value> octave_ref_map;
196 static int octave_java_refcount = 0;
197 
198 //! The thread id of the currently executing thread or @c -1 if this is
199 //! unknown.
200 //! @see #initialize_java()
201 
202 static long octave_thread_ID = -1;
203 
206 bool Vdebug_java = false;
207 
208 namespace octave
209 {
210  class JVMArgs
211  {
212  public:
213 
214  JVMArgs (void)
215  {
216  vm_args.version = JNI_VERSION_1_6;
217  vm_args.nOptions = 0;
218  vm_args.options = nullptr;
219  vm_args.ignoreUnrecognized = false;
220  }
221 
222  ~JVMArgs (void)
223  {
224  clean ();
225  }
226 
227  JavaVMInitArgs * to_args ()
228  {
229  update ();
230  return &vm_args;
231  }
232 
233  void add (const std::string& opt)
234  {
235  java_opts.push_back (opt);
236  }
237 
239  {
240  std::ifstream js (filename.c_str ());
241 
242  if (! js.bad () && ! js.fail ())
243  {
245 
246  while (! js.eof () && ! js.fail ())
247  {
248  std::getline (js, line);
249 
250  if (line.find ('-') == 0)
251  java_opts.push_back (line);
252  else if (line.length () > 0 && Vdebug_java)
253  std::cerr << "invalid JVM option, skipping: " << line
254  << std::endl;
255  }
256  }
257  }
258 
259  private:
260 
261  void clean (void)
262  {
263  if (vm_args.options != nullptr)
264  {
265  for (int i = 0; i < vm_args.nOptions; i++)
266  delete [] vm_args.options[i].optionString;
267 
268  delete [] vm_args.options;
269 
270  vm_args.options = nullptr;
271  vm_args.nOptions = 0;
272  }
273  }
274 
275  void update (void)
276  {
277  clean ();
278 
279  if (java_opts.size () > 0)
280  {
281  int index = 0;
282 
283  vm_args.nOptions = java_opts.size ();
284  vm_args.options = new JavaVMOption [vm_args.nOptions];
285 
286  for (const auto& opt : java_opts)
287  {
288  if (Vdebug_java)
289  std::cout << opt << std::endl;
290  vm_args.options[index++].optionString = strsave (opt.c_str ());
291  }
292 
293  java_opts.clear ();
294  }
295  }
296 
297  private:
298 
299  JavaVMInitArgs vm_args;
300 
301  std::list<std::string> java_opts;
302  };
303 }
304 
305 
306 //! The java initialization directory is given by the environment variable
307 //! @c OCTAVE_JAVA_DIR if defined; otherwise it is the directory of Octave's
308 //! m-files defining Java functions.
309 //!
310 //! The Java initialization directory is the directory where resides:
311 //!
312 //! - @c octave.jar, defining the java classes implementing octave's java
313 //! interface,
314 //! - @c javaclasspath.txt, defining the installation defined portion of the
315 //! (static) classpath,
316 //! - @c java.opts, defining the configurable options of the java virtual
317 //! machine.
318 //!
319 //! Note that the (static) java classpath of the java virtual machine starts
320 //! with @c octave.jar, and that the static java classpath ends with what
321 //! is read from @c javaclasspath.txt located in the initial java directory.
322 //! Moreover, the java virtual machine is created essentially with
323 //! the options given by @c java.opts.
324 
325 static std::string
327 {
328  static std::string java_dir;
329 
330  if (java_dir.empty ())
331  {
332  java_dir = octave::sys::env::getenv ("OCTAVE_JAVA_DIR");
333 
334  if (java_dir.empty ())
335  java_dir = (octave::config::fcn_file_dir ()
336  + octave::sys::file_ops::dir_sep_str () + "java");
337  }
338 
339  return java_dir;
340 }
341 
342 //! Return the classpath in the given file @c filepath as a string.
343 //!
344 //! In the classpath file, each line which is neither empty nor a comment, is
345 //! interpreted as a segment of a path. Comment lines are those starting with
346 //! a @c # or with a @c % in the very first column.
347 //!
348 //! @param filepath The path to the file (usually @c classpath.txt) containing
349 //! a portion of the classpath.
350 //!
351 //! @returns A string consisting of the lines of @c filepath which are neither
352 //! comments nor empty without trailing whitespace separated by
353 //! `octave::directory_path::path_sep_str()`. The returned string also
354 //! starts with that path separator.
355 
356 static std::string
358 {
359  std::string classpath;
360 
361  std::ifstream fs (filepath.c_str ());
362 
363  if (! fs.bad () && ! fs.fail ())
364  {
366 
367  while (! fs.eof () && ! fs.fail ())
368  {
369  std::getline (fs, line);
370  if (line.length () > 0 && line[0] != '#' && line[0] != '%')
371  {
372  // prepend separator character
373  classpath.append (octave::directory_path::path_sep_str ());
374 
375  // append content of line without whitespace
376  int last = line.find_last_not_of (" \t\f\v\r\n");
377 
378  classpath.append (octave::sys::file_ops::tilde_expand (line.substr (0, last+1)));
379  }
380  }
381  }
382 
383  return (classpath);
384 }
385 
386 
387 //! Return the initial classpath.
388 //!
389 //! The initial classpath starts with a pointer to @c octave.jar which is
390 //! located in the initial java directory given by #java_init_dir().
391 //!
392 //! @attention This is nowhere documented and also the script
393 //! @c javaclasspath.m drops this. On the other hand, this is vital because
394 //! @c octave.jar contains the java core classes of octave's java interface.
395 //!
396 //! The rest of the classpath is read sequentially from files
397 //! @c javaclasspath.txt located in either:
398 //!
399 //! - the current directory,
400 //! - the user's home directory,
401 //! - the initial java directory returned by #initial_java_dir()
402 //!
403 //! @returns The initial classpath.
404 
405 static std::string
407 {
408  std::string java_dir = initial_java_dir ();
409 
410  std::string retval = java_dir;
411 
412  // Find octave.jar file.
413  if (! retval.empty ())
414  {
416 
417  std::string jar_file = java_dir + sep + "octave.jar";
418 
419  octave::sys::file_stat jar_exists (jar_file);
420 
421  if (jar_exists)
422  {
423  // Initialize static classpath to octave.jar.
424  retval = jar_file;
425 
426  // The base classpath has been set.
427  // Try to find an optional file specifying classpaths in 3 places.
428  // 1) Current directory
429  // 2) User's home directory
430  // 3) Octave installation directory where octave.jar resides
431 
434 
435  // The filename is "javaclasspath.txt", but historically has been
436  // "classpath.txt" so both are supported.
437  std::vector<std::string> cp_list = {"javaclasspath.txt",
438  "classpath.txt"};
439 
440  for (std::string filename : cp_list)
441  {
442  std::string cp_file = filename;
443  octave::sys::file_stat cp_exists;
444 
445  // Try to find classpath file in the current directory.
446 
447  cp_exists = octave::sys::file_stat (cp_file);
448  if (cp_exists)
449  {
450  // File found. Add its contents to the static classpath.
451  std::string classpath = read_classpath_txt (cp_file);
452  retval.append (classpath);
453  }
454 
455  // Try to find classpath file in the user's home directory.
456 
457  if (cwd != home_dir)
458  {
459  cp_file = '~' + sep + filename;
460  cp_file = octave::sys::file_ops::tilde_expand (cp_file);
461  cp_exists = octave::sys::file_stat (cp_file);
462  if (cp_exists)
463  {
464  // File found. Add its contents to the static classpath.
465  std::string classpath = read_classpath_txt (cp_file);
466  retval.append (classpath);
467  }
468  }
469 
470  // Try to find classpath file in the Octave install directory.
471 
472  if (cwd != java_dir)
473  {
474  cp_file = java_dir + sep + filename;
475  cp_exists = octave::sys::file_stat (cp_file);
476  if (cp_exists)
477  {
478  // File found. Add its contents to the static classpath.
479  std::string classpath = read_classpath_txt (cp_file);
480  retval.append (classpath);
481  }
482  }
483  }
484  }
485  else
486  error ("octave.jar does not exist: %s", jar_file.c_str ());
487  }
488  else
489  error ("initial java dir is empty");
490 
491  return retval;
492 }
493 
494 #if defined (OCTAVE_USE_WINDOWS_API)
495 // Declare function defined in sysdep.cc
496 extern LONG
497 get_regkey_value (HKEY h_rootkey, const std::string subkey,
499 #endif
500 
501 //! Initialize the java virtual machine (jvm) and field #jvm if necessary.
502 //!
503 //! If the jvm exists and is initialized, #jvm points to it, i.e. is not 0
504 //! and there is nothing to do.
505 //!
506 //! If #jvm is 0 and if at least one jvm exists, attach the current thread to
507 //! it by setting #jvm_attached. Otherwise, create a #jvm with some hard-
508 //! coded options:
509 //!
510 //! - `-Djava.class.path=classpath`, where @c classpath is given by
511 //! #initial_class_path().
512 //! - `-Djava.system.class.loader=org.octave.OctClassLoader`.
513 //! - `-Xrs`
514 //!
515 //! Further options are read from the file @c java.opts in the directory given
516 //! by #java_init_dir().
517 //!
518 //! Note that #initial_class_path() determines the initial classpath. This
519 //! is the static classpath which cannot be changed. Elements of the dynamic
520 //! classpath can be added and removed using the m-file scripts
521 //! @c javaaddpath.m and @c javarmpath.m.
522 //!
523 //! @see #terminate_jvm()
524 
525 static void
527 {
528  // Most of the time JVM already exists and has been initialized.
529  // Also it seems, as if jvm is set, the jvm is already attached.
530  // This does not fit terminate_jvm.
531  if (jvm)
532  return;
533 
534  JNIEnv *current_env;
535  const char *static_locale = setlocale (LC_ALL, nullptr);
536  const std::string locale (static_locale);
537 
538  octave::dynamic_library lib ("");
539  std::string jvm_lib_path = "linked in or loaded libraries";
540 
541  // Check whether the Java VM library is already loaded or linked in.
542  JNI_CreateJavaVM_t create_vm = reinterpret_cast<JNI_CreateJavaVM_t>
543  (lib.search ("JNI_CreateJavaVM"));
544  JNI_GetCreatedJavaVMs_t get_vm = reinterpret_cast<JNI_GetCreatedJavaVMs_t>
545  (lib.search ("JNI_GetCreatedJavaVMs"));
546 
547  if (! create_vm || ! get_vm)
548  {
549 #if defined (OCTAVE_USE_WINDOWS_API)
550  // In Windows, find the location of the JRE from the registry
551  // and load the symbol from the dll.
552  std::string key, jversion, value;
553 
554  // First search for JRE >= 9
555  key = R"(software\javasoft\jre)";
556 
557  jversion = octave::sys::env::getenv ("JAVA_VERSION");
558  octave_value regval;
559  LONG retval;
560  if (jversion.empty ())
561  {
562  value = "CurrentVersion";
563  retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
564 
565  if (retval != ERROR_SUCCESS)
566  {
567  // Search for JRE < 9
568  key = R"(software\javasoft\java runtime environment)";
569  retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value,
570  regval);
571  }
572 
573  if (retval != ERROR_SUCCESS)
574  error ("unable to find Java Runtime Environment: %s::%s",
575  key.c_str (), value.c_str ());
576 
577  jversion = regval.xstring_value (
578  "initialize_jvm: registry value \"%s\" at \"%s\" must be a string",
579  value.c_str (), key.c_str ());
580  }
581 
582  key = key + '\\' + jversion;
583  value = "RuntimeLib";
584  retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
585  if (retval != ERROR_SUCCESS)
586  {
587  // Search for JRE < 9
588  key = R"(software\javasoft\java runtime environment\)" + jversion;
589  retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
590  }
591 
592  if (retval != ERROR_SUCCESS)
593  error ("unable to find Java Runtime Environment: %s::%s",
594  key.c_str (), value.c_str ());
595 
596  jvm_lib_path = regval.xstring_value (
597  "initialize_jvm: registry value \"%s\" at \"%s\" must be a string",
598  value.c_str (), key.c_str ());
599 
600  if (jvm_lib_path.empty ())
601  error ("unable to find Java Runtime Environment: %s::%s",
602  key.c_str (), value.c_str ());
603 #else
604  // JAVA_LDPATH determined by configure and set in config.h
605 # if defined (__APPLE__)
606  jvm_lib_path = JAVA_LDPATH + std::string ("/libjvm.dylib");
607 # else
608  jvm_lib_path = JAVA_LDPATH + std::string ("/libjvm.so");
609 # endif
610 #endif
611  lib = octave::dynamic_library (jvm_lib_path);
612 
613  if (! lib)
614  error ("unable to load Java Runtime Environment from %s",
615  jvm_lib_path.c_str ());
616 
617  create_vm = reinterpret_cast<JNI_CreateJavaVM_t>
618  (lib.search ("JNI_CreateJavaVM"));
619  get_vm = reinterpret_cast<JNI_GetCreatedJavaVMs_t>
620  (lib.search ("JNI_GetCreatedJavaVMs"));
621 
622  if (! create_vm)
623  error ("unable to find JNI_CreateJavaVM in %s", jvm_lib_path.c_str ());
624 
625  if (! get_vm)
626  error ("unable to find JNI_GetCreatedJavaVMs in %s",
627  jvm_lib_path.c_str ());
628  }
629 
630  //! The number of created jvm's.
631  jsize nVMs = 0;
632 
633  if (get_vm (&jvm, 1, &nVMs) == 0 && nVMs > 0)
634  {
635  // At least one JVM exists, try to attach the current thread to it.
636 
637  switch (jvm->GetEnv (reinterpret_cast<void **> (&current_env),
638  JNI_VERSION_1_6))
639  {
640  case JNI_EDETACHED:
641  // Attach the current thread
642  JavaVMAttachArgs vm_args;
643  vm_args.version = JNI_VERSION_1_6;
644  vm_args.name = const_cast<char *> ("octave");
645  vm_args.group = nullptr;
646  if (jvm->AttachCurrentThread (reinterpret_cast<void **> (&current_env),
647  &vm_args) < 0)
648  error ("JVM internal error, unable to attach octave to existing JVM");
649  break;
650 
651  case JNI_EVERSION:
652  error ("JVM internal error, the required JNI version is not supported");
653  break;
654 
655  case JNI_OK:
656  // Don't do anything, the current thread is already attached to JVM
657  break;
658  }
659 
660  jvm_attached = true;
661  }
662  else
663  {
664  // No JVM exists, create one
665 
666  octave::JVMArgs vm_args;
667 
668  // Hard-coded options for the jvm.
669  vm_args.add ("-Djava.class.path=" + initial_class_path ());
670  vm_args.add ("-Djava.system.class.loader=org.octave.OctClassLoader");
671  vm_args.add ("-Xrs");
672 
673  // Additional options given by file java.opts.
674  vm_args.read_java_opts (initial_java_dir () +
676  "java.opts");
677 
678  if (create_vm (&jvm, &current_env, vm_args.to_args ()) != JNI_OK)
679  error ("unable to start Java VM in %s", jvm_lib_path.c_str ());
680  }
681 
682  jvm_lib = lib;
683 
684  setlocale (LC_ALL, locale.c_str ());
685 }
686 
687 //! Terminate the current jvm, if there is any.
688 //!
689 //! Otherwise, detach the jvm if this thread is attached to it and unload it
690 //! if this thread created it itself.
691 //!
692 //! @see #initialize_jvm()
693 
694 static void
696 {
697  // There is nothing to do if jvm is not set (= nullptr).
698  if (jvm)
699  {
700  // FIXME: Seems that if jvm_attached is always true if jvm is not null.
701  if (jvm_attached)
702  jvm->DetachCurrentThread ();
703  else
704  jvm->DestroyJavaVM ();
705 
706  jvm = nullptr;
707  jvm_attached = false;
708 
709  if (jvm_lib)
710  jvm_lib.close ();
711 
713  }
714 }
715 
716 //! Converts a Java string object to std::string.
717 //!{
718 static std::string
719 jstring_to_string (JNIEnv *jni_env, jstring s)
720 {
722 
723  if (jni_env)
724  {
725  const char *cstr = jni_env->GetStringUTFChars (s, nullptr);
726  retval = cstr;
727  jni_env->ReleaseStringUTFChars (s, cstr);
728  }
729 
730  return retval;
731 }
732 
733 static std::string
734 jstring_to_string (JNIEnv *jni_env, jobject obj)
735 {
737 
738  if (jni_env && obj)
739  {
740  jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String"));
741  if (cls)
742  {
743  if (jni_env->IsInstanceOf (obj, cls))
744  retval = jstring_to_string (jni_env,
745  reinterpret_cast<jstring> (obj));
746  }
747  }
748 
749  return retval;
750 }
751 //!}
752 
753 //! Returns a reference to the jni (java native interface) environment of the
754 //! Java virtual machine #jvm.
755 //!
756 //! @returns A reference to jni, if #jvm is present, otherwise @c nullptr.
757 
758 static inline JNIEnv *
760 {
761  JNIEnv *env = nullptr;
762 
763  if (jvm)
764  jvm->GetEnv (reinterpret_cast<void **> (&env), JNI_VERSION_1_6);
765 
766  return env;
767 }
768 
769 #endif
770 
771 bool
773 {
774 #if defined (HAVE_JAVA)
775 
776  JNIEnv *current_env = thread_jni_env ();
777 
778  if (current_env && java_object)
779  {
780  jclass_ref cls (current_env, current_env->FindClass ("java/lang/String"));
781  return current_env->IsInstanceOf (TO_JOBJECT (java_object), cls);
782  }
783 
784  return false;
785 
786 #else
787 
788  // This shouldn't happen because construction of octave_java objects is
789  // supposed to be impossible if Java is not available.
790 
791  panic_impossible ();
792 
793 #endif
794 }
795 
796 bool
798 {
799 #if defined (HAVE_JAVA)
800 
801  JNIEnv *current_env = thread_jni_env ();
802 
803  std::string cls_cpp = cls_name;
804  std::replace (cls_cpp.begin (), cls_cpp.end (), '.', '/');
805 
806  if (current_env && java_object)
807  {
808  jclass_ref cls (current_env, current_env->FindClass (cls_cpp.c_str ()));
809  if (current_env->ExceptionCheck ())
810  current_env->ExceptionClear ();
811  else
812  return current_env->IsInstanceOf (TO_JOBJECT (java_object), cls);
813  }
814  return false;
815 
816 #else
817 
818  octave_unused_parameter (cls_name);
819 
820  // This shouldn't happen because construction of octave_java objects is
821  // supposed to be impossible if Java is not available.
822 
823  panic_impossible ();
824 
825 #endif
826 }
827 
828 #if defined (HAVE_JAVA)
829 
830 static octave_value
831 check_exception (JNIEnv *jni_env)
832 {
834 
835  jthrowable_ref ex (jni_env, jni_env->ExceptionOccurred ());
836 
837  if (ex)
838  {
839  if (Vdebug_java)
840  jni_env->ExceptionDescribe ();
841 
842  jni_env->ExceptionClear ();
843 
844  jclass_ref jcls (jni_env, jni_env->GetObjectClass (ex));
845  jmethodID mID = jni_env->GetMethodID (jcls, "toString",
846  "()Ljava/lang/String;");
847  jstring_ref js (jni_env,
848  reinterpret_cast<jstring> (jni_env->CallObjectMethod (ex,
849  mID)));
850  std::string msg = jstring_to_string (jni_env, js);
851 
852  error ("[java] %s", msg.c_str ());
853  }
854  else
855  retval = Matrix ();
856 
857  return retval;
858 }
859 
860 static jclass
861 find_octave_class (JNIEnv *jni_env, const char *name)
862 {
863  static std::string class_loader;
864  static jclass uiClass = nullptr;
865 
866  jclass jcls = jni_env->FindClass (name);
867 
868  if (jcls == nullptr)
869  {
870  jni_env->ExceptionClear ();
871 
872  if (! uiClass)
873  {
874  if (class_loader.empty ())
875  {
876  jclass_ref syscls (jni_env,
877  jni_env->FindClass ("java/lang/System"));
878  jmethodID mID = jni_env->GetStaticMethodID
879  (syscls,
880  "getProperty",
881  "(Ljava/lang/String;)Ljava/lang/String;");
882  jstring_ref js (jni_env,
883  jni_env->NewStringUTF ("octave.class.loader"));
884  js = reinterpret_cast<jstring> (jni_env->CallStaticObjectMethod
885  (syscls, mID, jstring (js)));
886  class_loader = jstring_to_string (jni_env, jstring (js));
887  std::replace (class_loader.begin (), class_loader.end (),
888  '.', '/');
889  }
890 
891  jclass_ref uicls (jni_env,
892  jni_env->FindClass (class_loader.c_str ()));
893 
894  if (! uicls)
895  {
896  jni_env->ExceptionClear ();
897 
898  // Try the netbeans way
899  std::replace (class_loader.begin (), class_loader.end (),
900  '/', '.');
901  jclass_ref jcls2 (jni_env,
902  jni_env->FindClass ("org/openide/util/Lookup"));
903  jmethodID mID = jni_env->GetStaticMethodID
904  (jcls2, "getDefault", "()Lorg/openide/util/Lookup;");
905  jobject_ref lObj (jni_env,
906  jni_env->CallStaticObjectMethod (jcls2, mID));
907  mID = jni_env->GetMethodID (jcls2, "lookup",
908  "(Ljava/lang/Class;)Ljava/lang/Object;");
909  jclass_ref cLoaderCls (jni_env,
910  jni_env->FindClass ("java/lang/ClassLoader"));
911  jobject_ref cLoader (jni_env,
912  jni_env->CallObjectMethod
913  (lObj, mID, jclass (cLoaderCls)));
914  mID = jni_env->GetMethodID (cLoaderCls, "loadClass",
915  "(Ljava/lang/String;)Ljava/lang/Class;");
916  jstring_ref js (jni_env,
917  jni_env->NewStringUTF (class_loader.c_str ()));
918  uicls = reinterpret_cast<jclass>
919  (jni_env->CallObjectMethod (cLoader, mID, jstring (js)));
920  }
921 
922  if (uicls)
923  uiClass = reinterpret_cast<jclass>
924  (jni_env->NewGlobalRef (jclass (uicls)));
925  }
926 
927  if (uiClass)
928  {
929  jmethodID mID = jni_env->GetStaticMethodID
930  (uiClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
931  jstring_ref js (jni_env, jni_env->NewStringUTF (name));
932  jcls = reinterpret_cast<jclass>
933  (jni_env->CallStaticObjectMethod (uiClass, mID, jstring (js)));
934  }
935  }
936 
937  return jcls;
938 }
939 
940 static dim_vector
941 compute_array_dimensions (JNIEnv *jni_env, jobject obj)
942 {
943  jobjectArray_ref jobj (jni_env, reinterpret_cast<jobjectArray> (obj));
944  jclass_ref jcls (jni_env, jni_env->GetObjectClass (obj));
945  jclass_ref ccls (jni_env, jni_env->GetObjectClass (jcls));
946  jmethodID isArray_ID = jni_env->GetMethodID (ccls, "isArray", "()Z");
947  jmethodID getComponentType_ID = jni_env->GetMethodID (ccls,
948  "getComponentType",
949  "()Ljava/lang/Class;");
950 
951  dim_vector dv (1, 1);
952  int idx = 0;
953 
954  jobj.detach ();
955  while (jcls && jni_env->CallBooleanMethod (jcls, isArray_ID))
956  {
957  int len = (jobj ? jni_env->GetArrayLength (jobj) : 0);
958  if (idx >= dv.ndims ())
959  dv.resize (idx+1);
960  dv(idx) = len;
961  jcls = reinterpret_cast<jclass>
962  (jni_env->CallObjectMethod (jcls, getComponentType_ID));
963  jobj = len > 0
964  ? reinterpret_cast<jobjectArray> (jni_env->GetObjectArrayElement (jobj,
965  0))
966  : nullptr;
967  idx++;
968  }
969 
971 
972  return dv;
973 }
974 
975 static jobject
976 make_java_index (JNIEnv *jni_env, const octave_value_list& idx)
977 {
978  jclass_ref ocls (jni_env, jni_env->FindClass ("[I"));
979  jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, nullptr);
980  // Here retval has the same length as idx
981 
982  // Fill in entries of idx into retval
983  for (int i = 0; i < idx.length (); i++)
984  try
985  {
986  idx_vector v = idx(i).index_vector ();
987 
988  jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ()));
989  jint *buf = jni_env->GetIntArrayElements (i_array, nullptr);
990  // Here, buf points to the beginning of i_array
991 
992  // Copy v to buf.
993  for (int k = 0; k < v.length (); k++)
994  buf[k] = v(k);
995 
996  // Set retval[i] = i_array
997  jni_env->ReleaseIntArrayElements (i_array, buf, 0);
998  jni_env->SetObjectArrayElement (retval, i, i_array);
999 
1000  check_exception (jni_env);
1001  }
1002  catch (octave::index_exception& e)
1003  {
1004  // Rethrow to allow more info to be reported later.
1005  e.set_pos_if_unset (idx.length (), i + 1);
1006  throw;
1007  }
1008 
1009  return retval;
1010 }
1011 
1012 static octave_value
1013 get_array_elements (JNIEnv *jni_env, jobject jobj,
1014  const octave_value_list& idx)
1015 {
1017  jobject_ref resObj (jni_env);
1018  jobject_ref java_idx (jni_env, make_java_index (jni_env, idx));
1019 
1020  jclass_ref helperClass (jni_env,
1021  find_octave_class (jni_env,
1022  "org/octave/ClassHelper"));
1023  jmethodID mID = jni_env
1024  ->GetStaticMethodID (helperClass, "arraySubsref",
1025  "(Ljava/lang/Object;[[I)Ljava/lang/Object;");
1026  resObj = jni_env->CallStaticObjectMethod
1027  (helperClass, mID, jobj, jobject (java_idx));
1028 
1029  if (resObj)
1030  retval = box (jni_env, resObj);
1031  else
1032  retval = check_exception (jni_env);
1033 
1035 
1036  return retval;
1037 }
1038 
1039 static octave_value
1040 set_array_elements (JNIEnv *jni_env, jobject jobj,
1041  const octave_value_list& idx, const octave_value& rhs)
1042 {
1044 
1045  jclass_ref rhsCls (jni_env);
1046  jobject_ref resObj (jni_env);
1047  jobject_ref rhsObj (jni_env);
1048  jobject_ref java_idx (jni_env, make_java_index (jni_env, idx));
1049 
1050  if (unbox (jni_env, rhs, rhsObj, rhsCls))
1051  {
1052  jclass_ref helperClass (jni_env,
1053  find_octave_class (jni_env,
1054  "org/octave/ClassHelper"));
1055  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsasgn",
1056  "(Ljava/lang/Object;[[ILjava/lang/Object;)" "Ljava/lang/Object;");
1057  resObj = jni_env->CallStaticObjectMethod
1058  (helperClass, mID, jobj, jobject (java_idx), jobject (rhsObj));
1059  }
1060 
1061  if (resObj)
1062  retval = box (jni_env, resObj);
1063  else
1064  retval = check_exception (jni_env);
1065 
1067 
1068  return retval;
1069 }
1070 
1071 static string_vector
1072 get_invoke_list (JNIEnv *jni_env, void *jobj_arg)
1073 {
1074  jobject jobj = TO_JOBJECT (jobj_arg);
1075 
1076  std::list<std::string> name_list;
1077 
1078  if (jni_env)
1079  {
1080  jclass_ref cls (jni_env, jni_env->GetObjectClass (jobj));
1081  jclass_ref ccls (jni_env, jni_env->GetObjectClass (cls));
1082  jmethodID getMethods_ID = jni_env->GetMethodID
1083  (ccls, "getMethods", "()[Ljava/lang/reflect/Method;");
1084  jmethodID getFields_ID = jni_env->GetMethodID
1085  (ccls, "getFields", "()[Ljava/lang/reflect/Field;");
1086  jobjectArray_ref mList (jni_env,
1087  reinterpret_cast<jobjectArray>
1088  (jni_env->CallObjectMethod (cls, getMethods_ID)));
1089  jobjectArray_ref fList (jni_env,
1090  reinterpret_cast<jobjectArray>
1091  (jni_env->CallObjectMethod (cls, getFields_ID)));
1092  int mLen = jni_env->GetArrayLength (mList);
1093  int fLen = jni_env->GetArrayLength (fList);
1094  jclass_ref mCls (jni_env,
1095  jni_env->FindClass ("java/lang/reflect/Method"));
1096  jclass_ref fCls (jni_env,
1097  jni_env->FindClass ("java/lang/reflect/Field"));
1098  jmethodID m_getName_ID = jni_env->GetMethodID (mCls, "getName",
1099  "()Ljava/lang/String;");
1100  jmethodID f_getName_ID = jni_env->GetMethodID (fCls, "getName",
1101  "()Ljava/lang/String;");
1102 
1103  for (int i = 0; i < mLen; i++)
1104  {
1105  jobject_ref meth (jni_env, jni_env->GetObjectArrayElement (mList, i));
1106  jstring_ref methName (jni_env, reinterpret_cast<jstring>
1107  (jni_env->CallObjectMethod (meth,
1108  m_getName_ID)));
1109  name_list.push_back (jstring_to_string (jni_env, methName));
1110  }
1111 
1112  for (int i = 0; i < fLen; i++)
1113  {
1114  jobject_ref field (jni_env,
1115  jni_env->GetObjectArrayElement (fList, i));
1116  jstring_ref fieldName (jni_env,
1117  reinterpret_cast<jstring>
1118  (jni_env->CallObjectMethod
1119  (field, f_getName_ID)));
1120  name_list.push_back (jstring_to_string (jni_env, fieldName));
1121  }
1122 
1124  }
1125 
1126  string_vector v (name_list);
1127 
1128  return v.sort (true);
1129 }
1130 
1131 static octave_value
1132 convert_to_string (JNIEnv *jni_env, jobject java_object, bool force, char type)
1133 {
1135 
1136  if (jni_env && java_object)
1137  {
1138  jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String"));
1139 
1140  if (jni_env->IsInstanceOf (java_object, cls))
1141  retval = octave_value (jstring_to_string (jni_env, java_object), type);
1142  else if (force)
1143  {
1144  cls = jni_env->FindClass ("[Ljava/lang/String;");
1145 
1146  if (jni_env->IsInstanceOf (java_object, cls))
1147  {
1148  jobjectArray array = reinterpret_cast<jobjectArray> (java_object);
1149  int len = jni_env->GetArrayLength (array);
1150  Cell c (len, 1);
1151 
1152  for (int i = 0; i < len; i++)
1153  {
1154  jstring_ref js (jni_env,
1155  reinterpret_cast<jstring>
1156  (jni_env->GetObjectArrayElement (array, i)));
1157 
1158  if (js)
1159  c(i) = octave_value (jstring_to_string (jni_env, js), type);
1160  else
1161  c(i) = check_exception (jni_env);
1162  }
1163 
1164  retval = octave_value (c);
1165  }
1166  else
1167  {
1168  cls = jni_env->FindClass ("java/lang/Object");
1169  jmethodID mID = jni_env->GetMethodID (cls, "toString",
1170  "()Ljava/lang/String;");
1171  jstring_ref js (jni_env,
1172  reinterpret_cast<jstring>
1173  (jni_env->CallObjectMethod (java_object,
1174  mID)));
1175 
1176  if (js)
1177  retval = octave_value (jstring_to_string (jni_env, js), type);
1178  else
1179  retval = check_exception (jni_env);
1180  }
1181  }
1182  else
1183  error ("unable to convert Java object to string");
1184 
1186  }
1187 
1188  return retval;
1189 }
1190 
1191 #define TO_JAVA(obj) dynamic_cast<octave_java *> ((obj).internal_rep ())
1192 
1193 //! Return whether @c jobj shall be automatically converted to an Octave
1194 //! numeric value.
1195 //!
1196 //! If @c jobj is an instance of any of the numeric wrapper classes @c Byte,
1197 //! @c Integer, @c Long, @c Short, @c Float, or @c Double, then it will be
1198 //! converted using the @c java.lang.Number.doubleValue() method.
1199 //!
1200 //! @param jobj Java object being returned to Octave
1201 //! @return @c true if @c jobj shall be converted into a numeric value
1202 //! automatically, @c false otherwise
1203 static bool
1204 is_auto_convertible_number (JNIEnv *jni_env, jobject jobj)
1205 {
1206  jclass_ref cls (jni_env);
1207  cls = jni_env->FindClass ("java/lang/Double");
1208  if (jni_env->IsInstanceOf (jobj, cls))
1209  return true;
1210  cls = jni_env->FindClass ("java/lang/Float");
1211  if (jni_env->IsInstanceOf (jobj, cls))
1212  return true;
1213  cls = jni_env->FindClass ("java/lang/Byte");
1214  if (jni_env->IsInstanceOf (jobj, cls))
1215  return true;
1216  cls = jni_env->FindClass ("java/lang/Short");
1217  if (jni_env->IsInstanceOf (jobj, cls))
1218  return true;
1219  cls = jni_env->FindClass ("java/lang/Integer");
1220  if (jni_env->IsInstanceOf (jobj, cls))
1221  return true;
1222  cls = jni_env->FindClass ("java/lang/Long");
1223  if (jni_env->IsInstanceOf (jobj, cls))
1224  return true;
1225 
1226  return false;
1227 }
1228 
1229 //! Convert the Java object pointed to by @c jobj_arg with class @c jcls_arg
1230 //! to an Octave value.
1231 //!
1232 //! @param jni_env JNI environment pointer.
1233 //! @param jobj_arg Pointer to a Java object.
1234 //! @param jcls_arg Optional pointer to the Java class of @c jobj_arg.
1235 //!
1236 //! @return
1237 //! @arg numeric value as a @c double if @c jobj_arg is of type @c Byte,
1238 //! @c Short, @c Integer, @c Long, @c Float or @c Double
1239 //! @arg logical value if @c jobj_arg is of type @c Boolean
1240 //! @arg string value if @c jobj_arg is of type @c Character or @c String
1241 //! @arg Octave array of numeric, logical, or char type if @c jobj_arg is
1242 //! a Java array of primitive types
1243 //! @arg Octave matrix if @c jobj_arg is of type @c org.octave.Matrix and
1244 //! #Vjava_matrix_autoconversion is enabled
1245 //! @arg Octave object if @c jobj_arg is of type
1246 //! @c org.octave.OctaveReference
1247 //! @arg @c octave_java object wrapping the Java object otherwise.
1248 
1249 static octave_value
1250 box (JNIEnv *jni_env, void *jobj_arg, void *jcls_arg)
1251 {
1253 
1254  jobject jobj = TO_JOBJECT (jobj_arg);
1255  jclass jcls = TO_JCLASS (jcls_arg);
1256 
1257  jclass_ref cls (jni_env);
1258 
1259  if (! jobj)
1260  retval = Matrix ();
1261 
1262  while (retval.is_undefined ())
1263  {
1264  // Convert a scalar of any numeric class wrapping a primitive class
1265  // (byte, short, integer, long, float, double) to a double value.
1266  // Test whether java.lang.Number before testing for each type.
1267  cls = jni_env->FindClass ("java/lang/Number");
1268  if (jni_env->IsInstanceOf (jobj, cls)
1269  && is_auto_convertible_number (jni_env, jobj))
1270  {
1271  jmethodID m = jni_env->GetMethodID (cls, "doubleValue", "()D");
1272  retval = jni_env->CallDoubleMethod (jobj, m);
1273  break;
1274  }
1275 
1276  cls = jni_env->FindClass ("java/lang/Boolean");
1277  if (jni_env->IsInstanceOf (jobj, cls))
1278  {
1279  jmethodID m = jni_env->GetMethodID (cls, "booleanValue", "()Z");
1280  retval = (jni_env->CallBooleanMethod (jobj, m) ? true : false);
1281  break;
1282  }
1283 
1284  cls = jni_env->FindClass ("java/lang/String");
1285  if (jni_env->IsInstanceOf (jobj, cls))
1286  {
1287  retval = jstring_to_string (jni_env, jobj);
1288  break;
1289  }
1290 
1291  cls = jni_env->FindClass ("java/lang/Character");
1292  if (jni_env->IsInstanceOf (jobj, cls))
1293  {
1294  jmethodID m = jni_env->GetMethodID (cls, "charValue", "()C");
1295  retval = jni_env->CallCharMethod (jobj, m);
1296  retval = retval.convert_to_str (false, true);
1297  break;
1298  }
1299 
1300 #define BOX_PRIMITIVE_ARRAY(JAVA_TYPE, JAVA_ID, JAVA_TYPE_CAP, OCTAVE_ID) \
1301  cls = jni_env->FindClass (JAVA_ID); \
1302  if (jni_env->IsInstanceOf (jobj, cls)) \
1303  { \
1304  const JAVA_TYPE ## Array jarr = reinterpret_cast<JAVA_TYPE ## Array> (jobj); \
1305  const jsize len = jni_env->GetArrayLength (jarr); \
1306  OCTAVE_ID ## NDArray d (dim_vector (len, 1)); \
1307  JAVA_TYPE *buffer = reinterpret_cast<JAVA_TYPE *> (d.fortran_vec ()); \
1308  jni_env->Get ## JAVA_TYPE_CAP ## ArrayRegion (jarr, 0, len, buffer); \
1309  retval = d; \
1310  break; \
1311  }
1312 
1313  BOX_PRIMITIVE_ARRAY (jdouble, "[D", Double, )
1314  BOX_PRIMITIVE_ARRAY (jboolean, "[Z", Boolean, bool)
1315  BOX_PRIMITIVE_ARRAY (jfloat, "[F", Float, Float)
1316  BOX_PRIMITIVE_ARRAY (jchar, "[C", Char, char)
1317  BOX_PRIMITIVE_ARRAY (jbyte, "[B", Byte, int8)
1318  BOX_PRIMITIVE_ARRAY (jshort, "[S", Short, int16)
1319  BOX_PRIMITIVE_ARRAY (jint, "[I", Int, int32)
1320  BOX_PRIMITIVE_ARRAY (jlong, "[J", Long, int64)
1321 
1322 #undef BOX_PRIMITIVE_ARRAY
1323 
1325  {
1326  cls = find_octave_class (jni_env, "org/octave/Matrix");
1327 
1328  if (jni_env->IsInstanceOf (jobj, cls))
1329  {
1330  jmethodID mID = jni_env->GetMethodID (cls, "getDims", "()[I");
1331  jintArray_ref iv (jni_env,
1332  reinterpret_cast<jintArray>
1333  (jni_env->CallObjectMethod (jobj, mID)));
1334  jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv),
1335  nullptr);
1336  dim_vector dims;
1337  dims.resize (jni_env->GetArrayLength (jintArray (iv)));
1338 
1339  for (int i = 0; i < dims.ndims (); i++)
1340  dims(i) = iv_data[i];
1341 
1342  jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0);
1343  mID = jni_env->GetMethodID (cls, "getClassName",
1344  "()Ljava/lang/String;");
1345  jstring_ref js (jni_env,
1346  reinterpret_cast<jstring>
1347  (jni_env->CallObjectMethod (jobj, mID)));
1348 
1349  std::string s = jstring_to_string (jni_env, js);
1350 
1351  if (s == "double")
1352  {
1353  NDArray m (dims);
1354  mID = jni_env->GetMethodID (cls, "toDouble", "()[D");
1355  jdoubleArray_ref dv (jni_env,
1356  reinterpret_cast<jdoubleArray>
1357  (jni_env->CallObjectMethod (jobj,
1358  mID)));
1359  jni_env->GetDoubleArrayRegion (dv, 0, m.numel (),
1360  m.fortran_vec ());
1361  retval = m;
1362  break;
1363  }
1364  else if (s == "byte")
1365  {
1367  {
1368  uint8NDArray m (dims);
1369  mID = jni_env->GetMethodID (cls, "toByte", "()[B");
1370  jbyteArray_ref dv (jni_env,
1371  reinterpret_cast<jbyteArray>
1372  (jni_env->CallObjectMethod (jobj,
1373  mID)));
1374  jni_env->GetByteArrayRegion (dv, 0, m.numel (),
1375  reinterpret_cast<jbyte *>
1376  (m.fortran_vec ()));
1377  retval = m;
1378  break;
1379  }
1380  else
1381  {
1382  int8NDArray m (dims);
1383  mID = jni_env->GetMethodID (cls, "toByte", "()[B");
1384  jbyteArray_ref dv (jni_env,
1385  reinterpret_cast<jbyteArray>
1386  (jni_env->CallObjectMethod (jobj,
1387  mID)));
1388  jni_env->GetByteArrayRegion (dv, 0, m.numel (),
1389  reinterpret_cast<jbyte *>
1390  (m.fortran_vec ()));
1391  retval = m;
1392  break;
1393  }
1394  }
1395  else if (s == "integer")
1396  {
1398  {
1399  uint32NDArray m (dims);
1400  mID = jni_env->GetMethodID (cls, "toInt", "()[I");
1401  jintArray_ref dv (jni_env,
1402  reinterpret_cast<jintArray>
1403  (jni_env->CallObjectMethod (jobj,
1404  mID)));
1405  jni_env->GetIntArrayRegion (dv, 0, m.numel (),
1406  reinterpret_cast<jint *>
1407  (m.fortran_vec ()));
1408  retval = m;
1409  break;
1410  }
1411  else
1412  {
1413  int32NDArray m (dims);
1414  mID = jni_env->GetMethodID (cls, "toInt", "()[I");
1415  jintArray_ref dv (jni_env,
1416  reinterpret_cast<jintArray>
1417  (jni_env->CallObjectMethod (jobj,
1418  mID)));
1419  jni_env->GetIntArrayRegion (dv, 0, m.numel (),
1420  reinterpret_cast<jint *>
1421  (m.fortran_vec ()));
1422  retval = m;
1423  break;
1424  }
1425  }
1426  }
1427  }
1428 
1429  cls = find_octave_class (jni_env, "org/octave/OctaveReference");
1430  if (jni_env->IsInstanceOf (jobj, cls))
1431  {
1432  jmethodID mID = jni_env->GetMethodID (cls, "getID", "()I");
1433  int ID = jni_env->CallIntMethod (jobj, mID);
1434  std::map<int,octave_value>::iterator it = octave_ref_map.find (ID);
1435 
1436  if (it != octave_ref_map.end ())
1437  retval = it->second;
1438  break;
1439  }
1440 
1441  // No suitable class found. Return a generic octave_java object.
1442  retval = octave_value (new octave_java (jobj, jcls));
1443  break;
1444  }
1445 
1446  return retval;
1447 }
1448 
1449 static octave_value
1450 box_more (JNIEnv *jni_env, void *jobj_arg, void *jcls_arg)
1451 {
1452  jobject jobj = TO_JOBJECT (jobj_arg);
1453  jclass jcls = TO_JCLASS (jcls_arg);
1454 
1455  octave_value retval = box (jni_env, jobj, jcls);
1456 
1457  if (retval.isjava ())
1458  {
1459  retval = octave_value ();
1460 
1461  jclass_ref cls (jni_env);
1462 
1463  if (retval.is_undefined ())
1464  {
1465  cls = jni_env->FindClass ("[D");
1466 
1467  if (jni_env->IsInstanceOf (jobj, cls))
1468  {
1469  jdoubleArray jarr = reinterpret_cast<jdoubleArray> (jobj);
1470  int len = jni_env->GetArrayLength (jarr);
1471 
1472  if (len > 0)
1473  {
1474  Matrix m (1, len);
1475  jni_env->GetDoubleArrayRegion (jarr, 0, len,
1476  m.fortran_vec ());
1477  retval = m;
1478  }
1479  else
1480  retval = Matrix ();
1481  }
1482  }
1483 
1484  if (retval.is_undefined ())
1485  {
1486  cls = jni_env->FindClass ("[[D");
1487 
1488  if (jni_env->IsInstanceOf (jobj, cls))
1489  {
1490  jobjectArray jarr = reinterpret_cast<jobjectArray> (jobj);
1491  int rows = jni_env->GetArrayLength (jarr);
1492  int cols = 0;
1493 
1494  if (rows > 0)
1495  {
1496  Matrix m;
1497 
1498  for (int r = 0; r < rows; r++)
1499  {
1500  jdoubleArray_ref row (jni_env,
1501  reinterpret_cast<jdoubleArray>
1502  (jni_env->GetObjectArrayElement
1503  (jarr, r)));
1504 
1505  if (m.isempty ())
1506  {
1507  cols = jni_env->GetArrayLength (row);
1508  m.resize (cols, rows);
1509  }
1510  jni_env->GetDoubleArrayRegion
1511  (row, 0, cols, m.fortran_vec () + r * cols);
1512  }
1513  retval = m.transpose ();
1514  }
1515  else
1516  retval = Matrix ();
1517  }
1518  }
1519 
1520  if (retval.is_undefined ())
1521  {
1522  cls = jni_env->FindClass ("[Ljava/lang/String;");
1523 
1524  if (jni_env->IsInstanceOf (jobj, cls))
1525  {
1526  jobjectArray jarr = reinterpret_cast<jobjectArray> (jobj);
1527  int len = jni_env->GetArrayLength (jarr);
1528  Cell m (len, 1);
1529 
1530  for (int i = 0; i < len; i++)
1531  {
1532  jstring_ref js (jni_env,
1533  reinterpret_cast<jstring>
1534  (jni_env->GetObjectArrayElement (jarr, i)));
1535  m(i) = jstring_to_string (jni_env, js);
1536  }
1537 
1538  retval = m;
1539  }
1540  }
1541  }
1542 
1543  if (retval.is_undefined ())
1544  retval = octave_value (new octave_java (jobj, jcls));
1545 
1547 
1548  return retval;
1549 }
1550 
1551 static bool
1552 unbox (JNIEnv *jni_env, const octave_value& val, jobject_ref& jobj,
1553  jclass_ref& jcls)
1554 {
1555  bool found = true;
1556 
1557  if (val.isjava ())
1558  {
1559  octave_java *ovj = TO_JAVA (val);
1560  jobj = TO_JOBJECT (ovj->to_java ());
1561  jobj.detach ();
1562  jcls = jni_env->GetObjectClass (jobj);
1563  }
1564  else if (val.is_string ())
1565  {
1566  std::string s = val.string_value ();
1567 
1568  jobj = jni_env->NewStringUTF (s.c_str ());
1569  jcls = jni_env->GetObjectClass (jobj);
1570  }
1571  else if (val.iscellstr ())
1572  {
1573  const Array<std::string> str_arr = val.cellstr_value ();
1574  const octave_idx_type n = str_arr.numel ();
1575 
1576  jclass_ref scls (jni_env, jni_env->FindClass ("java/lang/String"));
1577  jobjectArray array = jni_env->NewObjectArray (n, scls, nullptr);
1578 
1579  for (octave_idx_type i = 0; i < n; i++)
1580  {
1581  jstring_ref jstr (jni_env, jni_env->NewStringUTF
1582  (str_arr(i).c_str ()));
1583  jni_env->SetObjectArrayElement (array, i, jstr);
1584  }
1585 
1586  jobj = array;
1587  jcls = jni_env->GetObjectClass (jobj);
1588  }
1589  else if (val.numel () > 1 && val.dims ().isvector ())
1590  {
1591  // FIXME: Is there any way to avoid code duplication here without
1592  // using a macro?
1593 
1594 #define UNBOX_PRIMITIVE_ARRAY(METHOD_T, OCTAVE_T, JAVA_T, JAVA_T_CAP) \
1595  do \
1596  { \
1597  const OCTAVE_T ## NDArray v = val.METHOD_T ## array_value (); \
1598  JAVA_T ## Array jarr = jni_env->New ## JAVA_T_CAP ## Array (v.numel ()); \
1599  const JAVA_T *jv = reinterpret_cast<const JAVA_T *> (v.data ()); \
1600  jni_env->Set ## JAVA_T_CAP ## ArrayRegion (jarr, 0, v.numel (), jv); \
1601  jobj = reinterpret_cast<jobject> (jarr); \
1602  jcls = jni_env->GetObjectClass (jobj); \
1603  } \
1604  while (0)
1605 
1606  // Note that we do NOT handle char here because they are unboxed
1607  // into a String[], not into a char array
1608 
1609  if (val.is_double_type ())
1610  UNBOX_PRIMITIVE_ARRAY ( , , jdouble, Double);
1611  else if (val.islogical ())
1612  UNBOX_PRIMITIVE_ARRAY (bool_, bool, jboolean, Boolean);
1613  else if (val.isfloat ())
1614  UNBOX_PRIMITIVE_ARRAY (float_, Float, jfloat, Float);
1615  else if (val.is_int8_type ())
1616  UNBOX_PRIMITIVE_ARRAY (int8_, int8, jbyte, Byte);
1617  else if (val.is_uint8_type ())
1618  UNBOX_PRIMITIVE_ARRAY (uint8_, uint8, jbyte, Byte);
1619  else if (val.is_int16_type ())
1620  UNBOX_PRIMITIVE_ARRAY (int16_, int16, jshort, Short);
1621  else if (val.is_uint16_type ())
1622  UNBOX_PRIMITIVE_ARRAY (uint16_, uint16, jshort, Short);
1623  else if (val.is_int32_type ())
1624  UNBOX_PRIMITIVE_ARRAY (int32_, int32, jint, Int);
1625  else if (val.is_uint32_type ())
1626  UNBOX_PRIMITIVE_ARRAY (uint32_, uint32, jint, Int);
1627  else if (val.is_int64_type ())
1628  UNBOX_PRIMITIVE_ARRAY (int64_, int64, jlong, Long);
1629  else if (val.is_uint64_type ())
1630  UNBOX_PRIMITIVE_ARRAY (uint64_, uint64, jlong, Long);
1631 
1632 #undef UNBOX_PRIMITIVE_ARRAY
1633  }
1634  else if (val.is_real_scalar () || val.is_bool_scalar ())
1635  {
1636  // FIXME: Is there any way to avoid code duplication here without
1637  // using a macro?
1638 
1639 #define UNBOX_PRIMITIVE_SCALAR(OCTAVE_T, METHOD_T, JAVA_T, JAVA_CON) \
1640  do \
1641  { \
1642  const OCTAVE_T ov = val.METHOD_T ## _value (); \
1643  jclass_ref dcls (jni_env, jni_env->FindClass (JAVA_T)); \
1644  const jfieldID fid = jni_env->GetStaticFieldID (dcls, "TYPE", "Ljava/lang/Class;"); \
1645  const jmethodID mid = jni_env->GetMethodID (dcls, "<init>", JAVA_CON); \
1646  jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (dcls, fid)); \
1647  jobj = jni_env->NewObject (dcls, mid, ov); \
1648  } \
1649  while (0)
1650 
1651  if (val.is_double_type ())
1652  UNBOX_PRIMITIVE_SCALAR (double, double, "java/lang/Double", "(D)V");
1653  else if (val.islogical ())
1654  UNBOX_PRIMITIVE_SCALAR (bool, bool, "java/lang/Boolean", "(Z)V");
1655  else if (val.isfloat ())
1656  UNBOX_PRIMITIVE_SCALAR (float, float, "java/lang/Float", "(F)V");
1657  else if (val.is_int8_type ())
1658  UNBOX_PRIMITIVE_SCALAR (int8_t, int8_scalar, "java/lang/Byte", "(B)V");
1659  else if (val.is_uint8_type ())
1660  UNBOX_PRIMITIVE_SCALAR (uint8_t, uint8_scalar, "java/lang/Byte", "(B)V");
1661  else if (val.is_int16_type ())
1662  UNBOX_PRIMITIVE_SCALAR (int16_t, int16_scalar, "java/lang/Short", "(S)V");
1663  else if (val.is_uint16_type ())
1664  UNBOX_PRIMITIVE_SCALAR (uint16_t, uint16_scalar, "java/lang/Short", "(S)V");
1665  else if (val.is_int32_type ())
1666  UNBOX_PRIMITIVE_SCALAR (int32_t, int32_scalar, "java/lang/Integer", "(I)V");
1667  else if (val.is_uint32_type ())
1668  UNBOX_PRIMITIVE_SCALAR (uint32_t, uint32_scalar, "java/lang/Integer", "(I)V");
1669  else if (val.is_int64_type ())
1670  UNBOX_PRIMITIVE_SCALAR (int64_t, int64_scalar, "java/lang/Long", "(J)V");
1671  else if (val.is_uint64_type ())
1672  UNBOX_PRIMITIVE_SCALAR (uint64_t, uint64_scalar, "java/lang/Long", "(J)V");
1673 
1674 #undef UNBOX_PRIMITIVE_SCALAR
1675  }
1676  else if (val.isempty ())
1677  {
1678  jobj = nullptr;
1679  jcls = nullptr;
1680  //jcls = jni_env->FindClass ("java/lang/Object");
1681  }
1682  else if (! Vjava_matrix_autoconversion
1683  && ((val.is_real_matrix ()
1684  && (val.rows () == 1 || val.columns () == 1))
1685  || val.is_range ()))
1686  {
1687  Matrix m = val.matrix_value ();
1688  jdoubleArray dv = jni_env->NewDoubleArray (m.numel ());
1689  jni_env->SetDoubleArrayRegion (dv, 0, m.numel (), m.fortran_vec ());
1690  jobj = dv;
1691  jcls = jni_env->GetObjectClass (jobj);
1692  }
1694  && (val.is_matrix_type () || val.is_range ())
1695  && val.isreal ())
1696  {
1697  jclass_ref mcls (jni_env, find_octave_class (jni_env,
1698  "org/octave/Matrix"));
1699  dim_vector dims = val.dims ();
1700  jintArray_ref iv (jni_env, jni_env->NewIntArray (dims.ndims ()));
1701  jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), nullptr);
1702 
1703  for (int i = 0; i < dims.ndims (); i++)
1704  iv_data[i] = dims(i);
1705 
1706  jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0);
1707 
1708  if (val.is_double_type ())
1709  {
1710  NDArray m = val.array_value ();
1711  jdoubleArray_ref dv (jni_env, jni_env->NewDoubleArray (m.numel ()));
1712  jni_env->SetDoubleArrayRegion (jdoubleArray (dv), 0, m.numel (),
1713  m.fortran_vec ());
1714  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([D[I)V");
1715  jobj = jni_env->NewObject (jclass (mcls), mID, jdoubleArray (dv),
1716  jintArray (iv));
1717  jcls = jni_env->GetObjectClass (jobj);
1718  }
1719  else if (val.is_int8_type ())
1720  {
1721  int8NDArray m = val.int8_array_value ();
1722  jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.numel ()));
1723  jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.numel (),
1724  reinterpret_cast<jbyte *>
1725  (m.fortran_vec ()));
1726  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([B[I)V");
1727  jobj = jni_env->NewObject
1728  (jclass (mcls), mID, jbyteArray (bv), jintArray (iv));
1729  jcls = jni_env->GetObjectClass (jobj);
1730  }
1731  else if (val.is_uint8_type ())
1732  {
1733  uint8NDArray m = val.uint8_array_value ();
1734  jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.numel ()));
1735  jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.numel (),
1736  reinterpret_cast<jbyte *>
1737  (m.fortran_vec ()));
1738  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([B[I)V");
1739  jobj = jni_env->NewObject
1740  (jclass (mcls), mID, jbyteArray (bv), jintArray (iv));
1741  jcls = jni_env->GetObjectClass (jobj);
1742  }
1743  else if (val.is_int32_type ())
1744  {
1745  int32NDArray m = val.int32_array_value ();
1746  jintArray_ref v (jni_env, jni_env->NewIntArray (m.numel ()));
1747  jni_env->SetIntArrayRegion (jintArray (v), 0, m.numel (),
1748  reinterpret_cast<jint *>
1749  (m.fortran_vec ()));
1750  jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([I[I)V");
1751  jobj = jni_env->NewObject
1752  (jclass (mcls), mID, jintArray (v), jintArray (iv));
1753  jcls = jni_env->GetObjectClass (jobj);
1754  }
1755  else
1756  {
1757  found = false;
1758  error ("cannot convert matrix of type '%s'",
1759  val.class_name ().c_str ());
1760  }
1761  }
1762  else
1763  {
1764  jclass rcls = find_octave_class (jni_env, "org/octave/OctaveReference");
1765  jmethodID mID = jni_env->GetMethodID (rcls, "<init>", "(I)V");
1766  int ID = octave_java_refcount++;
1767 
1768  jobj = jni_env->NewObject (rcls, mID, ID);
1769  jcls = rcls;
1770  octave_ref_map[ID] = val;
1771  }
1772 
1773  return found;
1774 }
1775 
1776 static bool
1777 unbox (JNIEnv *jni_env, const octave_value_list& args,
1778  jobjectArray_ref& jobjs, jobjectArray_ref& jclss)
1779 {
1780  bool found = true;
1781 
1782  jclass_ref ocls (jni_env, jni_env->FindClass ("java/lang/Object"));
1783  jclass_ref ccls (jni_env, jni_env->FindClass ("java/lang/Class"));
1784 
1785  if (! jobjs)
1786  jobjs = jni_env->NewObjectArray (args.length (), ocls, nullptr);
1787 
1788  if (! jclss)
1789  jclss = jni_env->NewObjectArray (args.length (), ccls, nullptr);
1790 
1791  for (int i = 0; i < args.length (); i++)
1792  {
1793  jobject_ref jobj (jni_env);
1794  jclass_ref jcls (jni_env);
1795 
1796  found = unbox (jni_env, args(i), jobj, jcls);
1797  if (! found)
1798  break;
1799 
1800  jni_env->SetObjectArrayElement (jobjs, i, jobj);
1801  jni_env->SetObjectArrayElement (jclss, i, jcls);
1802  }
1803 
1804  return found;
1805 }
1806 
1807 //! Returns the id of the current thread.
1808 //!
1809 //! @param jni_env The current environment or @c nullptr.
1810 //!
1811 //! @returns The id of the current thread or -1 otherwise. The latter happens
1812 //! if @c jni_env is @c nullptr, for example.
1813 
1814 static long
1815 get_current_thread_ID (JNIEnv *jni_env)
1816 {
1817  if (jni_env)
1818  {
1819  // Call Java method static Thread java.lang.Thread.currentThread().
1820  jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/Thread"));
1821  jmethodID mID = jni_env->GetStaticMethodID (cls, "currentThread",
1822  "()Ljava/lang/Thread;");
1823  jobject_ref jthread (jni_env, jni_env->CallStaticObjectMethod (cls, mID));
1824 
1825  if (jthread)
1826  {
1827  // Call Java method long java.lang.Thread.getId().
1828  jclass_ref jth_cls (jni_env, jni_env->GetObjectClass (jthread));
1829  mID = jni_env->GetMethodID (jth_cls, "getId", "()J");
1830  long result = jni_env->CallLongMethod (jthread, mID);
1831  return result;
1832  }
1833  }
1834 
1835  return -1;
1836 }
1837 
1838 //! Run the java method @c org.octave.Octave.checkPendingAction().
1839 //!
1840 //! @returns 0 in any case for good reason.
1841 
1842 static int
1843 java_event_hook (void)
1844 {
1845  JNIEnv *current_env = thread_jni_env ();
1846 
1847  if (current_env)
1848  {
1849  // Invoke static void org.octave.Octave.checkPendingAction().
1850  jclass_ref cls (current_env, find_octave_class (current_env,
1851  "org/octave/Octave"));
1852  jmethodID mID = current_env->GetStaticMethodID
1853  (cls, "checkPendingAction", "()V");
1854  current_env->CallStaticVoidMethod (cls, mID);
1855 
1857  }
1858 
1859  return 0;
1860 }
1861 
1862 //! Initialize java including the virtual machine (jvm) if necessary.
1863 //!
1864 //! Initializes the fields #jvm, #jvm_attached, #jvm_lib, and
1865 //! #octave_thread_ID. To ensure that java is initialized, this method is
1866 //! used as part of octave functions @c javaObject, @c javaMethod,
1867 //! @c __java_get__, @c __java_set__, and @c __java2mat__.
1868 
1869 static void
1870 initialize_java (void)
1871 {
1872  if (! jvm)
1873  {
1874  try
1875  {
1876  initialize_jvm ();
1877 
1878  JNIEnv *current_env = thread_jni_env ();
1879 
1880  octave::command_editor::add_event_hook (java_event_hook);
1881 
1882  octave_thread_ID = get_current_thread_ID (current_env);
1883  }
1884  catch (std::string msg)
1885  {
1886  error (msg.c_str ());
1887  }
1888 
1890  }
1891 }
1892 
1893 JNIEXPORT jboolean JNICALL
1894 Java_org_octave_Octave_call (JNIEnv *env, jclass, jstring funcName,
1895  jobjectArray argin, jobjectArray argout)
1896 {
1897  std::string fname = jstring_to_string (env, funcName);
1898 
1899  int nargout = env->GetArrayLength (argout);
1900  int nargin = env->GetArrayLength (argin);
1901 
1902  octave_value_list varargin, varargout;
1903 
1904  for (int i = 0; i < nargin; i++)
1905  varargin(i) = box (env, env->GetObjectArrayElement (argin, i), nullptr);
1906 
1907  varargout = octave::feval (fname, varargin, nargout);
1908 
1909  jobjectArray_ref out_objs (env, argout), out_clss (env);
1910  out_objs.detach ();
1911  return unbox (env, varargout, out_objs, out_clss);
1912 }
1913 
1914 JNIEXPORT void JNICALL
1915 Java_org_octave_OctaveReference_doFinalize (JNIEnv *, jclass, jint ID)
1916 {
1917  octave_ref_map.erase (ID);
1918 }
1919 
1920 JNIEXPORT void JNICALL
1921 Java_org_octave_Octave_doInvoke (JNIEnv *env, jclass, jint ID,
1922  jobjectArray args)
1923 {
1924  std::map<int,octave_value>::iterator it = octave_ref_map.find (ID);
1925 
1926  if (it != octave_ref_map.end ())
1927  {
1928  octave_value val = it->second;
1929  int len = env->GetArrayLength (args);
1930  octave_value_list oct_args;
1931 
1932  for (int i = 0; i < len; i++)
1933  {
1934  jobject_ref jobj (env, env->GetObjectArrayElement (args, i));
1935  oct_args(i) = box (env, jobj, nullptr);
1936  }
1937 
1938  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
1939 
1940  if (val.is_function_handle ())
1941  {
1942  octave_function *fcn = val.function_value ();
1943  octave::feval (fcn, oct_args);
1944  }
1945  else if (val.iscell () && val.length () > 0
1946  && (val.rows () == 1 || val.columns () == 1)
1947  && val.cell_value()(0).is_function_handle ())
1948  {
1949  Cell c = val.cell_value ();
1950  octave_function *fcn = c(0).function_value ();
1951 
1952  for (int i=1; i<c.numel (); i++)
1953  oct_args(len+i-1) = c(i);
1954 
1955  octave::feval (fcn, oct_args);
1956  }
1957  else
1958  error ("trying to invoke non-invocable object");
1959 
1960  END_INTERRUPT_WITH_EXCEPTIONS;
1961  }
1962 }
1963 
1964 JNIEXPORT void JNICALL
1965 Java_org_octave_Octave_doEvalString (JNIEnv *env, jclass, jstring cmd)
1966 {
1967  std::string s = jstring_to_string (env, cmd);
1968  int pstatus;
1969  octave::eval_string (s, false, pstatus, 0);
1970 }
1971 
1972 JNIEXPORT jboolean JNICALL
1974 {
1975  return (get_current_thread_ID (env) != octave_thread_ID);
1976 }
1977 
1978 #endif
1979 
1980 //! Ctor.
1981 
1983  : octave_base_value (), java_object (nullptr), java_class (nullptr)
1984 {
1985 #if ! defined (HAVE_JAVA)
1986 
1987  err_disabled_feature ("Java Objects", "Java");
1988 
1989 #endif
1990 }
1991 
1992 octave_java::octave_java (const voidptr& jobj, void *jcls)
1993  : octave_base_value (), java_object (nullptr), java_class (nullptr)
1994 {
1995 #if defined (HAVE_JAVA)
1996 
1997  init (jobj, jcls);
1998 
1999 #else
2000 
2001  octave_unused_parameter (jobj);
2002  octave_unused_parameter (jcls);
2003 
2004  err_disabled_feature ("Java Objects", "Java");
2005 
2006 #endif
2007 }
2008 
2009 int octave_java::t_id (-1);
2010 
2011 const std::string octave_java::t_name ("octave_java");
2012 
2013 void
2015 {
2016 #if defined (HAVE_JAVA)
2017 
2018  t_id = ti.register_type (octave_java::t_name, "<unknown>",
2019  octave_value (new octave_java ()));
2020 
2021 #else
2022 
2023  octave_unused_parameter (ti);
2024 
2025 #endif
2026 }
2027 
2028 dim_vector
2029 octave_java::dims (void) const
2030 {
2031 #if defined (HAVE_JAVA)
2032 
2033  JNIEnv *current_env = thread_jni_env ();
2034 
2035  if (current_env && java_object)
2036  return compute_array_dimensions (current_env, TO_JOBJECT (java_object));
2037  else
2038  return dim_vector (1, 1);
2039 
2040 #else
2041 
2042  // This shouldn't happen because construction of octave_java objects is
2043  // supposed to be impossible if Java is not available.
2044 
2045  panic_impossible ();
2046 
2047 #endif
2048 }
2049 
2052  const std::list<octave_value_list>& idx, int nargout)
2053 {
2054 #if defined (HAVE_JAVA)
2055 
2057  int skip = 1;
2058 
2059  JNIEnv *current_env = thread_jni_env ();
2060 
2061  switch (type[0])
2062  {
2063  case '.':
2064  if (type.length () > 1 && type[1] == '(')
2065  {
2067  count++;
2068  ovl(1) = octave_value (this);
2069  ovl(0) = (idx.front ())(0);
2070  std::list<octave_value_list>::const_iterator it = idx.begin ();
2071  ovl.append (*++it);
2072  retval = FjavaMethod (ovl, 1);
2073  skip++;
2074  }
2075  else
2076  {
2078  count++;
2079  ovl(0) = octave_value (this);
2080  ovl(1) = (idx.front ())(0);
2081  retval = F__java_get__ (ovl, 1);
2082  }
2083  break;
2084 
2085  case '(':
2086  if (current_env)
2088  (current_env, TO_JOBJECT (to_java ()), idx.front ());
2089  break;
2090 
2091  default:
2092  error ("subsref: Java object cannot be indexed with %c", type[0]);
2093  break;
2094  }
2095 
2096  if (idx.size () > 1 && type.length () > 1)
2097  retval = retval(0).next_subsref (nargout, type, idx, skip);
2098 
2099  return retval;
2100 
2101 #else
2102 
2103  octave_unused_parameter (type);
2104  octave_unused_parameter (idx);
2105  octave_unused_parameter (nargout);
2106 
2107  // This shouldn't happen because construction of octave_java objects is
2108  // supposed to be impossible if Java is not available.
2109 
2110  panic_impossible ();
2111 
2112 #endif
2113 }
2114 
2117  const std::list<octave_value_list>& idx,
2118  const octave_value& rhs)
2119 {
2120 #if defined (HAVE_JAVA)
2121 
2123 
2124  JNIEnv *current_env = thread_jni_env ();
2125 
2126  switch (type[0])
2127  {
2128  case '.':
2129  if (type.length () == 1)
2130  {
2131  // field assignment
2133  count++;
2134  ovl(0) = octave_value (this);
2135  ovl(1) = (idx.front ())(0);
2136  ovl(2) = rhs;
2137  F__java_set__ (ovl);
2138 
2139  count++;
2140  retval = octave_value (this);
2141  }
2142  else if (type.length () > 2 && type[1] == '(')
2143  {
2144  std::list<octave_value_list> new_idx;
2145  std::list<octave_value_list>::const_iterator it = idx.begin ();
2146  new_idx.push_back (*it++);
2147  new_idx.push_back (*it++);
2148  octave_value_list u = subsref (type.substr (0, 2), new_idx, 1);
2149 
2150  std::list<octave_value_list> next_idx (idx);
2151  next_idx.erase (next_idx.begin ());
2152  next_idx.erase (next_idx.begin ());
2153  u(0).subsasgn (type.substr (2), next_idx, rhs);
2154 
2155  count++;
2156  retval = octave_value (this);
2157  }
2158  else if (type[1] == '.')
2159  {
2160  octave_value_list u = subsref (type.substr (0, 1), idx, 1);
2161 
2162  std::list<octave_value_list> next_idx (idx);
2163  next_idx.erase (next_idx.begin ());
2164  u(0).subsasgn (type.substr (1), next_idx, rhs);
2165 
2166  count++;
2167  retval = octave_value (this);
2168  }
2169  else
2170  error ("invalid indexing/assignment on Java object");
2171  break;
2172 
2173  case '(':
2174  if (current_env)
2175  {
2176  set_array_elements (current_env, TO_JOBJECT (to_java ()),
2177  idx.front (), rhs);
2178 
2179  count++;
2180  retval = octave_value (this);
2181  }
2182  break;
2183 
2184  default:
2185  error ("Java object cannot be indexed with %c", type[0]);
2186  break;
2187  }
2188 
2189  return retval;
2190 
2191 #else
2192 
2193  octave_unused_parameter (type);
2194  octave_unused_parameter (idx);
2195  octave_unused_parameter (rhs);
2196 
2197  // This shouldn't happen because construction of octave_java objects is
2198  // supposed to be impossible if Java is not available.
2199 
2200  panic_impossible ();
2201 
2202 #endif
2203 }
2204 
2206 octave_java::map_keys (void) const
2207 {
2208 #if defined (HAVE_JAVA)
2209 
2210  JNIEnv *current_env = thread_jni_env ();
2211 
2212  if (current_env)
2213  return get_invoke_list (current_env, to_java ());
2214  else
2215  return string_vector ();
2216 
2217 #else
2218 
2219  // This shouldn't happen because construction of octave_java objects is
2220  // supposed to be impossible if Java is not available.
2221 
2222  panic_impossible ();
2223 
2224 #endif
2225 }
2226 
2228 octave_java::convert_to_str_internal (bool, bool force, char type) const
2229 {
2230 #if defined (HAVE_JAVA)
2231 
2232  JNIEnv *current_env = thread_jni_env ();
2233 
2234  if (current_env)
2235  return convert_to_string (current_env, TO_JOBJECT (to_java ()), force, type);
2236  else
2237  return octave_value ("");
2238 
2239 #else
2240 
2241  octave_unused_parameter (force);
2242  octave_unused_parameter (type);
2243 
2244  // This shouldn't happen because construction of octave_java objects is
2245  // supposed to be impossible if Java is not available.
2246 
2247  panic_impossible ();
2248 
2249 #endif
2250 }
2251 
2252 void
2253 octave_java::print (std::ostream& os, bool)
2254 {
2255  print_raw (os);
2256  newline (os);
2257 }
2258 
2259 void
2260 octave_java::print_raw (std::ostream& os, bool) const
2261 {
2262  os << "<Java object: " << java_classname << '>';
2263 }
2264 
2265 // FIXME: Need routines to actually save/load java objects through Serialize.
2266 // See bug #42112.
2267 
2268 bool
2269 octave_java::save_ascii (std::ostream& /* os */)
2270 {
2271  warning ("save: unable to save java objects, skipping");
2272 
2273  return true;
2274 }
2275 
2276 bool
2277 octave_java::load_ascii (std::istream& /* is */)
2278 {
2279  // Silently skip over java object that was not saved
2280  return true;
2281 }
2282 
2283 bool
2284 octave_java::save_binary (std::ostream& /* os */, bool& /* save_as_floats */)
2285 {
2286  warning ("save: unable to save java objects, skipping");
2287 
2288  return true;
2289 }
2290 
2291 bool
2292 octave_java::load_binary (std::istream& /* is */, bool /* swap*/,
2293  octave::mach_info::float_format /* fmt */)
2294 {
2295  // Silently skip over java object that was not saved
2296  return true;
2297 }
2298 
2299 bool
2300 octave_java::save_hdf5 (octave_hdf5_id /* loc_id */, const char * /* name */,
2301  bool /* save_as_floats */)
2302 {
2303  warning ("save: unable to save java objects, skipping");
2304 
2305  return true;
2306 }
2307 
2308 bool
2309 octave_java::load_hdf5 (octave_hdf5_id /* loc_id */, const char * /* name */)
2310 {
2311  // Silently skip object that was not saved
2312  return true;
2313 }
2314 
2315 octave_value
2316 octave_java::do_javaMethod (void *jni_env_arg, const std::string& name,
2317  const octave_value_list& args)
2318 {
2319 #if defined (HAVE_JAVA)
2320 
2321  octave_value retval;
2322 
2323  JNIEnv *jni_env = TO_JNIENV (jni_env_arg);
2324 
2325  if (jni_env)
2326  {
2327  jobjectArray_ref arg_objs (jni_env), arg_types (jni_env);
2328  if (unbox (jni_env, args, arg_objs, arg_types))
2329  {
2330  jclass_ref helperClass (jni_env, find_octave_class (jni_env, "org/octave/ClassHelper"));
2331  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeMethod",
2332  "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;");
2333  jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ()));
2334  jobjectArray_ref resObj (jni_env, reinterpret_cast<jobjectArray> (jni_env->CallStaticObjectMethod (helperClass, mID,
2335  to_java (), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types))));
2336  if (resObj)
2337  retval = box (jni_env, resObj);
2338  else
2339  retval = check_exception (jni_env);
2340  }
2341 
2342  octave_set_default_fpucw ();
2343  }
2344 
2345  return retval;
2346 
2347 #else
2348 
2349  octave_unused_parameter (jni_env_arg);
2350  octave_unused_parameter (name);
2351  octave_unused_parameter (args);
2352 
2353  // This shouldn't happen because construction of octave_java objects is
2354  // supposed to be impossible if Java is not available.
2355 
2356  panic_impossible ();
2357 
2358 #endif
2359 }
2360 
2363  const octave_value_list& args)
2364 {
2365 #if defined (HAVE_JAVA)
2366 
2367  return do_javaMethod (thread_jni_env (), name, args);
2368 
2369 #else
2370 
2371  octave_unused_parameter (name);
2372  octave_unused_parameter (args);
2373 
2374  // This shouldn't happen because construction of octave_java
2375  // objects is supposed to be impossible if Java is not available.
2376 
2377  panic_impossible ();
2378 
2379 #endif
2380 }
2381 
2383 octave_java::do_javaMethod (void *jni_env_arg,
2384  const std::string& class_name,
2385  const std::string& name,
2386  const octave_value_list& args)
2387 {
2388 #if defined (HAVE_JAVA)
2389 
2391 
2392  JNIEnv *jni_env = TO_JNIENV (jni_env_arg);
2393 
2394  if (jni_env)
2395  {
2396  jobjectArray_ref arg_objs (jni_env), arg_types (jni_env);
2397  if (unbox (jni_env, args, arg_objs, arg_types))
2398  {
2399  jclass_ref helperClass (jni_env,
2400  find_octave_class (jni_env,
2401  "org/octave/ClassHelper"));
2402  jmethodID mID = jni_env->GetStaticMethodID (helperClass,
2403  "invokeStaticMethod",
2404  "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;");
2405  jstring_ref methName (jni_env,
2406  jni_env->NewStringUTF (name.c_str ()));
2407  jstring_ref clsName (jni_env,
2408  jni_env->NewStringUTF (class_name.c_str ()));
2409  jobject_ref resObj (jni_env,
2410  jni_env->CallStaticObjectMethod (helperClass,
2411  mID,
2412  jstring (clsName),
2413  jstring (methName),
2414  jobjectArray (arg_objs),
2415  jobjectArray (arg_types)));
2416  if (resObj)
2417  retval = box (jni_env, resObj);
2418  else
2419  retval = check_exception (jni_env);
2420  }
2421 
2423  }
2424 
2425  return retval;
2426 
2427 #else
2428 
2429  octave_unused_parameter (jni_env_arg);
2430  octave_unused_parameter (class_name);
2431  octave_unused_parameter (name);
2432  octave_unused_parameter (args);
2433 
2434  // This shouldn't happen because construction of octave_java
2435  // objects is supposed to be impossible if Java is not available.
2436 
2437  panic_impossible ();
2438 
2439 #endif
2440 }
2441 
2443 octave_java::do_javaMethod (const std::string& class_name,
2444  const std::string& name,
2445  const octave_value_list& args)
2446 {
2447 #if defined (HAVE_JAVA)
2448 
2449  return do_javaMethod (thread_jni_env (), class_name, name, args);
2450 
2451 #else
2452 
2453  octave_unused_parameter (class_name);
2454  octave_unused_parameter (name);
2455  octave_unused_parameter (args);
2456 
2457  // This shouldn't happen because construction of octave_java
2458  // objects is supposed to be impossible if Java is not available.
2459 
2460  panic_impossible ();
2461 
2462 #endif
2463 }
2464 
2466 octave_java::do_javaObject (void *jni_env_arg, const std::string& name,
2467  const octave_value_list& args)
2468 {
2469 #if defined (HAVE_JAVA)
2470 
2472 
2473  JNIEnv *jni_env = TO_JNIENV (jni_env_arg);
2474 
2475  if (jni_env)
2476  {
2477  jobjectArray_ref arg_objs (jni_env), arg_types (jni_env);
2478 
2479  if (unbox (jni_env, args, arg_objs, arg_types))
2480  {
2481  jclass_ref helperClass (jni_env,
2482  find_octave_class (jni_env,
2483  "org/octave/ClassHelper"));
2484  jmethodID mID = jni_env->GetStaticMethodID (helperClass,
2485  "invokeConstructor",
2486  "(Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;");
2487  jstring_ref clsName (jni_env,
2488  jni_env->NewStringUTF (name.c_str ()));
2489  jobject_ref resObj (jni_env,
2490  jni_env->CallStaticObjectMethod (helperClass,
2491  mID,
2492  jstring (clsName),
2493  jobjectArray (arg_objs),
2494  jobjectArray (arg_types)));
2495 
2496  if (resObj)
2497  retval = octave_value (new octave_java (resObj, nullptr));
2498  else
2499  check_exception (jni_env);
2500  }
2501 
2503  }
2504 
2505  return retval;
2506 
2507 #else
2508 
2509  octave_unused_parameter (jni_env_arg);
2510  octave_unused_parameter (name);
2511  octave_unused_parameter (args);
2512 
2513  // This shouldn't happen because construction of octave_java
2514  // objects is supposed to be impossible if Java is not available.
2515 
2516  panic_impossible ();
2517 
2518 #endif
2519 }
2520 
2523  const octave_value_list& args)
2524 {
2525 #if defined (HAVE_JAVA)
2526 
2527  return do_javaObject (thread_jni_env (), name, args);
2528 
2529 #else
2530 
2531  octave_unused_parameter (name);
2532  octave_unused_parameter (args);
2533 
2534  // This shouldn't happen because construction of octave_java
2535  // objects is supposed to be impossible if Java is not available.
2536 
2537  panic_impossible ();
2538 
2539 #endif
2540 }
2541 
2543 octave_java::do_java_get (void *jni_env_arg, const std::string& name)
2544 {
2545 #if defined (HAVE_JAVA)
2546 
2548 
2549  JNIEnv *jni_env = TO_JNIENV (jni_env_arg);
2550 
2551  if (jni_env)
2552  {
2553  jclass_ref helperClass (jni_env,
2554  find_octave_class (jni_env,
2555  "org/octave/ClassHelper"));
2556  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getField",
2557  "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");
2558  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
2559  jobject_ref resObj (jni_env,
2560  jni_env->CallStaticObjectMethod (helperClass,
2561  mID,
2562  to_java (),
2563  jstring (fName)));
2564 
2565  if (resObj)
2566  retval = box (jni_env, resObj);
2567  else
2568  retval = check_exception (jni_env);
2569 
2571  }
2572 
2573  return retval;
2574 
2575 #else
2576 
2577  octave_unused_parameter (jni_env_arg);
2578  octave_unused_parameter (name);
2579 
2580  // This shouldn't happen because construction of octave_java
2581  // objects is supposed to be impossible if Java is not available.
2582 
2583  panic_impossible ();
2584 
2585 #endif
2586 }
2587 
2590 {
2591 #if defined (HAVE_JAVA)
2592 
2593  return do_java_get (thread_jni_env (), name);
2594 
2595 #else
2596 
2597  octave_unused_parameter (name);
2598 
2599  // This shouldn't happen because construction of octave_java
2600  // objects is supposed to be impossible if Java is not available.
2601 
2602  panic_impossible ();
2603 
2604 #endif
2605 }
2606 
2608 octave_java::do_java_get (void *jni_env_arg, const std::string& class_name,
2609  const std::string& name)
2610 {
2611 #if defined (HAVE_JAVA)
2612 
2614 
2615  JNIEnv *jni_env = TO_JNIENV (jni_env_arg);
2616 
2617  if (jni_env)
2618  {
2619  jclass_ref helperClass (jni_env,
2620  find_octave_class (jni_env,
2621  "org/octave/ClassHelper"));
2622  jmethodID mID = jni_env->GetStaticMethodID (helperClass,
2623  "getStaticField",
2624  "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
2625  jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ()));
2626  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
2627  jobject_ref resObj (jni_env,
2628  jni_env->CallStaticObjectMethod (helperClass, mID,
2629  jstring (cName),
2630  jstring (fName)));
2631  if (resObj)
2632  retval = box (jni_env, resObj);
2633  else
2634  retval = check_exception (jni_env);
2635 
2637  }
2638 
2639  return retval;
2640 
2641 #else
2642 
2643  octave_unused_parameter (jni_env_arg);
2644  octave_unused_parameter (class_name);
2645  octave_unused_parameter (name);
2646 
2647  // This shouldn't happen because construction of octave_java
2648  // objects is supposed to be impossible if Java is not available.
2649 
2650  panic_impossible ();
2651 
2652 #endif
2653 }
2654 
2656 octave_java::do_java_get (const std::string& class_name,
2657  const std::string& name)
2658 {
2659 #if defined (HAVE_JAVA)
2660 
2661  return do_java_get (thread_jni_env (), class_name, name);
2662 
2663 #else
2664 
2665  octave_unused_parameter (class_name);
2666  octave_unused_parameter (name);
2667 
2668  // This shouldn't happen because construction of octave_java
2669  // objects is supposed to be impossible if Java is not available.
2670 
2671  panic_impossible ();
2672 
2673 #endif
2674 }
2675 
2677 octave_java::do_java_set (void *jni_env_arg, const std::string& name,
2678  const octave_value& val)
2679 {
2680 #if defined (HAVE_JAVA)
2681 
2683 
2684  JNIEnv *jni_env = TO_JNIENV (jni_env_arg);
2685 
2686  if (jni_env)
2687  {
2688  jobject_ref jobj (jni_env);
2689  jclass_ref jcls (jni_env);
2690 
2691  if (unbox (jni_env, val, jobj, jcls))
2692  {
2693  jclass_ref helperClass (jni_env,
2694  find_octave_class (jni_env,
2695  "org/octave/ClassHelper"));
2696  jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setField",
2697  "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");
2698  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
2699  jni_env->CallStaticObjectMethod (helperClass, mID, to_java (),
2700  jstring (fName), jobject (jobj));
2701  check_exception (jni_env);
2702  }
2703 
2705  }
2706 
2707  return retval;
2708 
2709 #else
2710 
2711  octave_unused_parameter (jni_env_arg);
2712  octave_unused_parameter (name);
2713  octave_unused_parameter (val);
2714 
2715  // This shouldn't happen because construction of octave_java
2716  // objects is supposed to be impossible if Java is not available.
2717 
2718  panic_impossible ();
2719 
2720 #endif
2721 }
2722 
2725 {
2726 #if defined (HAVE_JAVA)
2727 
2728  return do_java_set (thread_jni_env (), name, val);
2729 
2730 #else
2731 
2732  octave_unused_parameter (name);
2733  octave_unused_parameter (val);
2734 
2735  // This shouldn't happen because construction of octave_java
2736  // objects is supposed to be impossible if Java is not available.
2737 
2738  panic_impossible ();
2739 
2740 #endif
2741 }
2742 
2744 octave_java::do_java_set (void *jni_env_arg, const std::string& class_name,
2745  const std::string& name, const octave_value& val)
2746 {
2747 #if defined (HAVE_JAVA)
2748 
2750 
2751  JNIEnv *jni_env = TO_JNIENV (jni_env_arg);
2752 
2753  if (jni_env)
2754  {
2755  jobject_ref jobj (jni_env);
2756  jclass_ref jcls (jni_env);
2757 
2758  if (unbox (jni_env, val, jobj, jcls))
2759  {
2760  jclass_ref helperClass (jni_env,
2761  find_octave_class (jni_env,
2762  "org/octave/ClassHelper"));
2763  jmethodID mID = jni_env->GetStaticMethodID (helperClass,
2764  "setStaticField",
2765  "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V");
2766  jstring_ref cName (jni_env,
2767  jni_env->NewStringUTF (class_name.c_str ()));
2768  jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ()));
2769  jni_env->CallStaticObjectMethod (helperClass, mID, jstring (cName),
2770  jstring (fName), jobject (jobj));
2771  check_exception (jni_env);
2772  }
2773 
2775  }
2776 
2777  return retval;
2778 
2779 #else
2780 
2781  octave_unused_parameter (jni_env_arg);
2782  octave_unused_parameter (class_name);
2783  octave_unused_parameter (name);
2784  octave_unused_parameter (val);
2785 
2786  // This shouldn't happen because construction of octave_java
2787  // objects is supposed to be impossible if Java is not available.
2788 
2789  panic_impossible ();
2790 
2791 #endif
2792 }
2793 
2795 octave_java::do_java_set (const std::string& class_name,
2796  const std::string& name,
2797  const octave_value& val)
2798 {
2799 #if defined (HAVE_JAVA)
2800 
2801  return do_java_set (thread_jni_env (), class_name, name, val);
2802 
2803 #else
2804 
2805  octave_unused_parameter (class_name);
2806  octave_unused_parameter (name);
2807  octave_unused_parameter (val);
2808 
2809  // This shouldn't happen because construction of octave_java
2810  // objects is supposed to be impossible if Java is not available.
2811 
2812  panic_impossible ();
2813 
2814 #endif
2815 }
2816 
2817 void
2818 octave_java::init (void *jobj_arg, void *jcls_arg)
2819 {
2820 #if defined (HAVE_JAVA)
2821 
2822  jobject jobj = TO_JOBJECT (jobj_arg);
2823  jclass jcls = TO_JCLASS (jcls_arg);
2824 
2825  JNIEnv *current_env = thread_jni_env ();
2826 
2827  if (current_env)
2828  {
2829  if (jobj)
2830  java_object = current_env->NewGlobalRef (jobj);
2831 
2832  if (jcls)
2833  java_class = current_env->NewGlobalRef (jcls);
2834  else if (java_object)
2835  {
2836  jclass_ref ocls (current_env,
2837  current_env->GetObjectClass(TO_JOBJECT (java_object)));
2838  java_class = current_env->NewGlobalRef (jclass (ocls));
2839  }
2840 
2841  if (java_class)
2842  {
2843  jclass_ref clsCls (current_env,
2844  current_env->GetObjectClass (TO_JCLASS (java_class)));
2845  jmethodID mID = current_env->GetMethodID (clsCls,
2846  "getCanonicalName",
2847  "()Ljava/lang/String;");
2848  jobject_ref resObj (current_env,
2849  current_env->CallObjectMethod (TO_JCLASS (java_class), mID));
2850  java_classname = jstring_to_string (current_env, resObj);
2851  }
2852  }
2853 
2854 #else
2855 
2856  octave_unused_parameter (jobj_arg);
2857  octave_unused_parameter (jcls_arg);
2858 
2859  // This shouldn't happen because construction of octave_java
2860  // objects is supposed to be impossible if Java is not available.
2861 
2862  panic_impossible ();
2863 
2864 #endif
2865 }
2866 
2867 void
2868 octave_java::release (void)
2869 {
2870 #if defined (HAVE_JAVA)
2871 
2872  JNIEnv *current_env = thread_jni_env ();
2873 
2874  if (current_env)
2875  {
2876  if (java_object)
2877  current_env->DeleteGlobalRef (TO_JOBJECT (java_object));
2878 
2879  if (java_class)
2880  current_env->DeleteGlobalRef (TO_JCLASS (java_class));
2881 
2882  java_object = nullptr;
2883  java_class = nullptr;
2884  }
2885 
2886 #else
2887 
2888  // This shouldn't happen because construction of octave_java objects is
2889  // supposed to be impossible if Java is not available.
2890 
2891  panic_impossible ();
2892 
2893 #endif
2894 }
2895 
2896 // DEFUN blocks below must be outside of HAVE_JAVA block so that documentation
2897 // strings are always available, even when functions are not.
2898 
2899 DEFUN (__java_init__, , ,
2900  doc: /* -*- texinfo -*-
2901 @deftypefn {} {} __java_init__ ()
2902 Internal function used @strong{only} when debugging Java interface.
2903 
2904 Function will directly call initialize_java to create an instance of a JVM.
2905 @end deftypefn */)
2906 {
2907 #if defined (HAVE_JAVA)
2908 
2909  octave_value retval = 0;
2910 
2911  initialize_java ();
2912 
2913  retval = 1;
2914 
2915  return retval;
2916 
2917 #else
2918 
2919  err_disabled_feature ("__java_init__", "Java");
2920 
2921 #endif
2922 }
2923 
2924 DEFUN (__java_exit__, , ,
2925  doc: /* -*- texinfo -*-
2926 @deftypefn {} {} __java_exit__ ()
2927 Internal function used @strong{only} when debugging Java interface.
2928 
2929 Function will directly call terminate_jvm to destroy the current JVM
2930 instance.
2931 @end deftypefn */)
2932 {
2933 #if defined (HAVE_JAVA)
2934 
2935  terminate_jvm ();
2936 
2937  return ovl ();
2938 
2939 #else
2940 
2941  err_disabled_feature ("__java_exit__", "Java");
2942 
2943 #endif
2944 }
2945 
2946 DEFUN (javaObject, args, ,
2947  doc: /* -*- texinfo -*-
2948 @deftypefn {} {@var{jobj} =} javaObject (@var{classname})
2949 @deftypefnx {} {@var{jobj} =} javaObject (@var{classname}, @var{arg1}, @dots{})
2950 Create a Java object of class @var{classsname}, by calling the class
2951 constructor with the arguments @var{arg1}, @dots{}
2952 
2953 The first example below creates an uninitialized object, while the second
2954 example supplies an initial argument to the constructor.
2955 
2956 @example
2957 @group
2958 x = javaObject ("java.lang.StringBuffer")
2959 x = javaObject ("java.lang.StringBuffer", "Initial string")
2960 @end group
2961 @end example
2962 
2963 @seealso{javaMethod, javaArray}
2964 @end deftypefn */)
2965 {
2966 #if defined (HAVE_JAVA)
2967 
2968  if (args.length () == 0)
2969  print_usage ();
2970 
2971  std::string classname = args(0).xstring_value ("javaObject: CLASSNAME must be a string");
2972 
2973  initialize_java ();
2974 
2975  JNIEnv *current_env = thread_jni_env ();
2976 
2978  for (int i=1; i<args.length (); i++)
2979  tmp(i-1) = args(i);
2980 
2981  return ovl (octave_java::do_javaObject (current_env, classname, tmp));
2982 
2983 #else
2984 
2985  octave_unused_parameter (args);
2986 
2987  err_disabled_feature ("javaObject", "Java");
2988 
2989 #endif
2990 }
2991 
2992 /*
2993 ## The tests below merely check if javaObject works at all. Whether
2994 ## it works properly, i.e., creates the right values, is a matter of
2995 ## Java itself. Create a Short and check if it really is a short, i.e.,
2996 ## whether it overflows.
2997 %!testif HAVE_JAVA; usejava ("jvm")
2998 %! assert (javaObject ("java.lang.Short", 40000).doubleValue < 0);
2999 */
3000 
3001 DEFUN (javaMethod, args, ,
3002  doc: /* -*- texinfo -*-
3003 @deftypefn {} {@var{ret} =} javaMethod (@var{methodname}, @var{obj})
3004 @deftypefnx {} {@var{ret} =} javaMethod (@var{methodname}, @var{obj}, @var{arg1}, @dots{})
3005 Invoke the method @var{methodname} on the Java object @var{obj} with the
3006 arguments @var{arg1}, @dots{}.
3007 
3008 For static methods, @var{obj} can be a string representing the fully
3009 qualified name of the corresponding class.
3010 
3011 When @var{obj} is a regular Java object, structure-like indexing can be
3012 used as a shortcut syntax. For instance, the two following statements are
3013 equivalent
3014 
3015 @example
3016 @group
3017  ret = javaMethod ("method1", x, 1.0, "a string")
3018  ret = x.method1 (1.0, "a string")
3019 @end group
3020 @end example
3021 
3022 @code{javaMethod} returns the result of the method invocation.
3023 
3024 @seealso{methods, javaObject}
3025 @end deftypefn */)
3026 {
3027 #if defined (HAVE_JAVA)
3028 
3029  if (args.length () < 2)
3030  print_usage ();
3031 
3032  std::string methodname = args(0).xstring_value ("javaMethod: METHODNAME must be a string");
3033 
3034  initialize_java ();
3035 
3036  JNIEnv *current_env = thread_jni_env ();
3037 
3039 
3041  for (int i=2; i<args.length (); i++)
3042  tmp(i-2) = args(i);
3043 
3044  if (args(1).isjava ())
3045  {
3046  octave_java *jobj = TO_JAVA (args(1));
3047  retval = jobj->do_javaMethod (current_env, methodname, tmp);
3048  }
3049  else if (args(1).is_string ())
3050  {
3051  std::string cls = args(1).string_value ();
3052  retval = octave_java::do_javaMethod (current_env, cls, methodname, tmp);
3053  }
3054  else
3055  error ("javaMethod: OBJ must be a Java object or a string");
3056 
3057  return retval;
3058 
3059 #else
3060 
3061  octave_unused_parameter (args);
3062 
3063  err_disabled_feature ("javaMethod", "Java");
3064 
3065 #endif
3066 }
3067 
3068 /*
3069 %!testif HAVE_JAVA; usejava ("jvm")
3070 %! jver = javaMethod ("getProperty", "java.lang.System", "java.version");
3071 %! jver = strsplit (jver, ".");
3072 %! if (numel (jver) > 1)
3073 %! assert (isfinite (str2double (jver{1})));
3074 %! assert (isfinite (str2double (jver{2})));
3075 %! else
3076 %! assert (isfinite (str2double (jver{1})));
3077 %! endif
3078 */
3079 
3080 DEFUN (__java_get__, args, ,
3081  doc: /* -*- texinfo -*-
3082 @deftypefn {} {@var{val} =} __java_get__ (@var{obj}, @var{name})
3083 Get the value of the field @var{name} of the Java object @var{obj}.
3084 
3085 For static fields, @var{obj} can be a string representing the fully
3086 qualified name of the corresponding class.
3087 
3088 When @var{obj} is a regular Java object, structure-like indexing can be used
3089 as a shortcut syntax. For instance, the two following statements are
3090 equivalent
3091 
3092 @example
3093 @group
3094  __java_get__ (x, "field1")
3095  x.field1
3096 @end group
3097 @end example
3098 
3099 @seealso{__java_set__, javaMethod, javaObject}
3100 @end deftypefn */)
3101 {
3102 #if defined (HAVE_JAVA)
3103 
3104  if (args.length () != 2)
3105  print_usage ();
3106 
3107  std::string name = args(1).string_value ("__java_get__: NAME must be a string");
3108 
3109  initialize_java ();
3110 
3111  JNIEnv *current_env = thread_jni_env ();
3112 
3114 
3115  if (args(0).isjava ())
3116  {
3117  octave_java *jobj = TO_JAVA (args(0));
3118  retval = jobj->do_java_get (current_env, name);
3119  }
3120  else if (args(0).is_string ())
3121  {
3122  std::string cls = args(0).string_value ();
3123  retval = octave_java::do_java_get (current_env, cls, name);
3124  }
3125  else
3126  error ("__java_get__: OBJ must be a Java object or a string");
3127 
3128  return retval;
3129 
3130 #else
3131 
3132  octave_unused_parameter (args);
3133 
3134  err_disabled_feature ("__java_get__", "Java");
3135 
3136 #endif
3137 }
3138 
3139 DEFUN (__java_set__, args, ,
3140  doc: /* -*- texinfo -*-
3141 @deftypefn {} {@var{obj} =} __java_set__ (@var{obj}, @var{name}, @var{val})
3142 Set the value of the field @var{name} of the Java object @var{obj} to
3143 @var{val}.
3144 
3145 For static fields, @var{obj} can be a string representing the fully
3146 qualified named of the corresponding Java class.
3147 
3148 When @var{obj} is a regular Java object, structure-like indexing can be
3149 used as a shortcut syntax. For instance, the two following statements are
3150 equivalent
3151 
3152 @example
3153 @group
3154  __java_set__ (x, "field1", val)
3155  x.field1 = val
3156 @end group
3157 @end example
3158 
3159 @seealso{__java_get__, javaMethod, javaObject}
3160 @end deftypefn */)
3161 {
3162 #if defined (HAVE_JAVA)
3163 
3164  if (args.length () != 3)
3165  print_usage ();
3166 
3167  std::string name = args(1).xstring_value ("__java_set__: NAME must be a string");
3168 
3169  initialize_java ();
3170 
3171  JNIEnv *current_env = thread_jni_env ();
3172 
3174 
3175  if (args(0).isjava ())
3176  {
3177  octave_java *jobj = TO_JAVA (args(0));
3178  retval = jobj->do_java_set (current_env, name, args(2));
3179  }
3180  else if (args(0).is_string ())
3181  {
3182  std::string cls = args(0).string_value ();
3183  retval = octave_java::do_java_set (current_env, cls, name, args(2));
3184  }
3185  else
3186  error ("__java_set__: OBJ must be a Java object or a string");
3187 
3188  return retval;
3189 
3190 #else
3191 
3192  octave_unused_parameter (args);
3193 
3194  err_disabled_feature ("__java_set__", "Java");
3195 
3196 #endif
3197 }
3198 
3199 DEFUN (__java2mat__, args, ,
3200  doc: /* -*- texinfo -*-
3201 @deftypefn {} {} __java2mat__ (@var{javaobj})
3202 Undocumented internal function.
3203 @end deftypefn */)
3204 {
3205 #if defined (HAVE_JAVA)
3206 
3207  if (args.length () != 1)
3208  print_usage ();
3209 
3210  initialize_java ();
3211 
3212  JNIEnv *current_env = thread_jni_env ();
3213 
3215 
3216  if (args(0).isjava ())
3217  {
3218  octave_java *jobj = TO_JAVA (args(0));
3219  retval = ovl (box_more (current_env, jobj->to_java (), nullptr));
3220  }
3221  else
3222  retval = ovl (args(0));
3223 
3224  return retval;
3225 
3226 #else
3227 
3228  octave_unused_parameter (args);
3229 
3230  err_disabled_feature ("__java2mat__", "Java");
3231 
3232 #endif
3233 }
3234 
3235 DEFUN (java_matrix_autoconversion, args, nargout,
3236  doc: /* -*- texinfo -*-
3237 @deftypefn {} {@var{val} =} java_matrix_autoconversion ()
3238 @deftypefnx {} {@var{old_val} =} java_matrix_autoconversion (@var{new_val})
3239 @deftypefnx {} {} java_matrix_autoconversion (@var{new_val}, "local")
3240 Query or set the internal variable that controls whether Java arrays are
3241 automatically converted to Octave matrices.
3242 
3243 The default value is false.
3244 
3245 When called from inside a function with the @qcode{"local"} option, the
3246 variable is changed locally for the function and any subroutines it calls.
3247 The original variable value is restored when exiting the function.
3248 @seealso{java_unsigned_autoconversion, debug_java}
3249 @end deftypefn */)
3250 {
3251 #if defined (HAVE_JAVA)
3252 
3253  return SET_INTERNAL_VARIABLE (java_matrix_autoconversion);
3254 
3255 #else
3256 
3257  octave_unused_parameter (args);
3258  octave_unused_parameter (nargout);
3259 
3260  err_disabled_feature ("java_matrix_autoconversion", "Java");
3261 
3262 #endif
3263 }
3264 
3265 DEFUN (java_unsigned_autoconversion, args, nargout,
3266  doc: /* -*- texinfo -*-
3267 @deftypefn {} {@var{val} =} java_unsigned_autoconversion ()
3268 @deftypefnx {} {@var{old_val} =} java_unsigned_autoconversion (@var{new_val})
3269 @deftypefnx {} {} java_unsigned_autoconversion (@var{new_val}, "local")
3270 Query or set the internal variable that controls how integer classes are
3271 converted when @code{java_matrix_autoconversion} is enabled.
3272 
3273 When enabled, Java arrays of class Byte or Integer are converted to matrices
3274 of class uint8 or uint32 respectively. The default value is true.
3275 
3276 When called from inside a function with the @qcode{"local"} option, the
3277 variable is changed locally for the function and any subroutines it calls.
3278 The original variable value is restored when exiting the function.
3279 @seealso{java_matrix_autoconversion, debug_java}
3280 @end deftypefn */)
3281 {
3282 #if defined (HAVE_JAVA)
3283 
3284  return SET_INTERNAL_VARIABLE (java_unsigned_autoconversion);
3285 
3286 #else
3287 
3288  octave_unused_parameter (args);
3289  octave_unused_parameter (nargout);
3290 
3291  err_disabled_feature ("java_unsigned_autoconversion", "Java");
3292 
3293 #endif
3294 }
3295 
3296 DEFUN (debug_java, args, nargout,
3297  doc: /* -*- texinfo -*-
3298 @deftypefn {} {@var{val} =} debug_java ()
3299 @deftypefnx {} {@var{old_val} =} debug_java (@var{new_val})
3300 @deftypefnx {} {} debug_java (@var{new_val}, "local")
3301 Query or set the internal variable that determines whether extra debugging
3302 information regarding the initialization of the JVM and any Java exceptions
3303 is printed.
3304 
3305 When called from inside a function with the @qcode{"local"} option, the
3306 variable is changed locally for the function and any subroutines it calls.
3307 The original variable value is restored when exiting the function.
3308 @seealso{java_matrix_autoconversion, java_unsigned_autoconversion}
3309 @end deftypefn */)
3310 {
3311 #if defined (HAVE_JAVA)
3312 
3313  return SET_INTERNAL_VARIABLE (debug_java);
3314 
3315 #else
3316 
3317  octave_unused_parameter (args);
3318  octave_unused_parameter (nargout);
3319 
3320  err_disabled_feature ("debug_java", "Java");
3321 
3322 #endif
3323 }
3324 
3325 // Outside of #if defined (HAVE_JAVA) because it is desirable to be able
3326 // to test for the presence of a Java object without having Java
3327 // installed.
3328 
3329 DEFUN (isjava, args, ,
3330  doc: /* -*- texinfo -*-
3331 @deftypefn {} {} isjava (@var{x})
3332 Return true if @var{x} is a Java object.
3333 @seealso{class, typeinfo, isa, javaObject}
3334 @end deftypefn */)
3335 {
3336  if (args.length () != 1)
3337  print_usage ();
3338 
3339  return ovl (args(0).isjava ());
3340 }
3341 
3342 /*
3343 ## Check automatic conversion of java primitive arrays into octave types.
3344 %!testif HAVE_JAVA; usejava ("jvm")
3345 %! assert (javaObject ("java.lang.String", "hello").getBytes (),
3346 %! int8 ([104 101 108 108 111]'));
3347 
3348 ## Check automatic conversion of octave types into java primitive arrays.
3349 ## Note that uint8 is casted to int8.
3350 %!testif HAVE_JAVA; usejava ("jvm")
3351 %! assert (javaMethod ("binarySearch", "java.util.Arrays", [90 100 255], 255), 2);
3352 %! assert (javaMethod ("binarySearch", "java.util.Arrays", uint8 ([90 100 255]), uint8 (255)) < 0);
3353 %! assert (javaMethod ("binarySearch", "java.util.Arrays", uint8 ([90 100 128]), uint8 (128)) < 0);
3354 %! assert (javaMethod ("binarySearch", "java.util.Arrays", uint8 ([90 100 127]), uint8 (127)), 2);
3355 %! assert (javaMethod ("binarySearch", "java.util.Arrays", uint16 ([90 100 128]), uint16 (128)), 2);
3356 
3357 ## Check we can create objects that wrap java literals
3358 %!testif HAVE_JAVA; usejava ("jvm") <*38821>
3359 %! assert (class (javaObject ("java.lang.Byte", uint8 (1))), "java.lang.Byte");
3360 %! assert (class (javaObject ("java.lang.Byte", int8 (1))), "java.lang.Byte");
3361 %! assert (class (javaObject ("java.lang.Short", uint16 (1))), "java.lang.Short");
3362 %! assert (class (javaObject ("java.lang.Short", int16 (1))), "java.lang.Short");
3363 %! assert (class (javaObject ("java.lang.Integer", uint32 (1))), "java.lang.Integer");
3364 %! assert (class (javaObject ("java.lang.Integer", int32 (1))), "java.lang.Integer");
3365 %! assert (class (javaObject ("java.lang.Long", uint64 (1))), "java.lang.Long");
3366 %! assert (class (javaObject ("java.lang.Long", int64 (1))), "java.lang.Long");
3367 
3368 ## More checks of java numeric and boolean class instances
3369 %!testif HAVE_JAVA; usejava ("jvm")
3370 %! n = javaObject ("java.lang.Double", 1.35);
3371 %! assert (n.compareTo (1.0), 1);
3372 %! assert (n.compareTo (1.35), 0);
3373 %! assert (n.compareTo (10), -1);
3374 %! assert (n.isInfinite (), false);
3375 
3376 %!testif HAVE_JAVA; usejava ("jvm")
3377 %! n = javaObject ("java.lang.Float", 1.35);
3378 %! assert (n.compareTo (1.0), 1);
3379 %! assert (n.compareTo (1.35), 0);
3380 %! assert (n.compareTo (10), -1);
3381 %! assert (n.doubleValue (), 1.35, 1e7);
3382 
3383 %!testif HAVE_JAVA; usejava ("jvm")
3384 %! n = javaObject ("java.lang.Long", (int64 (1)));
3385 %! assert (n.compareTo (int64 (0)), 1);
3386 %! assert (n.compareTo (int64 (1)), 0);
3387 %! assert (n.compareTo (int64 (2)), -1);
3388 %! assert (n.toString (), "1");
3389 
3390 %!testif HAVE_JAVA; usejava ("jvm") <51804>
3391 %! n = javaObject ("java.lang.Integer", 1.35);
3392 %! assert (n.compareTo (0), 1);
3393 %! assert (n.compareTo (1), 0);
3394 %! assert (n.compareTo (2), -1);
3395 
3396 %!testif HAVE_JAVA; usejava ("jvm") <51804>
3397 %! n = javaObject ("java.lang.Short", 1.35);
3398 %! assert (n.compareTo (0), 1);
3399 %! assert (n.compareTo (1), 0);
3400 %! assert (n.compareTo (2), -1);
3401 
3402 %!testif HAVE_JAVA; usejava ("jvm")
3403 %! n = javaObject ("java.lang.Byte", int8 (17));
3404 %! assert (n.compareTo (int8 (20)), -3);
3405 %! assert (n.compareTo (int8 (10)), 7);
3406 %! assert (n.compareTo (int8 (17)), 0);
3407 
3408 %!testif HAVE_JAVA; usejava ("jvm")
3409 %! b = javaObject ("java.lang.Boolean", true);
3410 %! assert (b.compareTo (true), 0);
3411 %! assert (b.compareTo (false), 1);
3412 %! b = javaObject ("java.lang.Boolean", false);
3413 %! assert (b.compareTo (true), -1);
3414 %! assert (b.compareTo (false), 0);
3415 
3416 ## Test for automatic conversion of specific numeric classes
3417 %!testif HAVE_JAVA; usejava ("jvm") <*48013>
3418 %! assert (javaMethod ("valueOf", "java.lang.Byte", int8 (1)), 1)
3419 %! assert (javaMethod ("valueOf", "java.lang.Short", int16 (1)), 1)
3420 %! assert (javaMethod ("valueOf", "java.lang.Integer", int32 (1)), 1)
3421 %! assert (javaMethod ("valueOf", "java.lang.Long", int64 (1)), 1)
3422 %! assert (javaMethod ("valueOf", "java.lang.Float", single (1)), 1)
3423 %! assert (javaMethod ("valueOf", "java.lang.Double", double (1)), 1)
3424 %! assert (class (javaMethod ("valueOf", "java.math.BigDecimal", double (1))), "java.math.BigDecimal")
3425 %! assert (class (javaMethod ("valueOf", "java.math.BigInteger", int64 (1))), "java.math.BigInteger")
3426 
3427 ## Automatic conversion from string cell array into String[]
3428 %!testif HAVE_JAVA; usejava ("jvm") <*45290>
3429 %! assert (javaMethod ("binarySearch", "java.util.Arrays", {"aaa", "bbb", "ccc", "zzz"}, "aaa"), 0);
3430 %! assert (javaMethod ("binarySearch", "java.util.Arrays", {"aaa", "bbb", "ccc", "zzz"}, "zzz"), 3);
3431 %! assert (javaMethod ("binarySearch", "java.util.Arrays", {"aaa", "bbb", "ccc", "zzz"}, "hhh") < 0);
3432 
3433 ## Test that Octave index syntax allows Java object method calls with args
3434 %!testif HAVE_JAVA; usejava ("jvm") <*51152>
3435 %! s = javaObject ("java.lang.String", "Octave");
3436 %! assert (s.length (), 6)
3437 %! assert (s.charAt (0), "O")
3438 %! assert (s.charAt (5), "e")
3439 %! assert (s.matches ("^Octave$"))
3440 %! assert (s.startsWith ("Oct"))
3441 %! ## same tests with Java object as part of another indexing expression
3442 %! a(1).s = s;
3443 %! assert (! a(1).s.isEmpty ())
3444 %! assert (a(1).s.length (), 6)
3445 %! assert (a(1).s.charAt (0), "O")
3446 %! assert (a(1).s.charAt (5), "e")
3447 %! assert (a(1).s.matches ("^Octave$"))
3448 %! assert (a(1).s.startsWith ("Oct"))
3449 
3450 ## Check for basic usability of the java awt library
3451 ## Skip the test on OS X where we currently have Java 9 and attempting
3452 ## to use awt causes Octave to exit with a message about Java not being
3453 ## installed (it is) instead of returning false.
3454 %!testif HAVE_JAVA; ! ismac () && usejava ("jvm") && usejava ("awt") && have_window_system ()
3455 %! frame = javaObject ("java.awt.Frame");
3456 %! frame.setResizable (true);
3457 %! assert (frame.isResizable ());
3458 */
void * to_java(void) const
Definition: ov-java.h:54
OCTINTERP_API octave_value_list feval(const std::string &name, const octave_value_list &args=octave_value_list(), int nargout=0)
JNIEnv * env
Definition: ov-java.cc:125
java_local_ref(JNIEnv *_env, T obj)
Definition: ov-java.cc:87
string_vector map_keys(void) const
static std::string get_current_directory(void)
Definition: oct-env.cc:136
JNIEXPORT void JNICALL Java_org_octave_Octave_doEvalString(JNIEnv *, jclass, jstring)
Definition: Cell.h:37
static octave_value get_array_elements(JNIEnv *jni_env, jobject jobj, const octave_value_list &idx)
Definition: ov-java.cc:1013
is already an absolute the name is checked against the file system instead of Octave s loadpath In this if otherwise an empty string is returned If the first argument is a cell array of search each directory of the loadpath for element of the cell array and return the first that matches If the second optional argument return a cell array containing the list of all files that have the same name in the path If no files are found
Definition: utils.cc:305
F77_RET_T const F77_INT F77_CMPLX const F77_INT F77_CMPLX * B
fname
Definition: load-save.cc:767
#define C(a, b)
Definition: Faddeeva.cc:246
java_local_ref(void)
Definition: ov-java.cc:117
void octave_set_default_fpucw(void)
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:148
#define UNBOX_PRIMITIVE_SCALAR(OCTAVE_T, METHOD_T, JAVA_T, JAVA_CON)
java_local_ref< jclass > jclass_ref
Definition: ov-java.cc:129
bool isempty(void) const
Definition: Array.h:565
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
java_local_ref< jstring > jstring_ref
Definition: ov-java.cc:130
static dim_vector compute_array_dimensions(JNIEnv *jni_env, jobject obj)
Definition: ov-java.cc:941
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
static std::string path_sep_str(void)
Definition: pathsearch.cc:127
void newline(std::ostream &os) const
Definition: ov-base.cc:1328
std::string xstring_value(const char *fmt,...) const
octave_value_list & append(const octave_value &val)
Definition: ovl.cc:83
std::string tilde_expand(const std::string &name)
Definition: file-ops.cc:276
for large enough k
Definition: lu.cc:617
java_local_ref< jbyteArray > jbyteArray_ref
Definition: ov-java.cc:133
void resize(int n, int fill_value=0)
Definition: dim-vector.h:310
const T * fortran_vec(void) const
Definition: Array.h:584
octave_value do_java_set(void *jni_env, const std::string &name, const octave_value &val)
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:53
octave_java(void)
void error(const char *fmt,...)
Definition: error.cc:578
#define SET_INTERNAL_VARIABLE(NM)
Definition: variables.h:109
JNIEXPORT jboolean JNICALL Java_org_octave_Octave_call(JNIEnv *, jclass, jstring, jobjectArray, jobjectArray)
static std::string initial_java_dir(void)
The java initialization directory is given by the environment variable OCTAVE_JAVA_DIR if defined; ot...
Definition: ov-java.cc:326
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
void detach(void)
Definition: ov-java.cc:105
static std::string jstring_to_string(JNIEnv *jni_env, jstring s)
Converts a Java string object to std::string.
Definition: ov-java.cc:719
std::string filename
Definition: urlwrite.cc:121
void init(void *jobj, void *jcls)
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * Z
u
Definition: lu.cc:138
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:997
#define BOX_PRIMITIVE_ARRAY(JAVA_TYPE, JAVA_ID, JAVA_TYPE_CAP, OCTAVE_ID)
static octave_value do_javaObject(void *jni_env, const std::string &name, const octave_value_list &args)
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
s
Definition: file-io.cc:2729
std::list< std::string > close(void)
Definition: oct-shlib.h:161
static std::string initial_class_path(void)
Return the initial classpath.
Definition: ov-java.cc:406
void update(void)
Definition: ov-java.cc:275
static jobject make_java_index(JNIEnv *jni_env, const octave_value_list &idx)
Definition: ov-java.cc:976
i e
Definition: data.cc:2591
static bool jvm_attached
Whether the current thread is attached to the jvm given by jvm.
Definition: ov-java.cc:186
static void initialize_jvm(void)
Initialize the java virtual machine (jvm) and field jvm if necessary.
Definition: ov-java.cc:526
std::string fcn_file_dir(void)
Definition: defaults.cc:294
void read_java_opts(const std::string &filename)
Definition: ov-java.cc:238
std::string dir_sep_str(void)
Definition: file-ops.cc:233
octave_function * fcn
Definition: ov-class.cc:1754
static std::string getenv(const std::string &name)
Definition: oct-env.cc:235
void clean(void)
Definition: ov-java.cc:261
#define TO_JCLASS(obj)
Definition: ov-java.cc:69
JNIEXPORT jboolean JNICALL Java_org_octave_Octave_needThreadedInvokation(JNIEnv *, jclass)
bool isjava(void) const
Definition: ov.h:615
static std::map< int, octave_value > listener_map
Definition: ov-java.cc:194
then the function must return scalars which will be concatenated into the return array(s). If code
Definition: cellfun.cc:400
Matrix transpose(void) const
Definition: dMatrix.h:132
nd deftypefn *std::string name
Definition: sysdep.cc:647
void release(void)
Definition: ov-java.cc:109
bool Vjava_matrix_autoconversion
Definition: ov-java.cc:204
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:997
static octave_value box(JNIEnv *jni_env, void *jobj, void *jcls_arg=nullptr)
static std::string get_home_directory(void)
Definition: oct-env.cc:143
~java_local_ref(void)
Definition: ov-java.cc:90
OCTINTERP_API octave_value_list eval_string(const std::string &, bool silent, int &parse_status, int nargout)
static JNIEnv * thread_jni_env(void)
}
Definition: ov-java.cc:759
std::string class_name(void) const
Definition: ov-java.h:176
octave_value do_java_get(void *jni_env, const std::string &name)
bool is_java_string(void) const
Definition: ov-java.cc:772
void * java_object
Definition: ov-java.h:166
static long octave_thread_ID
The thread id of the currently executing thread or -1 if this is unknown.
Definition: ov-java.cc:202
~JVMArgs(void)
Definition: ov-java.cc:222
jint(JNICALL * JNI_CreateJavaVM_t)(JavaVM **pvm, JNIEnv **penv, void *args)
Definition: ov-java.cc:73
static octave_value box_more(JNIEnv *jni_env, void *jobj_arg, void *jcls_arg=nullptr)
static bool unbox(JNIEnv *jni_env, const octave_value &val, jobject_ref &jobj, jclass_ref &jcls)
double tmp
Definition: data.cc:6252
is false
Definition: cellfun.cc:400
octave_value do_javaMethod(void *jni_env, const std::string &name, const octave_value_list &args)
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:557
octave_value retval
Definition: data.cc:6246
dim_vector dims(void) const
#define panic_impossible()
Definition: error.h:40
JNIEXPORT void JNICALL Java_org_octave_OctaveReference_doFinalize(JNIEnv *, jclass, jint)
static octave_value check_exception(JNIEnv *jni_env)
Definition: ov-java.cc:831
idx type
Definition: ov.cc:3114
static void register_type(void)
Definition: ov-base.cc:97
static int octave_java_refcount
Definition: ov-java.cc:196
Definition: dMatrix.h:36
static jclass find_octave_class(JNIEnv *jni_env, const char *name)
Definition: ov-java.cc:861
void release(void)
static std::string read_classpath_txt(const std::string &filepath)
Return the classpath in the given file filepath as a string.
Definition: ov-java.cc:357
java_local_ref(JNIEnv *_env)
Definition: ov-java.cc:84
the exceeded dimensions are set to if fewer subscripts than dimensions are the exceeding dimensions are merged into the final requested dimension For consider the following dims
Definition: sub2ind.cc:255
java_local_ref< jobjectArray > jobjectArray_ref
Definition: ov-java.cc:131
#define TO_JNIENV(env)
Definition: ov-java.cc:71
octave_value convert_to_str_internal(bool pad, bool force, char type) const
octave_value convert_to_str(bool pad=false, bool force=false, char type='\'') const
Definition: ov.h:1251
java_local_ref< jdoubleArray > jdoubleArray_ref
Definition: ov-java.cc:134
With real return the complex result
Definition: data.cc:3260
bool Vjava_unsigned_autoconversion
Definition: ov-java.cc:205
friend class octave_value
Definition: ov-base.h:228
T & operator=(T obj)
Definition: ov-java.cc:92
bool Vdebug_java
Definition: ov-java.cc:206
static const std::string t_name
Definition: ov-java.h:186
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
void * voidptr
Definition: ov-java.h:36
std::list< std::string > java_opts
Definition: ov-java.cc:301
int register_type(const std::string &, const std::string &, const octave_value &, bool abort_on_duplicate=false)
Definition: ov-typeinfo.cc:85
bool is_instance_of(const std::string &) const
Definition: ov-java.cc:797
JavaVMInitArgs * to_args()
Definition: ov-java.cc:227
static char * strsave(const char *s)
Definition: main.in.cc:190
bool is_undefined(void) const
Definition: ov.h:526
void print(std::ostream &os, bool pr_as_read_syntax=false)
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:362
std::string java_classname
Definition: ov-java.h:170
#define UNBOX_PRIMITIVE_ARRAY(METHOD_T, OCTAVE_T, JAVA_T, JAVA_T_CAP)
#define TO_JAVA(obj)
JNIEXPORT void JNICALL Java_org_octave_Octave_doInvoke(JNIEnv *, jclass, jint, jobjectArray)
java_local_ref< jobject > jobject_ref
Definition: ov-java.cc:128
octave_idx_type length(void) const
Definition: ovl.h:96
defaults to zero A value of zero computes the digamma a value of
Definition: psi.cc:68
static int t_id
Definition: ov-java.h:185
java_local_ref< jintArray > jintArray_ref
Definition: ov-java.cc:132
octave::sys::file_stat fs(filename)
octave::refcount< octave_idx_type > count
Definition: ov-base.h:862
args.length() nargin
Definition: file-io.cc:589
octave_value_list subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout)
void * java_class
Definition: ov-java.h:168
static void add_event_hook(event_hook_fcn f)
Definition: cmd-edit.cc:1554
static std::map< int, octave_value > octave_ref_map
Definition: ov-java.cc:195
for i
Definition: data.cc:5264
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:295
static void terminate_jvm(void)
Terminate the current jvm, if there is any.
Definition: ov-java.cc:695
void add(const std::string &opt)
Definition: ov-java.cc:233
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
write the output to stdout if nargout is
Definition: load-save.cc:1612
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
#define TO_JOBJECT(obj)
Definition: ov-java.cc:68
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
JavaVMInitArgs vm_args
Definition: ov-java.cc:299
static JavaVM * jvm
The pointer to a java virtual machine either created in the current thread or attached this thread to...
Definition: ov-java.cc:179
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
nd group nd example For each display the value
Definition: sysdep.cc:866
jint(JNICALL * JNI_GetCreatedJavaVMs_t)(JavaVM **pvm, jsize bufLen, jsize *nVMs)
Definition: ov-java.cc:76
dim_vector dv
Definition: sub2ind.cc:263
void * search(const std::string &nm, name_mangler mangler=nullptr) const
Definition: oct-shlib.h:172
static octave::dynamic_library jvm_lib
Need to keep hold of the shared library handle until exit.
Definition: ov-java.cc:192
java_local_ref< jthrowable > jthrowable_ref
Definition: ov-java.cc:135
octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, size_t skip=1)
octave::stream os
Definition: file-io.cc:627
where the brackets indicate optional arguments and and character or cell array For character arrays the conversion is repeated for every row
Definition: str2double.cc:342
void F(const TSRC *v, TRES *r, octave_idx_type m, octave_idx_type n)
Definition: mx-inlines.cc:756