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