[Applications.ComponentBased] Modify and Add classes for IPC feature (#2675)
authorhjhun <36876573+hjhun@users.noreply.github.com>
Wed, 24 Mar 2021 04:13:26 +0000 (13:13 +0900)
committerGitHub <noreply@github.com>
Wed, 24 Mar 2021 04:13:26 +0000 (13:13 +0900)
* Change directory name

The directory name is changed to 'ComponentPort'.

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Remove unncessary interop parcel methods

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix descriptions

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix typo

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix example code

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Rename directory to Port

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix ComponentPort implementation

Changes:
 - Removes abstract keyword from ComponentPort class
 - Changes OnRequestEvent() method to use virtual keyword instead of abstract keyword
 - Adds RequestEventArgs for OnRequestEvent()
 - Adds ComponentTask class for WaitForEvent() call
 - Changes the name of SendSync() to SendAndReceive().
 - Adds SendAndReceiveAsync() method
 - Adds WaitForPort() method

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Add EventHandler

- Uses EventHandler instead of virtual method

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix WaitForPort implementation

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix descriptions and implemenation

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix wrong implemenations and descriptions

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix descipriton of ComponentTask

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix WaitForPortCore()

- Uses Task.FromResult()

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
* Fix wrong description about permission denied error

Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/Tizen.Applications.ComponentBased.Port/Interop/Interop.ComponentPort.cs
src/Tizen.Applications.ComponentBased.Port/Interop/Interop.Parcel.cs
src/Tizen.Applications.ComponentBased.Port/Tizen.Applications.ComponentBased.Port/ComponentPort.cs
src/Tizen.Applications.ComponentBased.Port/Tizen.Applications.ComponentBased.Port/ComponentTask.cs [new file with mode: 0755]
src/Tizen.Applications.ComponentBased.Port/Tizen.Applications.ComponentBased.Port/RequestEventArgs.cs [new file with mode: 0755]

index 8dc3b3d..123b6aa 100755 (executable)
@@ -25,11 +25,20 @@ internal static partial class Interop
     {
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         internal delegate void ComponentPortRequestCallback(string sender, IntPtr request, IntPtr userData);
-        // typedef void (*component_port_request_cb)(const char *sender, parcel_h request, IntPtr user_data);
+        // typedef void (*component_port_request_cb)(const char *sender, parcel_h request, void *user_data);
 
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         internal delegate void ComponentPortSyncRequestCallback(string sender, IntPtr request, IntPtr response, IntPtr userData);
-        // typedef void (*component_port_request_cb)(const char *sender, parcel_h request, parcel_h response IntPtr user_data);
+        // typedef void (*component_port_request_cb)(const char *sender, parcel_h request, parcel_h response, void *user_data);
+
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void ComponentPortAppearedCallback(string endpoint, int owner, IntPtr userData);
+        // typedef void (*component_port_appeared_cb)(const char *endpoint, int owner, owner user_data);
+
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void ComponentPortVanishedCallback(string endpoint, IntPtr userData);
+        // typedef void (*component_port_vanished_cb)(const char *endpoint, void *user_data);
+
 
         internal enum ErrorCode
         {
@@ -75,5 +84,17 @@ internal static partial class Interop
         [DllImport(Libraries.ComponentPort, EntryPoint = "component_port_send_sync")]
         internal static extern ErrorCode SendSync(IntPtr handle, string endpoint, Int32 timeout, SafeParcelHandle request, out SafeParcelHandle response);
         // int component_port_send(component_port_h port, const char *endpoint, int timeout, parcel_h request, parcel_h *response);
+
+        [DllImport(Libraries.ComponentPort, EntryPoint = "component_port_is_running")]
+        internal static extern ErrorCode IsRunning(string endpoint, out bool isRunning);
+        // int component_port_is_running(const char *endpoint, bool *is_running);
+
+        [DllImport(Libraries.ComponentPort, EntryPoint = "component_port_watch")]
+        internal static extern ErrorCode Watch(string endpoint, ComponentPortAppearedCallback appearedCallback, ComponentPortVanishedCallback vanishedCallback, IntPtr userData, out uint watcherId);
+        // int component_port_watch(const char *endpoint, component_port_appeared_cb appeared_cb, component_port_vanished_cb vanished_cb, void *user_data, unsigned int *watcher_id);
+
+        [DllImport(Libraries.ComponentPort, EntryPoint = "component_port_unwatch")]
+        internal static extern ErrorCode Unwatch(uint watcherId);
+        // int component_port_unwatch(unsigned int watcher_id);
     }
 }
\ No newline at end of file
index a45bbd9..8eab548 100755 (executable)
@@ -40,114 +40,6 @@ internal static partial class Interop
         internal static extern ErrorCode DangerousDestroy(IntPtr handle);
         // int parcel_destroy(parcel_h parcel);
 
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_clone")]
-        internal static extern ErrorCode DangerousClone(IntPtr handle, out SafeParcelHandle clone);
-        // int parcel_clone(parcel_h parcel, parcel_h *clone);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_burst_write")]
-        internal static extern ErrorCode BurstWrite(SafeParcelHandle handle, byte[] buf, UInt32 size);
-        // int parcel_burst_write(parcel_h parcel, cont void *buf, uint32_t size);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_burst_read")]
-        internal static extern ErrorCode BurstRead(SafeParcelHandle handle, [In, Out] byte[] buf, UInt32 size);
-        // int parcel_burst_read(parcel_h parcel, void *buf, uint32_t size);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_bool")]
-        internal static extern ErrorCode WriteBool(SafeParcelHandle handle, bool val);
-        // int parcel_write_bool(parcel_h parcel, bool val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_byte")]
-        internal static extern ErrorCode WriteByte(SafeParcelHandle handle, byte val);
-        // int parcel_write_byte(parcel_h parcel, char val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_uint16")]
-        internal static extern ErrorCode WriteUInt16(SafeParcelHandle handle, UInt16 val);
-        // int parcel_write_uint16(parcel_h parcel, uint16_t val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_uint32")]
-        internal static extern ErrorCode WriteUInt32(SafeParcelHandle handle, UInt32 val);
-        // int parcel_write_uint32(parcel_h parcel, uint32_t val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_uint64")]
-        internal static extern ErrorCode WriteUInt64(SafeParcelHandle handle, UInt64 val);
-        // int parcel_write_uint64(parcel_h parcel, uint64_t val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_int16")]
-        internal static extern ErrorCode WriteInt16(SafeParcelHandle handle, Int16 val);
-        // int parcel_write_int16(parcel_h parcel, int16_t val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_int32")]
-        internal static extern ErrorCode WriteInt32(SafeParcelHandle handle, Int32 val);
-        // int parcel_write_int32(parcel_h parcel, int32_t val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_int64")]
-        internal static extern ErrorCode WriteInt64(SafeParcelHandle handle, Int64 val);
-        // int parcel_write_int64(parcel_h parcel, int64_t val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_float")]
-        internal static extern ErrorCode WriteFloat(SafeParcelHandle handle, float val);
-        // int parcel_write_float(parcel_h parcel, float val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_double")]
-        internal static extern ErrorCode WriteDouble(SafeParcelHandle handle, double val);
-        // int parcel_write_double(parcel_h parcel, double val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_string")]
-        internal static extern ErrorCode WriteString(SafeParcelHandle handle, string str);
-        // int parcel_write_string(parcel_h parcel, const char *str);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_write_bundle")]
-        internal static extern ErrorCode WriteBundle(SafeParcelHandle handle, IntPtr b);
-        // int parcel_write_bundle(parcel_h parcel, bundle *b);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_bool")]
-        internal static extern ErrorCode ReadBool(SafeParcelHandle handle, out bool val);
-        // int parcel_read_bool(parcel_h parcel, bool *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_byte")]
-        internal static extern ErrorCode ReadByte(SafeParcelHandle handle, out byte val);
-        // int parcel_read_byte(parcel_h parcel, char *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_uint16")]
-        internal static extern ErrorCode ReadUInt16(SafeParcelHandle handle, out UInt16 val);
-        // int parcel_read_uint16(parcel_h parcel, uint16_t *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_uint32")]
-        internal static extern ErrorCode ReadUInt32(SafeParcelHandle handle, out UInt32 val);
-        // int parcel_read_uint32(parcel_h parcel, uint32_t *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_uint64")]
-        internal static extern ErrorCode ReadUInt64(SafeParcelHandle handle, out UInt64 val);
-        // int parcel_read_uint64(parcel_h parcel, uint64_t *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_int16")]
-        internal static extern ErrorCode ReadInt16(SafeParcelHandle handle, out Int16 val);
-        // int parcel_read_int16(parcel_h parcel, int16_t *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_int32")]
-        internal static extern ErrorCode ReadInt32(SafeParcelHandle handle, out Int32 val);
-        // int parcel_read_int32(parcel_h parcel, int32_t *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_int64")]
-        internal static extern ErrorCode ReadInt64(SafeParcelHandle handle, out Int64 val);
-        // int parcel_read_int64(parcel_h parcel, int64_t *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_float")]
-        internal static extern ErrorCode ReadFloat(SafeParcelHandle handle, out float val);
-        // int parcel_read_float(parcel_h parcel, float *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_double")]
-        internal static extern ErrorCode ReadDouble(SafeParcelHandle handle, out double val);
-        // int parcel_read_double(parcel_h parcel, double *val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_string")]
-        internal static extern ErrorCode ReadString(SafeParcelHandle handle, out string val);
-        // int parcel_read_string(parcel_h parcel, char **val);
-
-        [DllImport(Libraries.Parcel, EntryPoint = "parcel_read_bundle")]
-        internal static extern ErrorCode ReadBundle(SafeParcelHandle handle, out IntPtr b);
-        // int parcel_read_bundle(parcel_h parcel, bundle **b);
-
         [DllImport(Libraries.Parcel, EntryPoint = "parcel_get_raw")]
         internal static extern ErrorCode GetRaw(SafeParcelHandle handle, out IntPtr raw, out UInt32 size);
         // int parcel_get_raw(parcel_h parcel, void **raw, uint32_t *size);
index 33779c5..a58a8eb 100755 (executable)
  */
 
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization.Formatters;
 using System.Runtime.Serialization.Formatters.Binary;
 using System.Security;
-using System.Xml.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace Tizen.Applications.ComponentBased
 {
     /// <summary>
-    /// Abstract class for creating a component port class.
+    /// The component port API provides functions to send and receive requests between components of component-based-application.
     /// </summary>
     /// <since_tizen> 9 </since_tizen>
-    public abstract class ComponentPort : IDisposable
+    public class ComponentPort : IDisposable
     {
         private static string LogTag = "ComponentPort";
-        private readonly string _portName;
         private IntPtr _port = IntPtr.Zero;
         private Interop.ComponentPort.ComponentPortRequestCallback _requestEventCallback;
         private Interop.ComponentPort.ComponentPortSyncRequestCallback _syncRequestEventCallback;
+        private static Dictionary<int, uint> _watcherIdMap = new Dictionary<int, uint>();
+        private static Dictionary<int, Interop.ComponentPort.ComponentPortAppearedCallback> _appearedNativeCallbackMap = new Dictionary<int, Interop.ComponentPort.ComponentPortAppearedCallback>();
+        private static Dictionary<int, Interop.ComponentPort.ComponentPortVanishedCallback> _vanishedNativeCallbackMap = new Dictionary<int, Interop.ComponentPort.ComponentPortVanishedCallback>();
+        private static int _requestId = 0;
 
         /// <summary>
         /// Constructor for this class.
@@ -51,7 +56,7 @@ namespace Tizen.Applications.ComponentBased
             if (ret != Interop.ComponentPort.ErrorCode.None)
                 throw ComponentPortErrorFactory.GetException(ret, "ComponentPort(" + portName + ").");
 
-            _portName = portName;
+            PortName = portName;
             _requestEventCallback = new Interop.ComponentPort.ComponentPortRequestCallback(OnRequestEvent);
             _syncRequestEventCallback = new Interop.ComponentPort.ComponentPortSyncRequestCallback(OnSyncRequestEvent);
             Interop.ComponentPort.SetRequestCb(_port, _requestEventCallback, IntPtr.Zero);
@@ -64,10 +69,8 @@ namespace Tizen.Applications.ComponentBased
         /// <since_tizen> 9 </since_tizen>
         public string PortName
         {
-            get
-            {
-                return _portName;
-            }
+            get;
+            private set;
         }
 
         /// <summary>
@@ -86,9 +89,83 @@ namespace Tizen.Applications.ComponentBased
             Interop.ComponentPort.AddPrivilege(_port, privilege);
         }
 
+        private static Task<bool> WaitForPortCore(string endpoint)
+        {
+            Interop.ComponentPort.IsRunning(endpoint, out bool isRunning);
+            if (isRunning)
+            {
+                return Task.FromResult(true);
+            }
+
+            var task = new TaskCompletionSource<bool>();
+            int requestId;
+            lock (_appearedNativeCallbackMap)
+            {
+                requestId = _requestId++;
+                _appearedNativeCallbackMap[requestId] = (string portName, int owner, IntPtr userData) =>
+                {
+                    int id = (int)userData;
+                    Log.Info(LogTag, portName + " is appeared");
+                    task.SetResult(true);
+                    lock (_watcherIdMap)
+                    {
+                        Interop.ComponentPort.Unwatch(_watcherIdMap[id]);
+                        _watcherIdMap.Remove(id);
+                    }
+
+                    lock (_vanishedNativeCallbackMap)
+                    {
+                        _vanishedNativeCallbackMap.Remove(id);
+                    }
+
+                    lock (_appearedNativeCallbackMap)
+                    {
+                        _appearedNativeCallbackMap.Remove(id);
+                    }
+                };
+            }
+
+            lock (_vanishedNativeCallbackMap)
+            {
+                _vanishedNativeCallbackMap[requestId] = (string portName, IntPtr userData) =>
+                {
+                    Log.Info(LogTag, portName + " is vanished");
+                };
+            }
+
+            lock (_watcherIdMap)
+            {
+                Interop.ComponentPort.Watch(endpoint, _appearedNativeCallbackMap[requestId], _vanishedNativeCallbackMap[requestId], (IntPtr)requestId, out uint watcherId);
+                _watcherIdMap[requestId] = watcherId;
+            }
+
+            return task.Task;
+        }
+
+        /// <summary>
+        /// Waits until the port is ready.
+        /// </summary>
+        /// <param name="endpoint">The name of the port</param>
+        /// <returns>A task.</returns>
+        public static Task WaitForPort(string endpoint)
+        {
+            return WaitForPortCore(endpoint);
+        }
+
         /// <summary>
         /// Waits for events.
         /// </summary>
+        /// <remarks>
+        /// This method runs a main loop until Cancel() is called.
+        /// The code in the next line will not run until Cancel() is called.
+        /// To avoid blocking the main thread, it's recommended to use the ComponentTask class.
+        /// </remarks>
+        /// <example>
+        /// <code>
+        /// ComponentTask task = new ComponentTask(new ComponentPort("Comm"));
+        /// task.Start();
+        /// </code>
+        /// </example>
         /// <since_tizen> 9 </since_tizen>
         public void WaitForEvent()
         {
@@ -109,10 +186,10 @@ namespace Tizen.Applications.ComponentBased
         /// </summary>
         /// <exception cref="ArgumentException">Thrown when the argument is invalid.</exception>
         /// <exception cref="OutOfMemoryException">Thrown when the memory is insufficient.</exception>
-        /// <exception cref="UnauthorizedAccessException">Thrown when because of permission denied.</exception>
+        /// <exception cref="UnauthorizedAccessException">Thrown when permission is denied.</exception>
         /// <exception cref="global::System.IO.IOException">Thrown when because of I/O error.</exception>
         /// <param name="endpoint">The name of the endpoint</param>
-        /// <param name="timeout">The interval of timeout</param>
+        /// <param name="timeout">The timeout in milliseconds, -1 to use the default timeout</param>
         /// <param name="request">The serializable data to send</param>
         /// <since_tizen> 9 </since_tizen>
         public void Send(string endpoint, int timeout, object request)
@@ -139,18 +216,18 @@ namespace Tizen.Applications.ComponentBased
         }
 
         /// <summary>
-        /// Sends the request data synchronously.
+        /// Sends the request data and receives the reply data.
         /// </summary>
         /// <exception cref="ArgumentException">Thrown when the argument is invalid.</exception>
         /// <exception cref="OutOfMemoryException">Thrown when the memory is insufficient.</exception>
-        /// <exception cref="UnauthorizedAccessException">Thrown when because of permission denied.</exception>
+        /// <exception cref="UnauthorizedAccessException">Thrown when permission is denied.</exception>
         /// <exception cref="global::System.IO.IOException">Thrown when because of I/O error.</exception>
         /// <param name="endpoint">The name of the endpoint</param>
-        /// <param name="timeout">The interval of timeout</param>
+        /// <param name="timeout">The timeout in milliseconds, -1 to use the default timeout</param>
         /// <param name="request">The serializable data to send</param>
         /// <returns>The received serializable data</returns>
-        /// /// <since_tizen> 9 </since_tizen>
-        public object SendSync(string endpoint, int timeout, object request)
+        /// <since_tizen> 9 </since_tizen>
+        public object SendAndReceive(string endpoint, int timeout, object request)
         {
             if (request == null)
             {
@@ -165,7 +242,7 @@ namespace Tizen.Applications.ComponentBased
             SafeParcelHandle resSafeHandle = null;
             Interop.ComponentPort.ErrorCode err;
             using (Parcel reqParcel = ToParcel(request))
-            {             
+            {
                 err = Interop.ComponentPort.SendSync(_port, endpoint, timeout, reqParcel.SafeParcelHandle, out resSafeHandle);
             }
             if (err != Interop.ComponentPort.ErrorCode.None)
@@ -177,26 +254,41 @@ namespace Tizen.Applications.ComponentBased
             {
                 object response = FromParcel(resParcel);
                 return response;
-            }            
+            }
         }
 
         /// <summary>
-        /// Abstract method for receiving a request event.
+        /// Sends the request data and receives the reply data asynchronously.
         /// </summary>
-        /// <param name="sender">The name of the sender</param>
-        /// <param name="request">The serializable data</param>
-        /// <since_tizen> 9 </since_tizen>
-        protected abstract void OnRequestEvent(string sender, object request);
+        /// <exception cref="ArgumentException">Thrown when the argument is invalid.</exception>
+        /// <exception cref="OutOfMemoryException">Thrown when the memory is insufficient.</exception>
+        /// <exception cref="UnauthorizedAccessException">Thrown when permission is denied.</exception>
+        /// <exception cref="global::System.IO.IOException">Thrown when because of I/O error.</exception>
+        /// <param name="endpoint">The name of the endpoint</param>
+        /// <param name="timeout">The timeout in milliseconds, -1 to use the default timeout</param>
+        /// <param name="request">The serializable data to send</param>
+        /// <returns>The received serializable data</returns>
+        /// /// <since_tizen> 9 </since_tizen>
+        public async Task<object> SendAndReceiveAsync(string endpoint, int timeout, object request)
+        {
+            try
+            {
+                return Task.Run(() => SendAndReceive(endpoint, timeout, request));
+            }
+            catch
+            {
+                throw;
+            }
+        }
 
         /// <summary>
-        /// Abstract method for receiving a synchronous request event.
+        /// Occurs whenever the request is received.
         /// </summary>
-        /// <param name="sender">The name of the sender</param>
-        /// <param name="request">The serializable data</param>
-        /// <returns>The serializable data</returns>
+        /// <remarks>
+        /// If the reply is requested, RequestEventArgs.Request should be set.
+        /// </remarks>
         /// <since_tizen> 9 </since_tizen>
-        protected abstract object OnSyncRequestEvent(string sender, object request);
-
+        public event EventHandler<RequestEventArgs> RequestReceived;
 
         private void OnRequestEvent(string sender, IntPtr request, IntPtr data)
         {
@@ -204,7 +296,7 @@ namespace Tizen.Applications.ComponentBased
             using (var reqParcel = new Parcel(reqSafeHandle))
             {
                 object req = FromParcel(reqParcel);
-                OnRequestEvent(sender, req);
+                RequestReceived?.Invoke(this, new RequestEventArgs(sender, req, false));
             }
         }
 
@@ -218,8 +310,15 @@ namespace Tizen.Applications.ComponentBased
                 req = FromParcel(reqParcel);
             }
 
-            object result = OnSyncRequestEvent(sender, req);
-            if (!result.GetType().IsSerializable)
+            var args = new RequestEventArgs(sender, req, true);
+            RequestReceived?.Invoke(this, args);
+
+            var result = args.Reply;
+            if (result == null)
+            {
+                Log.Error(LogTag, "result is null");
+            }
+            else if (!result.GetType().IsSerializable)
             {
                 Log.Error(LogTag, "result is not serializable");
             }
diff --git a/src/Tizen.Applications.ComponentBased.Port/Tizen.Applications.ComponentBased.Port/ComponentTask.cs b/src/Tizen.Applications.ComponentBased.Port/Tizen.Applications.ComponentBased.Port/ComponentTask.cs
new file mode 100755 (executable)
index 0000000..2134be1
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2021 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;
+using System.Threading;
+
+namespace Tizen.Applications.ComponentBased
+{
+    /// <summary>
+    /// Provides a task class for the ComponentPort class.
+    /// This is a convenience class to manage ComponentPort communication in a separate thread.
+    /// </summary>
+    /// <since_tizen> 9 </since_tizen>
+    public class ComponentTask
+    {
+        private Thread _thread;
+        private object _threadLock = new object();
+        private static List<ComponentTask> _holder = new List<ComponentTask>();
+
+        /// <summary>
+        /// Initializes the instance of the ComponentTask class.
+        /// </summary>
+        /// <param name="port">The component port object</param>
+        /// <since_tizen> 9 </since_tizen>
+        public ComponentTask(ComponentPort port)
+        {
+            Port = port;
+        }
+
+        private void OnThread()
+        {
+            lock (_holder)
+            {
+                _holder.Add(this);
+            }
+
+            IsRunning = true;
+            Port?.WaitForEvent();
+            IsRunning = false;
+
+            lock (_holder)
+            {
+                _holder.Remove(this);
+            }
+        }
+
+        /// <summary>
+        /// Starts the task.
+        /// <remark>
+        /// This method calls ComponentPort.WaitForEvent() in the thread.
+        /// </remark>
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public void Start()
+        {
+            lock (_threadLock)
+            {
+                if (_thread == null)
+                {
+                    _thread = new Thread(new ThreadStart(OnThread));
+                    _thread.Start();
+                    IsRunning = true;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Stops the task.
+        /// </summary>
+        /// <remarks>
+        /// This method calls ComponentPort.Cancel() before stopping the thread.
+        /// </remarks>
+        /// <since_tizen> 9 </since_tizen>
+        public void Stop()
+        {
+            lock (_threadLock)
+            {
+                if (_thread != null)
+                {
+                    Port?.Cancel();
+                    _thread.Join();
+                    _thread = null;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Checks whether the component task is running.
+        /// </summary>
+        /// <value>If the task is running, true; otherwise, false</value>
+        /// <since_tizen> 9 </since_tizen>
+        public bool IsRunning
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// Gets the component port.
+        /// </summary>
+        /// <value>The instance of the component port</value>
+        /// <since_tizen> 9 </since_tizen>
+        public ComponentPort Port
+        {
+            get;
+            private set;
+        }
+    }
+}
diff --git a/src/Tizen.Applications.ComponentBased.Port/Tizen.Applications.ComponentBased.Port/RequestEventArgs.cs b/src/Tizen.Applications.ComponentBased.Port/Tizen.Applications.ComponentBased.Port/RequestEventArgs.cs
new file mode 100755 (executable)
index 0000000..652c9b1
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021 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;
+
+namespace Tizen.Applications.ComponentBased
+{
+    /// <summary>
+    /// Arguments for the event raised when the request is received.
+    /// </summary>
+    /// <since_tizen> 9 </since_tizen>
+    public class RequestEventArgs : EventArgs
+    {
+        internal RequestEventArgs(string sender, object request, bool isReplyRequested)
+        {
+            Sender = sender;
+            Request = request;
+            IsReplyRequested = isReplyRequested;
+            Reply = null;
+        }
+
+        /// <summary>
+        /// The name of the sender port
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public string Sender
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// The received serialized data.
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public object Request
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// The flag indicating whether the reply is requested or not.
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public bool IsReplyRequested
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// The serialized reply data.
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public object Reply
+        {
+            get;
+            set;
+        }
+    }
+}