Clean up Tizen.Applications.Messages
[platform/core/csapi/tizenfx.git] / Tizen.Applications / Tizen.Applications.Messages / MessagePort.cs
1 using System;
2 using System.Collections.Generic;
3
4 namespace Tizen.Applications.Messages
5 {
6     /// <summary>
7     /// The Message Port API provides functions to send and receive messages between applications.
8     /// </summary>
9     /// <remarks>
10     /// 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.
11     /// If a remote application sends a message, the registered callback function of the local port is called.
12     /// The trusted message-port API allows communications between applications that are signed by the same developer(author) certificate.
13     /// </remarks>
14     public class MessagePort : IDisposable
15     {
16         private static readonly object s_lock = new object();
17         private static readonly HashSet<string> s_portMap = new HashSet<string>();
18
19         // The name of the local message port
20         private readonly string _portName = null;
21
22         // If true the message port is a trusted port, otherwise false it is not
23         private readonly bool _trusted = false;
24
25         // The local message port ID
26         private int _portId = 0;
27
28         // If true the message port is listening, otherwise false it is not
29         private bool _listening = false;
30
31         private Interop.MessagePort.message_port_message_cb _messageCallBack;
32
33         /// <summary>
34         /// Initializes the instance of the MessagePort class.
35         /// </summary>
36         /// <param name="portName">The name of the local message port</param>
37         /// <param name="trusted">If true is the trusted message port of application, otherwise false</param>
38         public MessagePort(string portName, bool trusted)
39         {
40             if (String.IsNullOrEmpty(portName))
41             {
42                 MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidParameter, "Invalid PortName", "PortName");
43             }
44             _portName = portName;
45             _trusted = trusted;
46         }
47
48         /// <summary>
49         /// Destructor of the MessagePort class.
50         /// </summary>
51         ~MessagePort()
52         {
53             Dispose(false);
54         }
55
56         /// <summary>
57         /// Called when a message is received.
58         /// </summary>
59         public event EventHandler<MessageReceivedEventArgs> MessageReceived;
60
61         /// <summary>
62         /// The name of the local message port
63         /// </summary>
64         public string PortName
65         {
66             get
67             {
68                 return _portName;
69             }
70         }
71         /// <summary>
72         /// If true the message port is a trusted port, otherwise false it is not
73         /// </summary>
74         public bool Trusted
75         {
76             get
77             {
78                 return _trusted;
79             }
80         }
81
82         /// <summary>
83         /// If true the message port is listening, otherwise false it is not
84         /// </summary>
85         public bool Listening
86         {
87             get
88             {
89                 return _listening;
90             }
91         }
92
93         /// <summary>
94         /// Register the local message port.
95         /// </summary>
96         public void Listen()
97         {
98             lock (s_lock)
99             {
100                 if (s_portMap.Contains(_portName))
101                 {
102                     throw new InvalidOperationException(_portName + " is already used");
103                 }
104                 _messageCallBack = (int localPortId, string remoteAppId, string remotePortName, bool trusted, IntPtr message, IntPtr userData) =>
105                 {
106                     MessageReceivedEventArgs args = new MessageReceivedEventArgs()
107                     {
108                         Message = Bundle.MakeRetainedBundle(message)
109                     };
110
111                     if (!String.IsNullOrEmpty(remotePortName) && !String.IsNullOrEmpty(remoteAppId))
112                     {
113                         args.Remote = new RemoteValues()
114                         {
115                             AppId = remoteAppId,
116                             PortName = remotePortName,
117                             Trusted = trusted
118                         };
119                     }
120                     MessageReceived?.Invoke(this, args);
121                 };
122
123                 _portId = _trusted ?
124                             Interop.MessagePort.RegisterTrustedPort(_portName, _messageCallBack, IntPtr.Zero) :
125                             Interop.MessagePort.RegisterPort(_portName, _messageCallBack, IntPtr.Zero);
126
127                 if (_portId <= 0)
128                     throw new InvalidOperationException("Can't Listening with " + _portName);
129
130                 s_portMap.Add(_portName);
131                 _listening = true;
132             }
133         }
134
135         /// <summary>
136         /// Unregisters the local message port.
137         /// </summary>
138         public void StopListening()
139         {
140             if (!_listening)
141             {
142                 throw new InvalidOperationException("Already stopped");
143             }
144
145             int ret = _trusted ?
146                         Interop.MessagePort.UnregisterTrustedPort(_portId) :
147                         Interop.MessagePort.UnregisterPort(_portId);
148
149             if (ret != (int)MessagePortError.None)
150             {
151                 MessagePortErrorFactory.ThrowException(ret);
152             }
153
154             lock (s_lock)
155             {
156                 s_portMap.Remove(_portName);
157             }
158             _portId = 0;
159             _listening = false;
160         }
161
162         /// <summary>
163         /// Sends a untrusted message to the message port of a remote application.
164         /// </summary>
165         /// <param name="message">The message to be passed to the remote application, the recommended message size is under 4KB</param>
166         /// <param name="remoteAppId">The ID of the remote application</param>
167         /// <param name="remotePortName">The name of the remote message port</param>
168         public void Send(Bundle message, string remoteAppId, string remotePortName)
169         {
170             Send(message, remoteAppId, remotePortName, false);
171         }
172
173         /// <summary>
174         /// Sends a message to the message port of a remote application.
175         /// </summary>
176         /// <param name="message">The message to be passed to the remote application, the recommended message size is under 4KB</param>
177         /// <param name="remoteAppId">The ID of the remote application</param>
178         /// <param name="remotePortName">The name of the remote message port</param>
179         /// <param name="trusted">If true the trusted message port of remote application otherwise false</param>
180         public void Send(Bundle message, string remoteAppId, string remotePortName, bool trusted)
181         {
182             if (!_listening)
183             {
184                 throw new InvalidOperationException("Should start listen before send");
185             }
186             if (message == null)
187             {
188                 throw new ArgumentNullException("message");
189             }
190             int ret = trusted ?
191                         Interop.MessagePort.SendTrustedMessageWithLocalPort(remoteAppId, remotePortName, message.Handle, _portId) :
192                         Interop.MessagePort.SendMessageWithLocalPort(remoteAppId, remotePortName, message.Handle, _portId);
193
194             if (ret != (int)MessagePortError.None)
195             {
196                 if (ret == (int)MessagePortError.MaxExceeded)
197                 {
198                     MessagePortErrorFactory.ThrowException(ret, "Message has exceeded the maximum limit(4KB)", "Message");
199                 }
200                 MessagePortErrorFactory.ThrowException(ret, "Can't send message");
201             }
202         }
203
204         /// <summary>
205         /// Releases the unmanaged resourced used by the MessagePort class specifying whether to perform a normal dispose operation.
206         /// </summary>
207         /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
208         protected virtual void Dispose(bool disposing)
209         {
210             if (_listening)
211             {
212                 try
213                 {
214                     StopListening();
215                 }
216                 catch (Exception e)
217                 {
218                     Log.Warn(GetType().Namespace, "Exception in Dispose :" + e.Message);
219                 }
220             }
221         }
222
223         /// <summary>
224         /// Releases all resources used by the MessagePort class.
225         /// </summary>
226         public void Dispose()
227         {
228             Dispose(true);
229             GC.SuppressFinalize(this);
230         }
231     }
232 }