Add <example> for API reference
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.MessagePort / Tizen.Applications.Messages / MessagePort.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using Tizen.Applications;
20
21 namespace Tizen.Applications.Messages
22 {
23     /// <summary>
24     /// The message port API provides functions to send and receive messages between applications.
25     /// </summary>
26     /// <remarks>
27     /// The message port API provides functions for passing messages between applications. An application should register its own local port to receive messages from remote applications.
28     /// If a remote application sends a message, the registered callback function of the local port is called.
29     /// The trusted message-port API allows communications between applications that are signed by the same developer(author) certificate.
30     /// </remarks>
31     public class MessagePort : IDisposable
32     {
33         private static readonly object s_lock = new object();
34         private static readonly HashSet<string> s_portMap = new HashSet<string>();
35
36         // The name of the local message port
37         private readonly string _portName = null;
38
39         // If true the message port is a trusted port, otherwise false it is not
40         private readonly bool _trusted = false;
41
42         // The local message port ID
43         private int _portId = 0;
44
45         // If true the message port is listening, otherwise false it is not
46         private bool _listening = false;
47
48         private Interop.MessagePort.message_port_message_cb _messageCallBack;
49
50         /// <summary>
51         /// Initializes the instance of the MessagePort class.
52         /// </summary>
53         /// <param name="portName">The name of the local message port.</param>
54         /// <param name="trusted">If true, it is the trusted message port of application, otherwise false.</param>
55         /// <exception cref="System.ArgumentException">Thrown when portName is null or empty.</exception>
56         /// <example>
57         /// <code>
58         /// MessagePort messagePort = new MessagePort("SenderPort", true);
59         /// </code>
60         /// </example>
61         public MessagePort(string portName, bool trusted)
62         {
63             if (String.IsNullOrEmpty(portName))
64             {
65                 MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidParameter, "Invalid PortName", "PortName");
66             }
67             _portName = portName;
68             _trusted = trusted;
69         }
70
71         /// <summary>
72         /// Destructor of the MessagePort class.
73         /// </summary>
74         ~MessagePort()
75         {
76             Dispose(false);
77         }
78
79         /// <summary>
80         /// Called when a message is received.
81         /// </summary>
82         /// <example>
83         /// <code>
84         /// MessagePort messagePort = new MessagePort("SenderPort", true);
85         /// messagePort.MessageReceived += MessageReceivedCallback;
86         /// static void MessageReceivedCallback(object sender, MessageReceivedEventArgs e)
87         /// {
88         ///     Console.WriteLine("Message Received ");
89         ///     if (e.Remote.AppId != null) {
90         ///         Console.WriteLine("from :"+e.Remote.AppId);
91         ///     }
92         /// }
93         /// </code>
94         /// </example>
95         public event EventHandler<MessageReceivedEventArgs> MessageReceived;
96
97         /// <summary>
98         /// The name of the local message port.
99         /// </summary>
100         public string PortName
101         {
102             get
103             {
104                 return _portName;
105             }
106         }
107         /// <summary>
108         /// If true, the message port is a trusted port, otherwise false.
109         /// </summary>
110         public bool Trusted
111         {
112             get
113             {
114                 return _trusted;
115             }
116         }
117
118         /// <summary>
119         /// If true, the message port is listening, otherwise false.
120         /// </summary>
121         public bool Listening
122         {
123             get
124             {
125                 return _listening;
126             }
127         }
128
129         /// <summary>
130         /// Register the local message port.
131         /// </summary>
132         /// <exception cref="System.InvalidOperationException">Thrown when portName is already used, when there is an I/O error.</exception>
133         /// <exception cref="System.ArgumentException">Thrown when there is an invalid parameter.</exception>
134         /// <exception cref="System.OutOfMemoryException">Thrown when out of memory.</exception>
135         /// <example>
136         /// <code>
137         /// MessagePort messagePort = new MessagePort("SenderPort", true);
138         /// messagePort.MessageReceived += MessageReceivedCallback;
139         /// messagePort.Listen();
140         /// </code>
141         /// </example>
142         public void Listen()
143         {
144             lock (s_lock)
145             {
146                 if (s_portMap.Contains(_portName))
147                 {
148                     MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidOperation, _portName + "is already used");
149                 }
150                 _messageCallBack = (int localPortId, string remoteAppId, string remotePortName, bool trusted, IntPtr message, IntPtr userData) =>
151                 {
152                     MessageReceivedEventArgs args = new MessageReceivedEventArgs()
153                     {
154                         Message = new Bundle(new SafeBundleHandle(message, false))
155                     };
156
157                     if (!String.IsNullOrEmpty(remotePortName) && !String.IsNullOrEmpty(remoteAppId))
158                     {
159                         args.Remote = new RemoteValues()
160                         {
161                             AppId = remoteAppId,
162                             PortName = remotePortName,
163                             Trusted = trusted
164                         };
165                     }
166                     MessageReceived?.Invoke(this, args);
167                 };
168
169                 _portId = _trusted ?
170                             Interop.MessagePort.RegisterTrustedPort(_portName, _messageCallBack, IntPtr.Zero) :
171                             Interop.MessagePort.RegisterPort(_portName, _messageCallBack, IntPtr.Zero);
172
173                 if (_portId <= 0)
174                     MessagePortErrorFactory.ThrowException(_portId, "RegisterPort", _portName);
175
176                 s_portMap.Add(_portName);
177                 _listening = true;
178             }
179         }
180
181         /// <summary>
182         /// Unregisters the local message port.
183         /// </summary>
184         /// <exception cref="System.InvalidOperationException">Thrown when messageport is already stopped, when there is an I/O error, when the port is not found.</exception>
185         /// <exception cref="System.ArgumentException">Thrown when there is an invalid parameter.</exception>
186         /// <exception cref="System.OutOfMemoryException">Thrown when out of memory.</exception>
187         /// <example>
188         /// <code>
189         /// MessagePort messagePort = new MessagePort("SenderPort", true);
190         /// messagePort.MessageReceived += MessageReceivedCallback;
191         /// messagePort.Listen();
192         /// using (var message = new Tizen.Application.Bundle())
193         /// {
194         ///     message.AddItem("message", "a_string");
195         ///     messagePort.Send(message, "ReceiverAppID", "ReceiverPort");
196         /// }
197         /// messagePort.StopListening();
198         /// </code>
199         /// </example>
200         public void StopListening()
201         {
202             if (!_listening)
203             {
204                 MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidOperation, "Already stopped");
205             }
206
207             int ret = _trusted ?
208                         Interop.MessagePort.UnregisterTrustedPort(_portId) :
209                         Interop.MessagePort.UnregisterPort(_portId);
210
211             if (ret != (int)MessagePortError.None)
212             {
213                 MessagePortErrorFactory.ThrowException(ret, "Error Unregister port");
214             }
215
216             lock (s_lock)
217             {
218                 s_portMap.Remove(_portName);
219             }
220             _portId = 0;
221             _listening = false;
222         }
223
224         /// <summary>
225         /// Sends an untrusted message to the message port of a remote application.
226         /// </summary>
227         /// <param name="message">The message to be passed to the remote application, the recommended message size is under 4KB.</param>
228         /// <param name="remoteAppId">The ID of the remote application.</param>
229         /// <param name="remotePortName">The name of the remote message port.</param>
230         /// <exception cref="System.InvalidOperationException">Thrown when there is an I/O error, when the port is not found.</exception>
231         /// <exception cref="System.ArgumentException">Thrown when there is an invalid parameter.</exception>
232         /// <exception cref="System.OutOfMemoryException">Thrown when out of memory.</exception>
233         /// <exception cref="System.ArgumentOutOfRangeException">Thrown when message has exceeded the maximum limit(4KB).</exception>
234         /// <example>
235         /// <code>
236         /// MessagePort messagePort = new MessagePort("SenderPort", true);
237         /// messagePort.MessageReceived += MessageReceivedCallback;
238         /// messagePort.Listen();
239         /// using (var message = new Tizen.Application.Bundle())
240         /// {
241         ///     message.AddItem("message", "a_string");
242         ///     messagePort.Send(message, "ReceiverAppID", "ReceiverPort");
243         /// }
244         /// </code>
245         /// </example>
246         public void Send(Bundle message, string remoteAppId, string remotePortName)
247         {
248             Send(message, remoteAppId, remotePortName, false);
249         }
250
251         /// <summary>
252         /// Sends a message to the message port of a remote application.
253         /// </summary>
254         /// <param name="message">The message to be passed to the remote application, the recommended message size is under 4KB.</param>
255         /// <param name="remoteAppId">The ID of the remote application.</param>
256         /// <param name="remotePortName">The name of the remote message port.</param>
257         /// <param name="trusted">If true, it is the trusted message port of remote application, otherwise false.</param>
258         /// <exception cref="System.InvalidOperationException">Thrown when there is an I/O error, when the port is not found.</exception>
259         /// <exception cref="System.ArgumentException">Thrown when there is an invalid parameter.</exception>
260         /// <exception cref="System.OutOfMemoryException">Thrown when out of memory.</exception>
261         /// <exception cref="System.ArgumentOutOfRangeException">Thrown when message has exceeded the maximum limit(4KB).</exception>
262         /// <exception cref="System.UnauthorizedAccessException">Thrown when the remote application is not signed with the same certificate.</exception>
263         /// <example>
264         /// <code>
265         /// MessagePort messagePort = new MessagePort("SenderPort", true);
266         /// messagePort.MessageReceived += MessageReceivedCallback;
267         /// messagePort.Listen();
268         /// using (var message = new Tizen.Application.Bundle())
269         /// {
270         ///     message.AddItem("message", "a_string");
271         ///     messagePort.Send(message, "ReceiverAppID", "ReceiverPort", true);
272         /// }
273         /// </code>
274         /// </example>
275         public void Send(Bundle message, string remoteAppId, string remotePortName, bool trusted)
276         {
277             if (!_listening)
278             {
279                 MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidOperation, "Should start listen before send");
280             }
281             if (message == null || message.SafeBundleHandle == null || message.SafeBundleHandle.IsInvalid)
282             {
283                 MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidParameter, "message is null", "Message");
284             }
285             int ret = trusted ?
286                         Interop.MessagePort.SendTrustedMessageWithLocalPort(remoteAppId, remotePortName, message.SafeBundleHandle, _portId) :
287                         Interop.MessagePort.SendMessageWithLocalPort(remoteAppId, remotePortName, message.SafeBundleHandle, _portId);
288
289             if (ret != (int)MessagePortError.None)
290             {
291                 if (ret == (int)MessagePortError.MaxExceeded)
292                 {
293                     MessagePortErrorFactory.ThrowException(ret, "Message has exceeded the maximum limit(4KB)", "Message");
294                 }
295                 MessagePortErrorFactory.ThrowException(ret, "Can't send message");
296             }
297         }
298
299         /// <summary>
300         /// Releases the unmanaged resources used by the MessagePort class specifying whether to perform a normal dispose operation.
301         /// </summary>
302         /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
303         protected virtual void Dispose(bool disposing)
304         {
305             if (_listening)
306             {
307                 try
308                 {
309                     StopListening();
310                 }
311                 catch (Exception e)
312                 {
313                     Log.Warn(GetType().Namespace, "Exception in Dispose :" + e.Message);
314                 }
315             }
316         }
317
318         /// <summary>
319         /// Releases all resources used by the MessagePort class.
320         /// </summary>
321         public void Dispose()
322         {
323             Dispose(true);
324             GC.SuppressFinalize(this);
325         }
326     }
327 }