Support NLP CAPI 75/274575/10
authorJihoon Kim <jihoon48.kim@samsung.com>
Mon, 2 May 2022 01:34:45 +0000 (10:34 +0900)
committerJihoon Kim <jihoon48.kim@samsung.com>
Mon, 16 May 2022 07:10:36 +0000 (16:10 +0900)
[==========] Running 7 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from NlpCAPITest
[ RUN      ] NlpCAPITest.utc_nlp_connect_n
[       OK ] NlpCAPITest.utc_nlp_connect_n (2 ms)
[ RUN      ] NlpCAPITest.utc_nlp_connect_p
status : 0
request id : 1
tag: NNP, token : Hello
tag: NNP, token : World
request id: 1
token : Hello, tag : NNPtoken: Hello, tag: NNP
token : World, tag : NNPtoken: World, tag: NNP
[       OK ] NlpCAPITest.utc_nlp_connect_p (12982 ms)
[ RUN      ] NlpCAPITest.utc_nlp_foreach_pos_tag_n
[       OK ] NlpCAPITest.utc_nlp_foreach_pos_tag_n (0 ms)
[----------] 3 tests from NlpCAPITest (12984 ms total)

Change-Id: I3d479cbaa48c76d4ce1d4725c0469c3abe4af473
Signed-off-by: Jihoon Kim <jihoon48.kim@samsung.com>
17 files changed:
CMakeLists.txt
client/CMakeLists.txt [new file with mode: 0644]
client/capi-ui-nlp.manifest [new file with mode: 0644]
client/capi-ui-nlp.pc.in [new file with mode: 0644]
client/nlp_client.c [new file with mode: 0644]
client/nlp_private.h [new file with mode: 0644]
include/nlp.h [new file with mode: 0644]
packaging/nlp.spec
service/CMakeLists.txt
service/inc/message.h [deleted file]
service/message.tidl [deleted file]
service/prebuild.sh
service/src/message.c [deleted file]
service/src/service.c
tests/CMakeLists.txt
tests/src/nlp_capi_unittests.cpp [new file with mode: 0644]
tidl/message.tidl [new file with mode: 0644]

index 7f49e8d16dd121ace68b7de92105429be0a15de4..3edb70ab5e707dc3442692462dff0eb3d08465a8 100755 (executable)
@@ -1,5 +1,6 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 
+ADD_SUBDIRECTORY(client)
 ADD_SUBDIRECTORY(service)
 ADD_SUBDIRECTORY(nlp_resource_data)
 
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9899bc3
--- /dev/null
@@ -0,0 +1,132 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+SET(project_prefix "capi")
+SET(prefix "/usr")
+SET(version "0.0.1")
+SET(maintainer "Jihoon Kim <jihoon48.kim@samsung.com>")
+SET(description "NLP APIs")
+SET(service "ui")
+SET(submodule "nlp")
+SET(dependents "dlog glib-2.0 rpc-port capi-appfw-app-common")
+SET(LIBDIR ${LIB_INSTALL_DIR})
+
+SET(Services
+        "application"
+        "base"
+        "content"
+        "location"
+        "media"
+        "messaging"
+        "network"
+        "social"
+        "telephony"
+        "system"
+        "ui"
+   )
+
+FOREACH(lines ${configs})
+    IF(${lines} MATCHES "([^=]*)=['\"](.*)['\"]")
+        SET(key ${CMAKE_MATCH_1})
+        SET(value ${CMAKE_MATCH_2})
+        SET(${key} "${value}")
+    ENDIF()
+ENDFOREACH(lines ${configs})
+
+LIST(FIND Services ${service} sfind)
+
+IF( ${sfind} EQUAL -1 )
+    MESSAGE(FATAL_ERROR "Service must be one of ")
+    FOREACH( s IN ${Services} )
+        MESSAGE(FATAL_ERROR "[${s}]")
+    ENDFOREACH( s IN ${Services} )
+ENDIF( ${sfind} EQUAL -1 )
+
+SET(fw_name "${project_prefix}-${service}-${submodule}")
+
+PROJECT(${fw_name} C)
+
+SET(CMAKE_INSTALL_PREFIX ${prefix})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(VERSION ${version})
+
+SET(INC_DIR ../include)
+INCLUDE_DIRECTORIES(${INC_DIR})
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${fw_name} REQUIRED ${dependents})
+FOREACH(flag ${${fw_name}_CFLAGS})
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -fpermissive")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+
+IF("${ARCH}" STREQUAL "arm")
+    ADD_DEFINITIONS("-DTARGET")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DTIZEN_DEBUG")
+
+SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib")
+
+AUX_SOURCE_DIRECTORY(. SOURCES)
+ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
+
+SET_TARGET_PROPERTIES(${fw_name}
+     PROPERTIES
+     VERSION ${FULLVER}
+     SOVERSION ${MAJORVER}
+     CLEAN_DIRECT_OUTPUT 1
+)
+
+INSTALL(TARGETS ${fw_name} DESTINATION ${LIBDIR})
+INSTALL(
+        DIRECTORY ${INC_DIR}/ DESTINATION include
+        FILES_MATCHING
+        PATTERN "*_private.h" EXCLUDE
+        PATTERN "${INC_DIR}/*.h"
+        )
+
+SET(PC_NAME ${fw_name})
+SET(PC_REQUIRED ${dependents})
+SET(PC_LDFLAGS -l${fw_name})
+
+CONFIGURE_FILE(
+    capi-ui-nlp.pc.in
+    ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc
+    @ONLY
+)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIBDIR}/pkgconfig)
+
+IF(UNIX)
+
+ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution)
+ADD_CUSTOM_COMMAND(
+        DEPENDS clean
+        COMMENT "distribution clean"
+        COMMAND find
+        ARGS    .
+        -not -name config.cmake -and \(
+        -name tester.c -or
+        -name Testing -or
+        -name CMakeFiles -or
+        -name cmake.depends -or
+        -name cmake.check_depends -or
+        -name CMakeCache.txt -or
+        -name cmake.check_cache -or
+        -name *.cmake -or
+        -name Makefile -or
+        -name core -or
+        -name core.* -or
+        -name gmon.out -or
+        -name install_manifest.txt -or
+        -name *.pc -or
+        -name *~ \)
+        | grep -v TC | xargs rm -rf
+        TARGET  distclean
+        VERBATIM
+)
+
+ENDIF(UNIX)
diff --git a/client/capi-ui-nlp.manifest b/client/capi-ui-nlp.manifest
new file mode 100644 (file)
index 0000000..dfdc35c
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+  <domain name="_"/>
+ </request>
+</manifest>
diff --git a/client/capi-ui-nlp.pc.in b/client/capi-ui-nlp.pc.in
new file mode 100644 (file)
index 0000000..3bcc226
--- /dev/null
@@ -0,0 +1,13 @@
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=@LIBDIR@
+includedir=/usr/include
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
diff --git a/client/nlp_client.c b/client/nlp_client.c
new file mode 100644 (file)
index 0000000..9043ec6
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlog.h>
+#include <unistd.h>
+#include <tizen.h>
+#include <nlp.h>
+#include <rpc-port.h>
+#include <app_common.h>
+
+#include "nlp_private.h"
+#include "message_proxy.h"
+
+#define NLP_SERVICE_APP_ID "org.tizen.nlp.service"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "NLP_CLIENT"
+
+static int _nlp_context_count = 0;
+static unsigned int _request_id = 0;
+
+typedef struct {
+    const char *token;
+    const char *tag;
+} pos_tag_s;
+
+//LCOV_EXCL_START
+static void _notify_cb(void *user_data, const char *sender, bundle *msg)
+{
+    nlp_h nh = user_data;
+    LOGD("sender: %s", sender);
+    char *request_id = NULL;
+    char *command = NULL;
+
+    bundle_get_str(msg, "request_id", &request_id);
+    bundle_get_str(msg, "command", &command);
+
+    LOGD("id : %s, command : %s", request_id, command);
+
+    if (!command) return;
+
+    if (strcmp(command, "pos_tag") == 0) {
+        const char **tag_array = NULL;
+        const char **token_array = NULL;
+        int len_tag_array = 0;
+        int len_token_array = 0;
+        pos_tag_s* pos_tag_pair = NULL;
+        GList *glist = NULL;
+        nlp_pos_tag_result_h pos_tag_result_h = NULL;
+
+        tag_array = bundle_get_str_array(msg, "return_tag", &len_tag_array);
+        token_array = bundle_get_str_array(msg, "return_token", &len_token_array);
+
+        for (int i=0; i < len_tag_array; i++) {
+            pos_tag_pair = (pos_tag_s* )calloc(1, sizeof(pos_tag_s));
+            if (pos_tag_pair) {
+                pos_tag_pair->token = token_array[i];
+                pos_tag_pair->tag = tag_array[i];
+            }
+
+            LOGD("tag: %s, token : %s", tag_array[i], token_array[i]);
+
+            glist = g_list_append(glist, pos_tag_pair);
+        }
+
+        pos_tag_result_h = glist;
+
+        if (nh->pos_tag_result_cb)
+            nh->pos_tag_result_cb((unsigned int)atoi(request_id), pos_tag_result_h, nh->pos_tag_result_data);
+    }
+}
+
+static void __on_connected(rpc_port_proxy_message_h h, void *user_data)
+{
+    nlp_h nh = user_data;
+    if (!nh) {
+        LOGW("no user data");
+        return;
+    }
+
+    nh->connected = true;
+
+    LOGI("connected");
+
+    rpc_port_proxy_message_notify_cb_h notify_cb_h;
+    rpc_port_proxy_message_notify_cb_create(&notify_cb_h);
+    rpc_port_proxy_message_notify_cb_set_callback(notify_cb_h, _notify_cb, nh);
+    rpc_port_proxy_message_notify_cb_set_once(notify_cb_h, false);
+
+    char *app_id = NULL;
+    app_get_id(&app_id);
+    if (!app_id) {
+        char pid[256];
+        snprintf(pid, sizeof(pid), "%u", getpid());
+        app_id = strdup(pid);
+    }
+
+    int r = rpc_port_proxy_message_invoke_coregister(h, app_id, notify_cb_h);
+    if (r != 0)
+        LOGW("[ERROR] Failed to invoke Register");
+
+    free(app_id);
+
+    if (nh->connection_callback)
+        nh->connection_callback(nh, NLP_CONNECTION_STATUS_CONNECTED, nh->connection_userdata);
+}
+
+//LCOV_EXCL_START
+static void __on_disconnected(rpc_port_proxy_message_h h, void *user_data)
+{
+    LOGI("disconnected");
+
+    nlp_h nh = user_data;
+    if (nh) {
+        nh->connected = false;
+
+        if (nh && nh->connection_callback)
+            nh->connection_callback(nh, NLP_CONNECTION_STATUS_DISCONNECTED, nh->connection_userdata);
+
+        nh->rpc_h = NULL;
+    }
+}
+
+static void __on_rejected(rpc_port_proxy_message_h h, void *user_data)
+{
+    LOGW("Connection rejected");
+
+    nlp_h nh = user_data;
+
+    if (nh && nh->connection_callback)
+        nh->connection_callback(nh, NLP_CONNECTION_STATUS_REJECTED, nh->connection_userdata);
+}
+//LCOV_EXCL_STOP
+
+EXPORT_API int nlp_create(nlp_h *nh)
+{
+    int ret;
+
+    if (!nh)
+        return NLP_ERROR_INVALID_PARAMETER;
+
+    rpc_port_proxy_message_callback_s rpc_callback = {
+        .connected = __on_connected,
+        .disconnected = __on_disconnected,
+        .rejected = __on_rejected
+    };
+
+    struct nlp_s *ns = (nlp_h)calloc(1, sizeof(struct nlp_s));
+    if (!ns)
+        return NLP_ERROR_OUT_OF_MEMORY;
+
+    ret = rpc_port_proxy_message_create(NLP_SERVICE_APP_ID, &rpc_callback, ns, &ns->rpc_h);
+    if (ret != RPC_PORT_ERROR_NONE) {
+        LOGW("[ERROR] Failed to create rpc port. err = %d", ret);
+        free(ns);
+        return NLP_ERROR_OUT_OF_MEMORY;
+    }
+
+    ns->context_id = _nlp_context_count++;
+    *nh = ns;
+
+    return NLP_ERROR_NONE;
+}
+
+EXPORT_API int nlp_destroy(nlp_h nh)
+{
+    if (!nh)
+        return NLP_ERROR_INVALID_PARAMETER;
+
+    nh->connection_callback = NULL;
+
+    if (nh->rpc_h) {
+        rpc_port_proxy_message_destroy(nh->rpc_h);
+        nh->rpc_h = NULL;
+    }
+
+    free(nh);
+
+    return NLP_ERROR_NONE;
+}
+
+EXPORT_API int nlp_connect(nlp_h nh, nlp_connection_status_changed_cb callback, void *user_data)
+{
+    LOGI("nlp client connect. handle : %p", nh);
+
+    int ret;
+
+    if (!nh || !callback) {
+        LOGW("[ERROR] Invalid parameter");
+        return NLP_ERROR_INVALID_PARAMETER;
+    }
+
+    if (!nh->rpc_h) {
+        return NLP_ERROR_OPERATION_FAILED;
+    }
+
+    nh->connection_callback = callback;
+    nh->connection_userdata = user_data;
+
+    ret = rpc_port_proxy_message_connect(nh->rpc_h);
+    if (ret != RPC_PORT_ERROR_NONE) {
+        //LCOV_EXCL_START
+        switch(ret) {
+            case RPC_PORT_ERROR_IO_ERROR:
+                LOGW("[ERROR] Failed to connect rpc port. I/O Error");
+                break;
+            case RPC_PORT_ERROR_OUT_OF_MEMORY:
+                LOGW("[ERROR] Failed to connect rpc port. Out of memory");
+                return NLP_ERROR_OUT_OF_MEMORY;
+                break;
+            case RPC_PORT_ERROR_INVALID_PARAMETER:
+                LOGW("[ERROR] Failed to connect rpc port. Invalid parameter");
+                break;
+            case RPC_PORT_ERROR_PERMISSION_DENIED:
+                LOGW("[ERROR] Failed to connect rpc port. Permission denied");
+                return NLP_ERROR_PERMISSION_DENIED;
+                break;
+            default:
+                LOGW("[ERROR] Failed to connect rpc port. errcode = %d", ret);
+                break;
+        }
+        return NLP_ERROR_OPERATION_FAILED;
+        //LCOV_EXCL_STOP
+    }
+    else {
+        return NLP_ERROR_NONE;
+    }
+}
+
+EXPORT_API int nlp_request_pos_tag(nlp_h nh, const char *str, unsigned int *request_id)
+{
+    if (!nh || !str) {
+        LOGW("[ERROR] Invalid parameter");
+        return NLP_ERROR_INVALID_PARAMETER;
+    }
+
+    if (!nh->rpc_h) {
+        return NLP_ERROR_OPERATION_FAILED;
+    }
+
+    _request_id++;
+    char id[16];
+    snprintf(id, sizeof(id), "%u", _request_id);
+
+    bundle *msg = bundle_create();
+    bundle_add_str(msg, "command", "pos_tag");
+    bundle_add_str(msg, "info", str);
+    bundle_add_str(msg, "request_id", id);
+
+    rpc_port_proxy_message_invoke_send(nh->rpc_h, msg);
+    bundle_free(msg);
+
+    if (request_id)
+        *request_id = _request_id;
+
+    return NLP_ERROR_NONE;
+}
+
+EXPORT_API int nlp_set_pos_tag_result_cb(nlp_h nh, nlp_pos_tag_result_cb callback, void *user_data)
+{
+    if (!nh || !callback) {
+        LOGW("[ERROR] Invalid parameter");
+        return NLP_ERROR_INVALID_PARAMETER;
+    }
+
+    nh->pos_tag_result_cb = callback;
+    nh->pos_tag_result_data = user_data;
+
+    return NLP_ERROR_NONE;
+}
+
+EXPORT_API int nlp_unset_pos_tag_result_cb(nlp_h nh)
+{
+    if (!nh) {
+        LOGW("[ERROR] Invalid parameter");
+        return NLP_ERROR_INVALID_PARAMETER;
+    }
+
+    nh->pos_tag_result_cb = NULL;
+    nh->pos_tag_result_data = NULL;
+
+    return NLP_ERROR_NONE;
+}
+
+int nlp_foreach_pos_tag(nlp_pos_tag_result_h pos_tag_result_h, nlp_pos_tag_foreach_cb callback, void* user_data)
+{
+    if (!pos_tag_result_h || !callback) {
+        LOGW("[ERROR] Invalid parameter");
+        return NLP_ERROR_INVALID_PARAMETER;
+    }
+
+    GList *glist = pos_tag_result_h;
+
+    GList* iter = NULL;
+    pos_tag_s* pos_tag_pair = NULL;
+
+    if (g_list_length(glist) > 0) {
+        iter = g_list_first(glist);
+
+        while (NULL != iter) {
+            pos_tag_pair = iter->data;
+            if (NULL != pos_tag_pair) {
+                LOGD("token : %s, tag : %s", pos_tag_pair->token, pos_tag_pair->tag);
+                callback(pos_tag_pair->token, pos_tag_pair->tag, user_data);
+            }
+
+            /* next item */
+            iter = g_list_next(iter);
+
+            free(pos_tag_pair);
+        }
+
+        g_list_free(glist);
+        glist = NULL;
+    }
+
+    return NLP_ERROR_NONE;
+}
diff --git a/client/nlp_private.h b/client/nlp_private.h
new file mode 100644 (file)
index 0000000..f51fcfc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd 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.
+ */
+
+#ifndef __TIZEN_UIX_NLP_PRIVATE_H__
+#define __TIZEN_UIX_NLP_PRIVATE_H__
+
+#include "../client/message_proxy.h"
+
+struct nlp_s {
+    rpc_port_proxy_message_h rpc_h;
+
+    unsigned int context_id;
+
+    bool connected;
+
+    nlp_connection_status_changed_cb connection_callback;
+    void *connection_userdata;
+
+    nlp_pos_tag_result_cb pos_tag_result_cb;
+    void *pos_tag_result_data;
+};
+
+#endif /* __TIZEN_UIX_NLP_PRIVATE_H__ */
diff --git a/include/nlp.h b/include/nlp.h
new file mode 100644 (file)
index 0000000..a938b1b
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd 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.
+ */
+
+#ifndef __TIZEN_UIX_NLP_H__
+#define __TIZEN_UIX_NLP_H__
+
+#include <tizen.h>
+#include <glib.h>
+
+/**
+ * @file nlp.h
+ * @brief This file contains NLP APIs and related enumeration.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup CAPI_UIX_NLP_CLIENT_MODULE
+ * @{
+ */
+
+#define TIZEN_ERROR_NLP            -0x030E0000
+
+/**
+ * @brief Enumeration for NLP function error.
+ *
+ * @since_tizen 7.0
+ */
+typedef enum {
+    NLP_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+    NLP_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+    NLP_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
+    NLP_ERROR_OPERATION_FAILED = TIZEN_ERROR_NLP | 0x0001, /**< Operation failed */
+    NLP_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+    NLP_ERROR_SERVICE_NOT_CONNECTED = TIZEN_ERROR_NLP | 0x0002, /**< Unable to connect to NLP Service */
+} nlp_error_e;
+
+/**
+ * @brief Enumeration of connection status.
+ * @since_tizen 7.0
+ */
+typedef enum {
+    NLP_CONNECTION_STATUS_CONNECTED = 0, /**< Connected */
+    NLP_CONNECTION_STATUS_DISCONNECTED, /**< Disconnected */
+    NLP_CONNECTION_STATUS_REJECTED, /**< Rejected */
+} nlp_connection_status_e;
+
+/**
+ * @brief The nlp handle.
+ * @since_tizen 7.0
+ */
+typedef struct nlp_s *nlp_h;
+
+typedef GList *nlp_pos_tag_result_h;
+
+/**
+ * @brief Called when the connection status is changed.
+ * @since_tizen 7.0
+ * @remarks @a nh should not be freed and can be used only in the callback.
+ * @param[in] nh The nlp handle
+ * @param[in] status The connection status
+ * @param[in] user_data The user data passed from the callback function
+ * @see nlp_connect()
+ */
+typedef void (*nlp_connection_status_changed_cb)(nlp_h nh, nlp_connection_status_e status, void* user_data);
+
+typedef void (*nlp_pos_tag_result_cb)(unsigned int request_id, nlp_pos_tag_result_h pos_tag_result_h, void *user_data);
+
+typedef bool (*nlp_pos_tag_foreach_cb)(const char* token, const char *tag, void* user_data);
+
+/**
+ * @brief Creates a handle for nlp.
+ * @since_tizen 7.0
+ * @remarks If the function succeeds, @a nh handle must be released with nlp_destroy().
+ * @param[out] nh The nlp handle
+ * @return 0 on success, otherwise a negative error value
+ * @retval #NLP_ERROR_NONE No error
+ * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #NLP_ERROR_OUT_OF_MEMORY Out of memory
+ * @see nlp_destroy()
+ */
+int nlp_create(nlp_h *nh);
+
+/**
+ * @brief Destroys an nlp.
+ * @since_tizen 7.0
+ * @param[in] nh The nlp handle
+ * @return 0 on success, otherwise a negative error value
+ * @retval #NLP_ERROR_NONE No error
+ * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see nlp_create()
+ */
+int nlp_destroy(nlp_h nh);
+
+/**
+ * @brief Connects to nlp service application.
+ * @since_tizen 7.0
+ * @param[in] nh The nlp handle
+ * @param[in] callback The callback function to register
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return 0 on success, otherwise a negative error value
+ * @retval #NLP_ERROR_NONE No error
+ * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #NLP_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #NLP_ERROR_OPERATION_FAILED Operation failure
+ */
+int nlp_connect(nlp_h nh, nlp_connection_status_changed_cb callback, void *user_data);
+
+/**
+ * @brief Requests to get the part of speech tagging given the string @str.
+ * @since_tizen 7.0
+ * @remarks The result can be received by the callback function registered by nlp_set_pos_tag_result_cb().
+ * @param[in] nh The nlp handle
+ * @param[in] str The string to be requested to get the part of speech tagging
+ * @param[out] request_id The request ID to be distingushed
+ * @return 0 on success, otherwise a negative error value
+ * @retval #NLP_ERROR_NONE No error
+ * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #NLP_ERROR_OPERATION_FAILED Operation failure
+ */
+int nlp_request_pos_tag(nlp_h ah, const char *str, unsigned int *request_id);
+
+/**
+ * @brief Sets the callback to receive the part of speech tagging.
+ * @since_tizen 7.0
+ * @param[in] nh The NLP handle
+ * @param[in] callback The callback function to register
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return 0 on success, otherwise a negative error value
+ * @retval #NLP_ERROR_NONE No error
+ * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see nlp_unset_pos_tag_result_cb()
+ */
+int nlp_set_pos_tag_result_cb(nlp_h nh, nlp_pos_tag_result_cb callback, void *user_data);
+
+/**
+ * @brief Unsets the callback to receive the part of speech tagging.
+ * @since_tizen 7.0
+ * @param[in] nh The NLP handle
+ * @return 0 on success, otherwise a negative error value
+ * @retval #NLP_ERROR_NONE No error
+ * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see nlp_set_pos_tag_result_cb()
+ */
+int nlp_unset_pos_tag_result_cb(nlp_h nh);
+
+/**
+ * @brief Retrieves the part of speech tagging using callback function.
+ * @since_tizen 7.0
+ * @param[in] pos_tag_result_h The part of speech tagging result handle
+ * @param[in] callback The callback function to register
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return 0 on success, otherwise a negative error value
+ * @retval #NLP_ERROR_NONE No error
+ * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int nlp_foreach_pos_tag(nlp_pos_tag_result_h pos_tag_result_h, nlp_pos_tag_foreach_cb callback, void* user_data);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIZEN_UIX_NLP_H__ */
index 2c6f3ff81bf576317f5dfd0ee626f60e1a78cdd0..9b0cba72cb41e906dcf007085dfb1b20260d8534 100755 (executable)
@@ -7,6 +7,7 @@ Group:      Graphics & UI Framework/Input
 License:    Apache-2.0
 Source0:    %{name}-%{version}.tar.gz
 BuildRequires: cmake
+BuildRequires: tidl
 BuildRequires: pkgconfig(capi-appfw-service-application)
 BuildRequires: pkgconfig(libtzplatform-config)
 BuildRequires: pkgconfig(bundle)
@@ -22,10 +23,33 @@ Requires: %{name}-data-en
 
 # runtime requires
 Requires(post): coreutils
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%if 0%{?gcov:1}
+BuildRequires:  lcov
+BuildRequires:  zip
+%endif
 
 %description
 Natural Language Processing service.
 
+%package devel
+Summary:  NLP Client Library (Development)
+Group:    Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+NLP Library (Development)
+
+%if 0%{?gcov:1}
+%package gcov
+Summary:  NLP Library (gcov)
+Group:      Graphics & UI Framework/Input
+%description gcov
+NLP gcov objects
+%endif
+
 %package data-en
 Summary:    Data files for English
 Group:      Graphics & UI Framework/Input
@@ -44,19 +68,59 @@ GTest for NLP
 %prep
 %setup -q
 
+tidlc -p -l C -i tidl/message.tidl -o message_proxy
+mv message_proxy.h ./client/
+mv message_proxy.c ./client/
+
+tidlc -s -l C -i tidl/message.tidl -o message_stub
+mv message_stub.h ./service/src
+mv message_stub.c ./service/src
+
 %build
+%if 0%{?gcov:1}
+export CFLAGS+=" -fprofile-arcs -ftest-coverage"
+export CXXFLAGS+=" -fprofile-arcs -ftest-coverage"
+export FFLAGS+=" -fprofile-arcs -ftest-coverage"
+export LDFLAGS+=" -lgcov"
+%endif
+
 %define _app_home_dir   %{TZ_SYS_RO_APP}/%{name}
 %define _app_bin_dir    %{_app_home_dir}/bin
 
+export CFLAGS+=" -DTIZEN_DEBUG_ENABLE -fvisibility=hidden -Werror"
+export CXXFLAGS+=" -DTIZEN_DEBUG_ENABLE -fvisibility=hidden -Werror"
+export FFLAGS+=" -DTIZEN_DEBUG_ENABLE -fvisibility=hidden"
+
+rm -rf CMakeFiles
+rm -rf CMakeCache.txt
 MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
 cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DLIB_INSTALL_DIR:PATH=%{_libdir} -DPYTHON3_SITELIB_PATH=%{python3_sitelib}
 
 make %{?jobs:-j%jobs}
+
 %install
 rm -rf %{buildroot}
 
 %make_install
 
+%if 0%{?gcov:1}
+find . -name '*_proxy.c.gcno' -exec rm {} \;
+find . -name '*_stub.c.gcno' -exec rm {} \;
+
+find . -name '*.gcno' | tar cf %{name}-gcov.tar -T -
+install -d -m 755 %{buildroot}%{_datadir}/gcov/obj
+tar xf %{name}-gcov.tar -C %{buildroot}%{_datadir}/gcov/obj
+%endif
+
+%check
+%if 0%{?gcov:1}
+ctest --output-on-failure %{?_smp_mflags}
+lcov -c --ignore-errors graph --no-external -q -d . -o %{name}.info
+genhtml %{name}.info -o %{name}.out
+zip -r %{name}.zip %{name}.out %{name}.info
+install -m 0644 %{name}.zip %{buildroot}%{_datadir}/gcov/
+%endif
+
 %define tizen_sign 1
 %define tizen_sign_base %{TZ_SYS_RO_APP}/%{name}
 %define tizen_sign_level public
@@ -64,19 +128,26 @@ rm -rf %{buildroot}
 %define tizen_dist_sign 1
 
 %post
+/sbin/ldconfig
 
-%postun
+%postun -p /sbin/ldconfig
 
 %files
 %manifest service/%{name}.manifest
 %defattr(-,root,root,-)
 %attr(755,root,root) %{_app_bin_dir}/%{name}
+%{_libdir}/libcapi-ui-nlp.so.*
+%{_libdir}/libcapi-ui-nlp.so
 %{_app_bin_dir}/*
 %{TZ_SYS_RO_PACKAGES}/%{name}.xml
 %{python3_sitelib}/langdetect/*
 %{python3_sitelib}/nltk/*
 %license LICENSE
 
+%files devel
+%{_includedir}/nlp.h
+%{_libdir}/pkgconfig/capi-ui-nlp.pc
+
 %files data-en
 %manifest service/%{name}.manifest
 %defattr(-,root,root,-)
@@ -85,3 +156,8 @@ rm -rf %{buildroot}
 
 %files unittests
 %{_bindir}/*
+
+%if 0%{?gcov:1}
+%files gcov
+%{_datadir}/gcov/*
+%endif
index ef5a8bdd6d018662eae8f494f079a6b49cdcebcd..86bfed633642dea85c2208c20e0a37e8004197f1 100755 (executable)
@@ -6,7 +6,7 @@ INCLUDE(FindPkgConfig)
 
 SET(SERVICE_SRC
     src/service.c
-    src/message.c
+    src/message_stub.c
     src/main.c
     src/nltk.c
     )
diff --git a/service/inc/message.h b/service/inc/message.h
deleted file mode 100644 (file)
index a699078..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Generated by tidlc 1.2.4.
- *
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
- *
- * 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.
- */
-
-#pragma once
-
-#include <stdbool.h>
-#include <bundle.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct message_context_s* rpc_port_stub_message_context_h;
-
-int rpc_port_stub_message_context_set_tag(rpc_port_stub_message_context_h ctx, void *tag);
-
-int rpc_port_stub_message_context_get_tag(rpc_port_stub_message_context_h ctx, void **tag);
-
-int rpc_port_stub_message_context_get_sender(rpc_port_stub_message_context_h ctx, char **sender);
-
-typedef struct message_notify_cb_s *rpc_port_message_notify_cb_h;
-
-int rpc_port_message_notify_cb_destroy(rpc_port_message_notify_cb_h h);
-
-int rpc_port_message_notify_cb_clone(rpc_port_message_notify_cb_h h, rpc_port_message_notify_cb_h *clone);
-
-int rpc_port_message_notify_cb_invoke(rpc_port_message_notify_cb_h h, const char *sender, bundle *msg);
-
-typedef struct {
-    void (*create)(rpc_port_stub_message_context_h context, void *user_data);
-    void (*terminate)(rpc_port_stub_message_context_h context, void *user_data);
-
-    int (*coregister)(rpc_port_stub_message_context_h context, const char *name, rpc_port_message_notify_cb_h cb, void *user_data);
-    void (*unregister)(rpc_port_stub_message_context_h context, void *user_data);
-    int (*send)(rpc_port_stub_message_context_h context, bundle *msg, void *user_data);
-} rpc_port_stub_message_callback_s;
-
-int rpc_port_stub_message_register(rpc_port_stub_message_callback_s *callback, void *user_data);
-
-int rpc_port_stub_message_unregister(void);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/service/message.tidl b/service/message.tidl
deleted file mode 100644 (file)
index 76ea688..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-interface message {
-    void notify_cb(string sender, bundle *msg) delegate;
-
-    int coregister(string name, notify_cb cb);
-    void unregister() async;
-    int send(bundle *msg);
-}
index 979a7d2c645fb6a60e028304780cd53789e51410..dc112bca9f65e022b8582d0b7cce7c2f55715d95 100755 (executable)
@@ -1,4 +1,5 @@
 #!/bin/bash
-tidlc -s -l C -i message.tidl -o message
-mv message.h ./inc/
-mv message.c ./src/
\ No newline at end of file
+tidlc -s -l C -i message.tidl -o messageStub
+tidlc -p -l C -i message.tidl -o messageProxy
+mv messageStub.h ./inc/
+mv messageStub.c ./src/
diff --git a/service/src/message.c b/service/src/message.c
deleted file mode 100644 (file)
index 6eff7e8..0000000
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Generated by tidlc 1.2.4.
- *
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
- *
- * 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.
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <libgen.h>
-#include <glib.h>
-#include <dlog.h>
-#include <rpc-port.h>
-#include <rpc-port-parcel.h>
-
-#include "message.h"
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-
-#define LOG_TAG "RPC_PORT_STUB"
-
-#ifdef _E
-#undef _E
-#endif
-
-#ifdef _W
-#undef _W
-#endif
-
-#ifdef _I
-#undef _I
-#endif
-
-#ifdef _D
-#undef _D
-#endif
-
-#define _E(fmt, ...) dlog_print(DLOG_ERROR, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define _W(fmt, ...) dlog_print(DLOG_WARN, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define _I(fmt, ...) dlog_print(DLOG_INFO, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define _D(fmt, ...) dlog_print(DLOG_DEBUG, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-
-typedef int (*stub_method)(rpc_port_h, rpc_port_parcel_h, void *data);
-
-enum message_method_e {
-    message_METHOD_Result,
-    message_METHOD_Callback,
-    message_METHOD_coregister,
-    message_METHOD_unregister,
-    message_METHOD_send,
-};
-
-enum message_delegate_e {
-    message_DELEGATE_notify_cb = 1,
-};
-
-static rpc_port_stub_h __message_stub;
-static rpc_port_stub_message_callback_s __message_callback;
-static void *__message_user_data;
-static GList *__message_contexts;
-
-struct message_context_s {
-    char *sender;
-    char *instance;
-    rpc_port_h port;
-    void *tag;
-    rpc_port_stub_message_callback_s callback;
-    void *user_data;
-};
-
-static struct message_context_s *__create_message_context(const char *sender, const char *instance)
-{
-    struct message_context_s *handle;
-
-    handle = calloc(1, sizeof(struct message_context_s));
-    if (!handle) {
-        _E("Out of memory");
-        return NULL;
-    }
-
-    handle->sender = strdup(sender);
-    if (!handle->sender) {
-        _E("Out of memory");
-        free(handle);
-        return NULL;
-    }
-
-    handle->instance = strdup(instance);
-    if (!handle->instance) {
-        _E("Out of memory");
-        free(handle->sender);
-        free(handle);
-        return NULL;
-    }
-
-    handle->callback = __message_callback;
-    handle->user_data = __message_user_data;
-
-    return handle;
-}
-
-static void __destroy_message_context(gpointer data)
-{
-    struct message_context_s *handle = data;
-
-    if (!handle) {
-        _E("Critical error!");
-        return;
-    }
-
-    free(handle->instance);
-    free(handle->sender);
-    free(handle);
-}
-
-static struct message_context_s *__find_message_context(const char *instance)
-{
-    struct message_context_s *handle;
-    GList *iter;
-
-    iter = __message_contexts;
-    while (iter) {
-        handle = (struct message_context_s *)iter->data;
-        if (!strcmp(handle->instance, instance))
-            return handle;
-        iter = g_list_next(iter);
-    }
-
-    return NULL;
-}
-
-int rpc_port_stub_message_context_set_tag(rpc_port_stub_message_context_h ctx, void *tag)
-{
-    if (!ctx) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    ctx->tag = tag;
-
-    return 0;
-}
-
-int rpc_port_stub_message_context_get_tag(rpc_port_stub_message_context_h ctx, void **tag)
-{
-    if (!ctx || !tag) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    *tag = ctx->tag;
-
-    return 0;
-}
-
-int rpc_port_stub_message_context_get_sender(rpc_port_stub_message_context_h ctx, char **sender)
-{
-    if (!ctx || !sender) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    *sender = strdup(ctx->sender);
-    if (*sender == NULL) {
-        _E("Out of memory");
-        return -1;
-    }
-
-    return 0;
-}
-
-struct message_notify_cb_s {
-    rpc_port_parcelable_t parcelable;
-    rpc_port_h port;
-    int id;
-    int seq_id;
-    bool once;
-    bool valid;
-};
-
-static void __message_notify_cb_to(rpc_port_parcel_h parcel, void *data)
-{
-    rpc_port_message_notify_cb_h handle = data;
-
-    if (!handle) {
-        _E("Invalid parameter");
-        return;
-    }
-
-    rpc_port_parcel_write_int32(parcel, handle->id);
-    rpc_port_parcel_write_int32(parcel, handle->seq_id);
-    rpc_port_parcel_write_bool(parcel, handle->once);
-}
-
-static void __message_notify_cb_from(rpc_port_parcel_h parcel, void *data)
-{
-    rpc_port_message_notify_cb_h handle = data;
-
-    if (!handle) {
-        _E("Invalid parameter");
-        return;
-    }
-
-    rpc_port_parcel_read_int32(parcel, &handle->id);
-    rpc_port_parcel_read_int32(parcel, &handle->seq_id);
-    rpc_port_parcel_read_bool(parcel, &handle->once);
-}
-
-int rpc_port_message_notify_cb_create(rpc_port_message_notify_cb_h *h)
-{
-    struct message_notify_cb_s *handle;
-    static int seq_num;
-
-    if (!h) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    handle = calloc(1, sizeof(struct message_notify_cb_s));
-    if (!handle) {
-        _E("Out of memory");
-        return -1;
-    }
-
-    handle->parcelable.to = __message_notify_cb_to;
-    handle->parcelable.from = __message_notify_cb_from;
-    handle->id = message_DELEGATE_notify_cb;
-    handle->seq_id = g_atomic_int_add(&seq_num, 1) + 1;
-    handle->once = false;
-    handle->valid = true;
-
-    *h = handle;
-
-    return 0;
-}
-
-int rpc_port_message_notify_cb_destroy(rpc_port_message_notify_cb_h h)
-{
-    if (!h) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    free(h);
-
-    return 0;
-}
-
-int rpc_port_message_notify_cb_clone(rpc_port_message_notify_cb_h h, rpc_port_message_notify_cb_h *clone)
-{
-    rpc_port_message_notify_cb_h handle;
-
-    if (!h || !clone) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    handle = calloc(1, sizeof(struct message_notify_cb_s));
-    if (!handle) {
-        _E("Out of memory");
-        return -1;
-    }
-
-    handle->parcelable = h->parcelable;
-    handle->port = h->port;
-    handle->id = h->id;
-    handle->seq_id = h->seq_id;
-    handle->once = h->once;
-    handle->valid = h->valid;
-
-    *clone = handle;
-
-    return 0;
-}
-
-int rpc_port_message_notify_cb_invoke(rpc_port_message_notify_cb_h h, const char *sender, bundle *msg)
-{
-    rpc_port_parcel_h parcel = NULL;
-
-    if (!h || !h->port) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    if (h->once && !h->valid) {
-        _E("Invalid callback");
-        return -1;
-    }
-
-    rpc_port_parcel_create(&parcel);
-    if (!parcel) {
-        _E("Failed to create parcel");
-        return -1;
-    }
-
-    rpc_port_parcel_write_int32(parcel, message_METHOD_Callback);
-    rpc_port_parcel_write(parcel, &h->parcelable, h);
-    rpc_port_parcel_write_string(parcel, sender ? sender : "");
-    rpc_port_parcel_write_bundle(parcel, msg);
-
-    rpc_port_parcel_send(parcel, h->port);
-    rpc_port_parcel_destroy(parcel);
-    h->valid = false;
-
-    return 0;
-}
-
-int rpc_port_message_notify_cb_set_port(rpc_port_message_notify_cb_h h, rpc_port_h port)
-{
-    if (!h || !port) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    h->port = port;
-
-    return 0;
-}
-
-static int __message_method_coregister(rpc_port_h port, rpc_port_parcel_h parcel, void *data)
-{
-    rpc_port_stub_message_context_h context = data;
-    rpc_port_h callback_port;
-    int r;
-
-    r = rpc_port_stub_get_port(__message_stub, RPC_PORT_PORT_CALLBACK, context->instance, &callback_port);
-    if (r != 0)
-        _E("Failed to get callback port");
-
-    char *name;
-    rpc_port_message_notify_cb_h cb;
-
-    rpc_port_parcel_read_string(parcel, &name);
-    rpc_port_message_notify_cb_create(&cb);
-    rpc_port_message_notify_cb_set_port(cb, callback_port);
-    rpc_port_parcel_read(parcel, &cb->parcelable, cb);
-
-    int ret = context->callback.coregister(context, name, cb, context->user_data);
-    do {
-        rpc_port_parcel_h result;
-
-        rpc_port_parcel_create(&result);
-        rpc_port_parcel_write_int32(result, message_METHOD_Result);
-        rpc_port_parcel_write_int32(result, ret);
-        rpc_port_parcel_send(result, port);
-        rpc_port_parcel_destroy(result);
-    } while (0);
-
-    free(name);
-    rpc_port_message_notify_cb_destroy(cb);
-    return 0;
-}
-
-static int __message_method_unregister(rpc_port_h port, rpc_port_parcel_h parcel, void *data)
-{
-    rpc_port_stub_message_context_h context = data;
-    rpc_port_h callback_port;
-    int r;
-
-    r = rpc_port_stub_get_port(__message_stub, RPC_PORT_PORT_CALLBACK, context->instance, &callback_port);
-    if (r != 0)
-        _E("Failed to get callback port");
-
-    context->callback.unregister(context, context->user_data);
-
-    return 0;
-}
-
-static int __message_method_send(rpc_port_h port, rpc_port_parcel_h parcel, void *data)
-{
-    rpc_port_stub_message_context_h context = data;
-    rpc_port_h callback_port;
-    int r;
-
-    r = rpc_port_stub_get_port(__message_stub, RPC_PORT_PORT_CALLBACK, context->instance, &callback_port);
-    if (r != 0)
-        _E("Failed to get callback port");
-
-    bundle *msg;
-
-    rpc_port_parcel_read_bundle(parcel, &msg);
-
-    int ret = context->callback.send(context, msg, context->user_data);
-    do {
-        rpc_port_parcel_h result;
-
-        rpc_port_parcel_create(&result);
-        rpc_port_parcel_write_int32(result, message_METHOD_Result);
-        rpc_port_parcel_write_int32(result, ret);
-        rpc_port_parcel_send(result, port);
-        rpc_port_parcel_destroy(result);
-    } while (0);
-
-    bundle_free(msg);
-    return 0;
-}
-
-static stub_method __message_method_table[] = {
-    [message_METHOD_coregister] = __message_method_coregister,
-    [message_METHOD_unregister] = __message_method_unregister,
-    [message_METHOD_send] = __message_method_send,
-};
-
-static void __message_on_connected(const char *sender, const char *instance, void *data)
-{
-    rpc_port_stub_message_context_h context;
-
-    _I("[__RPC_PORT__] sender(%s), instance(%s)", sender, instance);
-    context = __create_message_context(sender, instance);
-    if (!context)
-        return;
-
-    if (context->callback.create)
-        context->callback.create(context, context->user_data);
-    __message_contexts = g_list_append(__message_contexts, context);
-}
-
-static void __message_on_disconnected(const char *sender, const char *instance, void *data)
-{
-    rpc_port_stub_message_context_h context;
-
-    _I("[__RPC_PORT__] sender(%s), instance(%s)", sender, instance);
-    context = __find_message_context(instance);
-    if (!context)
-        return;
-
-    if (context->callback.terminate)
-        context->callback.terminate(context, context->user_data);
-    __message_contexts = g_list_remove(__message_contexts, context);
-    __destroy_message_context(context);
-}
-
-static int __message_on_received(const char *sender, const char *instance, rpc_port_h port, void *data)
-{
-    rpc_port_stub_message_context_h context;
-    rpc_port_parcel_h parcel;
-    int cmd = -1;
-    int r;
-
-    _I("[__RPC_PORT__] sender(%s), instance(%s)", sender, instance);
-    context = __find_message_context(instance);
-    if (!context) {
-        _E("Failed to find message context(%s)", instance);
-        return -1;
-    }
-
-    context->port = port;
-    r = rpc_port_parcel_create_from_port(&parcel, port);
-    if (r != 0) {
-        _E("Failed to create parcel from port");
-        return r;
-    }
-
-    rpc_port_parcel_read_int32(parcel, &cmd);
-    if (cmd > 1 && cmd < (sizeof(__message_method_table) / sizeof(__message_method_table[0]))) {
-        if (__message_method_table[cmd])
-            r = __message_method_table[cmd](port, parcel, context);
-    } else {
-        _E("Unknown Command(%d)", cmd);
-        r = -1;
-    }
-
-    rpc_port_parcel_destroy(parcel);
-
-    return r;
-}
-
-static int __message_add_privileges(void)
-{
-
-    return 0;
-}
-
-int rpc_port_stub_message_register(rpc_port_stub_message_callback_s *callback, void *user_data)
-{
-    int r;
-
-    if (__message_stub) {
-        _W("Already exists");
-        return -1;
-    }
-
-    if (!callback) {
-        _E("Invalid parameter");
-        return -1;
-    }
-
-    __message_callback = *callback;
-    __message_user_data = user_data;
-    r = rpc_port_stub_create(&__message_stub, "message");
-    if (r != 0) {
-        _E("Failed to create stub handle");
-        return r;
-    }
-
-    r = rpc_port_stub_add_received_event_cb(__message_stub, __message_on_received, NULL);
-    if (r != 0) {
-        _E("Failed to add received event callback");
-        rpc_port_stub_destroy(__message_stub);
-        __message_stub = NULL;
-        return r;
-    }
-
-    r = rpc_port_stub_add_connected_event_cb(__message_stub, __message_on_connected, NULL);
-    if (r != 0) {
-        _E("Failed to add connected event callback");
-        rpc_port_stub_destroy(__message_stub);
-        __message_stub = NULL;
-        return r;
-    }
-
-    r = rpc_port_stub_add_disconnected_event_cb(__message_stub, __message_on_disconnected, NULL);
-    if (r != 0) {
-        _E("Failed to add disconnected event callback");
-        rpc_port_stub_destroy(__message_stub);
-        __message_stub = NULL;
-        return r;
-    }
-
-    r = __message_add_privileges();
-    if (r != 0) {
-        _E("Failed to add privileges");
-        rpc_port_stub_destroy(__message_stub);
-        __message_stub = NULL;
-        return r;
-    }
-
-    r = rpc_port_stub_listen(__message_stub);
-    if (r != 0) {
-        _E("Failed to listen stub");
-        rpc_port_stub_destroy(__message_stub);
-        __message_stub = NULL;
-        return r;
-    }
-
-    return 0;
-}
-
-int rpc_port_stub_message_unregister(void)
-{
-    int r;
-
-    if (!__message_stub)
-        return -1;
-
-    if (__message_contexts) {
-        g_list_free_full(__message_contexts, __destroy_message_context);
-        __message_contexts = NULL;
-    }
-
-    r = rpc_port_stub_destroy(__message_stub);
-    __message_stub = NULL;
-
-    return r;
-}
index 4a11dfae3c12a359d1e34048d8d0e51aba897458..1c97f9b60003a7a8d6a55be5b9abcddc63d4c324 100755 (executable)
@@ -6,7 +6,7 @@
 #undef _POSIX_C_SOURCE
 #include "service.h"
 #include "nlp_log.h"
-#include "message.h"
+#include "message_stub.h"
 #include "nltk.h"
 
 typedef enum {
@@ -23,11 +23,11 @@ static gint service_close_timer = 0;
 
 struct client_s {
     char *id;
-    rpc_port_message_notify_cb_h cb;
+    rpc_port_stub_message_notify_cb_h cb;
 };
 
 static struct client_s *__create_client(const char *id,
-        rpc_port_message_notify_cb_h cb)
+        rpc_port_stub_message_notify_cb_h cb)
 {
     PENTER();
     struct client_s *handle;
@@ -45,7 +45,7 @@ static struct client_s *__create_client(const char *id,
         return NULL;
     }
 
-    rpc_port_message_notify_cb_clone(cb, &handle->cb);
+    rpc_port_stub_message_notify_cb_clone(cb, &handle->cb);
     if (!handle->cb) {
         PERR("Out of memory");
         free(handle->id);
@@ -88,7 +88,7 @@ static void __destroy_client(gpointer data)
         return;
 
     if (handle->cb)
-        rpc_port_message_notify_cb_destroy(handle->cb);
+        rpc_port_stub_message_notify_cb_destroy(handle->cb);
     if (handle->id)
         free(handle->id);
     free(handle);
@@ -124,7 +124,7 @@ static void __message_terminate(rpc_port_stub_message_context_h context,
 }
 
 static int __message_register(rpc_port_stub_message_context_h context,
-        const char *name, rpc_port_message_notify_cb_h cb,
+        const char *name, rpc_port_stub_message_notify_cb_h cb,
         void *user_data)
 {
     struct client_s *client;
@@ -146,7 +146,10 @@ static int __message_send(rpc_port_stub_message_context_h context,
     char *message = NULL;
     bundle_get_str(msg, "command", &message);
     rpc_port_stub_message_context_get_tag(context, (void *)&sender_client);
-    PLOG("[__RPC_PORT__] name(%s), msg(%s)", sender_client->id, message);
+    if (sender_client) 
+        PLOG("[__RPC_PORT__] name(%s), msg(%s)", sender_client->id, message);
+    else
+        PERR("[__RPC_PORT__] no sender info. msg(%s)", message);
 
     bundle *reply = bundle_create();
     char *info = NULL;
@@ -357,8 +360,12 @@ static int __message_send(rpc_port_stub_message_context_h context,
             bundle_add_str(reply, "command", "Exception happens");
             break;
     }
-    bundle_add_str(reply, "request_id", request_id);
-    rpc_port_message_notify_cb_invoke(sender_client->cb, sender_client->id, reply);
+    bundle_add_str(reply, "request_id", request_id ? request_id : "");
+    if (sender_client)
+        rpc_port_stub_message_notify_cb_invoke(sender_client->cb, sender_client->id, reply);
+    else
+        PERR("No sender info");
+
     bundle_free(reply);
     start_timer();
     return 0;
index d6b58b0c4b5ab09f0420a869838bef14d0908770..a851d5dd1adbb5645a49741660d0d8a4747527ef 100644 (file)
@@ -34,12 +34,16 @@ AUX_SOURCE_DIRECTORY(src SOURCES)
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../service/src NLP_SERVICE_SOURCES)
 list(REMOVE_ITEM NLP_SERVICE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../service/src/main.c")
 
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../client NLP_CLIENT_SOURCES)
+
 ADD_DEFINITIONS("-DFULLVER=\"${FULLVER}\"")
 
 ADD_EXECUTABLE(${UTC_NLP}
        ${NLP_SERVICE_SOURCES}
+       ${NLP_CLIENT_SOURCES}
        ${SOURCES}
        )
+
 TARGET_LINK_LIBRARIES(${UTC_NLP} ${GTEST_LIBRARIES} ${pkgs_LDFLAGS} ${EXTRA_LDFLAGS})
 
 INSTALL(TARGETS ${UTC_NLP} DESTINATION /usr/bin)
diff --git a/tests/src/nlp_capi_unittests.cpp b/tests/src/nlp_capi_unittests.cpp
new file mode 100644 (file)
index 0000000..aa9b54e
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * 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 <gtest/gtest.h>
+
+#include <glib.h>
+#include <string>
+#include <chrono>
+#include <thread>
+#include <nlp.h>
+
+#define GMAINLOOP 1
+#define WAIT_RESULT_DELAY 10
+
+static int g_init = false;
+static GMainLoop *loop = NULL;
+
+static gint service_close_timer = 0;
+
+using namespace std;
+
+namespace {
+
+static void STOP_LOOP();
+static void WAIT_FOR_CALLBACK();
+
+gboolean timer_cb(gpointer data)
+{
+    printf("time runs out\n");
+    service_close_timer = 0;
+    STOP_LOOP();
+
+    return FALSE;
+}
+
+void stop_timer()
+{
+    if (service_close_timer > 0)
+        g_source_remove(service_close_timer);
+
+    service_close_timer = 0;
+}
+
+bool pos_tag_foreach_cb(const char* token, const char *tag, void* user_data)
+{
+    printf("token: %s, tag: %s\n", token, tag);
+
+    return true;
+}
+
+void pos_tag_result_cb(unsigned int request_id, nlp_pos_tag_result_h pos_tag_result_h, void *user_data)
+{
+    printf("request id: %d\n", request_id);
+
+    nlp_foreach_pos_tag(pos_tag_result_h, pos_tag_foreach_cb, NULL);
+
+    STOP_LOOP();
+}
+
+static void _connection_cb(nlp_h nh, nlp_connection_status_e status, void* user_data)
+{
+    printf("status : %d\n", status);
+
+    unsigned int request_id = 0;
+
+    nlp_set_pos_tag_result_cb(nh, pos_tag_result_cb, NULL);
+
+    nlp_request_pos_tag(nh, "Hello World", &request_id);
+    printf("request id : %d\n", request_id);
+
+    WAIT_FOR_CALLBACK();
+}
+
+static void STOP_LOOP()
+{
+    printf("quit loop\n");
+    if (loop)
+        g_main_loop_quit(loop);
+}
+
+static void WAIT_FOR_CALLBACK()
+{
+    stop_timer();
+
+    service_close_timer = g_timeout_add(WAIT_RESULT_DELAY*1000, timer_cb, NULL);
+    if (service_close_timer == 0)
+        printf("failed to create timer\n");
+
+    printf("start loop\n");
+
+    if (loop) {
+        g_main_loop_quit(loop);
+        g_main_loop_run(loop);
+    }
+    else {
+        printf("Can't run loop. loop NULL\n");
+    }
+}
+
+class NlpCAPITest : public testing::Test {
+    public:
+        nlp_h nh = NULL;
+
+        virtual void SetUp() {
+            if (!g_init) {
+                g_init = true;
+            }
+
+            loop = g_main_loop_new(NULL, FALSE);
+
+            int ret = nlp_create(&nh);
+            EXPECT_EQ(ret, NLP_ERROR_NONE);
+            EXPECT_NE(nh, nullptr);
+        }
+        virtual void TearDown() {
+            if (nh)
+                nlp_destroy(nh);
+
+            if (loop)
+                g_main_loop_unref(loop);
+
+            loop = NULL;
+        }
+};
+
+TEST_F(NlpCAPITest, utc_nlp_connect_invalid_parameter)
+{
+    int ret = nlp_connect(nh, NULL, NULL);
+    EXPECT_EQ(ret, NLP_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(NlpCAPITest, utc_nlp_connect_p)
+{
+    int ret = nlp_connect(nh, _connection_cb, NULL);
+    EXPECT_EQ(ret, NLP_ERROR_NONE);
+
+    WAIT_FOR_CALLBACK();
+}
+
+TEST_F(NlpCAPITest, utc_nlp_foreach_pos_tag_invalid_parameter)
+{
+    int ret = nlp_foreach_pos_tag(NULL, NULL, NULL);
+    EXPECT_EQ(ret, NLP_ERROR_INVALID_PARAMETER);
+}
+
+} // namespace
diff --git a/tidl/message.tidl b/tidl/message.tidl
new file mode 100644 (file)
index 0000000..bd52a79
--- /dev/null
@@ -0,0 +1,7 @@
+interface message {
+    void notify_cb(string sender, bundle msg) delegate;
+
+    int coregister(string name, notify_cb cb);
+    void unregister() async;
+    int send(bundle msg);
+}