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