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