Fix code for building with corefx
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.IoTConnectivity / Tizen.Network.IoTConnectivity / Resource.cs
1 /// Copyright 2016 by Samsung Electronics, Inc.,
2 ///
3 /// This software is the confidential and proprietary information
4 /// of Samsung Electronics, Inc. ("Confidential Information"). You
5 /// shall not disclose such Confidential Information and shall use
6 /// it only in accordance with the terms of the license agreement
7 /// you entered into with Samsung.
8
9 using System;
10 using System.Collections.Generic;
11 using System.Collections.ObjectModel;
12 using System.Runtime.InteropServices;
13
14 namespace Tizen.Network.IoTConnectivity
15 {
16     /// <summary>
17     /// Abstract class respresenting a resource.
18     /// All resources need to inherit from this class.
19     /// </summary>
20     public abstract class Resource : IDisposable
21     {
22         private IntPtr _resourceHandle = IntPtr.Zero;
23         private bool _disposed = false;
24         private ObservableCollection<Resource> _children = new ObservableCollection<Resource>();
25         private IntPtr _observerHandle = IntPtr.Zero;
26
27         /// <summary>
28         /// The constructor
29         /// </summary>
30         /// <remarks>
31         /// @a uri format would be relative URI path like '/a/light'
32         /// and its length must be less than 128.
33         /// </remarks>
34         /// <privilege>
35         /// http://tizen.org/privilege/internet
36         /// </privilege>
37         /// <param name="uri">The URI path of the resource</param>
38         /// <param name="types">Resource types</param>
39         /// <param name="interfaces">Resource interfaces</param>
40         /// <param name="policy">The policies of the resoruce</param>
41         /// <pre>
42         /// IoTConnectivityServerManager.Initialize() should be called to initialize
43         /// </pre>
44         /// <seealso cref="ResourceTypes"/>
45         /// <seealso cref="ResourceInterfaces"/>
46         /// <seealso cref="ResourcePolicy"/>
47         /// <code>
48         /// // Create a class which inherits from Resource
49         /// public class DoorResource : Resource
50         /// {
51         ///     public DoorResource(string uri, ResourceTypes types, ResourceInterfaces interfaces, ResourcePolicy policy)
52         ///             : base(uri, types, interfaces, policy) {
53         ///     }
54         ///     protected override Response OnDelete(Request request) {
55         ///         // Do something
56         ///     }
57         ///     protected override Response OnGet(Request request) {
58         ///         // Do something
59         ///     }
60         ///     // Override other abstract methods of Resource class
61         /// }
62         ///
63         /// // Use it like below
64         /// ResourceInterfaces ifaces = new ResourceInterfaces(new List<string>(){ ResourceInterfaces.DefaultInterface });
65         /// ResourceTypes types = new ResourceTypes(new List<string>(){ "oic.iot.door.new" });
66         /// Resource resource = new DoorResource("/door/uri1", types, ifaces, ResourcePolicy.Discoverable | ResourcePolicy.Observable);
67         /// </code>
68         protected Resource(string uri, ResourceTypes types, ResourceInterfaces interfaces, ResourcePolicy policy)
69         {
70             UriPath = uri;
71             Types = types;
72             Interfaces = interfaces;
73             Policy = policy;
74
75             _children.CollectionChanged += ChildrenCollectionChanged;
76
77             int ret = Interop.IoTConnectivity.Server.Observers.Create(out _observerHandle);
78             if (ret != (int)IoTConnectivityError.None)
79             {
80                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to create obsever handle");
81                 throw IoTConnectivityErrorFactory.GetException(ret);
82             }
83         }
84
85         /// <summary>
86         /// Destructor of the Resource class.
87         /// </summary>
88         ~Resource()
89         {
90             Dispose(false);
91         }
92
93         /// <summary>
94         /// Type details of the resource
95         /// </summary>
96         public ResourceTypes Types { get; internal set; }
97
98         /// <summary>
99         /// Interface details of the resource
100         /// </summary>
101         public ResourceInterfaces Interfaces { get; internal set; }
102
103         /// <summary>
104         /// The policies of the resource
105         /// </summary>
106         public ResourcePolicy Policy { get; internal set; }
107
108         /// <summary>
109         /// URI path of the resource
110         /// </summary>
111         public string UriPath { get; internal set; }
112
113         /// <summary>
114         /// List of Child resources
115         /// </summary>
116         public ICollection<Resource> Children
117         {
118             get
119             {
120                 return _children;
121             }
122         }
123
124         internal IntPtr ResourceHandle
125         {
126             get
127             {
128                 return _resourceHandle;
129             }
130             set
131             {
132                 _resourceHandle = value;
133             }
134         }
135
136         /// <summary>
137         /// Notify the specified representation and qos.
138         /// </summary>
139         /// <privilege>
140         /// http://tizen.org/privilege/internet
141         /// </privilege>
142         /// <param name="representation">Representation.</param>
143         /// <param name="qos">The quality of service for message transfer.</param>
144         /// <pre>
145         /// IoTConnectivityServerManager.Initialize() should be called to initialize
146         /// </pre>
147         /// <seealso cref="Representation"/>
148         /// <seealso cref="QualityOfService"/>
149         /// <code>
150         /// ResourceInterfaces ifaces = new ResourceInterfaces(new List<string>(){ ResourceInterfaces.DefaultInterface });
151         /// ResourceTypes types = new ResourceTypes(new List<string>(){ "oic.iot.door.new.notify" });
152         /// Resource resource = new DoorResource("/door/uri/new/notify", types, ifaces, ResourcePolicy.Discoverable | ResourcePolicy.Observable);
153         /// IoTConnectivityServerManager.RegisterResource(resource);
154         ///
155         /// Representation repr = new Representation();
156         /// repr.UriPath = "/door/uri/new/notify";
157         /// repr.Type = new ResourceTypes(new List<string>(){ "oic.iot.door.new.notify" });
158         /// repr.Attributes = new Attributes() {
159         ///      _attribute, 1 }
160         /// };
161         /// resource.Notify(repr, QualityOfService.High);
162         /// </code>
163         public void Notify(Representation representation, QualityOfService qos)
164         {
165             int ret = (int)IoTConnectivityError.None;
166             ret = Interop.IoTConnectivity.Server.Resource.Notify(_resourceHandle, representation._representationHandle, _observerHandle, (int)qos);
167             if (ret != (int)IoTConnectivityError.None)
168             {
169                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to send notification");
170                 throw IoTConnectivityErrorFactory.GetException(ret);
171             }
172         }
173
174         /// <summary>
175         /// This is Called when the client performs get operation on this resource.
176         /// </summary>
177         /// <param name="request">A request from client</param>
178         /// <returns>A response having the representation and the result</returns>
179         protected abstract Response OnGet(Request request);
180
181         /// <summary>
182         /// This is Called when the client performs put operation on this resource.
183         /// </summary>
184         /// <param name="request">A request from client</param>
185         /// <returns>A response</returns>
186         protected abstract Response OnPut(Request request);
187
188         /// <summary>
189         /// This is Called when the client performs post operation on this resource.
190         /// </summary>
191         /// <param name="request">A request from client</param>
192         /// <returns>A response having the representation and the result</returns>
193         protected abstract Response OnPost(Request request);
194
195         /// <summary>
196         /// This is Called when the client performs delete operation on this resource.
197         /// </summary>
198         /// <param name="request">A request from client</param>
199         /// <returns>A response</returns>
200         protected abstract Response OnDelete(Request request);
201
202         /// <summary>
203         /// Called on the observing event.
204         /// </summary>
205         /// <param name="request">A request from client</param>
206         /// <param name="type">Observer type</param>
207         /// <param name="observeId">Observe identifier.</param>
208         /// <returns>Returns true if it wants to be observed, else false.</returns>
209         protected abstract bool OnObserving(Request request, ObserveType type, int observeId);
210
211         /// <summary>
212         /// Releases any unmanaged resources used by this object.
213         /// </summary>
214         public void Dispose()
215         {
216             Dispose(true);
217             GC.SuppressFinalize(this);
218         }
219
220         /// <summary>
221         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
222         /// </summary>
223         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
224         protected virtual void Dispose(bool disposing)
225         {
226             if (_disposed)
227                 return;
228
229             if (disposing)
230             {
231                 Types?.Dispose();
232                 Interfaces?.Dispose();
233             }
234
235             if (_resourceHandle != IntPtr.Zero)
236                 Interop.IoTConnectivity.Server.Resource.Destroy(_resourceHandle);
237             if (_observerHandle != IntPtr.Zero)
238                 Interop.IoTConnectivity.Server.Observers.Destroy(_observerHandle);
239             _disposed = true;
240         }
241
242         // This method is used as callback for Resource
243         internal void OnRequest(IntPtr resourceHandle, IntPtr requestHandle, IntPtr userData)
244         {
245             Request request = GetRequest(requestHandle);
246             Response response = null;
247
248             if (request == null)
249             {
250                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get Request");
251                 return;
252             }
253
254             try
255             {
256                 int observeType;
257                 int ret = Interop.IoTConnectivity.Server.Request.GetObserveType(requestHandle, out observeType);
258                 if (ret != (int)IoTConnectivityError.None)
259                 {
260                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get observe type");
261                     return;
262                 }
263                 if ((ObserveType)observeType != ObserveType.NoType)
264                 {
265                     int observeId;
266                     ret = Interop.IoTConnectivity.Server.Request.GetObserveId(requestHandle, out observeId);
267                     if (ret != (int)IoTConnectivityError.None)
268                     {
269                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get observe id");
270                         return;
271                     }
272                     switch ((ObserveType)observeType)
273                     {
274                         case ObserveType.Register:
275                         {
276                             if (OnObserving(request, ObserveType.Register, observeId))
277                             {
278                                 ret = Interop.IoTConnectivity.Server.Observers.Add(_observerHandle, observeId);
279                                 if (ret != (int)IoTConnectivityError.None)
280                                 {
281                                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add observer id");
282                                     return;
283                                 }
284                                 break;
285                             }
286                             else
287                             {
288                                 // If OnObserving for ObserveType.Register returns false, do not operate for Get operation after Observe operation.
289                                 return;
290                             }
291                         }
292                         case ObserveType.Deregister:
293                         {
294                             if (OnObserving(request, ObserveType.Deregister, observeId))
295                             {
296                                 ret = Interop.IoTConnectivity.Server.Observers.Remove(_observerHandle, observeId);
297                                 if (ret != (int)IoTConnectivityError.None)
298                                 {
299                                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove observer id");
300                                     return;
301                                 }
302                                 break;
303                             }
304                             else
305                             {
306                                 // If OnObserving for ObserveType.Deregister returns false, do not operate for Get operation after Observe operation.
307                                 return;
308                             }
309                         }
310                     }
311                 }
312                 int requestType;
313                 ret = Interop.IoTConnectivity.Server.Request.GetRequestType(requestHandle, out requestType);
314                 if (ret != (int)IoTConnectivityError.None)
315                 {
316                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get request type");
317                     return;
318                 }
319                 switch ((Interop.IoTConnectivity.Server.RequestType)requestType)
320                 {
321                     case Interop.IoTConnectivity.Server.RequestType.Put:
322                     {
323                         response = OnPut(request);
324                         break;
325                     }
326                     case Interop.IoTConnectivity.Server.RequestType.Get:
327                     {
328                         response = OnGet(request);
329                         break;
330                     }
331                     case Interop.IoTConnectivity.Server.RequestType.Post:
332                     {
333                         response = OnPost(request);
334                         break;
335                     }
336                     case Interop.IoTConnectivity.Server.RequestType.Delete:
337                     {
338                         response = OnDelete(request);
339                         break;
340                     }
341                     default:
342                     break;
343                 }
344                 if (response == null)
345                 {
346                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to send Response");
347                     return;
348                 }
349
350                 if (!response.Send(requestHandle))
351                 {
352                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to send Response");
353                     return;
354                 }
355             }
356             finally
357             {
358                 request?.Dispose();
359                 response?.Dispose();
360             }
361         }
362
363         private Request GetRequest(IntPtr requestHandle)
364         {
365             IntPtr hostAddressPtr;
366             int ret = Interop.IoTConnectivity.Server.Request.GetHostAddress(requestHandle, out hostAddressPtr);
367             if (ret != (int)IoTConnectivityError.None)
368             {
369                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get host address");
370                 return null;
371             }
372
373             IntPtr optionsHandle = IntPtr.Zero;
374             ret = Interop.IoTConnectivity.Server.Request.GetOptions(requestHandle, out optionsHandle);
375             if (ret != (int)IoTConnectivityError.None)
376             {
377                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get options");
378                 return null;
379             }
380
381             IntPtr queryHandle = IntPtr.Zero;
382             ret = Interop.IoTConnectivity.Server.Request.GetQuery(requestHandle, out queryHandle);
383             if (ret != (int)IoTConnectivityError.None)
384             {
385                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get Query");
386                 return null;
387             }
388
389             IntPtr representationHandle = IntPtr.Zero;
390             ret = Interop.IoTConnectivity.Server.Request.GetRepresentation(requestHandle, out representationHandle);
391             if (ret != (int)IoTConnectivityError.None)
392             {
393                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get representation");
394                 return null;
395             }
396
397             ResourceOptions opts = null;
398             ResourceQuery query = null;
399             Representation representation = null;
400             try
401             {
402                 opts = (optionsHandle == IntPtr.Zero) ? null : new ResourceOptions(optionsHandle);
403             }
404             catch (Exception exp)
405             {
406                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new ResourceOptions: " + exp.Message);
407                 return null;
408             }
409
410             try
411             {
412                 query = (queryHandle == IntPtr.Zero) ? null : new ResourceQuery(queryHandle);
413             }
414             catch (Exception exp)
415             {
416                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new ResourceQuery: " + exp.Message);
417                 return null;
418             }
419
420             try
421             {
422                 representation = (representationHandle == IntPtr.Zero) ? null : new Representation(representationHandle); ;
423             }
424             catch (Exception exp)
425             {
426                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new Representation: " + exp.Message);
427                 return null;
428             }
429
430             return new Request()
431             {
432                 HostAddress = Marshal.PtrToStringAnsi(hostAddressPtr),
433                 Options = opts,
434                 Query = query,
435                 Representation = representation
436             };
437         }
438
439         private void ChildrenCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs eventArgs)
440         {
441             if (eventArgs.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
442             {
443                 foreach (Resource r in eventArgs.NewItems)
444                 {
445                     int ret = Interop.IoTConnectivity.Server.Resource.BindChildResource(_resourceHandle, r._resourceHandle);
446                     if (ret != (int)IoTConnectivityError.None)
447                     {
448                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to bind resource ");
449                         throw IoTConnectivityErrorFactory.GetException(ret);
450                     }
451                 }
452             }
453             else if (eventArgs.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
454             {
455                 foreach (Resource r in eventArgs.NewItems)
456                 {
457                     int ret = Interop.IoTConnectivity.Server.Resource.UnbindChildResource(_resourceHandle, r._resourceHandle);
458                     if (ret != (int)IoTConnectivityError.None)
459                     {
460                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to unbind resource");
461                         throw IoTConnectivityErrorFactory.GetException(ret);
462                     }
463                 }
464             }
465         }
466     }
467 }