]> git.proxmox.com Git - ceph.git/blob - ceph/src/arrow/java/c/src/main/cpp/jni_wrapper.cc
import quincy 17.2.0
[ceph.git] / ceph / src / arrow / java / c / src / main / cpp / jni_wrapper.cc
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. 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,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17
18 #include <jni.h>
19
20 #include <cassert>
21 #include <memory>
22 #include <stdexcept>
23 #include <string>
24
25 #include "./abi.h"
26 #include "org_apache_arrow_c_jni_JniWrapper.h"
27
28 namespace {
29
30 jclass CreateGlobalClassReference(JNIEnv* env, const char* class_name) {
31 jclass local_class = env->FindClass(class_name);
32 jclass global_class = (jclass)env->NewGlobalRef(local_class);
33 env->DeleteLocalRef(local_class);
34 return global_class;
35 }
36
37 jclass illegal_access_exception_class;
38 jclass illegal_argument_exception_class;
39 jclass runtime_exception_class;
40 jclass private_data_class;
41
42 jmethodID private_data_close_method;
43
44 jint JNI_VERSION = JNI_VERSION_1_6;
45
46 class JniPendingException : public std::runtime_error {
47 public:
48 explicit JniPendingException(const std::string& arg) : std::runtime_error(arg) {}
49 };
50
51 void ThrowPendingException(const std::string& message) {
52 throw JniPendingException(message);
53 }
54
55 void JniThrow(std::string message) { ThrowPendingException(message); }
56
57 jmethodID GetMethodID(JNIEnv* env, jclass this_class, const char* name, const char* sig) {
58 jmethodID ret = env->GetMethodID(this_class, name, sig);
59 if (ret == nullptr) {
60 std::string error_message = "Unable to find method " + std::string(name) +
61 " within signature " + std::string(sig);
62 ThrowPendingException(error_message);
63 }
64 return ret;
65 }
66
67 class InnerPrivateData {
68 public:
69 InnerPrivateData(JavaVM* vm, jobject private_data)
70 : vm_(vm), j_private_data_(private_data) {}
71
72 JavaVM* vm_;
73 jobject j_private_data_;
74 };
75
76 class JNIEnvGuard {
77 public:
78 explicit JNIEnvGuard(JavaVM* vm) : vm_(vm), should_detach_(false) {
79 JNIEnv* env;
80 jint code = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION);
81 if (code == JNI_EDETACHED) {
82 JavaVMAttachArgs args;
83 args.version = JNI_VERSION;
84 args.name = NULL;
85 args.group = NULL;
86 code = vm->AttachCurrentThread(reinterpret_cast<void**>(&env), &args);
87 should_detach_ = (code == JNI_OK);
88 }
89 if (code != JNI_OK) {
90 ThrowPendingException("Failed to attach the current thread to a Java VM");
91 }
92 env_ = env;
93 }
94
95 JNIEnv* env() { return env_; }
96
97 ~JNIEnvGuard() {
98 if (should_detach_) {
99 vm_->DetachCurrentThread();
100 should_detach_ = false;
101 }
102 }
103
104 private:
105 bool should_detach_;
106 JavaVM* vm_;
107 JNIEnv* env_;
108 };
109
110 template <typename T>
111 void release_exported(T* base) {
112 // This should not be called on already released structure
113 assert(base->release != nullptr);
114
115 // Release children
116 for (int64_t i = 0; i < base->n_children; ++i) {
117 T* child = base->children[i];
118 if (child->release != nullptr) {
119 child->release(child);
120 assert(child->release == nullptr);
121 }
122 }
123
124 // Release dictionary
125 T* dict = base->dictionary;
126 if (dict != nullptr && dict->release != nullptr) {
127 dict->release(dict);
128 assert(dict->release == nullptr);
129 }
130
131 // Release all data directly owned by the struct
132 InnerPrivateData* private_data =
133 reinterpret_cast<InnerPrivateData*>(base->private_data);
134
135 JNIEnvGuard guard(private_data->vm_);
136 JNIEnv* env = guard.env();
137
138 env->CallObjectMethod(private_data->j_private_data_, private_data_close_method);
139 if (env->ExceptionCheck()) {
140 env->ExceptionDescribe();
141 env->ExceptionClear();
142 ThrowPendingException("Error calling close of private data");
143 }
144 env->DeleteGlobalRef(private_data->j_private_data_);
145 delete private_data;
146 base->private_data = nullptr;
147
148 // Mark released
149 base->release = nullptr;
150 }
151 } // namespace
152
153 #define JNI_METHOD_START try {
154 // macro ended
155
156 #define JNI_METHOD_END(fallback_expr) \
157 } \
158 catch (JniPendingException & e) { \
159 env->ThrowNew(runtime_exception_class, e.what()); \
160 return fallback_expr; \
161 }
162 // macro ended
163
164 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
165 JNIEnv* env;
166 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK) {
167 return JNI_ERR;
168 }
169 JNI_METHOD_START
170 illegal_access_exception_class =
171 CreateGlobalClassReference(env, "Ljava/lang/IllegalAccessException;");
172 illegal_argument_exception_class =
173 CreateGlobalClassReference(env, "Ljava/lang/IllegalArgumentException;");
174 runtime_exception_class =
175 CreateGlobalClassReference(env, "Ljava/lang/RuntimeException;");
176 private_data_class =
177 CreateGlobalClassReference(env, "Lorg/apache/arrow/c/jni/PrivateData;");
178
179 private_data_close_method = GetMethodID(env, private_data_class, "close", "()V");
180
181 return JNI_VERSION;
182 JNI_METHOD_END(JNI_ERR)
183 }
184
185 void JNI_OnUnload(JavaVM* vm, void* reserved) {
186 JNIEnv* env;
187 vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION);
188 env->DeleteGlobalRef(illegal_access_exception_class);
189 env->DeleteGlobalRef(illegal_argument_exception_class);
190 env->DeleteGlobalRef(runtime_exception_class);
191 }
192
193 /*
194 * Class: org_apache_arrow_c_jni_JniWrapper
195 * Method: releaseSchema
196 * Signature: (J)V
197 */
198 JNIEXPORT void JNICALL Java_org_apache_arrow_c_jni_JniWrapper_releaseSchema(
199 JNIEnv* env, jobject, jlong address) {
200 JNI_METHOD_START
201 ArrowSchema* schema = reinterpret_cast<ArrowSchema*>(address);
202 if (schema->release != nullptr) {
203 schema->release(schema);
204 }
205 JNI_METHOD_END()
206 }
207
208 /*
209 * Class: org_apache_arrow_c_jni_JniWrapper
210 * Method: releaseArray
211 * Signature: (J)V
212 */
213 JNIEXPORT void JNICALL
214 Java_org_apache_arrow_c_jni_JniWrapper_releaseArray(JNIEnv* env, jobject, jlong address) {
215 JNI_METHOD_START
216 ArrowArray* array = reinterpret_cast<ArrowArray*>(address);
217 if (array->release != nullptr) {
218 array->release(array);
219 }
220 JNI_METHOD_END()
221 }
222
223 /*
224 * Class: org_apache_arrow_c_jni_JniWrapper
225 * Method: exportSchema
226 * Signature: (JLorg/apache/arrow/c/jni/PrivateData;)V
227 */
228 JNIEXPORT void JNICALL Java_org_apache_arrow_c_jni_JniWrapper_exportSchema(
229 JNIEnv* env, jobject, jlong address, jobject private_data) {
230 JNI_METHOD_START
231 ArrowSchema* schema = reinterpret_cast<ArrowSchema*>(address);
232
233 JavaVM* vm;
234 if (env->GetJavaVM(&vm) != JNI_OK) {
235 JniThrow("Unable to get JavaVM instance");
236 }
237 jobject private_data_ref = env->NewGlobalRef(private_data);
238
239 schema->private_data = new InnerPrivateData(vm, private_data_ref);
240 schema->release = &release_exported<ArrowSchema>;
241 JNI_METHOD_END()
242 }
243
244 /*
245 * Class: org_apache_arrow_c_jni_JniWrapper
246 * Method: exportArray
247 * Signature: (JLorg/apache/arrow/c/jni/PrivateData;)V
248 */
249 JNIEXPORT void JNICALL Java_org_apache_arrow_c_jni_JniWrapper_exportArray(
250 JNIEnv* env, jobject, jlong address, jobject private_data) {
251 JNI_METHOD_START
252 ArrowArray* array = reinterpret_cast<ArrowArray*>(address);
253
254 JavaVM* vm;
255 if (env->GetJavaVM(&vm) != JNI_OK) {
256 JniThrow("Unable to get JavaVM instance");
257 }
258 jobject private_data_ref = env->NewGlobalRef(private_data);
259
260 array->private_data = new InnerPrivateData(vm, private_data_ref);
261 array->release = &release_exported<ArrowArray>;
262 JNI_METHOD_END()
263 }