Implementation of Logger interface between Application and
authorHarish Kumara Marappa <h.marappa@samsung.com>
Thu, 6 Aug 2015 08:40:14 +0000 (14:10 +0530)
committerMadan Lanka <lanka.madan@samsung.com>
Fri, 7 Aug 2015 00:54:52 +0000 (00:54 +0000)
simulator C++ modules.

Change-Id: I572a52907f16e06b9f0877e7dc150056d0aa7532
Signed-off-by: Harish Kumara Marappa <h.marappa@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1870
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Madan Lanka <lanka.madan@samsung.com>
service/simulator/examples/server/service_provider.cpp
service/simulator/inc/simulator_manager.h
service/simulator/java/jni/simulator_common_jni.h
service/simulator/java/jni/simulator_manager_jni.cpp
service/simulator/java/jni/simulator_manager_jni.h
service/simulator/src/simulator_logger.cpp [new file with mode: 0644]
service/simulator/src/simulator_logger.h [new file with mode: 0644]
service/simulator/src/simulator_manager.cpp

index e9e3ed6..8f634ca 100644 (file)
 
 #include "simulator_manager.h"
 
+class AppLogger : public ILogger
+{
+    public:
+        void write(std::string time, ILogger::Level level, std::string message)
+        {
+            std::cout << "[APPLogger] " << time << " " << ILogger::getString(level) << " " << message;
+        }
+};
+std::shared_ptr<AppLogger> gAppLogger(new AppLogger());
+
 class SimLightResource
 {
     public:
@@ -72,6 +82,12 @@ class SimLightResource
 
         int selectResource()
         {
+            if (0 == m_resources.size())
+            {
+                std::cout << "No resouces!" << std::endl;
+                return -1;
+            }
+
             int index = 1;
             for (auto & resource : m_resources)
             {
@@ -99,7 +115,8 @@ class SimLightResource
             std::cout << "#### Modified attributes are ####" << std::endl;
             for (auto & attribute : resModel.getAttributes())
             {
-                std::cout << attribute.second.getName() << " :  " << attribute.second.valueToString().c_str() << std::endl;
+                std::cout << attribute.second.getName() << " :  " << attribute.second.valueToString().c_str() <<
+                          std::endl;
             }
             std::cout << "########################" << std::endl;
         }
@@ -287,7 +304,7 @@ class SimLightResource
             int choice = -1;
             std::cout << "Select the attribute which you want to automate for updation: " << std::endl;
             std::cin >> choice;
-            if (choice == -1 || choice > size)
+            if (choice < 0 || choice > size)
             {
                 std::cout << "Invalid selection!" << std::endl;
                 return;
@@ -335,11 +352,45 @@ void printMainMenu()
 {
     std::cout << "############### MAIN MENU###############" << std::endl;
     std::cout << "1. Test simulation of light resource" << std::endl;
-    std::cout << "2. Help" << std::endl;
+    std::cout << "2. Set Logger" << std::endl;
+    std::cout << "3. Help" << std::endl;
     std::cout << "0. Exit" << std::endl;
     std::cout << "######################################" << std::endl;
 }
 
+void setLogger()
+{
+    std::cout << "1. Default console logger" << std::endl;
+    std::cout << "2. Default file logger" << std::endl;
+    std::cout << "3. custom logger" << std::endl;
+
+    int choice = -1;
+    std::cin >> choice;
+    if (choice <= 0 || choice > 3)
+    {
+        std::cout << "Invalid selection !" << std::endl;
+        return;
+    }
+
+    switch (choice)
+    {
+        case 1:
+            {
+                if (false == SimulatorManager::getInstance()->setDefaultConsoleLogger())
+                    std::cout << "Failed to set the default console logger" << std::endl;
+            } break;
+        case 2:
+            {
+                std::string filePath;
+                std::cout << "Enter the file path (without file name) : ";
+                std::cin >> filePath;
+                if (false == SimulatorManager::getInstance()->setDefaultFileLogger(filePath))
+                    std::cout << "Failed to set default file logger" << std::endl;
+            } break;
+        case 3: SimulatorManager::getInstance()->setLogger(gAppLogger);
+    }
+}
+
 int main(void)
 {
     SimLightResource lightResource;
@@ -351,7 +402,7 @@ int main(void)
         int choice = -1;
         std::cout << "Enter your choice: ";
         std::cin >> choice;
-        if (choice < 0 || choice > 2)
+        if (choice < 0 || choice > 3)
         {
             std::cout << "Invaild choice !" << std::endl; continue;
         }
@@ -361,7 +412,8 @@ int main(void)
             case 1: lightResource.startTest();
                 std::cout << "Welcome back to main menu !" << std::endl;
                 break;
-            case 2: printMainMenu(); break;
+            case 2: setLogger(); break;
+            case 3: printMainMenu(); break;
             case 0: cont = false;
         }
     }
index 2d83c7e..424791c 100644 (file)
@@ -31,6 +31,7 @@
 #include <vector>
 #include "simulator_error_codes.h"
 #include "simulator_resource.h"
+#include "simulator_logger.h"
 
 /**
  * @class   SimulatorManager
@@ -96,6 +97,34 @@ class SimulatorManager
           */
         SimulatorResult deleteResources(const std::string &resourceType = "");
 
+        /**
+         * API for setting logger target for receiving the log messages.
+         *
+         * @param logger - ILogger interface for handling the log messages.
+         *
+         */
+        void setLogger(std::shared_ptr<ILogger> logger);
+
+        /**
+         * API for setting console as logger target.
+         *
+         * @return true if console set as logger target,
+         *         otherwise false.
+         *
+         */
+        bool setDefaultConsoleLogger();
+
+        /**
+         * API for setting file as logger target.
+         *
+         * @param path - File to which log messages to be saved.
+         *
+         * @return true if console set as logger target,
+         *         otherwise false.
+         *
+         */
+        bool setDefaultFileLogger(std::string &path);
+
     private:
         SimulatorManager();
 };
index 1e49152..10e7c9d 100644 (file)
 
 #include <jni.h>
 
-static jfieldID GetHandleField(JNIEnv *env, jobject jobj)
-{
-    jclass cls = env->GetObjectClass(jobj);
-    return env->GetFieldID(cls, "nativeHandle", "J");
-}
-
-template <typename T>
-static T *GetHandle(JNIEnv *env, jobject jobj)
-{
-    jlong handle = env->GetLongField(jobj, GetHandleField(env, jobj));
-    return reinterpret_cast<T *>(handle);
-}
-
-template <typename T>
-static void SetHandle(JNIEnv *env, jobject jobj, T *type)
-{
-    jlong handle = reinterpret_cast<jlong>(type);
-
-    env->SetLongField(jobj, GetHandleField(env, jobj), handle);
-}
-
 typedef struct
 {
     jclass classInteger;
     jclass classDouble;
     jclass classString;
     jclass classHashMap;
+    jclass classVector;
     jclass classSimulatorResource;
     jclass classSimulatorResourceModel;
     jclass classSimulatorResourceAttribute;
+    jclass classSimulatorRemoteResource;
+    jclass classSimulatorCallback;
 
     jmethodID classIntegerCtor;
     jmethodID classDoubleCtor;
     jmethodID classHashMapCtor;
     jmethodID classHashMapPut;
+    jmethodID classVectorCtor;
+    jmethodID classVectorAddElement;
     jmethodID classSimulatorResourceCtor;
     jmethodID classSimulatorResourceSetURI;
     jmethodID classSimulatorResourceSetResourceType;
@@ -67,4 +51,28 @@ typedef struct
     jmethodID classSimulatorResourceAttributeCtor;
 } SimulatorClassRefs;
 
+static jfieldID GetHandleField(JNIEnv *env, jobject jobj)
+{
+    jclass cls = env->GetObjectClass(jobj);
+    return env->GetFieldID(cls, "nativeHandle", "J");
+}
+
+template <typename T>
+static T *GetHandle(JNIEnv *env, jobject jobj)
+{
+    jlong handle = env->GetLongField(jobj, GetHandleField(env, jobj));
+    return reinterpret_cast<T *>(handle);
+}
+
+template <typename T>
+static void SetHandle(JNIEnv *env, jobject jobj, T *type)
+{
+    jlong handle = reinterpret_cast<jlong>(type);
+
+    env->SetLongField(jobj, GetHandleField(env, jobj), handle);
+}
+
+JNIEnv *getEnv();
+void releaseEnv();
+
 #endif
index d0958bc..406dcfa 100644 (file)
 #include "simulator_common_jni.h"
 #include "simulator_manager.h"
 
-#define SIMULATOR_RESOURCE_PATH "org/iotivity/simulator/SimulatorResourceServer"
-#define SIMULATOR_RESOURCE_TYPE "Lorg/iotivity/simulator/SimulatorResourceServer;"
+SimulatorClassRefs gSimulatorClassRefs;
+std::mutex gEnvMutex;
+JavaVM *gvm;
 
-#define SIMULATOR_RESOURCE_MODEL_PATH "org/iotivity/simulator/SimulatorResourceModel"
-#define SIMULATOR_RESOURCE_MODEL_TYPE "Lorg/iotivity/simulator/SimulatorResourceModel;"
+JNIEnv *getEnv()
+{
+    std::unique_lock<std::mutex> lock(gEnvMutex);
+    if (nullptr == gvm)
+        return NULL;
 
-#define SIMULATOR_RESOURCE_ATTRIBUTE_PATH "org/iotivity/simulator/SimulatorResourceAttribute"
-#define SIMULATOR_RESOURCE_ATTRIBUTE_TYPE "Lorg/iotivity/simulator/SimulatorResourceAttribute;"
+    JNIEnv *env = NULL;
+    jint ret = gvm->GetEnv((void **)&env, JNI_VERSION_1_6);
+    switch (ret)
+    {
+        case JNI_OK:
+            return env;
+        case JNI_EDETACHED:
+            if (0 == gvm->AttachCurrentThread((void **)&env, NULL))
+                return env;
+    }
+
+    return NULL;
+}
+
+void releaseEnv()
+{
+    std::unique_lock<std::mutex> lock(gEnvMutex);
+    if (nullptr == gvm)
+        return;
+    gvm->DetachCurrentThread();
+}
+
+class JNILogger : public ILogger
+{
+    public:
+        void setJavaLogger(JNIEnv *env, jobject logger)
+        {
+            m_logger = env->NewWeakGlobalRef(logger);
+        }
+
+        void write(std::string time, ILogger::Level level, std::string message)
+        {
+            JNIEnv *env = getEnv();
+            if (nullptr == env)
+                return;
+
+            jobject logger = env->NewLocalRef(m_logger);
+            if (!logger)
+            {
+                releaseEnv();
+                return;
+            }
+
+            jclass loggerCls = env->GetObjectClass(logger);
+            if (!loggerCls)
+            {
+                releaseEnv();
+                return;
+            }
+
+            jmethodID writeMId = env->GetMethodID(loggerCls, "write",
+                                                  "(Ljava/lang/String;ILjava/lang/String;)V");
+            if (!writeMId)
+            {
+                releaseEnv();
+                return;
+            }
+
+            jstring msg = env->NewStringUTF(message.c_str());
+            jstring timeStr = env->NewStringUTF(time.c_str());
+            env->CallVoidMethod(logger, writeMId, timeStr, static_cast<jint>(level), msg);
+            env->DeleteLocalRef(msg);
+            env->DeleteLocalRef(timeStr);
+            releaseEnv();
+        }
+
+    private:
+        jweak m_logger;
+};
 
-SimulatorClassRefs gSimulatorClassRefs;
 
 JNIEXPORT jobject JNICALL
 Java_org_iotivity_simulator_SimulatorManagerNativeInterface_createResource
@@ -114,6 +184,15 @@ Java_org_iotivity_simulator_SimulatorManagerNativeInterface_deleteResources
 }
 
 
+JNIEXPORT void JNICALL
+Java_org_iotivity_simulator_SimulatorManagerNativeInterface_setLogger
+(JNIEnv *env, jclass object, jobject logger)
+{
+    static std::shared_ptr<ILogger> target(new JNILogger());
+    dynamic_cast<JNILogger *>(target.get())->setJavaLogger(env, logger);
+    SimulatorManager::getInstance()->setLogger(target);
+}
+
 static bool getClassRef(JNIEnv *env, const char *className, jclass &classRef)
 {
     jclass localClassRef = nullptr;
@@ -142,7 +221,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
         return JNI_ERR;
     }
 
-    // Get the class references and constructor methods
+    // Get the class references
     if (false == getClassRef(env, "java/lang/Integer", gSimulatorClassRefs.classInteger))
     {
         return JNI_ERR;
@@ -163,24 +242,37 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
         return JNI_ERR;
     }
 
-    if (false == getClassRef(env, SIMULATOR_RESOURCE_PATH, gSimulatorClassRefs.classSimulatorResource))
+    if (false == getClassRef(env, "java/util/Vector", gSimulatorClassRefs.classVector))
+    {
+        return JNI_ERR;
+    }
+
+    if (false == getClassRef(env, "org/oic/simulator/serviceprovider/SimulatorResourceServer",
+                             gSimulatorClassRefs.classSimulatorResource))
     {
         return JNI_ERR;
     }
 
-    if (false == getClassRef(env, SIMULATOR_RESOURCE_MODEL_PATH,
+    if (false == getClassRef(env, "org/oic/simulator/serviceprovider/SimulatorResourceModel",
                              gSimulatorClassRefs.classSimulatorResourceModel))
     {
         return JNI_ERR;
     }
 
-    if (false == getClassRef(env, SIMULATOR_RESOURCE_ATTRIBUTE_PATH,
+    if (false == getClassRef(env, "org/oic/simulator/SimulatorResourceAttribute",
                              gSimulatorClassRefs.classSimulatorResourceAttribute))
     {
         return JNI_ERR;
     }
 
-    // Get the constructor methods
+    if (false == getClassRef(env, "org/oic/simulator/clientcontroller/SimulatorRemoteResource",
+                             gSimulatorClassRefs.classSimulatorRemoteResource))
+    {
+        return JNI_ERR;
+    }
+
+
+    // Get the reference to methods
     gSimulatorClassRefs.classIntegerCtor = env->GetMethodID(gSimulatorClassRefs.classInteger, "<init>",
                                            "(I)V");
     if (!gSimulatorClassRefs.classIntegerCtor)
@@ -201,6 +293,17 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
     if (!gSimulatorClassRefs.classHashMapPut)
         return JNI_ERR;
 
+    gSimulatorClassRefs.classVectorCtor = env->GetMethodID(gSimulatorClassRefs.classVector, "<init>",
+                                          "()V");
+    if (!gSimulatorClassRefs.classVectorCtor)
+        return JNI_ERR;
+
+    gSimulatorClassRefs.classVectorAddElement = env->GetMethodID(gSimulatorClassRefs.classVector,
+            "addElement",
+            "(Ljava/lang/Object;)V");
+    if (!gSimulatorClassRefs.classVectorAddElement)
+        return JNI_ERR;
+
     gSimulatorClassRefs.classSimulatorResourceCtor = env->GetMethodID(
                 gSimulatorClassRefs.classSimulatorResource, "<init>", "(J)V");
     if (!gSimulatorClassRefs.classSimulatorResourceCtor)
@@ -236,16 +339,12 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
     if (!gSimulatorClassRefs.classSimulatorResourceAttributeCtor)
         return JNI_ERR;
 
+    gvm = vm;
     return JNI_VERSION_1_6;
 }
 
 JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
 {
-    JNIEnv *env = NULL;
-    if (JNI_OK != vm->GetEnv((void **)&env, JNI_VERSION_1_6))
-    {
-        return;
-    }
 }
 
 #ifdef __cplusplus
index 28a9cbb..a18d062 100644 (file)
@@ -55,6 +55,10 @@ JNIEXPORT void JNICALL
 Java_org_iotivity_simulator_SimulatorManagerNativeInterface_deleteResources
 (JNIEnv *env, jclass object, jstring resourceType);
 
+JNIEXPORT void JNICALL
+Java_org_iotivity_simulator_SimulatorManagerNativeInterface_setLogger
+(JNIEnv *env, jclass object, jobject logger);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/service/simulator/src/simulator_logger.cpp b/service/simulator/src/simulator_logger.cpp
new file mode 100644 (file)
index 0000000..e8ed2ea
--- /dev/null
@@ -0,0 +1,117 @@
+/******************************************************************
+ *
+ * Copyright 2015 Samsung Electronics All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "simulator_logger.h"
+#include <sstream>
+#include <fstream>
+#include <time.h>
+
+class ConsoleLogger : public ILogger
+{
+    public:
+        void write(std::string time, ILogger::Level level, std::string message)
+        {
+            std::ostringstream out;
+            out << time << " " << ILogger::getString(level) << " " << message;
+            std::cout << out.str() << std::endl;
+        }
+};
+
+class FileLogger : public ILogger
+{
+    public:
+        FileLogger(std::string filePath) : m_filePath(filePath) {}
+
+        bool open()
+        {
+            m_out.open(m_filePath, std::ofstream::out);
+            return m_out.is_open();
+        }
+
+        void close()
+        {
+            if (m_out.is_open())
+                m_out.close();
+        }
+
+        void write(std::string time, ILogger::Level level, std::string message)
+        {
+            m_out << time << " " << ILogger::getString(level) << " " << message;
+        }
+
+    private:
+        std::ofstream m_out;
+        std::string m_filePath;
+};
+
+bool Logger::setDefaultConsoleTarget()
+{
+    if (nullptr != m_target)
+        return false;
+
+    m_target = std::make_shared<ConsoleLogger>();
+    return true;
+}
+
+bool Logger::setDefaultFileTarget(std::string &path)
+{
+    if (nullptr != m_target || path.empty())
+        return false;
+
+    time_t timeInfo = time(NULL);
+    struct tm *localTime = localtime(&timeInfo);
+    std::ostringstream newFileName;
+    newFileName << path << "/Simulator_";
+    newFileName << localTime->tm_year << localTime->tm_mon << localTime->tm_mday << localTime->tm_hour
+                << localTime->tm_min << localTime->tm_sec;
+    newFileName << ".log";
+
+    std::shared_ptr<FileLogger> fileLogger(new FileLogger(newFileName.str()));
+    if (fileLogger->open())
+    {
+        m_target = fileLogger;
+        return true;
+    }
+
+    return false;
+}
+
+void Logger::setCustomTarget(std::shared_ptr<ILogger> target)
+{
+    m_target = target;
+}
+
+void Logger::write(ILogger::Level level, std::ostringstream &str)
+{
+    if (nullptr != m_target)
+    {
+        time_t timeInfo = time(NULL);
+        struct tm *localTime = localtime(&timeInfo);
+        std::ostringstream timeStr;
+        timeStr << localTime->tm_hour << "." << localTime->tm_min << "." << localTime->tm_sec;
+        m_target->write(timeStr.str(), level, str.str());
+    }
+}
+
+auto simLogger() -> Logger &
+{
+    static Logger logger;
+    return logger;
+}
\ No newline at end of file
diff --git a/service/simulator/src/simulator_logger.h b/service/simulator/src/simulator_logger.h
new file mode 100644 (file)
index 0000000..9c7e407
--- /dev/null
@@ -0,0 +1,79 @@
+/******************************************************************
+ *
+ * Copyright 2015 Samsung Electronics All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+/**
+ * @file   simulator_logger.h
+ *
+ * @brief   This file provides the interface for logging messages to different targets (console/file).
+ */
+
+#ifndef SIMULATOR_LOGGER_H_
+#define SIMULATOR_LOGGER_H_
+
+#include <iostream>
+#include <memory>
+
+class ILogger
+{
+    public:
+        enum Level
+        {
+            INFO = 0,
+            DEBUG,
+            WARNING,
+            ERROR
+        };
+
+        static const char *getString(Level level)
+        {
+            switch (level)
+            {
+                case Level::INFO: return "INFO";
+                case Level::DEBUG: return "DEBUG";
+                case Level::WARNING: return "WARNING";
+                case Level::ERROR: return "ERROR";
+                default: return "UNKNOWN";
+            }
+        }
+
+        virtual void write(std::string, Level, std::string) = 0;
+};
+
+class Logger
+{
+    public:
+        bool setDefaultConsoleTarget();
+        bool setDefaultFileTarget(std::string &path);
+        void setCustomTarget(std::shared_ptr<ILogger> target);
+        void write(ILogger::Level level, std::ostringstream &str);
+
+    private:
+        std::shared_ptr<ILogger> m_target;
+};
+
+auto simLogger() -> Logger &;
+
+#ifndef SIM_LOG
+#define SIM_LOG(LEVEL, MSG) { \
+        simLogger().write(LEVEL, static_cast<std::ostringstream&>(std::ostringstream()<<MSG)); \
+    }
+#endif
+
+#endif
\ No newline at end of file
index 21d8539..5d195fb 100644 (file)
@@ -68,4 +68,19 @@ SimulatorResult SimulatorManager::deleteResource(SimulatorResourcePtr &resource)
 SimulatorResult SimulatorManager::deleteResources(const std::string &resourceType)
 {
     return ResourceManager::getInstance()->deleteResources(resourceType);
+}
+
+void SimulatorManager::setLogger(std::shared_ptr<ILogger> logger)
+{
+    simLogger().setCustomTarget(logger);
+}
+
+bool SimulatorManager::setDefaultConsoleLogger()
+{
+    return simLogger().setDefaultConsoleTarget();
+}
+
+bool SimulatorManager::setDefaultFileLogger(std::string &path)
+{
+    return simLogger().setDefaultFileTarget(path);
 }
\ No newline at end of file