1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <string>
18
19#include "jni/jni_util.h"
20
21#include "base/logging.h"
22
23#if 0
24JavaObject::JavaObject()
25    : object_(JNI_NULL),
26      ref_count_(new int(0)) {
27}
28
29JavaObject::JavaObject(const JavaObject& java_obj)
30    : object_(java_obj.object_),
31      ref_count_(java_obj.ref_count_) {
32  Retain();
33}
34
35JavaObject::JavaObject(jobject object, JNIEnv* env)
36    : object_(NULL),
37      ref_count_(new int(0)) {
38  Retain();
39  object_ = env->NewGlobalRef(object_);
40}
41
42JavaObject::~JavaObject() {
43  Release();
44}
45
46JavaObject& JavaObject::operator=(const JavaObject& java_obj) {
47  Release();
48  object_ = java_obj.object_;
49  ref_count_ = java_obj.ref_count_;
50  Retain();
51  return *this;
52}
53
54void JavaObject::Retain() {
55  if (ref_count_)
56    ++(*ref_count_);
57  else
58    ALOGE("JavaObject: Reference count is NULL! JavaObject may be corrupted.");
59}
60
61void JavaObject::Release() {
62  if (ref_count_) {
63    if (*ref_count_ > 0)
64      --(*ref_count_);
65    if (*ref_count_ == 0) {
66      JNIEnv* env = GetCurrentJNIEnv();
67      if (!env)
68        ALOGE("JavaObject: Releasing outside of Java thread. Will just leak!");
69      else if (object_)
70        env->DeleteGlobalRef(object_);
71      delete ref_count_;
72      ref_count_ = NULL;
73    }
74  } else {
75    ALOGE("JavaObject: Reference count is NULL! JavaObject may be corrupted.");
76  }
77}
78
79void JavaObject::Reset() {
80  Release();
81  object_ = NULL;
82  ref_count_ = new int(0);
83}
84
85JavaVM* GetCurrentJavaVM() {
86  return g_current_java_vm_;
87}
88
89JNIEnv* GetCurrentJNIEnv() {
90  JavaVM* vm = GetCurrentJavaVM();
91  JNIEnv* env = NULL;
92  const jint result = vm->GetEnv(reinterpret_cast<void**>(&env),
93                                 JNI_VERSION_1_4);
94  return result == JNI_OK ? env : NULL;
95}
96#endif
97
98jstring ToJString(JNIEnv* env, const std::string& value) {
99  return env->NewStringUTF(value.c_str());
100}
101
102std::string ToCppString(JNIEnv* env, jstring value) {
103  jboolean isCopy;
104  const char* c_value = env->GetStringUTFChars(value, &isCopy);
105  std::string result(c_value);
106  if (isCopy == JNI_TRUE)
107    env->ReleaseStringUTFChars(value, c_value);
108  return result;
109}
110
111jboolean ToJBool(bool value) {
112  return value ? JNI_TRUE : JNI_FALSE;
113}
114
115bool ToCppBool(jboolean value) {
116  return value == JNI_TRUE;
117}
118
119// TODO: We actually shouldn't use such a function as it requires a class name lookup at every
120// invocation. Instead, store the class objects and use those.
121bool IsJavaInstanceOf(JNIEnv* env, jobject object, const std::string& class_name) {
122  jclass clazz = env->FindClass(class_name.c_str());
123  return clazz ? env->IsInstanceOf(object, clazz) == JNI_TRUE : false;
124}
125
126template<typename T>
127jobject CreateJObject(JNIEnv* env, const std::string& class_name, const std::string& signature, T value) {
128  jobject result = JNI_NULL;
129
130  return result;
131}
132
133Value ToCValue(JNIEnv* env, jobject object) {
134  Value result = MakeNullValue();
135  if (object != NULL) {
136    if (IsJavaInstanceOf(env, object, "java/lang/Boolean")) {
137      jmethodID method = env->GetMethodID(env->GetObjectClass(object), "booleanValue", "()Z");
138      result = MakeIntValue(env->CallBooleanMethod(object, method) == JNI_TRUE ? 1 : 0);
139    } else if (IsJavaInstanceOf(env, object, "java/lang/Integer")) {
140      jmethodID method = env->GetMethodID(env->GetObjectClass(object), "intValue", "()I");
141      result = MakeIntValue(env->CallIntMethod(object, method));
142    } else if (IsJavaInstanceOf(env, object, "java/lang/Float")) {
143      jmethodID method = env->GetMethodID(env->GetObjectClass(object), "floatValue", "()F");
144      result = MakeFloatValue(env->CallFloatMethod(object, method));
145    } else if (IsJavaInstanceOf(env, object, "java/lang/String")) {
146      result = MakeStringValue(ToCppString(env, static_cast<jstring>(object)).c_str());
147    } else if (IsJavaInstanceOf(env, object, "[I")) {
148      jint* elems = env->GetIntArrayElements(static_cast<jintArray>(object), NULL);
149      const jint count = env->GetArrayLength(static_cast<jintArray>(object));
150      result = MakeIntArrayValue(elems, count);
151      env->ReleaseIntArrayElements(static_cast<jintArray>(object), elems, JNI_ABORT);
152    } else if (IsJavaInstanceOf(env, object, "[F")) {
153      jfloat* elems = env->GetFloatArrayElements(static_cast<jfloatArray>(object), NULL);
154      const jint count = env->GetArrayLength(static_cast<jfloatArray>(object));
155      result = MakeFloatArrayValue(elems, count);
156      env->ReleaseFloatArrayElements(static_cast<jfloatArray>(object), elems, JNI_ABORT);
157    }
158  }
159  return result;
160}
161
162jobject ToJObject(JNIEnv* env, const Value& value) {
163  jobject result = JNI_NULL;
164  if (ValueIsInt(value)) {
165    jclass clazz = env->FindClass("java/lang/Integer");
166    jmethodID constructorID = env->GetMethodID(clazz, "<init>", "(I)V");
167    result = env->NewObject(clazz, constructorID, GetIntValue(value));
168  } else if (ValueIsFloat(value)) {
169    jclass clazz = env->FindClass("java/lang/Float");
170    jmethodID constructorID = env->GetMethodID(clazz, "<init>", "(F)V");
171    result = env->NewObject(clazz, constructorID, GetFloatValue(value));
172  } else if (ValueIsString(value)) {
173    result = ToJString(env, GetStringValue(value));
174  } else if (ValueIsIntArray(value)) {
175    result = env->NewIntArray(GetValueCount(value));
176    env->SetIntArrayRegion(static_cast<jintArray>(result),
177                           0,
178                           GetValueCount(value),
179                           reinterpret_cast<const jint*>(GetIntArrayValue(value)));
180  } else if (ValueIsFloatArray(value)) {
181    result = env->NewFloatArray(GetValueCount(value));
182    env->SetFloatArrayRegion(static_cast<jfloatArray>(result),
183                             0,
184                             GetValueCount(value),
185                             reinterpret_cast<const jfloat*>(GetFloatArrayValue(value)));
186  }
187  return result;
188}
189