lib/java: reorganize the java group to include the primitive arrays
[nit.git] / lib / java / base.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Supporting services for the FFI with Java
16 #
17 # This modules relies on `Sys::jvm`, `Sys::jni_env` and
18 # `Sys::create_default_jvm` to get a handle on a JVM. You can adapt the
19 # behavior of the FFI and services in this module by redefing
20 # `Sys::create_default_jvm` and supply your own JVM object. You can manage
21 # multiple java thread by switching the current environment in a redef
22 # of `Sys::jni_env`, and multiple JVM using `Sys::jvm`.
23 module base is
24 cflags "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
25 ldflags "-L $(JNI_LIB_PATH) -ljvm"
26 new_annotation extra_java_files
27 end
28
29 import jvm
30
31 redef class Sys
32 private var jvm_cache: nullable JavaVM = null
33 private var jni_env_cache: nullable JniEnv = null
34
35 # Default Java Virtual Machine to use (will be instantiated using
36 # `create_default_jvm` if not already set)
37 fun jvm: JavaVM
38 do
39 if jvm_cache == null then create_default_jvm
40 return jvm_cache.as(not null)
41 end
42
43 # Sets the current default Java Virtual Machine (use with `jni_env=`)
44 fun jvm=(jvm: JavaVM) do jvm_cache = jvm
45
46 # Current main `JniEnv`
47 fun jni_env: JniEnv
48 do
49 if jni_env_cache == null then create_default_jvm
50 return jni_env_cache.as(not null)
51 end
52
53 # Sets the current default JNI env (use with `jvm=`)
54 fun jni_env=(jni_env: JniEnv) do jni_env_cache = jni_env
55
56 # Called by `jvm` and `jni_env` to instantiate a Java Virtual Machine.
57 # Used mostly for the FFI with Java.
58 protected fun create_default_jvm
59 do
60 var builder = new JavaVMBuilder
61
62 # By default, look for Java classes in a jar file the same directory as the executable
63 builder.options.add "-Djava.class.path={sys.program_name}.jar"
64
65 var jvm = builder.create_jvm
66 assert jvm != null else print "JVM creation failed"
67
68 self.jvm = jvm
69 self.jni_env = builder.jni_env.as(not null)
70 end
71
72 # Get a Java class by its name from the current `jni_env`
73 fun load_jclass(name: NativeString): JClass import jni_env `{
74 JNIEnv *nit_ffi_jni_env = Sys_jni_env(self);
75
76 // retrieve the implementation Java class
77 jclass java_class = (*nit_ffi_jni_env)->FindClass(nit_ffi_jni_env, name);
78 if (java_class == NULL) {
79 fprintf(stderr, "Nit FFI with Java error: failed to load class.\\n");
80 (*nit_ffi_jni_env)->ExceptionDescribe(nit_ffi_jni_env);
81 exit(1);
82 }
83
84 return java_class;
85 `}
86 end
87
88 # A standard Java string `java.lang.String`
89 #
90 # Converted to a Nit string using `to_s`, or to a C string with `to_cstring`.
91 # Created using `String::to_java_string` or `NativeString::to_java_string`.
92 extern class JavaString in "Java" `{ java.lang.String `}
93 super JavaObject
94
95 # Get the string from Java and copy it to Nit memory
96 fun to_cstring: NativeString import sys, Sys.jni_env `{
97 Sys sys = JavaString_sys(self);
98 JNIEnv *env = Sys_jni_env(sys);
99
100 // Get the data from Java
101 const char *java_cstr = (*env)->GetStringUTFChars(env, self, NULL);
102 jsize len = (*env)->GetStringUTFLength(env, self);
103
104 // Copy it in control of Nit
105 char *nit_cstr = (char*)malloc(len+1);
106 memcpy(nit_cstr, java_cstr, len);
107 nit_cstr[len] = '\0';
108
109 // Free JNI ref and return
110 (*env)->ReleaseStringUTFChars(env, self, java_cstr);
111 return nit_cstr;
112 `}
113
114 redef fun to_s do return to_cstring.to_s
115 end
116
117 redef class NativeString
118 # Get a Java string from this C string
119 #
120 # This instance is only valid until the next execution of Java code.
121 # You can use `new_local_ref` to keep it longer.
122 fun to_java_string: JavaString import sys, Sys.jni_env `{
123 Sys sys = JavaString_sys(self);
124 JNIEnv *env = Sys_jni_env(sys);
125 return (*env)->NewStringUTF(env, self);
126 `}
127 end
128
129 redef class Text
130 # Get `self` as a `JavaString`
131 fun to_java_string: JavaString do return to_cstring.to_java_string
132 end
133
134 redef extern class JavaObject
135
136 # Returns a global reference to the Java object behind this reference
137 #
138 # You must use a global reference when keeping a Java object
139 # across execution of Java code, per JNI specification.
140 fun new_global_ref: SELF import sys, Sys.jni_env `{
141 Sys sys = JavaObject_sys(self);
142 JNIEnv *env = Sys_jni_env(sys);
143 return (*env)->NewGlobalRef(env, self);
144 `}
145
146 # Delete this global reference
147 fun delete_global_ref import sys, Sys.jni_env `{
148 Sys sys = JavaObject_sys(self);
149 JNIEnv *env = Sys_jni_env(sys);
150 (*env)->DeleteGlobalRef(env, self);
151 `}
152
153 # Delete this local reference
154 fun delete_local_ref import sys, Sys.jni_env `{
155 Sys sys = JavaObject_sys(self);
156 JNIEnv *env = Sys_jni_env(sys);
157 (*env)->DeleteLocalRef(env, self);
158 `}
159
160 # Pops the current local reference frame and return a valid reference to self
161 #
162 # Similar to `JavaVM::pop_local_frame` but returns a value.
163 fun pop_from_local_frame: SELF
164 do
165 var jni_env = sys.jni_env
166 return pop_from_local_frame_with_env(jni_env)
167 end
168
169 # Java implementation of `pop_from_local_frame`
170 protected fun pop_from_local_frame_with_env(jni_env: JniEnv): SELF `{
171 return (*jni_env)->PopLocalFrame(jni_env, self);
172 `}
173
174 # Is `self` null in Java?
175 #
176 # Since Java type system doesn't have the same `nullable` concept as Nit's,
177 # the two systems are not directly compatible. Any Nit instances of
178 # `JavaObject` may hold a Java null.
179 #
180 # To benefit from the safer type system of Nit, it is recommended to check
181 # the return of all extern methods implemented in Java to ensure the value
182 # is not a Java null. In case it is, you should replace it by a normal Nit
183 # `null`.
184 fun is_java_null: Bool in "Java" `{ return self == null; `}
185
186 # `JavaString` representation of `self` using Java's `toString`
187 fun to_java_string: JavaString in "Java" `{ return self.toString(); `}
188
189 # Use Java's `toString` for any `JavaObject`
190 redef fun to_s
191 do
192 if is_java_null then return super
193 return to_java_string.to_s
194 end
195 end