Implementation of JNI for subscribe device presence to RD
authorJaehong Jo <jaehong.jo@samsung.com>
Wed, 17 Aug 2016 08:25:53 +0000 (17:25 +0900)
committerAshok Babu Channa <ashok.channa@samsung.com>
Thu, 18 Aug 2016 06:10:08 +0000 (06:10 +0000)
Added JNI code for subscribeDevicePresence() of OCPlatform for converting
from Java to C++ and vice versa.

Change-Id: I852116b06c8b59ee16593572b47aaa80eb2fd1b5
Signed-off-by: Jaehong Jo <jaehong.jo@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/10063
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: jihwan seo <jihwan.seo@samsung.com>
Reviewed-by: Hyuna Jo <hyuna0213.jo@samsung.com>
Reviewed-by: Ashok Babu Channa <ashok.channa@samsung.com>
android/android_api/base/jni/JniOcPlatform.cpp
android/android_api/base/jni/JniOcPlatform.h
android/android_api/base/jni/JniOcPresenceHandle.cpp
android/android_api/base/jni/JniOcPresenceHandle.h
android/android_api/base/jni/JniOnObserveListener.cpp
android/android_api/base/jni/JniOnObserveListener.h
android/android_api/base/src/main/java/org/iotivity/base/OcPlatform.java

index 231f1c9..c9c2cbf 100644 (file)
@@ -326,6 +326,74 @@ void RemoveOnPresenceListener(JNIEnv* env, jobject jListener)
     presenceMapLock.unlock();
 }
 
+JniOnObserveListener* AddOnObserveListener(JNIEnv* env, jobject jListener)
+{
+    JniOnObserveListener *onObserveListener = nullptr;
+
+    observeMapLock.lock();
+
+    for (auto it = onObserveListenerMap.begin(); it != onObserveListenerMap.end(); ++it)
+    {
+        if (env->IsSameObject(jListener, it->first))
+        {
+            auto refPair = it->second;
+            onObserveListener = refPair.first;
+            refPair.second++;
+            it->second = refPair;
+            onObserveListenerMap.insert(*it);
+            LOGD("OnObserveListener: ref. count incremented");
+            break;
+        }
+    }
+    if (!onObserveListener)
+    {
+        onObserveListener = new JniOnObserveListener(env, jListener, nullptr);
+        jobject jgListener = env->NewGlobalRef(jListener);
+        onObserveListenerMap.insert(
+            std::pair<jobject, std::pair<JniOnObserveListener*, int>>(
+                jgListener,
+                std::pair<JniOnObserveListener*, int>(onObserveListener, 1)));
+        LOGI("OnObserveListener: new listener");
+    }
+    observeMapLock.unlock();
+    return onObserveListener;
+}
+
+void RemoveOnObserveListener(JNIEnv* env, jobject jListener)
+{
+    observeMapLock.lock();
+    bool isFound = false;
+    for (auto it = onObserveListenerMap.begin(); it != onObserveListenerMap.end(); ++it)
+    {
+        if (env->IsSameObject(jListener, it->first))
+        {
+            auto refPair = it->second;
+            if (refPair.second > 1)
+            {
+                refPair.second--;
+                it->second = refPair;
+                onObserveListenerMap.insert(*it);
+                LOGI("OnObserveListener: ref. count decremented");
+            }
+            else
+            {
+                env->DeleteGlobalRef(it->first);
+                JniOnObserveListener* listener = refPair.first;
+                delete listener;
+                onObserveListenerMap.erase(it);
+                LOGI("OnObserveListener is removed");
+            }
+            isFound = true;
+            break;
+        }
+    }
+    if (!isFound)
+    {
+        ThrowOcException(JNI_EXCEPTION, "OnObserveListener not found");
+    }
+    observeMapLock.unlock();
+}
+
 JniOnDPDevicesFoundListener* AddOnDPDevicesFoundListener(JNIEnv* env, jobject jListener)
 {
     JniOnDPDevicesFoundListener *onDPDeviceListener = nullptr;
@@ -2355,12 +2423,102 @@ JNIEXPORT void JNICALL Java_org_iotivity_base_OcPlatform_unsubscribePresence0(
         {
             RemoveOnPresenceListener(env, jwOnPresenceListener);
         }
+        jweak jwOnObserveListener =
+            jniPresenceHandle->getJniOnObserveListener()->getJWListener();
+        if (jwOnObserveListener)
+        {
+            RemoveOnObserveListener(env, jwOnObserveListener);
+        }
+    }
+    catch (OCException& e)
+    {
+        LOGE("%s", e.reason().c_str());
+        ThrowOcException(e.code(), e.reason().c_str());
+    }
+}
+
+/*
+* Class:     org_iotivity_base_OcPlatform
+* Method:    subscribeDevicePresence0
+* Signature: (Ljava/lang/String;[Ljava/lang/String;I
+Lorg/iotivity/base/OcResource/OnObserveListener;)Lorg/iotivity/base/OcPresenceHandle;
+*/
+JNIEXPORT jobject JNICALL Java_org_iotivity_base_OcPlatform_subscribeDevicePresence0(
+    JNIEnv *env,
+    jclass clazz,
+    jstring jHost,
+    jobjectArray jDiArray,
+    jint jConnectivityType,
+    jobject jListener)
+{
+    LOGD("OcPlatform_subscribeDevicePresence0");
+#ifdef WITH_CLOUD
+    std::string host;
+    if (jHost)
+    {
+        host = env->GetStringUTFChars(jHost, nullptr);
+    }
+
+    if (!jDiArray)
+    {
+        ThrowOcException(OC_STACK_INVALID_PARAM, "device id List cannot be null");
+        return nullptr;
+    }
+
+    std::vector<std::string> di;
+    JniUtils::convertJavaStrArrToStrVector(env, jDiArray, di);
+
+    if (!jListener)
+    {
+        ThrowOcException(OC_STACK_INVALID_PARAM, "onObserveListener cannot be null");
+        return nullptr;
+    }
+
+    JniOnObserveListener *onObserveListener = AddOnObserveListener(env, jListener);
+
+    ObserveCallback observeCallback = [onObserveListener](const HeaderOptions& opts,
+        const OCRepresentation& rep, const int& eCode, const int& sequenceNumber)
+    {
+        onObserveListener->onObserveCallback(opts, rep, eCode, sequenceNumber);
+    };
+
+    OCPlatform::OCPresenceHandle presenceHandle;
+    try
+    {
+        OCStackResult result = OCPlatform::subscribeDevicePresence(
+            presenceHandle,
+            host,
+            di,
+            static_cast<OCConnectivityType>(jConnectivityType),
+            observeCallback);
+
+        if (OC_STACK_OK != result)
+        {
+            ThrowOcException(result, "subscribe device presence has failed");
+        }
     }
     catch (OCException& e)
     {
         LOGE("%s", e.reason().c_str());
         ThrowOcException(e.code(), e.reason().c_str());
+        return nullptr;
+    }
+
+    JniOcPresenceHandle* jniPresenceHandle =
+        new JniOcPresenceHandle(onObserveListener, presenceHandle);
+    jlong jhandle = reinterpret_cast<jlong>(jniPresenceHandle);
+    jobject jPresenceHandle =
+        env->NewObject(g_cls_OcPresenceHandle, g_mid_OcPresenceHandle_N_ctor, jhandle);
+    if (!jPresenceHandle)
+    {
+        LOGE("Failed to create OcPresenceHandle");
+        delete jniPresenceHandle;
     }
+    return jPresenceHandle;
+#else
+    ThrowOcException(JNI_EXCEPTION, "Not support");
+    return nullptr;
+#endif
 }
 
 /*
@@ -2547,8 +2705,8 @@ JNIEXPORT void JNICALL Java_org_iotivity_base_OcPlatform_publishResourceToRD1(
         jstring jHost,
         jint jConnectivityType,
         jobjectArray jResourceHandleArray,
-        jint jQoS,
-        jobject jListener)
+        jobject jListener,
+        jint jQoS)
 {
     LOGD("OcPlatform_publishResourceToRD");
 #ifdef RD_CLIENT
@@ -2697,8 +2855,8 @@ JNIEXPORT void JNICALL Java_org_iotivity_base_OcPlatform_deleteResourceFromRD1(
         jstring jHost,
         jint jConnectivityType,
         jobjectArray jResourceHandleArray,
-        jint jQoS,
-        jobject jListener)
+        jobject jListener,
+        jint jQoS)
 {
     LOGD("OcPlatform_deleteResourceFromRD");
 #ifdef RD_CLIENT
index e2bb0a3..b6c59c2 100644 (file)
@@ -26,6 +26,7 @@
 #include "JniOnDPDevicesFoundListener.h"
 #include "JniOnDirectPairingListener.h"
 #include "JniOnPresenceListener.h"
+#include "JniOnObserveListener.h"
 #include "JniOnPublishResourceListener.h"
 #include "JniOnDeleteResourceListener.h"
 #include <mutex>
@@ -47,6 +48,9 @@ void RemoveOnPlatformInfoListener(JNIEnv* env, jobject jListener);
 JniOnPresenceListener* AddOnPresenceListener(JNIEnv* env, jobject jListener);
 void RemoveOnPresenceListener(JNIEnv* env, jobject jListener);
 
+JniOnObserveListener* AddOnObserveListener(JNIEnv* env, jobject jListener);
+void RemoveOnObserveListener(JNIEnv* env, jobject jListener);
+
 JniOnDPDevicesFoundListener* AddOnDPDevicesFoundListener(JNIEnv* env, jobject jListener);
 void RemoveOnDPDevicesFoundListener(JNIEnv* env, jobject jListener);
 
@@ -63,6 +67,7 @@ std::map<jobject, std::pair<JniOnResourceFoundListener*, int>> onResourceFoundLi
 std::map<jobject, std::pair<JniOnDeviceInfoListener*, int>> onDeviceInfoListenerMap;
 std::map<jobject, std::pair<JniOnPlatformInfoListener*, int>> onPlatformInfoListenerMap;
 std::map<jobject, std::pair<JniOnPresenceListener*, int>> onPresenceListenerMap;
+std::map<jobject, std::pair<JniOnObserveListener*, int>> onObserveListenerMap;
 std::map<jobject, std::pair<JniOnDPDevicesFoundListener*, int>> onDPDevicesFoundListenerMap;
 std::map<jobject, std::pair<JniOnDirectPairingListener*, int>> directPairingListenerMap;
 std::map<jobject, std::pair<JniOnPublishResourceListener*, int>> onPublishResourceListenerMap;
@@ -72,6 +77,7 @@ std::mutex resourceFoundMapLock;
 std::mutex deviceInfoMapLock;
 std::mutex platformInfoMapLock;
 std::mutex presenceMapLock;
+std::mutex observeMapLock;
 std::mutex dpDevicesFoundListenerMapLock;
 std::mutex directPairingListenerMapLock;
 std::mutex publishResourceListenerMapLock;
@@ -298,6 +304,15 @@ extern "C" {
 
     /*
     * Class:     org_iotivity_base_OcPlatform
+    * Method:    subscribeDevicePresence0
+    * Signature: (Ljava/lang/String;[Ljava/lang/String;I
+    * Lorg/iotivity/base/OcResource/OnObserveListener;)Lorg/iotivity/base/OcPresenceHandle;
+    */
+    JNIEXPORT jobject JNICALL Java_org_iotivity_base_OcPlatform_subscribeDevicePresence0
+        (JNIEnv *, jclass, jstring, jobjectArray, jint, jobject);
+
+    /*
+    * Class:     org_iotivity_base_OcPlatform
     * Method:    constructResourceObject0
     * Signature: (Ljava/lang/String;Ljava/lang/String;IZ[Ljava/lang/String;[Ljava/lang/String;)Lorg/iotivity/base/OcResource;
     */
index 28b7859..22e2896 100644 (file)
@@ -27,6 +27,11 @@ JniOcPresenceHandle::JniOcPresenceHandle(JniOnPresenceListener* jniListener, OCP
 {
 }
 
+JniOcPresenceHandle::JniOcPresenceHandle(JniOnObserveListener* jniListener, OCPresenceHandle presenceHandle)
+    : m_jniObserveListener(jniListener), m_presenceHandle(presenceHandle)
+{
+}
+
 JniOcPresenceHandle::~JniOcPresenceHandle()
 {
     LOGD("~JniOcPresenceHandle()");
@@ -60,6 +65,11 @@ JniOnPresenceListener* JniOcPresenceHandle::getJniOnPresenceListener()
     return this->m_jniListener;
 }
 
+JniOnObserveListener* JniOcPresenceHandle::getJniOnObserveListener()
+{
+    return this->m_jniObserveListener;
+}
+
 /*
 * Class:     org_iotivity_base_OcPresenceHandle
 * Method:    dispose
index 4052cec..9c543e6 100644 (file)
@@ -20,6 +20,7 @@
 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 */
 #include "JniOcStack.h"
+#include "JniOnObserveListener.h"
 #include "JniOnPresenceListener.h"
 #include "OCPlatform.h"
 
@@ -33,6 +34,7 @@ class JniOcPresenceHandle
 public:
 
     JniOcPresenceHandle(JniOnPresenceListener* jniListener, OCPresenceHandle presenceHandle);
+    JniOcPresenceHandle(JniOnObserveListener* jniListener, OCPresenceHandle presenceHandle);
     ~JniOcPresenceHandle();
     JniOcPresenceHandle(const JniOcPresenceHandle &) = delete;
     void operator=(const JniOcPresenceHandle &) = delete;
@@ -41,9 +43,11 @@ public:
 
     OCPresenceHandle getOCPresenceHandle();
     JniOnPresenceListener* getJniOnPresenceListener();
+    JniOnObserveListener* getJniOnObserveListener();
 
 private:
     JniOnPresenceListener* m_jniListener;
+    JniOnObserveListener* m_jniObserveListener;
     OCPresenceHandle m_presenceHandle;
 };
 
index c1e4a2e..48eda10 100644 (file)
@@ -185,3 +185,8 @@ void JniOnObserveListener::checkExAndRemoveListener(JNIEnv* env)
         m_ownerResource->removeOnObserveListener(env, m_jwListener);
     }
 }
+
+jweak JniOnObserveListener::getJWListener()
+{
+    return this->m_jwListener;
+}
index 38f9aae..5092dc1 100644 (file)
@@ -35,6 +35,7 @@ public:
     ~JniOnObserveListener();
     void onObserveCallback(const HeaderOptions headerOptions, const OCRepresentation& rep,
         const int& eCode, const int& sequenceNumber);
+    jweak getJWListener();
 private:
     jweak m_jwListener;
     JniOcResource* m_ownerResource;
index 5160221..1d73f7f 100644 (file)
@@ -834,6 +834,43 @@ public final class OcPlatform {
             OcPresenceHandle ocPresenceHandle) throws OcException;
 
     /**
+     * Subscribes to a server's device presence change events.
+     *
+     * @param host                The IP address/addressable name of the server to subscribe to.
+     * @param di                  Vector which can have the devices id.
+     * @param connectivityTypeSet Set of connectivity types, e.g. IP.
+     * @param onObserveListener   The handler method will be invoked with a map
+     *                            of attribute name and values.
+     * @return a handle object that can be used to identify this subscription request.
+     *         It can be used to unsubscribe from these events in the future.
+     * @throws OcException if failure.
+     */
+    public static OcPresenceHandle subscribeDevicePresence(
+            String host,
+            List<String> di,
+            EnumSet<OcConnectivityType> connectivityTypeSet,
+            OcResource.OnObserveListener onObserveListener) throws OcException {
+        OcPlatform.initCheck();
+        int connTypeInt = 0;
+
+        for (OcConnectivityType connType : OcConnectivityType.values()) {
+            if (connectivityTypeSet.contains(connType))
+                connTypeInt |= connType.getValue();
+        }
+        return OcPlatform.subscribeDevicePresence0(
+                host,
+                di.toArray(new String[di.size()]),
+                connTypeInt,
+                onObserveListener);
+    }
+
+    private static native OcPresenceHandle subscribeDevicePresence0(
+            String host,
+            String[] di,
+            int connectivityType,
+            OcResource.OnObserveListener onObserveListener) throws OcException;
+
+    /**
      * Creates a resource proxy object so that get/put/observe functionality can be used without
      * discovering the object in advance. Note that the consumer of this method needs to provide
      * all of the details required to correctly contact and observe the object. If the consumer