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