Imported Upstream version 1.0.0
[platform/upstream/iotivity.git] / service / resource-encapsulation / android / service / src / main / jni / JniRcsValue.cpp
1 /******************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20
21 #include "JniRcsValue.h"
22
23 #include "JniRcsObject.h"
24 #include "JniRcsResourceAttributes.h"
25 #include "JavaClasses.h"
26 #include "JavaExceptions.h"
27 #include "JavaLocalRef.h"
28 #include "Log.h"
29
30 using namespace OIC::Service;
31
32 #define LOG_TAG "JNI-RCSValue"
33
34 #define CLS_NAME_VALUE_TYPE CLS_NAME_VALUE "$Type"
35 #define CLS_NAME_VALUE_TYPEID CLS_NAME_VALUE "$TypeId"
36 #define CLS_NAME_VALUE_NULL_TYPE CLS_NAME_VALUE "$NullType"
37
38 namespace
39 {
40     jclass g_cls_RCSValue;
41     jclass g_cls_Type;
42     jclass g_cls_TypeId;
43
44     jmethodID g_ctor_RCSValue;
45
46     jmethodID g_smethod_Type_getDepth;
47     jmethodID g_smethod_Type_getBaseTypeId;
48
49     jmethodID g_method_RCSValue_getType;
50
51     jfieldID g_field_RCSValue_mObject;
52     jfieldID g_field_RCSValue_sNullValue;
53
54     jobject g_obj_TypeId_Null;
55     jobject g_obj_TypeId_Boolean;
56     jobject g_obj_TypeId_Integer;
57     jobject g_obj_TypeId_Double;
58     jobject g_obj_TypeId_String;
59     jobject g_obj_TypeId_Attributes;
60     jobject g_obj_TypeId_Array;
61
62     template< int >
63     struct Int2Type{ };
64
65     template< int DEPTH, typename BASE_TYPE >
66     struct SeqType
67     {
68         typedef std::vector< typename SeqType< DEPTH - 1, BASE_TYPE >::type > type;
69     };
70
71     template< typename BASE_TYPE >
72     struct SeqType< 0, BASE_TYPE >
73     {
74         typedef BASE_TYPE type;
75     };
76
77     template< typename T >
78     struct BaseType
79     {
80       typedef T type;
81     };
82
83     template< typename T >
84     struct BaseType< std::vector< T > >
85     {
86       typedef typename BaseType< T >::type type;
87     };
88
89
90     template< int D >
91     struct ArrayPrefix
92     {
93         static constexpr char str[] = "";
94     };
95     template< int D >
96     constexpr char ArrayPrefix< D >::str[];
97
98     template<>
99     struct ArrayPrefix< 1 >
100     {
101         static constexpr char str[] = "[";
102     };
103     constexpr char ArrayPrefix< 1 >::str[];
104
105     template<>
106     struct ArrayPrefix< 2 >
107     {
108         static constexpr char str[] = "[[";
109     };
110     constexpr char ArrayPrefix< 2 >::str[];
111
112     struct PrimitiveType {
113         static constexpr bool isPrimitive = true;
114     };
115
116     struct ObjectType {
117         static constexpr bool isPrimitive = false;
118     };
119
120     template< typename T >
121     struct JniTypeTrait;
122
123     template<>
124     struct JniTypeTrait< int >: public PrimitiveType
125     {
126         static_assert(sizeof(int) == sizeof(jint), "int and jint have different size!");
127
128         static constexpr decltype(&JNIEnvWrapper::NewIntArray) newArrayFunc =
129                 &JNIEnvWrapper::NewIntArray;
130         static constexpr decltype(&JNIEnvWrapper::SetIntArrayRegion) setArrayRegionFunc =
131                       &JNIEnvWrapper::SetIntArrayRegion;
132
133         static constexpr decltype(&invoke_Integer_intValue<JNIEnvWrapper>) converter =
134                       &invoke_Integer_intValue<JNIEnvWrapper>;
135
136         static constexpr decltype(&newIntegerObject<JNIEnvWrapper>) newObjectFunc =
137                 &newIntegerObject<JNIEnvWrapper>;
138
139         static constexpr char className[] = "I";
140     };
141     constexpr char JniTypeTrait< int >::className[];
142
143     template<>
144     struct JniTypeTrait< bool >: public PrimitiveType
145     {
146         static_assert(sizeof(bool) == sizeof(jboolean), "bool and jboolean have different size!");
147
148         static constexpr decltype(&JNIEnvWrapper::NewBooleanArray) newArrayFunc =
149                 &JNIEnvWrapper::NewBooleanArray;
150         static constexpr decltype(&JNIEnvWrapper::SetBooleanArrayRegion) setArrayRegionFunc =
151                       &JNIEnvWrapper::SetBooleanArrayRegion;
152
153         static constexpr decltype(&invoke_Boolean_booleanValue<JNIEnvWrapper>) converter =
154                       &invoke_Boolean_booleanValue<JNIEnvWrapper>;
155
156         static constexpr decltype(&newBooleanObject<JNIEnvWrapper>) newObjectFunc =
157                 &newBooleanObject<JNIEnvWrapper>;
158
159         static constexpr char className[] = "Z";
160     };
161     constexpr char JniTypeTrait< bool >::className[];
162
163     template<>
164     struct JniTypeTrait< double > : public PrimitiveType
165     {
166         static_assert(sizeof(double) == sizeof(jdouble), "double and jdouble have different size!");
167
168         static constexpr decltype(&JNIEnvWrapper::NewDoubleArray) newArrayFunc =
169                 &JNIEnvWrapper::NewDoubleArray;
170         static constexpr decltype(&JNIEnvWrapper::SetDoubleArrayRegion) setArrayRegionFunc =
171                       &JNIEnvWrapper::SetDoubleArrayRegion;
172
173         static constexpr decltype(&invoke_Double_doubleValue<JNIEnvWrapper>) converter =
174                       &invoke_Double_doubleValue<JNIEnvWrapper>;
175
176         static constexpr decltype(&newDoubleObject<JNIEnvWrapper>) newObjectFunc =
177                 &newDoubleObject<JNIEnvWrapper>;
178
179         static constexpr char className[] = "D";
180     };
181     constexpr char JniTypeTrait< double >::className[];
182
183     template<>
184     struct JniTypeTrait< std::string >: public ObjectType
185     {
186         static constexpr decltype(&newStringObject<JNIEnvWrapper>) newObjectFunc =
187                 &newStringObject<JNIEnvWrapper>;
188
189         static constexpr char className[] = "L" CLS_NAME_STRING ";";
190     };
191     constexpr char JniTypeTrait< std::string >::className[];
192
193     template<>
194     struct JniTypeTrait< RCSResourceAttributes >: public ObjectType
195     {
196         inline static jobject newObjectFunc(JNIEnvWrapper* env, const RCSResourceAttributes& value)
197         {
198             return newAttributesObject(env, value);
199         }
200
201         inline static RCSResourceAttributes converter(JNIEnvWrapper* env, jobject obj)
202         {
203             return toNativeAttributes(env, obj);
204         }
205
206         static constexpr char className[] = "L" CLS_NAME_RESOURCEATTRIBUTES ";";
207     };
208     constexpr char JniTypeTrait< RCSResourceAttributes >::className[];
209
210     inline void toNativeValue(JNIEnvWrapper* env, jobject obj, std::string& result, Int2Type< 0 >)
211     {
212         result = toStdString(env, static_cast< jstring >(obj));
213     }
214
215     template< typename T >
216     inline void toNativeValue(JNIEnvWrapper* env, jobject obj, T& result, Int2Type< 0 >)
217     {
218         result = JniTypeTrait< T >::converter(env, obj);
219     }
220
221     template< int DEPTH, typename RET >
222     inline void toNativeValue(JNIEnvWrapper* env, jobject obj, RET& result, Int2Type< DEPTH >)
223     {
224         const auto arrayObj = static_cast< jobjectArray >(obj);
225         result.resize(env->GetArrayLength(arrayObj));
226
227         for (typename RET::size_type i = 0; i < result.size(); ++i)
228         {
229             JavaLocalObject elementObj{ env, env->GetObjectArrayElement(arrayObj, i) };
230
231             toNativeValue(env, elementObj, result[i], Int2Type< DEPTH - 1 >{ });
232         }
233     }
234
235     template< typename T >
236     inline typename std::enable_if< JniTypeTrait< T >::isPrimitive >::type
237     toNativeValue(JNIEnvWrapper* env, jobject obj, std::vector< T >& result, Int2Type< 1 >)
238     {
239         const auto arrayObj = static_cast< jobjectArray >(obj);
240         const jsize arraySize = env->GetArrayLength(arrayObj);
241
242         T* raw = static_cast< T* >(env->GetPrimitiveArrayCritical(arrayObj, nullptr));
243
244         try
245         {
246             result = std::vector< T >(raw, raw + arraySize);
247         } catch (...)
248         {
249         }
250
251         env->ReleasePrimitiveArrayCritical(arrayObj, raw, JNI_ABORT);
252     }
253
254     template< typename T >
255     inline typename std::enable_if< !JniTypeTrait< T >::isPrimitive >::type
256     toNativeValue(JNIEnvWrapper* env, jobject obj, std::vector< T >& result, Int2Type< 1 >)
257     {
258         const auto arrayObj = static_cast< jobjectArray >(obj);
259         const jsize arraySize = env->GetArrayLength(arrayObj);
260
261         result.resize(arraySize);
262
263         for (typename std::vector< T >::size_type i = 0; i < result.size(); ++i)
264         {
265             JavaLocalObject elementObj{ env,  env->GetObjectArrayElement(arrayObj, i) };
266             toNativeValue(env, elementObj, result[i], Int2Type< 0 >{ });
267         }
268     }
269
270
271     template< typename T, int DEPTH, typename RET = typename SeqType< DEPTH, T >::type >
272     inline RET toNativeValue(JNIEnvWrapper* env, jobject obj)
273     {
274         static_assert(DEPTH >= 0, "DEPTH must be positive!");
275
276         typename SeqType< DEPTH, T >::type result;
277
278         toNativeValue(env, obj, result, Int2Type< DEPTH >{ });
279
280         return result;
281     }
282
283     template< typename T >
284     inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth)
285     {
286         switch (depth)
287         {
288             case 0: return toNativeValue< T, 0 >(env, val);
289             case 1: return toNativeValue< T, 1 >(env, val);
290             case 2: return toNativeValue< T, 2 >(env, val);
291             case 3: return toNativeValue< T, 3 >(env, val);
292         }
293
294         return {};
295     }
296
297     inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth,
298             RCSResourceAttributes::TypeId typeId)
299     {
300         LOGD("toNativeValue depth is %d", depth);
301         EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
302
303         switch (typeId)
304          {
305              case RCSResourceAttributes::TypeId::NULL_T: return { };
306
307              case RCSResourceAttributes::TypeId::BOOL:
308                  return toNativeValue< bool >(env, val, depth);
309
310              case RCSResourceAttributes::TypeId::INT:
311                  return toNativeValue< int >(env, val, depth);
312
313              case RCSResourceAttributes::TypeId::DOUBLE:
314                  return toNativeValue< double >(env, val, depth);
315
316              case RCSResourceAttributes::TypeId::STRING:
317                  return toNativeValue< std::string >(env, val, depth);
318
319              case RCSResourceAttributes::TypeId::ATTRIBUTES:
320                  return toNativeValue< RCSResourceAttributes >(env, val, depth);
321          }
322
323         throwRCSException(env, "Failed to convert RCSValue : unknown type id");
324         return {};
325     }
326
327     template< typename T, int DEPTH, typename BASE_TYPE = typename BaseType< T >::type >
328     inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< DEPTH >)
329     {
330         const std::string elementClsName{ std::string{ ArrayPrefix< DEPTH - 1 >::str }
331             + JniTypeTrait< BASE_TYPE >::className };
332
333         LOGD("create array %dd, %s", DEPTH, elementClsName.c_str());
334
335         auto cls = env->FindClass(elementClsName.c_str());
336
337         const jsize len = value.size();
338
339         auto array = env->NewObjectArray(len, cls, nullptr);
340
341         for(jsize i = 0; i < len; ++i)
342         {
343             auto element = createJavaObject(env, value[i], Int2Type< DEPTH - 1>{ });
344             env->SetObjectArrayElement(array, i, element);
345         }
346
347         return array;
348     }
349
350     template< typename T, typename TRAIT = JniTypeTrait< T > >
351     inline typename std::enable_if< TRAIT::isPrimitive, jobject >::type
352     createJavaObject(JNIEnvWrapper* env, const std::vector< T >& value, Int2Type< 1 >)
353     {
354         LOGD("create array with newArray");
355         const jsize len = value.size();
356
357         auto array = (env->*TRAIT::newArrayFunc)(len);
358
359         if (!value.empty()) (env->*TRAIT::setArrayRegionFunc)(array, 0, len, &value[0]);
360
361         return array;
362     }
363
364     inline jobject createJavaObject(JNIEnvWrapper* env, const std::vector< bool >& value, Int2Type< 1 >)
365     {
366         const auto len = value.size();
367         LOGD("create bool array with newArray %d", len);
368
369         auto arrayObj = env->NewBooleanArray(len);
370
371         bool* raw = static_cast< bool* >(env->GetPrimitiveArrayCritical(arrayObj, 0));
372
373         std::copy(value.begin(), value.end(), raw);
374
375         env->ReleasePrimitiveArrayCritical(arrayObj, raw, 0);
376
377         return arrayObj;
378     }
379
380     template< typename T, typename TRAIT = JniTypeTrait< T > >
381     inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< 0 >)
382     {
383         LOGD("createJavaObject 0-depth");
384         return TRAIT::newObjectFunc(env, value);
385     }
386
387     template< int DEPTH >
388     inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
389     {
390         const auto type = value.getType();
391         const auto baseType = RCSResourceAttributes::Type::getBaseTypeId(type);
392
393         LOGD("createJavaObject with DEPTH. type is %d", static_cast< int >(baseType));
394
395         switch (baseType)
396         {
397             case RCSResourceAttributes::TypeId::NULL_T:
398                 return env->GetStaticObjectField(g_cls_RCSValue, g_field_RCSValue_sNullValue);
399
400             case RCSResourceAttributes::TypeId::BOOL:
401                 return createJavaObject(env, value.get< typename SeqType< DEPTH, bool >::type >(),
402                         Int2Type< DEPTH >{ });
403
404             case RCSResourceAttributes::TypeId::INT:
405                 return createJavaObject(env, value.get< typename SeqType< DEPTH, int >::type >(),
406                         Int2Type< DEPTH >{ });
407
408             case RCSResourceAttributes::TypeId::DOUBLE:
409                 return createJavaObject(env, value.get< typename SeqType< DEPTH, double >::type >(),
410                         Int2Type< DEPTH >{ });
411
412             case RCSResourceAttributes::TypeId::STRING:
413                 return createJavaObject(env,
414                         value.get< typename SeqType< DEPTH, std::string >::type >(),
415                         Int2Type< DEPTH >{ });
416
417             case RCSResourceAttributes::TypeId::ATTRIBUTES:
418                 return createJavaObject(env,
419                         value.get< typename SeqType< DEPTH, RCSResourceAttributes >::type >(),
420                         Int2Type< DEPTH >{ });
421         }
422
423         LOGE("Unknown type!");
424
425         return nullptr;
426     }
427
428     inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
429     {
430         const auto type = value.getType();
431         const auto depth = RCSResourceAttributes::Type::getDepth(type);
432
433         EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
434
435         switch (depth)
436         {
437             case 0: return createJavaObject< 0 >(env, value);
438             case 1: return createJavaObject< 1 >(env, value);
439             case 2: return createJavaObject< 2 >(env, value);
440             case 3: return createJavaObject< 3 >(env, value);
441         }
442
443         return nullptr;
444     }
445
446     inline RCSResourceAttributes::TypeId toNativeTypeId(JNIEnvWrapper* env, jobject typeIdObj)
447     {
448         typedef RCSResourceAttributes::TypeId TypeId;
449
450         if (env->IsSameObject(g_obj_TypeId_Null, typeIdObj)) return TypeId::NULL_T;
451         if (env->IsSameObject(g_obj_TypeId_Boolean, typeIdObj)) return TypeId::BOOL;
452         if (env->IsSameObject(g_obj_TypeId_Integer, typeIdObj)) return TypeId::INT;
453         if (env->IsSameObject(g_obj_TypeId_Double, typeIdObj)) return TypeId::DOUBLE;
454         if (env->IsSameObject(g_obj_TypeId_String, typeIdObj)) return TypeId::STRING;
455         if (env->IsSameObject(g_obj_TypeId_Attributes, typeIdObj)) return TypeId::ATTRIBUTES;
456         if (env->IsSameObject(g_obj_TypeId_Array, typeIdObj)) return TypeId::VECTOR;
457
458         throwRCSException(env, "Failed to convert RCSValue : unknown type id");
459         return TypeId::NULL_T;
460     }
461
462     jobject getTypeIdObj(JNIEnvWrapper* env, const char* name)
463     {
464         return env->NewGlobalRef(
465                 env->GetStaticObjectField(g_cls_TypeId, name, AS_SIG(CLS_NAME_VALUE_TYPEID)));
466     }
467 }
468
469 void initRCSValue(JNIEnvWrapper* env)
470 {
471     g_cls_RCSValue = env->FindClassAsGlobalRef(CLS_NAME_VALUE);
472     g_ctor_RCSValue = env->GetConstructorID(g_cls_RCSValue, "(" AS_SIG(CLS_NAME_OBJECT) ")V");
473
474     g_method_RCSValue_getType = env->GetMethodID(g_cls_RCSValue, "getType",
475             "()" AS_SIG(CLS_NAME_VALUE_TYPE));
476
477     g_field_RCSValue_mObject = env->GetFieldID(g_cls_RCSValue, "mObject", AS_SIG(CLS_NAME_OBJECT));
478
479     g_field_RCSValue_sNullValue = env->GetStaticFieldID(g_cls_RCSValue, "sNullValue",
480             AS_SIG(CLS_NAME_VALUE_NULL_TYPE));
481
482     g_cls_Type = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPE);
483
484     g_smethod_Type_getBaseTypeId = env->GetStaticMethodID(g_cls_Type, "getBaseTypeId",
485             "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")" AS_SIG(CLS_NAME_VALUE_TYPEID));
486
487     g_smethod_Type_getDepth = env->GetStaticMethodID(g_cls_Type, "getDepth",
488                 "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")I");
489
490     g_cls_TypeId = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPEID);
491
492     g_obj_TypeId_Null = getTypeIdObj(env, "NULL");
493     g_obj_TypeId_Boolean = getTypeIdObj(env, "BOOLEAN");
494     g_obj_TypeId_Integer = getTypeIdObj(env, "INTEGER");
495     g_obj_TypeId_Double = getTypeIdObj(env, "DOUBLE");
496     g_obj_TypeId_String = getTypeIdObj(env, "STRING");
497     g_obj_TypeId_Attributes = getTypeIdObj(env, "ATTRIBUTES");
498     g_obj_TypeId_Array = getTypeIdObj(env, "ARRAY");
499 }
500
501 void clearRCSValue(JNIEnvWrapper* env)
502 {
503     env->DeleteGlobalRef(g_cls_RCSValue);
504     env->DeleteGlobalRef(g_cls_Type);
505     env->DeleteGlobalRef(g_cls_TypeId);
506
507     env->DeleteGlobalRef(g_obj_TypeId_Null);
508     env->DeleteGlobalRef(g_obj_TypeId_Boolean);
509     env->DeleteGlobalRef(g_obj_TypeId_Integer);
510     env->DeleteGlobalRef(g_obj_TypeId_Double);
511     env->DeleteGlobalRef(g_obj_TypeId_String);
512     env->DeleteGlobalRef(g_obj_TypeId_Attributes);
513     env->DeleteGlobalRef(g_obj_TypeId_Array);
514 }
515
516 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnv* env, jobject valueObj)
517 {
518     JNIEnvWrapper envWrapper(env);
519
520     try
521     {
522         return toNativeAttrsValue(&envWrapper, valueObj);
523     }
524     catch (const JavaException&)
525     {
526         return { };
527     }
528 }
529
530 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnvWrapper* env, jobject valueObj)
531 {
532     auto typeObj = env->CallObjectMethod(valueObj, g_method_RCSValue_getType);
533     auto typeIdObj = env->CallStaticObjectMethod(g_cls_Type, g_smethod_Type_getBaseTypeId, typeObj);
534     auto depth = env->CallStaticIntMethod(g_cls_Type, g_smethod_Type_getDepth, typeObj);
535     auto memObj = env->GetObjectField(valueObj, g_field_RCSValue_mObject);
536
537     auto ret = toNativeValue(env, memObj, depth, toNativeTypeId(env, typeIdObj));
538
539     if (env->get()->ExceptionCheck()) throw JavaException();
540
541     return ret;
542 }
543
544 jobject newRCSValueObject(JNIEnv* env, const RCSResourceAttributes::Value& value)
545 {
546     JNIEnvWrapper envWrapper(env);
547
548     try
549     {
550         return newRCSValueObject(&envWrapper, value);
551     }
552     catch (const JavaException&)
553     {
554         return {};
555     }
556 }
557
558 jobject newRCSValueObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
559 {
560     LOGD("newRCSValueObject");
561
562     JavaLocalObject valueObj{ env, createJavaObject(env, value) };
563
564     if (env->get()->ExceptionCheck()) throw JavaException();
565
566     return env->NewObject(g_cls_RCSValue, g_ctor_RCSValue, valueObj.get());
567 }