void GroupSynchronizationCallbacks::onFoundGroup(std::shared_ptr<OC::OCResource> groupResource)
{
    LOGI("FindGroup : Enter");

    if (NULL == groupResource.get())
    {
        LOGE("FindGroup : Invalid received GroupResource!");
        return;
    }

    JNIEnv *env = ThingsManagerJVM::getEnv();
    if (env == NULL)
    {
        LOGE("FindGroup : Getting JNIEnv failed");
        return;
    }

    // Get ThingsManagerCallback class reference
    jclass groupSynchronizationCallbacks = GetJClass(TM_SERVICE_GROUP_SYNCHRONIZATION_CLASS_PATH);
    if (NULL == groupSynchronizationCallbacks)
    {
        LOGE("FindGroup : GetJClass TMServiceCallbackInterface failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    // Get the ThingsManagerCallback class instance
    jobject jobjectCallback = GetJObjectInstance(TM_SERVICE_GROUP_SYNCHRONIZATION_CLASS_PATH);
    if (NULL == jobjectCallback)
    {
        LOGE("FindGroup: getInstance failed!");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    // Get onGroupFindCallback method reference
    jmethodID method_id = env->GetMethodID(groupSynchronizationCallbacks,
                                           "onGroupFindCallback",
                                           METHOD_ONGROUP_FIND_CALLBACK);
    if (NULL == method_id)
    {
        LOGE("FindGroup : GetMethodID failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    if ((env)->ExceptionCheck())
    {
        LOGE("FindGroup : ExceptionCheck failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    JniOcResource *jniOcResource = new JniOcResource(groupResource);
    if (!jniOcResource)
    {
        LOGE("FindGroup : groupResource is invalid!");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    jobject resource = OcResourceToJava(env, reinterpret_cast<jlong>(jniOcResource));

    env->CallVoidMethod(jobjectCallback, method_id, resource);

    if ((env)->ExceptionCheck())
    {
        LOGE("FindGroup : CallVoidMethod failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    ThingsManagerJVM::releaseEnv();
    LOGI("FindGroup : Exit");
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
    LOGD("JNI_OnLoad: Enter");

    if (!vm)
    {
        LOGE("JNI_OnLoad: vm is invalid");
        return JNI_ERR;
    }

    JNIEnv *env = NULL;
    if (JNI_OK != vm->GetEnv((void **) &env, JNI_CURRENT_VERSION))
    {
        LOGE("JNI_OnLoad: Version check is failed!");
        return JNI_ERR;
    }

    if (0 != InitializeJClassMapArray(env))
    {
        LOGE("JNI_OnLoad: Initialize JClass Array failed!");
        return JNI_ERR;
    }

    if (0 != InitializeJObjectMapArray(env))
    {
        LOGE("JNI_OnLoad: Initialize JObject Array failed!");
        return JNI_ERR;
    }

    // Group Manager
    jclass groupManagerClassRef = GetJClass(TM_SERVICE_GROUP_MANAGER_CLASS_PATH);

    if (NULL == groupManagerClassRef)
    {
        LOGE("JNI_OnLoad: GetJClass gThingsManagerClass failed !");
        return JNI_ERR;
    }

    env->RegisterNatives(groupManagerClassRef, gGroupManagerMethodTable,
                         gGroupManagerMethodTableSize);

    // Group Synchronization
    jclass groupSynchronizationClassRef = GetJClass(TM_SERVICE_GROUP_SYNCHRONIZATION_CLASS_PATH);

    if (NULL == groupSynchronizationClassRef)
    {
        LOGE("JNI_OnLoad: GetJClass gThingsManagerClass failed !");
        return JNI_ERR;
    }

    env->RegisterNatives(groupSynchronizationClassRef, gGroupSynchronizationMethodTable,
                         gGroupSynchronizationMethodTableSize);

    //Things Configuration
    jclass thingsConfigurationClassRef = GetJClass(TM_SERVICE_THINGS_CONFIGURATION_CLASS_PATH);

    if (NULL == thingsConfigurationClassRef)
    {
        LOGE("JNI_OnLoad: GetJClass gThingsManagerClass failed !");
        return JNI_ERR;
    }

    env->RegisterNatives(thingsConfigurationClassRef, gThingsConfigurationMethodTable,
                         gThingsConfigurationMethodTableSize);

    //Things Maintenance
    jclass thingsMaintenanceClassRef = GetJClass(TM_SERVICE_THINGS_MAINTENANCE_CLASS_PATH);

    if (NULL == thingsMaintenanceClassRef)
    {
        LOGE("JNI_OnLoad: GetJClass gThingsManagerClass failed !");
        return JNI_ERR;
    }

    env->RegisterNatives(thingsMaintenanceClassRef, gThingsMaintenanceMethodTable,
                         gThingsMaintenanceMethodTableSize);

    ThingsManagerJVM::m_jvm = vm;

    LOGI("JNI_OnLoad: Exit");
    return JNI_CURRENT_VERSION;
}
void ThingsConfigurationCallbacks::invokeCallback(const OC::HeaderOptions &headerOptions,
        const OC::OCRepresentation &rep, const int eCode, const char  *callbackName,
        const char *signature)
{
    LOGI("InvokeCallback : Enter %s", callbackName);

    JNIEnv *env = ThingsManagerJVM::getEnv();
    if (env == NULL)
    {
        LOGE("InvokeCallback : Getting JNIEnv failed");
        return;
    }

    // Get ThingsManagerCallback class reference
    jclass thingsConfigurationCallbacks = GetJClass(TM_SERVICE_THINGS_CONFIGURATION_CLASS_PATH);
    if (NULL == thingsConfigurationCallbacks)
    {
        LOGE("InvokeCallback : GetJClass TMServiceCallbackInterface failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    // Get the ThingsManagerCallback class instance
    jobject jobjectCallback = GetJObjectInstance(TM_SERVICE_THINGS_CONFIGURATION_CLASS_PATH);
    if (NULL == jobjectCallback)
    {
        LOGE("InvokeCallback: getInstance( %s) failed!", TM_SERVICE_THINGS_CONFIGURATION_CLASS_PATH);
        ThingsManagerJVM::releaseEnv();
        return;
    }

    jmethodID method_id = env->GetMethodID(thingsConfigurationCallbacks, callbackName, signature);
    if (!method_id)
    {
        LOGE("InvokeCallback : GetMethodID failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    if ((env)->ExceptionCheck())
    {
        LOGE("InvokeCallback : ExceptionCheck failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    // Convert vector<OC:HeaderOption::OCHeaderOption> to java type
    jclass vectorCls = env->FindClass(TM_JAVA_VECTOR_CLASS_PATH);
    if (!vectorCls)
    {
        LOGE("InvokeCallback: failed to get %s class reference", TM_JAVA_VECTOR_CLASS_PATH);
        ThingsManagerJVM::releaseEnv();
        return;
    }

    jmethodID constr = env->GetMethodID(vectorCls, "<init>", "()V");
    if (!constr)
    {
        LOGE("InvokeCallback: failed to get %s constructor", TM_JAVA_VECTOR_CLASS_PATH);
        ThingsManagerJVM::releaseEnv();
        return;
    }

    jobject vectorObj = env->NewObject(vectorCls, constr);
    if (!vectorObj)
    {
        LOGE("InvokeCallback: failed to create a %s object", TM_JAVA_VECTOR_CLASS_PATH);
        ThingsManagerJVM::releaseEnv();
        return;
    }

    jmethodID addElement = env->GetMethodID(vectorCls, "addElement", "(Ljava/lang/Object;)V");
    if (NULL == addElement)
    {
        LOGE("InvokeCallback: failed to create a addElement method");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    jobject headerOptionTemp;
    for (int i = 0; i < headerOptions.size(); i++)
    {
        headerOptionTemp = OcHeaderOptionToJava(env, headerOptions[i]);
        env->CallVoidMethod(vectorObj, addElement, headerOptionTemp);
    }

    // Convert OCRepresentation to java type
    jobject jrepresentation = OcRepresentationToJava(env, (jlong) reinterpret_cast<jlong>(&rep));
    if (!jrepresentation)
    {
        LOGE("InvokeCallback : cannot create OCRepresentation class");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    env->CallVoidMethod(jobjectCallback, method_id, vectorObj, jrepresentation, (jint)eCode);

    if ((env)->ExceptionCheck())
    {
        LOGE("InvokeCallback : CallVoidMethod failed");
        ThingsManagerJVM::releaseEnv();
        return;
    }

    ThingsManagerJVM::releaseEnv();
    LOGI("InvokeCallback : Exit %s", callbackName);
}