Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.IoTConnectivity / Tizen.Network.IoTConnectivity / RemoteResource.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
18 using System;
19 using System.Collections.Generic;
20 using System.Net;
21 using System.Runtime.InteropServices;
22 using System.Threading.Tasks;
23
24 namespace Tizen.Network.IoTConnectivity
25 {
26     /// <summary>
27     /// This class represents a remote resource.
28     /// It provides APIs to manage remote resource.
29     /// </summary>
30     /// <since_tizen> 3 </since_tizen>
31     public class RemoteResource : IDisposable
32     {
33         internal const int TimeOutMax = 3600;
34         internal IntPtr _remoteResourceHandle = IntPtr.Zero;
35
36         private bool _disposed = false;
37         private bool _cacheEnabled = false;
38         private ResourceOptions _options;
39
40         private int _responseCallbackId = 1;
41         private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback> _responseCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback>();
42
43         private Interop.IoTConnectivity.Client.RemoteResource.CachedRepresentationChangedCallback _cacheUpdatedCallback;
44         private Interop.IoTConnectivity.Client.RemoteResource.StateChangedCallback _stateChangedCallback;
45         private Interop.IoTConnectivity.Client.RemoteResource.ObserveCallback _observeCallback;
46
47         private EventHandler<StateChangedEventArgs> _stateChangedEventHandler;
48
49         /// <summary>
50         /// Creates a remote resource instance.
51         /// </summary>
52         /// <since_tizen> 3 </since_tizen>
53         /// <remarks>
54         /// To use this API, you should provide all the details required to correctly contact and
55         /// observe the object.\n
56         /// If not, you should discover the resource object manually.\n
57         /// The @a policy can contain multiple policies like ResourcePolicy.Discoverable | ResourcePolicy.Observable.
58         /// </remarks>
59         /// <param name="hostAddress">The host address of the resource.</param>
60         /// <param name="uriPath">The URI path of the resource.</param>
61         /// <param name="policy">The policies of the resource.</param>
62         /// <param name="resourceTypes">The resource types of the resource.</param>
63         /// <param name="resourceInterfaces">The resource interfaces of the resource.</param>
64         /// <feature>http://tizen.org/feature/iot.ocf</feature>
65         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
66         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
67         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
68         public RemoteResource(string hostAddress, string uriPath, ResourcePolicy policy, ResourceTypes resourceTypes, ResourceInterfaces resourceInterfaces)
69         {
70             if (hostAddress == null || uriPath == null || resourceTypes == null || resourceInterfaces == null)
71             {
72                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Invalid parameters");
73                 throw new ArgumentException("Invalid parameter");
74             }
75
76             HostAddress = hostAddress;
77             UriPath = uriPath;
78             Policy = policy;
79             Types = new List<string>(resourceTypes);
80             Interfaces = new List<string>(resourceInterfaces);
81             DeviceId = null;
82
83             CreateRemoteResource(resourceTypes._resourceTypeHandle, resourceInterfaces.ResourceInterfacesHandle);
84         }
85
86         internal RemoteResource(IntPtr handleToClone)
87         {
88             int ret = Interop.IoTConnectivity.Client.RemoteResource.Clone(handleToClone, out _remoteResourceHandle);
89             if (ret != (int)IoTConnectivityError.None)
90             {
91                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to clone");
92                 throw IoTConnectivityErrorFactory.GetException(ret);
93             }
94             SetRemoteResource();
95         }
96
97         /// <summary>
98         /// Destructor of the RemoteResource class.
99         /// </summary>
100         ~RemoteResource()
101         {
102             Dispose(false);
103         }
104
105         /// <summary>
106         /// The event is invoked with cached resource attributes.
107         /// </summary>
108         /// <since_tizen> 3 </since_tizen>
109         public event EventHandler<CacheUpdatedEventArgs> CacheUpdated;
110
111         /// <summary>
112         /// Observe an event on the resource sent by the server.
113         /// </summary>
114         /// <since_tizen> 3 </since_tizen>
115         public event EventHandler<ObserverNotifiedEventArgs> ObserverNotified;
116
117         /// <summary>
118         /// The event is called when remote resource's state are changed.
119         /// </summary>
120         /// <since_tizen> 3 </since_tizen>
121         public event EventHandler<StateChangedEventArgs> StateChanged
122         {
123             add
124             {
125                 if (_stateChangedEventHandler == null)
126                 {
127                     RegisterStateChangedEvent();
128                 }
129                 _stateChangedEventHandler += value;
130             }
131             remove
132             {
133                 _stateChangedEventHandler -= value;
134                 if (_stateChangedEventHandler == null)
135                 {
136                     UnregisterStateChangedEvent();
137                 }
138             }
139         }
140
141         /// <summary>
142         /// The host address of the resource.
143         /// </summary>
144         /// <since_tizen> 3 </since_tizen>
145         /// <value>The host address of the resource.</value>
146         public string HostAddress { get; private set; }
147
148         /// <summary>
149         /// The URI path of the resource.
150         /// </summary>
151         /// <since_tizen> 3 </since_tizen>
152         /// <value>The URI path of the resource.</value>
153         public string UriPath { get; private set; }
154
155         /// <summary>
156         /// The resource types of the remote resource.
157         /// </summary>
158         /// <since_tizen> 3 </since_tizen>
159         /// <value>The resource types of the remote resource.</value>
160         public IEnumerable<string> Types { get; private set; }
161
162         /// <summary>
163         /// The interfaces of the resource.
164         /// </summary>
165         /// <since_tizen> 3 </since_tizen>
166         /// <value>The interfaces of the resource.</value>
167         public IEnumerable<string> Interfaces { get; private set; }
168
169         /// <summary>
170         /// The policy of the resource.
171         /// </summary>
172         /// <since_tizen> 3 </since_tizen>
173         /// <value>The policy of the resource.</value>
174         public ResourcePolicy Policy { get; private set; }
175
176         /// <summary>
177         /// The header options of the resource.
178         /// </summary>
179         /// <since_tizen> 3 </since_tizen>
180         /// <value>The header options of the resource.</value>
181         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
182         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
183         public ResourceOptions Options
184         {
185             get
186             {
187                 return _options;
188             }
189             set
190             {
191                 _options = value;
192                 if (value != null)
193                 {
194                     int ret = Interop.IoTConnectivity.Client.RemoteResource.SetOptions(_remoteResourceHandle, value._resourceOptionsHandle);
195                     if (ret != (int)IoTConnectivityError.None)
196                     {
197                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set options");
198                         throw IoTConnectivityErrorFactory.GetException(ret);
199                     }
200                 }
201             }
202         }
203
204         /// <summary>
205         /// Indicates the CacheEnabled status of the remote resource.
206         /// </summary>
207         /// <since_tizen> 3 </since_tizen>
208         /// <value>
209         /// Client can start caching only when this is set true. Set it to false to stop caching the resource attributes.
210         /// </value>
211         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
212         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
213         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
214         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
215         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
216         public bool CacheEnabled
217         {
218             get
219             {
220                 return _cacheEnabled;
221             }
222             set
223             {
224                 if (_cacheEnabled != value)
225                 {
226                     _cacheEnabled = value;
227                     HandleCachePolicyChanged();
228                 }
229             }
230         }
231
232         /// <summary>
233         /// Time interval of monitoring and caching API.
234         /// </summary>
235         /// <since_tizen> 3 </since_tizen>
236         /// <value>
237         /// Default time interval is 10 seconds.
238         /// Seconds for time interval (must be in range from 1 to 3600).
239         /// </value>
240         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
241         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
242         public int TimeInterval
243         {
244             get
245             {
246                 int interval;
247                 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetTimeInterval(_remoteResourceHandle, out interval);
248                 if (ret != (int)IoTConnectivityError.None)
249                 {
250                     Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get time interval");
251                     return 0;
252                 }
253                 return interval;
254             }
255             set
256             {
257                 int ret = (int)IoTConnectivityError.InvalidParameter;
258                 if (value <= TimeOutMax && value > 0)
259                 {
260                     ret = Interop.IoTConnectivity.Client.RemoteResource.SetTimeInterval(_remoteResourceHandle, value);
261                 }
262                 if (ret != (int)IoTConnectivityError.None)
263                 {
264                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set time interval");
265                     throw IoTConnectivityErrorFactory.GetException(ret);
266                 }
267             }
268         }
269
270         /// <summary>
271         /// The device ID of the resource.
272         /// </summary>
273         /// <since_tizen> 3 </since_tizen>
274         /// <value>The device ID of the resource.</value>
275         public string DeviceId { get; private set; }
276
277         /// <summary>
278         /// Gets cached representation from the remote resource.
279         /// </summary>
280         /// <since_tizen> 3 </since_tizen>
281         /// <returns>cached representation from the remote resource.</returns>
282         /// <feature>http://tizen.org/feature/iot.ocf</feature>
283         public Representation CachedRepresentation()
284         {
285             IntPtr handle;
286             int ret = Interop.IoTConnectivity.Client.RemoteResource.GetCachedRepresentation(_remoteResourceHandle, out handle);
287             if (ret != (int)IoTConnectivityError.None)
288             {
289                 Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get CachedRepresentation");
290                 return null;
291             }
292
293             Representation representation = new Representation(handle);
294             return representation;
295         }
296
297         /// <summary>
298         /// Starts observing on the resource.
299         /// </summary>
300         /// <since_tizen> 3 </since_tizen>
301         /// <remarks>
302         /// When server sends notification message, <see cref="ObserverNotified"/> will be called.
303         /// </remarks>
304         /// <privilege>
305         /// http://tizen.org/privilege/internet
306         /// </privilege>
307         /// <privlevel>public</privlevel>
308         /// <param name="policy">The type to specify how client wants to observe.</param>
309         /// <param name="query">The query to send to server.</param>
310         /// <feature>http://tizen.org/feature/iot.ocf</feature>
311         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
312         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
313         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
314         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
315         public void StartObserving(ObservePolicy policy, ResourceQuery query = null)
316         {
317             _observeCallback = (IntPtr resource, int err, int sequenceNumber, IntPtr response, IntPtr userData) =>
318             {
319                 int result;
320                 IntPtr representationHandle;
321                 int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
322                 if (ret != (int)IoTConnectivityError.None)
323                 {
324                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
325                     return;
326                 }
327
328                 ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
329                 if (ret != (int)IoTConnectivityError.None)
330                 {
331                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
332                     return;
333                 }
334
335                 Representation repr = null;
336                 try
337                 {
338                     repr = new Representation(representationHandle);
339                 }
340                 catch (Exception exp)
341                 {
342                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new representation: " + exp.Message);
343                     return;
344                 }
345
346                 ObserverNotifiedEventArgs e = new ObserverNotifiedEventArgs()
347                 {
348                     Representation = repr,
349                     Result = (ResponseCode)result
350                 };
351                 ObserverNotified?.Invoke(this, e);
352             };
353
354             IntPtr queryHandle = IntPtr.Zero;
355             if (query != null)
356             {
357                 queryHandle = query._resourceQueryHandle;
358             }
359
360             int errCode = Interop.IoTConnectivity.Client.RemoteResource.RegisterObserve(_remoteResourceHandle, (int)policy, queryHandle, _observeCallback, IntPtr.Zero);
361             if (errCode != (int)IoTConnectivityError.None)
362             {
363                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register observe callbacks");
364                 throw IoTConnectivityErrorFactory.GetException(errCode);
365             }
366         }
367
368         /// <summary>
369         /// Stops observing on the resource.
370         /// </summary>
371         /// <since_tizen> 3 </since_tizen>
372         /// <privilege>
373         /// http://tizen.org/privilege/internet
374         /// </privilege>
375         /// <privlevel>public</privlevel>
376         /// <feature>http://tizen.org/feature/iot.ocf</feature>
377         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
378         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
379         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
380         public void StopObserving()
381         {
382             int ret = Interop.IoTConnectivity.Client.RemoteResource.DeregisterObserve(_remoteResourceHandle);
383             if (ret != (int)IoTConnectivityError.None)
384             {
385                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister observe callbacks");
386                 throw IoTConnectivityErrorFactory.GetException(ret);
387             }
388         }
389
390         /// <summary>
391         /// Gets the attributes of a resource asynchronously.
392         /// </summary>
393         /// <since_tizen> 3 </since_tizen>
394         /// <privilege>
395         /// http://tizen.org/privilege/internet
396         /// </privilege>
397         /// <privlevel>public</privlevel>
398         /// <param name="query">The ResourceQuery to send to server.</param>
399         /// <returns>Remote response with result and representation.</returns>
400         /// <feature>http://tizen.org/feature/iot.ocf</feature>
401         public async Task<RemoteResponse> GetAsync(ResourceQuery query = null)
402         {
403             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
404
405             IntPtr id = IntPtr.Zero;
406             lock (_responseCallbacksMap)
407             {
408                 id = (IntPtr)_responseCallbackId++;
409             }
410             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
411             {
412                 IntPtr responseCallbackId = userData;
413                 lock(_responseCallbacksMap)
414                 {
415                     _responseCallbacksMap.Remove(responseCallbackId);
416                 }
417
418                 if (responseHandle != IntPtr.Zero)
419                 {
420                     try
421                     {
422                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
423                     }
424                     catch(Exception exp)
425                     {
426                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
427                         tcsRemoteResponse.TrySetException(exp);
428                     }
429                 }
430                 else
431                 {
432                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
433                 }
434             };
435
436             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
437             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Get(_remoteResourceHandle, queryHandle, _responseCallbacksMap[id], id);
438             if (errCode != (int)IoTConnectivityError.None)
439             {
440                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource attributes");
441                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
442             }
443             return await tcsRemoteResponse.Task;
444         }
445
446         /// <summary>
447         /// Puts the representation of a resource asynchronously.
448         /// </summary>
449         /// <since_tizen> 3 </since_tizen>
450         /// <privilege>
451         /// http://tizen.org/privilege/internet
452         /// </privilege>
453         /// <privlevel>public</privlevel>
454         /// <param name="representation">Resource representation to put.</param>
455         /// <param name="query">The ResourceQuery to send to server.</param>
456         /// <returns>Remote response with result and representation.</returns>
457         /// <feature>http://tizen.org/feature/iot.ocf</feature>
458         public async Task<RemoteResponse> PutAsync(Representation representation, ResourceQuery query = null)
459         {
460             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
461
462             IntPtr id = IntPtr.Zero;
463             lock (_responseCallbacksMap)
464             {
465                 id = (IntPtr)_responseCallbackId++;
466             }
467             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
468             {
469                 IntPtr responseCallbackId = userData;
470                 lock (_responseCallbacksMap)
471                 {
472                     _responseCallbacksMap.Remove(responseCallbackId);
473                 }
474                 if (err == (int)(IoTConnectivityError.Iotivity))
475                 {
476                     RemoteResponse response = new RemoteResponse();
477                     response.Result = ResponseCode.Forbidden;
478                     response.Representation = null;
479                     tcsRemoteResponse.TrySetResult(response);
480                 }
481                 else if (responseHandle != IntPtr.Zero)
482                 {
483                     try
484                     {
485                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
486                     }
487                     catch (Exception exp)
488                     {
489                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
490                         tcsRemoteResponse.TrySetException(exp);
491                     }
492                 }
493                 else
494                 {
495                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
496                 }
497             };
498             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
499             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
500             if (errCode != (int)IoTConnectivityError.None)
501             {
502                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to put resource representation");
503                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
504             }
505             return await tcsRemoteResponse.Task;
506         }
507
508         /// <summary>
509         /// Posts request on a resource asynchronously.
510         /// </summary>
511         /// <since_tizen> 3 </since_tizen>
512         /// <privilege>
513         /// http://tizen.org/privilege/internet
514         /// </privilege>
515         /// <privlevel>public</privlevel>
516         /// <param name="representation">Resource representation of request.</param>
517         /// <param name="query">The ResourceQuery to send to server.</param>
518         /// <returns>Remote response with result and representation.</returns>
519         /// <feature>http://tizen.org/feature/iot.ocf</feature>
520         public async Task<RemoteResponse> PostAsync(Representation representation, ResourceQuery query = null)
521         {
522             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
523
524             IntPtr id = IntPtr.Zero;
525             lock (_responseCallbacksMap)
526             {
527                 id = (IntPtr)_responseCallbackId++;
528             }
529             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
530             {
531                 IntPtr responseCallbackId = userData;
532                 lock (_responseCallbacksMap)
533                 {
534                     _responseCallbacksMap.Remove(responseCallbackId);
535                 }
536                 if (responseHandle != IntPtr.Zero)
537                 {
538                     try
539                     {
540                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
541                     }
542                     catch (Exception exp)
543                     {
544                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
545                         tcsRemoteResponse.TrySetException(exp);
546                     }
547                 }
548                 else
549                 {
550                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
551                 }
552             };
553             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
554             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
555             if (errCode != (int)IoTConnectivityError.None)
556             {
557                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to post request");
558                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
559             }
560             return await tcsRemoteResponse.Task;
561         }
562
563         /// <summary>
564         /// Deletes the resource asynchronously.
565         /// </summary>
566         /// <since_tizen> 3 </since_tizen>
567         /// <privilege>
568         /// http://tizen.org/privilege/internet
569         /// </privilege>
570         /// <privlevel>public</privlevel>
571         /// <returns>Remote response with result and representation.</returns>
572         /// <feature>http://tizen.org/feature/iot.ocf</feature>
573         public async Task<RemoteResponse> DeleteAsync()
574         {
575             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
576
577             IntPtr id = IntPtr.Zero;
578             lock (_responseCallbacksMap)
579             {
580                 id = (IntPtr)_responseCallbackId++;
581             }
582             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
583             {
584                 IntPtr responseCallbackId = userData;
585                 lock (_responseCallbacksMap)
586                 {
587                     _responseCallbacksMap.Remove(responseCallbackId);
588                 }
589                 if (err == (int)(IoTConnectivityError.Iotivity))
590                 {
591                     RemoteResponse response = new RemoteResponse();
592                     response.Result = ResponseCode.Forbidden;
593                     response.Representation = null;
594                     tcsRemoteResponse.TrySetResult(response);
595                 }
596                 else if (responseHandle != IntPtr.Zero)
597                 {
598                     try
599                     {
600                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
601                     }
602                     catch (Exception exp)
603                     {
604                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
605                         tcsRemoteResponse.TrySetException(exp);
606                     }
607                 }
608                 else
609                 {
610                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
611                 }
612             };
613
614             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Delete(_remoteResourceHandle, _responseCallbacksMap[id], id);
615             if (errCode != (int)IoTConnectivityError.None)
616             {
617                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to delete");
618                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
619             }
620             return await tcsRemoteResponse.Task;
621         }
622
623         /// <summary>
624         /// Releases any unmanaged resources used by this object.
625         /// </summary>
626         /// <since_tizen> 3 </since_tizen>
627         /// <feature>http://tizen.org/feature/iot.ocf</feature>
628         public void Dispose()
629         {
630             Dispose(true);
631             GC.SuppressFinalize(this);
632         }
633
634         internal static Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType GetConnectivityType(string hostAddress)
635         {
636             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None;
637
638             Log.Info(IoTConnectivityErrorFactory.LogTag, hostAddress);
639
640             if (hostAddress == IoTConnectivityClientManager.MulticastAddress)
641             {
642                 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
643             }
644             else
645             {
646                 IPAddress address;
647                 string hostName = hostAddress;
648                 if (hostAddress.Contains(":"))
649                 {
650                     string[] hostParts = hostAddress.Split(':');
651                     if (hostParts.Length == 2)
652                     {
653                         hostName = hostParts[0];
654                     }
655                 }
656                 if (hostAddress.Contains("%"))
657                 {
658                     string[] hostParts = hostAddress.Split('%');
659                     if (hostParts.Length == 2)
660                     {
661                         hostName = hostParts[0];
662                     }
663                 }
664                 if (hostName.Contains("["))
665                 {
666                     string[] hostParts = hostName.Split('[');
667                     if (hostParts.Length == 2)
668                     {
669                         hostName = hostParts[1];
670                     }
671                 }
672                 Log.Info(IoTConnectivityErrorFactory.LogTag, hostName);
673                 if (IPAddress.TryParse(hostName, out address))
674                 {
675                     switch (address.AddressFamily)
676                     {
677                         case System.Net.Sockets.AddressFamily.InterNetwork:
678                             type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
679                             break;
680                         case System.Net.Sockets.AddressFamily.InterNetworkV6:
681                             type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv6;
682                             break;
683                         default:
684                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse for Ipv4 or Ipv6");
685                             break;
686                     }
687                 }
688                 else
689                 {
690                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse hostname " + hostName);
691                 }
692             }
693             return type;
694         }
695
696         /// <summary>
697         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
698         /// </summary>
699         /// <since_tizen> 3 </since_tizen>
700         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
701         /// <feature>http://tizen.org/feature/iot.ocf</feature>
702         protected virtual void Dispose(bool disposing)
703         {
704             if (_disposed)
705                 return;
706
707             if (disposing)
708             {
709                 // Free managed objects
710             }
711
712             Interop.IoTConnectivity.Client.RemoteResource.Destroy(_remoteResourceHandle);
713             _disposed = true;
714         }
715
716         private void HandleCachePolicyChanged()
717         {
718             if (_cacheEnabled)
719             {
720                 _cacheUpdatedCallback = (IntPtr resource, IntPtr representation, IntPtr userData) =>
721                 {
722                     if (CacheEnabled)
723                     {
724                         Representation repr = null;
725                         try
726                         {
727                             repr = new Representation(representation);
728                         }
729                         catch (Exception exp)
730                         {
731                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new Representation: " + exp.Message);
732                             return;
733                         }
734
735                         CacheUpdatedEventArgs e = new CacheUpdatedEventArgs()
736                         {
737                             Representation = repr
738                         };
739                         CacheUpdated?.Invoke(this, e);
740                     }
741                 };
742
743                 int ret = Interop.IoTConnectivity.Client.RemoteResource.StartCaching(_remoteResourceHandle, _cacheUpdatedCallback, IntPtr.Zero);
744                 if (ret != (int)IoTConnectivityError.None)
745                 {
746                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add cache updated event handler");
747                     throw IoTConnectivityErrorFactory.GetException(ret);
748                 }
749             }
750             else
751             {
752                 int ret = Interop.IoTConnectivity.Client.RemoteResource.StopCaching(_remoteResourceHandle);
753                 if (ret != (int)IoTConnectivityError.None)
754                 {
755                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove cache updated event handler");
756                     throw IoTConnectivityErrorFactory.GetException(ret);
757                 }
758             }
759         }
760
761         private void RegisterStateChangedEvent()
762         {
763             _stateChangedCallback = (IntPtr resource, int state, IntPtr userData) =>
764             {
765                 StateChangedEventArgs e = new StateChangedEventArgs()
766                 {
767                     State = (ResourceState)state
768                 };
769                 _stateChangedEventHandler?.Invoke(null, e);
770             };
771
772             int ret = Interop.IoTConnectivity.Client.RemoteResource.StartMonitoring(_remoteResourceHandle, _stateChangedCallback, IntPtr.Zero);
773             if (ret != (int)IoTConnectivityError.None)
774             {
775                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add state changed event handler");
776                 throw IoTConnectivityErrorFactory.GetException(ret);
777             }
778         }
779
780         private void UnregisterStateChangedEvent()
781         {
782             int ret = Interop.IoTConnectivity.Client.RemoteResource.StopMonitoring(_remoteResourceHandle);
783             if (ret != (int)IoTConnectivityError.None)
784             {
785                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove state changed event handler");
786                 throw IoTConnectivityErrorFactory.GetException(ret);
787             }
788         }
789
790         private void CreateRemoteResource(IntPtr resourceTypeHandle, IntPtr resourceInterfaceHandle)
791         {
792             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = GetConnectivityType(HostAddress);
793             if (connectivityType == Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None)
794             {
795                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Unable to parse host address");
796                 throw new ArgumentException("Unable to parse host address");
797             }
798             int ret = Interop.IoTConnectivity.Client.RemoteResource.Create(HostAddress, (int)connectivityType, UriPath, (int)Policy, resourceTypeHandle, resourceInterfaceHandle, out _remoteResourceHandle);
799             if (ret != (int)IoTConnectivityError.None)
800             {
801                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get remote resource");
802                 throw IoTConnectivityErrorFactory.GetException(ret);
803             }
804         }
805
806         private void SetRemoteResource()
807         {
808             IntPtr hostAddressPtr, uriPathPtr;
809             int ret = Interop.IoTConnectivity.Client.RemoteResource.GetHostAddress(_remoteResourceHandle, out hostAddressPtr);
810             if (ret != (int)IoTConnectivityError.None)
811             {
812                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get host address");
813                 throw IoTConnectivityErrorFactory.GetException(ret);
814             }
815
816             ret = Interop.IoTConnectivity.Client.RemoteResource.GetUriPath(_remoteResourceHandle, out uriPathPtr);
817             if (ret != (int)IoTConnectivityError.None)
818             {
819                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
820                 throw IoTConnectivityErrorFactory.GetException(ret);
821             }
822
823             int policy = (int)ResourcePolicy.NoProperty;
824             ret = Interop.IoTConnectivity.Client.RemoteResource.GetPolicies(_remoteResourceHandle, out policy);
825             if (ret != (int)IoTConnectivityError.None)
826             {
827                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
828                 throw IoTConnectivityErrorFactory.GetException(ret);
829             }
830
831             IntPtr typesHandle, interfacesHandle;
832             ret = Interop.IoTConnectivity.Client.RemoteResource.GetTypes(_remoteResourceHandle, out typesHandle);
833             if (ret != (int)IoTConnectivityError.None)
834             {
835                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource types");
836                 throw IoTConnectivityErrorFactory.GetException(ret);
837             }
838
839             ret = Interop.IoTConnectivity.Client.RemoteResource.GetInterfaces(_remoteResourceHandle, out interfacesHandle);
840             if (ret != (int)IoTConnectivityError.None)
841             {
842                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource interfaces");
843                 throw IoTConnectivityErrorFactory.GetException(ret);
844             }
845
846             IntPtr deviceIdPtr;
847             ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceId(_remoteResourceHandle, out deviceIdPtr);
848             if (ret != (int)IoTConnectivityError.None)
849             {
850                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
851                 throw IoTConnectivityErrorFactory.GetException(ret);
852             }
853             DeviceId = (deviceIdPtr != IntPtr.Zero) ? Marshal.PtrToStringAnsi(deviceIdPtr) : string.Empty;
854             HostAddress = (hostAddressPtr != IntPtr.Zero) ? Marshal.PtrToStringAnsi(hostAddressPtr) : string.Empty;
855             UriPath = (uriPathPtr != IntPtr.Zero) ? Marshal.PtrToStringAnsi(uriPathPtr) : string.Empty;
856             Types = new ResourceTypes(typesHandle);
857             Interfaces = new ResourceInterfaces(interfacesHandle);
858             Policy = (ResourcePolicy)policy;
859         }
860
861         private RemoteResponse GetRemoteResponse(IntPtr response)
862         {
863             int result;
864             IntPtr representationHandle, optionsHandle;
865             int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
866             if (ret != (int)IoTConnectivityError.None)
867             {
868                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
869                 throw IoTConnectivityErrorFactory.GetException(ret);
870             }
871
872             ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
873             if (ret != (int)IoTConnectivityError.None)
874             {
875                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
876                 throw IoTConnectivityErrorFactory.GetException(ret);
877             }
878
879             ret = Interop.IoTConnectivity.Server.Response.GetOptions(response, out optionsHandle);
880             if (ret != (int)IoTConnectivityError.None)
881             {
882                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get options");
883                 throw IoTConnectivityErrorFactory.GetException(ret);
884             }
885             return new RemoteResponse()
886             {
887                 Result = (ResponseCode)result,
888                 Representation = new Representation(representationHandle),
889                 Options = (optionsHandle == IntPtr.Zero)? null : new ResourceOptions(optionsHandle)
890             };
891         }
892     }
893 }