[NLP] Introduce nlp project (#366)
authorzg2nets <40655877+zg2nets@users.noreply.github.com>
Tue, 4 Sep 2018 07:53:49 +0000 (15:53 +0800)
committerpsw0405 <sungwook79.park@samsung.com>
Tue, 4 Sep 2018 07:53:49 +0000 (16:53 +0900)
* add nlp project

* Fix naming rules as PascalCase and fix errors in .csproj file

* Modify Nlp project about the code and TizenFx rule

* Modify Nlp project for  ACR review suggestion

* Modify Nlp project about the code and TizenFx rule

* Modify Nlp project about the code and TizenFx rule

* Modify Nlp project as suggestion of 20180817AM

* Modify Nlp project as suggestion of 20180817PM14:49

* Modify Nlp project as suggestion of 20180817PM16:25

* Modify Nlp project about return value and typo issue

* Modify Nlp project about void return

* Modify Nlp project with new async solution

* Modify Nlp project as async suggestion

* Modify Nlp project with more support

* Modify Nlp project about common steps

* Modify Nlp project about dispose etc.

* Modify Nlp project about Close api

* Modify Nlp project about error.

* Modify Nlp project about logic error

* Modify Nlp project about misc issue

* Modify Nlp project about SA1201

* Modify Nlp project about else logic

src/Tizen.Nlp/Tizen.Nlp.csproj [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp.sln [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/LanguageDetectedResult.cs [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/LemmatizeResult.cs [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/MessageReceivedEventArgs.cs [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/NamedEntityRecognitionResult.cs [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/NaturalLanguageProcess.cs [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/NlpProxy.cs [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/PosTagResult.cs [new file with mode: 0644]
src/Tizen.Nlp/Tizen.Nlp/WordTokenizeResult.cs [new file with mode: 0644]

diff --git a/src/Tizen.Nlp/Tizen.Nlp.csproj b/src/Tizen.Nlp/Tizen.Nlp.csproj
new file mode 100644 (file)
index 0000000..1ac9515
--- /dev/null
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Tizen.Applications.Common\Tizen.Applications.Common.csproj" />
+  </ItemGroup>
+
+</Project>
\ No newline at end of file
diff --git a/src/Tizen.Nlp/Tizen.Nlp.sln b/src/Tizen.Nlp/Tizen.Nlp.sln
new file mode 100644 (file)
index 0000000..4e44df0
--- /dev/null
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2035
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Nlp", "Tizen.Nlp.csproj", "{AE6ACB66-52B4-409B-9ED4-9BE172EB1309}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {AE6ACB66-52B4-409B-9ED4-9BE172EB1309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {AE6ACB66-52B4-409B-9ED4-9BE172EB1309}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {AE6ACB66-52B4-409B-9ED4-9BE172EB1309}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {AE6ACB66-52B4-409B-9ED4-9BE172EB1309}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {7232C1FE-9BD2-4252-945C-F2A260A04BB3}
+       EndGlobalSection
+EndGlobal
diff --git a/src/Tizen.Nlp/Tizen.Nlp/LanguageDetectedResult.cs b/src/Tizen.Nlp/Tizen.Nlp/LanguageDetectedResult.cs
new file mode 100644 (file)
index 0000000..f05c666
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+namespace Tizen.Nlp
+{
+    /// <summary>
+    /// This class contains result of language detected.
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    public class LanguageDetectedResult
+    {
+        /// <summary>
+        /// The language info.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public string Language { get; set; }
+    }
+}
diff --git a/src/Tizen.Nlp/Tizen.Nlp/LemmatizeResult.cs b/src/Tizen.Nlp/Tizen.Nlp/LemmatizeResult.cs
new file mode 100644 (file)
index 0000000..c93f630
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tizen.Nlp
+{
+    /// <summary>
+    /// This class contains result of lemmatized.
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    public class LemmatizeResult
+    {
+        /// <summary>
+        /// The whole sentence.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public string ActualWord { get; set; }
+    }
+}
diff --git a/src/Tizen.Nlp/Tizen.Nlp/MessageReceivedEventArgs.cs b/src/Tizen.Nlp/Tizen.Nlp/MessageReceivedEventArgs.cs
new file mode 100644 (file)
index 0000000..8b582f7
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+using System;
+using System.Collections.Generic;
+
+namespace Tizen.Nlp
+{
+    /// <summary>
+    /// This custom class extend from EventArgs to obtain Bundle object.
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    internal class MessageReceivedEventArgs : EventArgs
+    {
+        /// <summary>
+        /// An Bundle type to carry an array struct return from tidl service.
+        /// To check which nlp command be return by  msg.GetItem("command")
+        /// To get value by  msg.GetItem("return_tag") and cast the value to string []
+        /// To get value by  msg.GetItem("return_token") and cast the value to string []
+        /// </summary>
+        public Dictionary<string, string[]> Message { get; set; }
+
+        /// <summary>
+        /// An id about nlp request
+        /// </summary>
+        public int RequestId { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Nlp/Tizen.Nlp/NamedEntityRecognitionResult.cs b/src/Tizen.Nlp/Tizen.Nlp/NamedEntityRecognitionResult.cs
new file mode 100644 (file)
index 0000000..6703bd6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+using System.Collections.Generic;
+
+namespace Tizen.Nlp
+{
+    /// <summary>
+    /// This class contains result of named entity recognition.
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    public class NamedEntityRecognitionResult
+    {
+        /// <summary>
+        /// The tokens of sentence.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public IList<string> Tokens { get; set; }
+
+        /// <summary>
+        /// The tags of sentence.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public IList<string> Tags { get; set; }
+    }
+
+}
diff --git a/src/Tizen.Nlp/Tizen.Nlp/NaturalLanguageProcess.cs b/src/Tizen.Nlp/Tizen.Nlp/NaturalLanguageProcess.cs
new file mode 100644 (file)
index 0000000..bc5cbe6
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Tizen.Applications;
+using Tizen.Applications.RPCPort;
+
+
+namespace Tizen.Nlp
+{
+
+    /// <summary>
+    /// This class contains the methods in the NLP processing.
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    public class NaturalLanguageProcess
+    {
+        private Message _msg;
+        private Message.NotifyCb _noti = new Message.NotifyCb();
+        private const string ServiceId = "org.tizen.nlp.service";
+        private const string LogTag = "tizen.nlp.client";
+        private bool disposed = false;
+        private int _requestIdPos = 0;
+        private int _requestIdLang = 0;
+        private int _requestIdNeChunk = 0;
+        private int _requestIdWordTokenize = 0;
+        private int _requestIdLemmatize = 0;
+        private Task _connectionTask;
+        private ConnectedState _connectionState = ConnectedState.Disconnected;
+
+        private readonly Dictionary<int, PostagCallback> _mapsPosTag = new Dictionary<int, PostagCallback>();
+
+        private readonly Dictionary<int, LangDetectCallback>
+            _mapsLangDetect = new Dictionary<int, LangDetectCallback>();
+
+        private readonly Dictionary<int, WordTokenizeCallback> _mapsWordTokenize =
+            new Dictionary<int, WordTokenizeCallback>();
+
+        private readonly Dictionary<int, NamedEntityRecognitionCallback> _mapsNamedEntity =
+            new Dictionary<int, NamedEntityRecognitionCallback>();
+
+        private readonly Dictionary<int, LemmatizeCallback> _mapsLemmatize = new Dictionary<int, LemmatizeCallback>();
+
+        /// <summary>
+        /// An construct method  to init local env of NLP .
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public NaturalLanguageProcess()
+        {
+            _noti.Received += ResultReceived;
+        }
+
+        private delegate bool LangDetectCallback(MessageReceivedEventArgs e);
+
+        private delegate bool WordTokenizeCallback(MessageReceivedEventArgs e);
+
+        private delegate bool PostagCallback(MessageReceivedEventArgs e);
+
+        private delegate bool NamedEntityRecognitionCallback(MessageReceivedEventArgs e);
+
+        private delegate bool LemmatizeCallback(MessageReceivedEventArgs e);
+
+        /// <summary>
+        /// A connection status change event
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public event EventHandler Disconnected;
+        private enum ConnectedState
+        {
+            Disconnected,
+            Connecting,
+            Connected
+        }
+
+        private void MakeRequest(string cmd, string sentence, int requestid)
+        {
+            if (_connectionState == ConnectedState.Connected)
+            {
+                using (Bundle b = new Bundle())
+                {
+                    b.AddItem("command", cmd);
+                    b.AddItem("info", sentence);
+                    b.AddItem("request_id", requestid.ToString());
+                    _msg.Send(b);
+                    b.Dispose();
+                }
+            }
+            else if (_connectionState == ConnectedState.Connecting)
+            {
+                throw new InvalidOperationException("natural language service is connecting");
+            }
+            else
+            {
+                throw new InvalidOperationException("disconnected from natural language service");
+            }
+        }
+
+        private void ResultReceived(string sender, Bundle msg)
+        {
+            Log.Debug(LogTag, "OnReceived ");
+            MessageReceivedEventArgs e = new MessageReceivedEventArgs();
+            int requestid;
+            Dictionary<string, string[]> result = new Dictionary<string, string[]>();
+            result.Add("token", (string[])msg.GetItem("return_token"));
+            e.RequestId = requestid = int.Parse((string)msg.GetItem("request_id"));
+            if (msg.GetItem("command").Equals("word_tokenize"))
+            {
+                e.Message = result;
+                if (_mapsWordTokenize.ContainsKey(requestid))
+                {
+                    _mapsWordTokenize[requestid]?.Invoke(e);
+                    _mapsWordTokenize.Remove(requestid);
+                }
+            }
+            else if (msg.GetItem("command").Equals("pos_tag"))
+            {
+                result.Add("tag", (string[])msg.GetItem("return_tag"));
+                e.Message = result;
+                if (_mapsPosTag.ContainsKey(requestid))
+                {
+                    _mapsPosTag[requestid]?.Invoke(e);
+                    _mapsPosTag.Remove(requestid);
+                }
+            }
+            else if (msg.GetItem("command").Equals("ne_chunk"))
+            {
+                result.Add("tag", (string[])msg.GetItem("return_tag"));
+                e.Message = result;
+                if (_mapsNamedEntity.ContainsKey(requestid))
+                {
+                    _mapsNamedEntity[requestid]?.Invoke(e);
+                    _mapsNamedEntity.Remove(requestid);
+                }
+            }
+            else if (msg.GetItem("command").Equals("lemmatize"))
+            {
+                e.Message = result;
+                if (_mapsLemmatize.ContainsKey(requestid))
+                {
+                    _mapsLemmatize[requestid]?.Invoke(e);
+                    _mapsLemmatize.Remove(requestid);
+                }
+            }
+            else if (msg.GetItem("command").Equals("langdetect"))
+            {
+                e.Message = result;
+                if (_mapsLangDetect.ContainsKey(requestid))
+                {
+                    _mapsLangDetect[requestid]?.Invoke(e);
+                    _mapsLangDetect.Remove(requestid);
+                }
+            }
+        }
+
+        /// <summary>
+        /// An async method  to connect remote service.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        /// <exception cref="InvalidOperationException">Thrown when the connect is rejected.</exception>
+        public Task Connect()
+        {
+            if (_connectionState == ConnectedState.Connected)
+            {
+                return Task.CompletedTask;
+            }
+            else if (_connectionState == ConnectedState.Connecting)
+            {
+
+                return _connectionTask;
+            }
+            _connectionState = ConnectedState.Connecting;
+            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+            _msg = new Message(ServiceId);
+            _msg.Disconnected += (s, e) =>
+            {
+                _connectionState = ConnectedState.Disconnected;
+                Disconnected?.Invoke(this, e);
+            };
+            _msg.Connected += (sender, e) =>
+            {
+                Log.Debug(LogTag, "start to register");
+                _msg.CoRegister(Application.Current.ApplicationInfo.ApplicationId, _noti);
+                tcs.SetResult(true);
+                _connectionState = ConnectedState.Connected;
+            };
+            _msg.Rejected += (sender, e) =>
+            {
+                _connectionState = ConnectedState.Disconnected;
+                tcs.SetException(new InvalidOperationException("invalid id cause exception"));
+            };
+            _msg.Connect();
+            return _connectionTask = tcs.Task;
+        }
+
+        /// <summary>
+        /// A method to close message connection
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public void Close()
+        {
+            if (_connectionState == ConnectedState.Disconnected) return;
+            _msg.UnRegister();
+            _msg.Dispose();
+            _msg = null;
+            _connectionState = ConnectedState.Disconnected;
+            _connectionTask.Dispose();
+            _connectionTask = null;
+        }
+
+
+        private void MapClear()
+        {
+            _mapsWordTokenize.Clear();
+            _mapsPosTag.Clear();
+            _mapsNamedEntity.Clear();
+            _mapsLemmatize.Clear();
+            _mapsLangDetect.Clear();
+        }
+
+        /// <summary>
+        /// A method to release resource of library
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposed)
+                return;
+
+            if (disposing)
+            {
+                Close();
+                _noti.Received -= ResultReceived;
+                _noti = null;
+                MapClear();
+            }
+            disposed = true;
+        }
+
+        /// <summary>
+        /// Send Pos of Tag request to remote tidl service with one parameters.
+        /// </summary>
+        /// <param name="sentence">A sentence need to be processed.</param>
+        /// <returns>PosTagResult</returns>
+        /// <since_tizen> 5 </since_tizen>
+        public Task<PosTagResult> PosTagAsync(string sentence)
+        {
+            int id = _requestIdPos++;
+            MakeRequest("pos_tag", sentence, id);
+            var task = new TaskCompletionSource<PosTagResult>();
+            _mapsPosTag[id] = (e) =>
+            {
+                PosTagResult pr = new PosTagResult();
+                e.Message.TryGetValue("token", out string[] tokens);
+                e.Message.TryGetValue("tag", out string[] tags);
+                pr.Tokens = tokens;
+                pr.Tags = tags;
+                task.SetResult(pr);
+                return true;
+            };
+            return task.Task;
+        }
+
+        /// <summary>
+        /// Send Named Entity recognition request to remote tidl service with one parameters.
+        /// </summary>
+        /// <param name="sentence">A sentence need to be processed.</param>
+        /// <returns>NamedEntityRecognitionResult</returns>
+        /// <since_tizen> 5 </since_tizen>
+        public Task<NamedEntityRecognitionResult> NamedEntityRecognitionAsync(string sentence)
+        {
+            int id = _requestIdNeChunk++;
+            MakeRequest("ne_chunk", sentence, id);
+            var task = new TaskCompletionSource<NamedEntityRecognitionResult>();
+            _mapsNamedEntity[id] = (e) =>
+            {
+                NamedEntityRecognitionResult nr = new NamedEntityRecognitionResult();
+                e.Message.TryGetValue("token", out string[] tokens);
+                e.Message.TryGetValue("tag", out string[] tags);
+                nr.Tokens = tokens;
+                nr.Tags = tags;
+                task.SetResult(nr);
+                return true;
+            };
+            return task.Task;
+        }
+
+        /// <summary>
+        /// Send language detect request to remote tidl service with one parameters.
+        /// </summary>
+        /// <param name="sentence">A sentence need to be processed.</param>
+        /// <returns>LanguageDetectedResult</returns>
+        /// <since_tizen> 5 </since_tizen>
+        public Task<LanguageDetectedResult> LanguageDetectAsync(string sentence)
+        {
+            int id = _requestIdLang++;
+            MakeRequest("langdetect", sentence, id);
+            var task = new TaskCompletionSource<LanguageDetectedResult>();
+            _mapsLangDetect[id] = (e) =>
+            {
+                LanguageDetectedResult lr = new LanguageDetectedResult();
+                e.Message.TryGetValue("token", out string[] lang);
+                if (lang != null) lr.Language = lang[0];
+                task.SetResult(lr);
+                return true;
+            };
+            return task.Task;
+        }
+
+        /// <summary>
+        /// Send Lemmatize request to remote tidl service with one parameters.
+        /// </summary>
+        /// <param name="sentence">A sentence need to be processed.</param>
+        /// <returns>ProcessResult</returns>
+        /// <since_tizen> 5 </since_tizen>
+        public Task<LemmatizeResult> LemmatizeaAsync(string sentence)
+        {
+            int id = _requestIdLemmatize++;
+            MakeRequest("lemmatize", sentence, id);
+            var task = new TaskCompletionSource<LemmatizeResult>();
+            _mapsLemmatize[id] = (e) =>
+            {
+                LemmatizeResult mr = new LemmatizeResult();
+                e.Message.TryGetValue("token", out string[] tokens);
+                if (tokens != null) mr.ActualWord = tokens[0];
+                task.SetResult(mr);
+                return true;
+            };
+            return task.Task;
+        }
+
+        /// <summary>
+        /// Send word tokenize request to remote tidl service with one parameters.
+        /// </summary>
+        /// <param name="sentence">A sentence need to be processed.</param>
+        /// <returns>ProcessResult</returns>
+        /// <since_tizen> 5 </since_tizen>
+        public Task<WordTokenizeResult> WordTokenizeAsync(string sentence)
+        {
+            int id = _requestIdWordTokenize++;
+            MakeRequest("word_tokenize", sentence, id);
+            var task = new TaskCompletionSource<WordTokenizeResult>();
+            _mapsWordTokenize[id] = (e) =>
+            {
+                WordTokenizeResult wr = new WordTokenizeResult();
+                e.Message.TryGetValue("token", out string[] tokens);
+                wr.Tokens = tokens;
+                task.SetResult(wr);
+                return true;
+            };
+            return task.Task;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Nlp/Tizen.Nlp/NlpProxy.cs b/src/Tizen.Nlp/Tizen.Nlp/NlpProxy.cs
new file mode 100644 (file)
index 0000000..0cfb0c3
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+using System;
+using System.Collections.Generic;
+using Tizen.Applications;
+using Tizen.Applications.RPCPort;
+
+namespace Tizen.Nlp
+{
+    internal class Message : ProxyBase
+    {
+        public event EventHandler Connected;
+        public event EventHandler Disconnected;
+        public event EventHandler Rejected;
+
+        private bool _online;
+        private readonly string _appId = null;
+        private readonly Object _lock = new Object();
+        private readonly List<CallbackBase> _delegateList = new List<CallbackBase>();
+
+        public abstract class CallbackBase
+        {
+            internal int Id;
+            internal int SeqId;
+            internal bool Once;
+            private static volatile int _seqNum = 0;
+
+            public string Tag => Id.ToString() + "::" + SeqId.ToString();
+
+            protected CallbackBase(int delegateId, bool once)
+            {
+                Id = delegateId;
+                SeqId = _seqNum++;
+                Once = once;
+            }
+
+            internal virtual void OnReceivedEvent(Parcel p) { }
+
+            internal static void Serialize(Parcel h, CallbackBase param)
+            {
+                h.WriteInt(param.Id);
+                h.WriteInt(param.SeqId);
+                h.WriteBool(param.Once);
+            }
+
+            internal static void Deserialize(Parcel h, CallbackBase param)
+            {
+                param.Id = h.ReadInt();
+                param.SeqId = h.ReadInt();
+                param.Once = h.ReadBool();
+            }
+        }
+
+        public sealed class NotifyCb : CallbackBase
+        {
+            public NotifyCb(bool once = false) : base((int)DelegateId.NotifyCb, once)
+            {
+            }
+
+            public delegate void Callback(string sender, Bundle msg);
+            public event Callback Received;
+
+            internal override void OnReceivedEvent(Parcel parcel)
+            {
+                string param1 = parcel.ReadString();
+                Bundle param2 = parcel.ReadBundle();
+                Received?.Invoke(param1, param2);
+            }
+
+        }
+
+        private enum DelegateId
+        {
+            NotifyCb = 1,
+        }
+
+        private enum MethodId
+        {
+            Result = 0,
+            Callback = 1,
+            CoRegister = 2,
+            UnRegister = 3,
+            Send = 4,
+        }
+
+        protected override void OnConnectedEvent(string endPoint, string portName, Port port)
+        {
+            _online = true;
+            Connected?.Invoke(this, null);
+        }
+
+        protected override void OnDisconnectedEvent(string endPoint, string portName)
+        {
+            _online = false;
+            Disconnected?.Invoke(this, null);
+        }
+
+        protected override void OnRejectedEvent(string endPoint, string portName)
+        {
+            Rejected?.Invoke(this, null);
+        }
+
+        private void ProcessReceivedEvent(Parcel parcel)
+        {
+            int id = parcel.ReadInt();
+            int seqId = parcel.ReadInt();
+            bool once = parcel.ReadBool();
+
+            foreach (var i in _delegateList)
+            {
+                if (i.Id == id && i.SeqId == seqId)
+                {
+                    i.OnReceivedEvent(parcel);
+                    if (i.Once)
+                        _delegateList.Remove(i);
+                    break;
+                }
+            }
+        }
+
+        protected override void OnReceivedEvent(string endPoint, string portName)
+        {
+            Parcel parcelReceived;
+
+            parcelReceived = new Parcel(CallbackPort);
+
+            using (parcelReceived)
+            {
+                int cmd = parcelReceived.ReadInt();
+                if (cmd != (int)MethodId.Callback)
+                {
+                    return;
+                }
+
+                ProcessReceivedEvent(parcelReceived);
+            }
+        }
+
+        private void ConsumeCommand(out Parcel parcel, Port port)
+        {
+            do
+            {
+                var p = new Parcel(port);
+
+                int cmd = p.ReadInt();
+                if (cmd == (int)MethodId.Result)
+                {
+                    parcel = p;
+                    return;
+                }
+
+                p.Dispose();
+                parcel = null;
+            } while (true);
+        }
+
+        public Message(string appId) => _appId = appId;
+
+        public void Connect()
+        {
+            Connect(_appId, "message");
+        }
+
+        void DisposeCallback(string tag)
+        {
+            foreach (var i in _delegateList)
+            {
+                if (i.Tag.Equals(tag))
+                {
+                    _delegateList.Remove(i);
+                    return;
+                }
+            }
+        }
+
+        public int CoRegister(string name, NotifyCb cb)
+        {
+            if (!_online)
+                throw new NotConnectedSocketException();
+
+            using (Parcel p = new Parcel())
+            {
+                p.WriteInt((int)MethodId.CoRegister);
+                p.WriteString(name);
+                CallbackBase.Serialize(p, cb);
+
+                Parcel parcelReceived;
+                lock (_lock)
+                {
+                    _delegateList.Add(cb);
+
+                    // Send
+                    p.Send(Port);
+
+                    // Receive
+                    ConsumeCommand(out parcelReceived, Port);
+                }
+                if (parcelReceived == null)
+                {
+                    throw new InvalidProtocolException();
+                }
+
+                int ret = parcelReceived.ReadInt();
+                parcelReceived.Dispose();
+                return ret;
+            }
+        }
+
+        public void UnRegister()
+        {
+            if (!_online)
+                throw new NotConnectedSocketException();
+
+            using (Parcel p = new Parcel())
+            {
+                p.WriteInt((int)MethodId.UnRegister);
+
+                lock (_lock)
+                {
+                    // Send
+                    p.Send(Port);
+
+                }
+            }
+        }
+
+        public int Send(Bundle msg)
+        {
+            if (!_online)
+                throw new NotConnectedSocketException();
+
+            using (Parcel p = new Parcel())
+            {
+                p.WriteInt((int)MethodId.Send);
+                p.WriteBundle(msg);
+
+                Parcel parcelReceived;
+                lock (_lock)
+                {
+                    // Send
+                    p.Send(Port);
+
+                    // Receive
+                    ConsumeCommand(out parcelReceived, Port);
+                }
+                if (parcelReceived == null)
+                {
+                    throw new InvalidProtocolException();
+                }
+
+                int ret = parcelReceived.ReadInt();
+                parcelReceived.Dispose();
+                return ret;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Nlp/Tizen.Nlp/PosTagResult.cs b/src/Tizen.Nlp/Tizen.Nlp/PosTagResult.cs
new file mode 100644 (file)
index 0000000..cf1618c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+using System.Collections.Generic;
+
+namespace Tizen.Nlp
+{
+    /// <summary>
+    /// This class contains result of position tagged .
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    public class PosTagResult
+    {
+        /// <summary>
+        /// The tokens of sentence.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public IList<string> Tokens { get; set; }
+
+        /// <summary>
+        /// The tags of sentence.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public IList<string> Tags { get; set; }
+    }
+}
diff --git a/src/Tizen.Nlp/Tizen.Nlp/WordTokenizeResult.cs b/src/Tizen.Nlp/Tizen.Nlp/WordTokenizeResult.cs
new file mode 100644 (file)
index 0000000..199a547
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2018 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.
+*/
+
+using System.Collections.Generic;
+
+namespace Tizen.Nlp
+{
+    /// <summary>
+    /// This class contains result of word tokenized.
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    public class WordTokenizeResult
+    {
+        /// <summary>
+        /// The tokens of sentence.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public IList<string> Tokens { get; set; }
+    }
+}