Twitch SDK (Internal)
java_utility.h
Go to the documentation of this file.
1 /********************************************************************************************
2 * Twitch Broadcasting SDK
3 *
4 * This software is supplied under the terms of a license agreement with Twitch Interactive, Inc. and
5 * may not be copied or used except in accordance with the terms of that agreement
6 * Copyright (c) 2012-2016 Twitch Interactive, Inc.
7 *********************************************************************************************/
8 
9 #pragma once
10 
12 #include "twitchsdk/core/mutex.h"
13 
14 #include <vector>
15 #include <unordered_map>
16 #include <map>
17 #include <jni.h>
18 
19 
20 #define TTV_JNI_RETURN_ON_NULL(jni,ptr,err) { if ( (ptr) == nullptr) { ASSERT_ON_ERROR(err); return GetJavaInstance_ErrorCode(jni, err); } }
21 #define TTV_JNI_RETURN_ON_NOT_NULL(jni,ptr,err) { if ( (ptr) != nullptr) { ASSERT_ON_ERROR(err); return GetJavaInstance_ErrorCode(jni, err); } }
22 #define TTV_JNI_RETURN_ON_FALSE(jni,val,err) { if (!val) { return GetJavaInstance_ErrorCode(jni, err); } }
23 
24 
25 // Used to release local references when they variable goes out of scope.
26 #define AUTO_DELETE_LOCAL_REF(JENV, TYPE, VAR, VALUE) \
27  TYPE VAR = static_cast<TYPE>(VALUE); \
28  JavaLocalReferenceDeleter VAR##_Deleter(JENV, VAR, #VAR);
29 
30 #define AUTO_DELETE_LOCAL_REF_NO_DECLARE(JENV, TYPE, VAR) \
31  JavaLocalReferenceDeleter VAR##_Deleter(JENV, VAR, #VAR);
32 
33 
34 namespace ttv
35 {
36  namespace binding
37  {
38  namespace java
39  {
40  extern JavaVM* gGlobalJavaVirtualMachine;
41  extern JNIEnv* gActiveJavaEnvironment;
42 
43  class JavaLocalReferenceDeleter;
44  class ScopedJavaUTFStringConverter;
45  class ScopedJavaWcharStringConverter;
46  class ScopedJavaEnvironmentCacher;
47  class AutoJEnv;
48  class GlobalJavaObjectReference;
49 
50  template <typename PROXY_TYPE>
51  struct ProxyContext;
52 
53  template <typename PROXY_TYPE, typename LISTENER_TYPE>
55 
56  template <typename NativeInstanceType, typename ContextType>
58 
59  struct JavaClassInfo;
60 
61  bool CacheJavaVirtualMachine(JNIEnv* jEnv);
62 
63  bool LookupJavaClass(JNIEnv* jEnv, JavaClassInfo& info, const char* klass);
64  bool LookupJavaMethod(JNIEnv* jEnv, JavaClassInfo& info, const char* method, const char* signature);
65  bool LookupJavaStaticMethod(JNIEnv* jEnv, JavaClassInfo& info, const char* method, const char* signature);
66  bool LookupJavaField(JNIEnv* jEnv, JavaClassInfo& info, const char* field, const char* signature);
67 
70  JavaClassInfo& GetJavaClassInfo_Long(JNIEnv* jEnv);
77 
78  jobject GetJavaInstance_Boolean(JNIEnv* jEnv, bool value);
79  jobject GetJavaInstance_Integer(JNIEnv* jEnv, int32_t value);
80  jobject GetJavaInstance_Integer(JNIEnv* jEnv, uint32_t value);
81  jobject GetJavaInstance_Long(JNIEnv* jEnv, uint64_t value);
82  jobject GetJavaInstance_Long(JNIEnv* jEnv, int64_t value);
83  jobject GetJavaInstance_Float(JNIEnv* jEnv, float value);
84  jobject GetJavaInstance_Double(JNIEnv* jEnv, double value);
85 
86  jstring GetJavaInstance_StringWithEncoding(JNIEnv* jEnv, const std::string& str);
87  jstring GetJavaInstance_String(JNIEnv* jEnv, const char* str);
88  jstring GetJavaInstance_String(JNIEnv* jEnv, const std::string& str);
89 
90  jobject GetJavaInstance_EnumValue(JNIEnv* jEnv, const ttv::EnumValue& value);
91  jobjectArray GetJavaInstance_EnumValueArray(JNIEnv* jEnv, const std::vector<ttv::EnumValue>& arr);
92  jobject GetJavaInstance_ErrorCode(JNIEnv* jEnv, TTV_ErrorCode err);
93  jobjectArray GetJavaInstance_StringArray(JNIEnv* jEnv, const std::vector<std::string>& arr);
94  jobject GetJavaInstance_StringHashMap(JNIEnv* jEnv, const std::map<std::string, std::string>& map);
95  jobject GetJavaInstance_ResultContainer(JNIEnv* jEnv);
96  jobject GetJavaInstance_GetResultFromResultContainer(JNIEnv* jEnv, jobject jResultContainer);
97 
98  void GetNativeInstance_HttpRequestResult(JNIEnv* jEnv, jobject jRequestResult, uint& statusCode, std::map<std::string, std::string>& resultHeaders, std::vector<char>& response);
99  void GetNativeInstance_StringVector(JNIEnv* jEnv, jobjectArray jArray, std::vector<std::string>& result);
100 
101  void SetResultContainerResult(JNIEnv* jEnv, jobject jResultContainer, jobject jResult);
102 
103  jobjectArray GetJavaInstance_Array(JNIEnv* jEnv, JavaClassInfo& javaArrayTypeClassInfo, const uint32_t size, std::function<jobject(uint32_t index)> entryFunc);
104 
105  void GetNativeFromJava_ByteArray(JNIEnv* jEnv, jbyteArray jSource, std::vector<uint8_t>& dest);
106 
110  void LoadAllUtilityJavaClassInfo(JNIEnv* jEnv);
111 
112  template<typename... ArgTypes>
113  std::function<void(ArgTypes...)> CreateJavaCallbackWrapper(JNIEnv* jEnv, jobject jCallback, JavaClassInfo& callbackInfo);
114 
115  template <typename ContainerType, typename KVTransformerType>
116  jobject GetJavaInstance_HashMap(JNIEnv* jEnv, const ContainerType& container, const KVTransformerType& transformer);
117 
118  template <typename T>
119  jobject GetJavaInstance_SimpleEnum(JNIEnv* jEnv, JavaClassInfo& info, T val);
120 
121  template <typename T>
122  T GetNativeFromJava_SimpleEnum(JNIEnv* jEnv, JavaClassInfo& info, jobject jEnumValue, T defaultValue);
123  }
124  }
125 }
126 
127 
129 {
130 public:
131  JavaLocalReferenceDeleter(JNIEnv* jEnv, jobject jObject, const char* name);
133 
134 protected:
135  JNIEnv* mjEnv;
136  jobject mObject;
137  const char* mName;
138 };
139 
140 
142 {
143 public:
144  ScopedJavaUTFStringConverter(JNIEnv* jEnv, jstring jstr);
146 
147  const char* GetNativeString();
148  int GetCharacterLength() const { return mCharacterLength; }
149  int GetByteLength() const { return mByteLength; }
150 
151  operator const char*() { return GetNativeString(); }
152  operator std::string() { return GetNativeString(); }
153 
154 protected:
155  JNIEnv* mjEnv;
156  jstring mJavaString;
157  const char* mNativeString;
160 };
161 
162 
164 {
165 public:
166  ScopedJavaWcharStringConverter(JNIEnv* jEnv, jstring jstr);
167 
168  const wchar_t* GetNativeString() const;
169 
170 protected:
171  JNIEnv* mjEnv;
172  jstring mJavaString;
173  const wchar_t* mNativeString;
174  std::wstring mSTDWideString;
175 };
176 
177 
179 {
180 public:
181  ScopedJavaEnvironmentCacher(JNIEnv* jenv);
183 
184  static int GetMinLocalReferenceTableCapacity();
185 
186 protected:
187  static int mCacheCount;
188 };
189 
190 
195 {
196 public:
197  AutoJEnv();
198  AutoJEnv(JavaVM* jvm);
199  ~AutoJEnv();
200 
201  JavaVM* GetJvm() { return mJvm; }
202 
203  JNIEnv* operator->();
204  operator JNIEnv*();
205 
206 private:
207  bool Lock();
208  void Unlock();
209 
210  JavaVM* mJvm;
211  JNIEnv* mJEnv;
213 };
214 
215 
217 {
218 public:
220  virtual ~GlobalJavaObjectReference();
221 
225  bool Bind(JNIEnv* jEnv, jobject jLocalObject);
226  void Release();
227 
228  jobject GetInstance() const { return mObject; }
229  jbyteArray GetInstanceAsByteArray() const { return static_cast<jbyteArray>(mObject); }
230 
231 protected:
232  jobject mObject;
233 };
234 
235 
236 template <typename PROXY_TYPE>
238 {
239  std::shared_ptr<PROXY_TYPE> instance;
240 };
241 
242 template <typename PROXY_TYPE, typename LISTENER_TYPE>
244 {
245  std::shared_ptr<PROXY_TYPE> instance;
246  std::shared_ptr<LISTENER_TYPE> nativeListener;
247 };
248 
249 
253 template <typename NativeInstanceType, typename ContextType>
255 {
256 public:
257  void Register(const std::shared_ptr<NativeInstanceType>& nativeInstance, const std::shared_ptr<ContextType>& nativeContext, jobject javaInstance)
258  {
259  if (mMutex == nullptr)
260  {
261  CreateMutex(mMutex);
262  }
263 
264  AutoJEnv jEnv;
265 
266  auto entry = std::make_shared<Entry>();
267  entry->nativeInstance = nativeInstance;
268  entry->nativeContext = nativeContext;
269  entry->javaInstance.Bind(jEnv, javaInstance);
270 
271  ttv::AutoMutex mutex(mMutex);
272  mRegistry.push_back(entry);
273  }
274 
275  void Unregister(jlong jNativePointer)
276  {
277  Unregister(reinterpret_cast<NativeInstanceType*>(jNativePointer));
278  }
279 
280  void Unregister(NativeInstanceType* nativeInstance)
281  {
282  if (mMutex == nullptr)
283  {
284  return;
285  }
286 
287  ttv::AutoMutex mutex(mMutex);
288 
289  for (auto iter = mRegistry.begin(); iter != mRegistry.end(); ++iter)
290  {
291  auto& entry = *iter;
292 
293  if (entry->nativeInstance.get() == nativeInstance)
294  {
295  mRegistry.erase(iter);
296  return;
297  }
298  }
299  }
300 
301  void Unregister(jobject javaInstance)
302  {
303  if (mMutex == nullptr)
304  {
305  return;
306  }
307 
308  ttv::AutoMutex mutex(mMutex);
309  AutoJEnv jEnv;
310 
311  for (auto iter = mRegistry.begin(); iter != mRegistry.end(); ++iter)
312  {
313  auto& entry = *iter;
314 
315  if (jEnv->IsSameObject(javaInstance, entry->javaInstance.GetInstance()))
316  {
317  mRegistry.erase(iter);
318  return;
319  }
320  }
321  }
322 
326  std::shared_ptr<NativeInstanceType> LookupNativeInstance(jobject javaInstance)
327  {
328  if (mMutex == nullptr)
329  {
330  return nullptr;
331  }
332 
333  ttv::AutoMutex mutex(mMutex);
334  AutoJEnv jEnv;
335 
336  for (const auto& entry : mRegistry)
337  {
338  if (jEnv->IsSameObject(javaInstance, entry->javaInstance.GetInstance()))
339  {
340  return entry->nativeInstance;
341  }
342  }
343 
344  return nullptr;
345  }
346 
347  std::shared_ptr<ContextType> LookupNativeContext(jobject javaInstance)
348  {
349  if (mMutex == nullptr)
350  {
351  return nullptr;
352  }
353 
354  ttv::AutoMutex mutex(mMutex);
355  AutoJEnv jEnv;
356 
357  for (const auto& entry : mRegistry)
358  {
359  if (jEnv->IsSameObject(javaInstance, entry->javaInstance.GetInstance()))
360  {
361  return entry->nativeContext;
362  }
363  }
364 
365  return nullptr;
366  }
367 
368  std::shared_ptr<ContextType> LookupNativeContext(jlong nativeInstance)
369  {
370  if (mMutex == nullptr)
371  {
372  return nullptr;
373  }
374 
375  ttv::AutoMutex mutex(mMutex);
376  AutoJEnv jEnv;
377 
378  for (const auto& entry : mRegistry)
379  {
380  if (reinterpret_cast<NativeInstanceType*>(nativeInstance) == entry->nativeInstance.get())
381  {
382  return entry->nativeContext;
383  }
384  }
385 
386  return nullptr;
387  }
388 
389 private:
390  struct Entry
391  {
392  std::shared_ptr<NativeInstanceType> nativeInstance;
393  std::shared_ptr<ContextType> nativeContext;
395  };
396 
397  std::vector<std::shared_ptr<Entry>> mRegistry;
398  std::shared_ptr<ttv::IMutex> mMutex;
399 };
400 
401 
403 {
404  jclass klass;
405  std::unordered_map<std::string, jmethodID> methods;
406  std::unordered_map<std::string, jmethodID> staticMethods;
407  std::unordered_map<std::string, jfieldID> fields;
408 };
409 
410 
411 template<typename... ArgTypes>
412 std::function<void(ArgTypes...)> ttv::binding::java::CreateJavaCallbackWrapper(JNIEnv* jEnv, jobject jCallback, JavaClassInfo& callbackInfo)
413 {
414  auto callbackReference = std::make_shared<GlobalJavaObjectReference>();
415  callbackReference->Bind(jEnv, jCallback);
416 
417  // Capturing callbackInfo by reference here is fine because it is global
418  // and immutable.
419  return [callbackReference, &callbackInfo](ArgTypes... args)
420  {
421  auto callback = callbackReference->GetInstance();
422 
423  if (callback != nullptr)
424  {
425  gActiveJavaEnvironment->CallVoidMethod(callback, callbackInfo.methods["invoke"], args...);
426  }
427  };
428 };
429 
430 
431 template <typename ContainerType, typename KVTransformerType>
432 jobject ttv::binding::java::GetJavaInstance_HashMap(JNIEnv* jEnv, const ContainerType& container, const KVTransformerType& transformer)
433 {
434  JavaClassInfo& hashMapInfo = GetJavaClassInfo_HashMap(jEnv);
435  jobject jHashMap = jEnv->NewObject(hashMapInfo.klass, hashMapInfo.methods["<init>"]);
436 
437  for (const auto& pair : container)
438  {
439  auto jPair = transformer(pair);
440  AUTO_DELETE_LOCAL_REF(jEnv, jobject, jKey, jPair.first);
441  AUTO_DELETE_LOCAL_REF(jEnv, jobject, jValue, jPair.second);
442 
443  jEnv->CallObjectMethod(jHashMap, hashMapInfo.methods["put"], jKey, jValue);
444  }
445 
446  return jHashMap;
447 }
448 
449 
450 template <typename T>
452 {
453  return jEnv->CallStaticObjectMethod(info.klass, info.staticMethods["lookupValue"], static_cast<jint>(val));
454 }
455 
456 
457 template <typename T>
458 T ttv::binding::java::GetNativeFromJava_SimpleEnum(JNIEnv* jEnv, JavaClassInfo& info, jobject jEnumValue, T defaultValue)
459 {
460  if (jEnumValue == nullptr)
461  {
462  return defaultValue;
463  }
464 
465  return static_cast<T>( jEnv->CallIntMethod(jEnumValue, info.methods["getValue"]) );
466 }
jstring mJavaString
Definition: java_utility.h:156
jobjectArray GetJavaInstance_Array(JNIEnv *jEnv, JavaClassInfo &javaArrayTypeClassInfo, const uint32_t size, std::function< jobject(uint32_t index)> entryFunc)
void Unregister(NativeInstanceType *nativeInstance)
Definition: java_utility.h:280
jobject mObject
Definition: java_utility.h:232
void GetNativeInstance_HttpRequestResult(JNIEnv *jEnv, jobject jRequestResult, uint &statusCode, std::map< std::string, std::string > &resultHeaders, std::vector< char > &response)
int GetCharacterLength() const
Definition: java_utility.h:148
jobject GetJavaInstance_Double(JNIEnv *jEnv, double value)
const char * mNativeString
Definition: java_utility.h:157
void Unregister(jobject javaInstance)
Definition: java_utility.h:301
JavaVM * gGlobalJavaVirtualMachine
The Java virtual machine.
jobject GetJavaInstance_GetResultFromResultContainer(JNIEnv *jEnv, jobject jResultContainer)
bool LookupJavaClass(JNIEnv *jEnv, JavaClassInfo &info, const char *klass)
void Unregister(jlong jNativePointer)
Definition: java_utility.h:275
Definition: errortypes.h:267
bool CacheJavaVirtualMachine(JNIEnv *jEnv)
void SetResultContainerResult(JNIEnv *jEnv, jobject jResultContainer, jobject jResult)
JavaClassInfo & GetJavaClassInfo_Integer(JNIEnv *jEnv)
std::unordered_map< std::string, jfieldID > fields
Definition: java_utility.h:407
bool LookupJavaStaticMethod(JNIEnv *jEnv, JavaClassInfo &info, const char *method, const char *signature)
JavaClassInfo & GetJavaClassInfo_Charset(JNIEnv *jEnv)
std::unordered_map< std::string, jmethodID > methods
Definition: java_utility.h:405
Definition: java_utility.h:402
void LoadAllUtilityJavaClassInfo(JNIEnv *jEnv)
jobjectArray GetJavaInstance_StringArray(JNIEnv *jEnv, const std::vector< std::string > &arr)
jobject GetJavaInstance_Boolean(JNIEnv *jEnv, bool value)
JavaLocalReferenceDeleter(JNIEnv *jEnv, jobject jObject, const char *name)
Definition: java_utility.h:128
jstring GetJavaInstance_StringWithEncoding(JNIEnv *jEnv, const std::string &str)
bool mNeedsDetach
Definition: java_utility.h:212
jobject GetJavaInstance_ErrorCode(JNIEnv *jEnv, TTV_ErrorCode err)
JSON (JavaScript Object Notation).
Definition: adsapi.h:16
void Register(const std::shared_ptr< NativeInstanceType > &nativeInstance, const std::shared_ptr< ContextType > &nativeContext, jobject javaInstance)
Definition: java_utility.h:257
std::shared_ptr< ContextType > nativeContext
Definition: java_utility.h:393
#define AUTO_DELETE_LOCAL_REF(JENV, TYPE, VAR, VALUE)
Definition: java_utility.h:26
std::unordered_map< std::string, jmethodID > staticMethods
Definition: java_utility.h:406
std::wstring mSTDWideString
Definition: java_utility.h:174
static int mCacheCount
Definition: java_utility.h:187
bool LookupJavaMethod(JNIEnv *jEnv, JavaClassInfo &info, const char *method, const char *signature)
std::shared_ptr< NativeInstanceType > LookupNativeInstance(jobject javaInstance)
Definition: java_utility.h:326
JavaClassInfo & GetJavaClassInfo_String(JNIEnv *jEnv)
int mCharacterLength
Definition: java_utility.h:158
jclass klass
Definition: java_utility.h:404
std::vector< std::shared_ptr< Entry > > mRegistry
Definition: java_utility.h:397
std::shared_ptr< ttv::IMutex > mMutex
Definition: java_utility.h:398
jobject GetJavaInstance_HashMap(JNIEnv *jEnv, const ContainerType &container, const KVTransformerType &transformer)
Definition: java_utility.h:432
jstring GetJavaInstance_String(JNIEnv *jEnv, const char *str)
TTV_ErrorCode CreateMutex(std::shared_ptr< IMutex > &result)
jstring mJavaString
Definition: java_utility.h:172
jobject GetJavaInstance_Float(JNIEnv *jEnv, float value)
const wchar_t * mNativeString
Definition: java_utility.h:173
std::function< void(ArgTypes...)> CreateJavaCallbackWrapper(JNIEnv *jEnv, jobject jCallback, JavaClassInfo &callbackInfo)
Definition: java_utility.h:412
uint32_t TTV_ErrorCode
Definition: errortypes.h:30
JNIEnv * mJEnv
Definition: java_utility.h:211
jbyteArray GetInstanceAsByteArray() const
Definition: java_utility.h:229
std::shared_ptr< NativeInstanceType > nativeInstance
Definition: java_utility.h:392
jobject mObject
Definition: java_utility.h:136
JavaClassInfo & GetJavaClassInfo_Double(JNIEnv *jEnv)
unsigned int uint
Definition: coretypes.h:18
T GetNativeFromJava_SimpleEnum(JNIEnv *jEnv, JavaClassInfo &info, jobject jEnumValue, T defaultValue)
Definition: java_utility.h:458
const char * mName
Definition: java_utility.h:137
std::shared_ptr< PROXY_TYPE > instance
Definition: java_utility.h:245
JNIEnv * mjEnv
Definition: java_utility.h:171
JavaClassInfo & GetJavaClassInfo_HashSet(JNIEnv *jEnv)
JavaVM * GetJvm()
Definition: java_utility.h:201
JNIEnv * mjEnv
Definition: java_utility.h:155
JavaVM * mJvm
Definition: java_utility.h:210
void GetNativeInstance_StringVector(JNIEnv *jEnv, jobjectArray jArray, std::vector< std::string > &result)
std::shared_ptr< LISTENER_TYPE > nativeListener
Definition: java_utility.h:246
Definition: java_utility.h:194
jobject GetJavaInstance_EnumValue(JNIEnv *jEnv, const ttv::EnumValue &value)
JNIEnv * gActiveJavaEnvironment
This is cached on every call into native code so that it&#39;s current. Never use from another thread...
bool LookupJavaField(JNIEnv *jEnv, JavaClassInfo &info, const char *field, const char *signature)
JavaClassInfo & GetJavaClassInfo_Long(JNIEnv *jEnv)
JavaClassInfo & GetJavaClassInfo_HashMap(JNIEnv *jEnv)
Definition: java_utility.h:57
jobjectArray GetJavaInstance_EnumValueArray(JNIEnv *jEnv, const std::vector< ttv::EnumValue > &arr)
jobject GetJavaInstance_SimpleEnum(JNIEnv *jEnv, JavaClassInfo &info, T val)
Definition: java_utility.h:451
jobject GetJavaInstance_Long(JNIEnv *jEnv, uint64_t value)
jobject GetInstance() const
Definition: java_utility.h:228
Definition: mutex.h:119
jobject GetJavaInstance_StringHashMap(JNIEnv *jEnv, const std::map< std::string, std::string > &map)
int GetByteLength() const
Definition: java_utility.h:149
JNIEnv * mjEnv
Definition: java_utility.h:135
std::shared_ptr< ContextType > LookupNativeContext(jlong nativeInstance)
Definition: java_utility.h:368
JavaClassInfo & GetJavaClassInfo_Float(JNIEnv *jEnv)
GlobalJavaObjectReference javaInstance
Definition: java_utility.h:394
std::shared_ptr< PROXY_TYPE > instance
Definition: java_utility.h:239
std::shared_ptr< ContextType > LookupNativeContext(jobject javaInstance)
Definition: java_utility.h:347
int mByteLength
Definition: java_utility.h:159
JavaClassInfo & GetJavaClassInfo_Boolean(JNIEnv *jEnv)
jobject GetJavaInstance_ResultContainer(JNIEnv *jEnv)
void GetNativeFromJava_ByteArray(JNIEnv *jEnv, jbyteArray jSource, std::vector< uint8_t > &dest)
Definition: java_utility.h:216
Definition: java_utility.h:51
jobject GetJavaInstance_Integer(JNIEnv *jEnv, int32_t value)