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