lib/java: intro JavaObject::new/release_global_ref
[nit.git] / lib / java.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Supporting services for the FFI with Java
18 module java is
19 c_compiler_option("-I $(JAVA_HOME)/include/")
20 c_linker_option("-L $(JNI_LIB_PATH) -ljvm")
21 end
22
23 import jvm
24
25 redef class Sys
26 private var jvm_cache: nullable JavaVM = null
27 private var jni_env_cache: nullable JniEnv = null
28
29 # Default Java Virtual Machine to use (will be instanciated using
30 # `create_default_jvm` if not already set)
31 fun jvm: JavaVM
32 do
33 if jvm_cache == null then create_default_jvm
34 return jvm_cache.as(not null)
35 end
36
37 # Sets the current default Java Virtual Machine (use with `jni_env=`)
38 fun jvm=(jvm: JavaVM) do jvm_cache = jvm
39
40 # Current main `JniEnv`
41 # FIXME support threaded Java
42 fun jni_env: JniEnv
43 do
44 if jni_env_cache == null then create_default_jvm
45 return jni_env_cache.as(not null)
46 end
47
48 # Sets the current default JNI env (use with `jvm=`)
49 fun jni_env=(jni_env: JniEnv) do jni_env_cache = jni_env
50
51 # Called by `jvm` and `jni_env` to instanciate a Java Virual Machine.
52 # Used mostly for FFI with Java.
53 protected fun create_default_jvm
54 do
55 var builder = new JavaVMBuilder
56
57 # By default, look for Java classes in a jar file the same dir as the executable
58 builder.options.add "-Djava.class.path={sys.program_name}.jar"
59
60 var jvm = builder.create_jvm
61 assert jvm != null else print "JVM creation failed"
62
63 self.jvm = jvm
64 self.jni_env = builder.jni_env.as(not null)
65 end
66 end
67
68 # A standard Java string `java.lang.String`
69 #
70 # Converted to a Nit string using `to_s`, or to a C string with `to_cstring`.
71 # Created using `String::to_java_string` or `NativeString::to_java_string`.
72 extern class JavaString in "Java" `{ java.lang.String `}
73 super JavaObject
74
75 redef type SELF: JavaString
76
77 # Get the string from Java and copy it to Nit memory
78 fun to_cstring: NativeString import sys, Sys.jni_env `{
79 Sys sys = JavaString_sys(recv);
80 JNIEnv *env = Sys_jni_env(sys);
81
82 // Get the data from Java
83 const jbyte *java_cstr = (char*)(*env)->GetStringUTFChars(env, recv, NULL);
84 jsize len = (*env)->GetStringUTFLength(env, recv);
85
86 // Copy it in control of Nit
87 char *nit_cstr = (char*)malloc(len+1);
88 memcpy(nit_cstr, java_cstr, len);
89 nit_cstr[len] = '\0';
90
91 // Free JNI ref and return
92 (*env)->ReleaseStringUTFChars(env, recv, java_cstr);
93 return nit_cstr;
94 `}
95
96 redef fun to_s do return to_cstring.to_s
97 end
98
99 redef class NativeString
100 # Get a Java string from this C string
101 #
102 # This instance is only valid until the next execution of Java code.
103 # You can use `new_local_ref` to keep it longer.
104 fun to_java_string: JavaString import sys, Sys.jni_env `{
105 Sys sys = JavaString_sys(recv);
106 JNIEnv *env = Sys_jni_env(sys);
107 return (*env)->NewStringUTF(env, recv);
108 `}
109 end
110
111 redef class String
112 fun to_java_string: JavaString do return to_cstring.to_java_string
113 end
114
115 redef extern class JavaObject
116 type SELF: JavaObject
117
118 # Returns a global reference to the Java object behind this reference
119 #
120 # You must use a global reference when keeping a Java object
121 # across execution of Java code, per JNI specification.
122 fun new_global_ref: SELF import sys, Sys.jni_env `{
123 Sys sys = JavaObject_sys(recv);
124 JNIEnv *env = Sys_jni_env(sys);
125 return (*env)->NewGlobalRef(env, recv);
126 `}
127
128 # Delete this global reference
129 fun delete_global_ref import sys, Sys.jni_env `{
130 Sys sys = JavaObject_sys(recv);
131 JNIEnv *env = Sys_jni_env(sys);
132 (*env)->DeleteGlobalRef(env, recv);
133 `}
134 end