Update according to design review
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.IoTConnectivity / Tizen.Network.IoTConnectivity / RemoteResource.cs
index fcfc6f0..2672517 100755 (executable)
@@ -1,20 +1,31 @@
-/// Copyright 2016 by Samsung Electronics, Inc.,
-///
-/// This software is the confidential and proprietary information
-/// of Samsung Electronics, Inc. ("Confidential Information"). You
-/// shall not disclose such Confidential Information and shall use
-/// it only in accordance with the terms of the license agreement
-/// you entered into with Samsung.
+ /*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 
 using System;
 using System.Collections.Generic;
 using System.Net;
+using System.Runtime.InteropServices;
 using System.Threading.Tasks;
 
 namespace Tizen.Network.IoTConnectivity
 {
     /// <summary>
-    /// RemoteResource class
+    /// This class represents a remote resource.
+    /// It provides APIs to manage remote resource.
     /// </summary>
     public class RemoteResource : IDisposable
     {
@@ -35,8 +46,22 @@ namespace Tizen.Network.IoTConnectivity
         private EventHandler<StateChangedEventArgs> _stateChangedEventHandler;
 
         /// <summary>
-        /// Constructor
+        /// Creates a remote resource instance
         /// </summary>
+        /// <remarks>
+        /// To use this API, you should provide all of the details required to correctly contact and
+        /// observe the object.\n
+        /// If not, you should discover the resource object manually.\n
+        /// The @a policy can contain multiple policies like ResourcePolicy.Discoverable | ResourcePolicy.Observable.
+        /// </remarks>
+        /// <param name="hostAddress">The host address of the resource</param>
+        /// <param name="uriPath">The URI path of the resource</param>
+        /// <param name="policy">The policies of the resource</param>
+        /// <param name="resourceTypes">The resource types of the resource</param>
+        /// <param name="resourceInterfaces">The resource interfaces of the resource</param>
+        /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
+        /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
+        /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
         public RemoteResource(string hostAddress, string uriPath, ResourcePolicy policy, ResourceTypes resourceTypes, ResourceInterfaces resourceInterfaces)
         {
             if (hostAddress == null || uriPath == null || resourceTypes == null || resourceInterfaces == null)
@@ -66,18 +91,21 @@ namespace Tizen.Network.IoTConnectivity
             SetRemoteResource();
         }
 
+        /// <summary>
+        /// Destructor of the RemoteResource class.
+        /// </summary>
         ~RemoteResource()
         {
             Dispose(false);
         }
 
         /// <summary>
-        /// Event that is called to cache resource attribute's
+        /// Event that is invoked with cached resource attributes
         /// </summary>
         public event EventHandler<CacheUpdatedEventArgs> CacheUpdated;
 
         /// <summary>
-        /// Observe event on the resource
+        /// Observe event on the resource sent by the server
         /// </summary>
         public event EventHandler<ObserverNotifiedEventArgs> ObserverNotified;
 
@@ -130,8 +158,15 @@ namespace Tizen.Network.IoTConnectivity
         public ResourcePolicy Policy { get; private set; }
 
         /// <summary>
+        /// The device name of the remote resource
+        /// </summary>
+        public string DeviceName { get; private set; }
+
+        /// <summary>
         /// The header options of the resource
         /// </summary>
+        /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
+        /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
         public ResourceOptions Options
         {
             get
@@ -154,8 +189,16 @@ namespace Tizen.Network.IoTConnectivity
         }
 
         /// <summary>
-        /// Cache enabled property
+        /// Indicates the CacheEnabled status of the remote resource.
         /// </summary>
+        /// <remarks>
+        /// Client can start caching only when this is set true. Set it to false to stop caching the resource attributes.
+        /// </remarks>
+        /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
+        /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
+        /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
+        /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
+        /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
         public bool CacheEnabled
         {
             get
@@ -175,6 +218,12 @@ namespace Tizen.Network.IoTConnectivity
         /// <summary>
         /// Time interval of monitoring and caching API
         /// </summary>
+        /// <remarks>
+        /// Default time interval is 10 seconds.\n
+        /// Seconds for time interval (must be in range from 1 to 3600)
+        /// </remarks>
+        /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
+        /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
         public int TimeInterval
         {
             get
@@ -191,7 +240,7 @@ namespace Tizen.Network.IoTConnectivity
             set
             {
                 int ret = (int)IoTConnectivityError.InvalidParameter;
-                if (value < TimeOutMax && value > 0)
+                if (value <= TimeOutMax && value > 0)
                 {
                     ret = Interop.IoTConnectivity.Client.RemoteResource.SetTimeInterval(_remoteResourceHandle, value);
                 }
@@ -209,7 +258,7 @@ namespace Tizen.Network.IoTConnectivity
         public string DeviceId { get; private set; }
 
         /// <summary>
-        /// Gets cached representation of the remote resource
+        /// Gets cached representation from the remote resource
         /// </summary>
         public Representation CachedRepresentation()
         {
@@ -226,10 +275,21 @@ namespace Tizen.Network.IoTConnectivity
         }
 
         /// <summary>
-        /// Registers the observe callback on the resource
+        /// Starts observing on the resource
         /// </summary>
+        /// <remarks>
+        /// When server sends notification message, <see cref="ObserverNotified"/> will be called.
+        /// </remarks>
+        /// <privilege>
+        /// http://tizen.org/privilege/internet
+        /// </privilege>
         /// <param name="policy">The type to specify how client wants to observe</param>
-        /// <param name="query">The ResourceQuery to send to server</param>
+        /// <param name="query">The query to send to server</param>
+        /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
+        /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
+        /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
+        /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
+        /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
         public void StartObserving(ObservePolicy policy, ResourceQuery query = null)
         {
             _observeCallback = (IntPtr resource, int err, int sequenceNumber, IntPtr response, IntPtr userData) =>
@@ -266,7 +326,7 @@ namespace Tizen.Network.IoTConnectivity
                     Representation = repr,
                     Result = (ResponseCode)result
                 };
-                ObserverNotified?.Invoke(null, e);
+                ObserverNotified?.Invoke(this, e);
             };
 
             IntPtr queryHandle = IntPtr.Zero;
@@ -284,8 +344,15 @@ namespace Tizen.Network.IoTConnectivity
         }
 
         /// <summary>
-        /// Deregisters the observe callback on the resource
+        /// Stops observing on the resource
         /// </summary>
+        /// <privilege>
+        /// http://tizen.org/privilege/internet
+        /// </privilege>
+        /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
+        /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
+        /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
+        /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
         public void StopObserving()
         {
             int ret = Interop.IoTConnectivity.Client.RemoteResource.DeregisterObserve(_remoteResourceHandle);
@@ -297,10 +364,13 @@ namespace Tizen.Network.IoTConnectivity
         }
 
         /// <summary>
-        /// Gets the attributes of a resource
+        /// Gets the attributes of a resource, asynchronously
         /// </summary>
+        /// <privilege>
+        /// http://tizen.org/privilege/internet
+        /// </privilege>
         /// <param name="query">The ResourceQuery to send to server</param>
-        /// <returns></returns>
+        /// <returns>Remote response with result and representation</returns>
         public async Task<RemoteResponse> GetAsync(ResourceQuery query = null)
         {
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
@@ -349,9 +419,12 @@ namespace Tizen.Network.IoTConnectivity
         /// <summary>
         /// Puts the representation of a resource, asynchronously.
         /// </summary>
-        /// <param name="representation">Resource representation</param>
+        /// <privilege>
+        /// http://tizen.org/privilege/internet
+        /// </privilege>
+        /// <param name="representation">Resource representation to put</param>
         /// <param name="query">The ResourceQuery to send to server</param>
-        /// <returns></returns>
+        /// <returns>Remote response with result and representation</returns>
         public async Task<RemoteResponse> PutAsync(Representation representation, ResourceQuery query = null)
         {
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
@@ -368,8 +441,14 @@ namespace Tizen.Network.IoTConnectivity
                 {
                     _responseCallbacksMap.Remove(responseCallbackId);
                 }
-
-                if (responseHandle != IntPtr.Zero)
+                if (err == (int)(IoTConnectivityError.Iotivity))
+                {
+                    RemoteResponse response = new RemoteResponse();
+                    response.Result = ResponseCode.Forbidden;
+                    response.Representation = null;
+                    tcsRemoteResponse.TrySetResult(response);
+                }
+                else if (responseHandle != IntPtr.Zero)
                 {
                     try
                     {
@@ -386,7 +465,6 @@ namespace Tizen.Network.IoTConnectivity
                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
                 }
             };
-
             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
             if (errCode != (int)IoTConnectivityError.None)
@@ -398,11 +476,14 @@ namespace Tizen.Network.IoTConnectivity
         }
 
         /// <summary>
-        /// Post request on a resource
+        /// Post request on a resource, asynchronously
         /// </summary>
-        /// <param name="representation">Resource representation</param>
+        /// <privilege>
+        /// http://tizen.org/privilege/internet
+        /// </privilege>
+        /// <param name="representation">Resource representation of request</param>
         /// <param name="query">The ResourceQuery to send to server</param>
-        /// <returns></returns>
+        /// <returns>Remote response with result and representation</returns>
         public async Task<RemoteResponse> PostAsync(Representation representation, ResourceQuery query = null)
         {
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
@@ -419,7 +500,6 @@ namespace Tizen.Network.IoTConnectivity
                 {
                     _responseCallbacksMap.Remove(responseCallbackId);
                 }
-
                 if (responseHandle != IntPtr.Zero)
                 {
                     try
@@ -437,7 +517,6 @@ namespace Tizen.Network.IoTConnectivity
                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
                 }
             };
-
             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
             if (errCode != (int)IoTConnectivityError.None)
@@ -449,9 +528,12 @@ namespace Tizen.Network.IoTConnectivity
         }
 
         /// <summary>
-        /// Delete the resource
+        /// Deletes the resource, asynchronously
         /// </summary>
-        /// <returns></returns>
+        /// <privilege>
+        /// http://tizen.org/privilege/internet
+        /// </privilege>
+        /// <returns>Remote response with result and representation</returns>
         public async Task<RemoteResponse> DeleteAsync()
         {
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
@@ -468,8 +550,14 @@ namespace Tizen.Network.IoTConnectivity
                 {
                     _responseCallbacksMap.Remove(responseCallbackId);
                 }
-
-                if (responseHandle != IntPtr.Zero)
+                if (err == (int)(IoTConnectivityError.Iotivity))
+                {
+                    RemoteResponse response = new RemoteResponse();
+                    response.Result = ResponseCode.Forbidden;
+                    response.Representation = null;
+                    tcsRemoteResponse.TrySetResult(response);
+                }
+                else if (responseHandle != IntPtr.Zero)
                 {
                     try
                     {
@@ -496,6 +584,9 @@ namespace Tizen.Network.IoTConnectivity
             return await tcsRemoteResponse.Task;
         }
 
+        /// <summary>
+        /// Releases any unmanaged resources used by this object.
+        /// </summary>
         public void Dispose()
         {
             Dispose(true);
@@ -506,6 +597,8 @@ namespace Tizen.Network.IoTConnectivity
         {
             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None;
 
+            Log.Info(IoTConnectivityErrorFactory.LogTag, hostAddress);
+
             if (hostAddress == IoTConnectivityClientManager.MulticastAddress)
             {
                 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
@@ -513,7 +606,33 @@ namespace Tizen.Network.IoTConnectivity
             else
             {
                 IPAddress address;
-                if (IPAddress.TryParse(hostAddress, out address))
+                string hostName = hostAddress;
+                if (hostAddress.Contains(":"))
+                {
+                    string[] hostParts = hostAddress.Split(':');
+                    if (hostParts.Length == 2)
+                    {
+                        hostName = hostParts[0];
+                    }
+                }
+                if (hostAddress.Contains("%"))
+                {
+                    string[] hostParts = hostAddress.Split('%');
+                    if (hostParts.Length == 2)
+                    {
+                        hostName = hostParts[0];
+                    }
+                }
+                if (hostName.Contains("["))
+                {
+                    string[] hostParts = hostName.Split('[');
+                    if (hostParts.Length == 2)
+                    {
+                        hostName = hostParts[1];
+                    }
+                }
+                Log.Info(IoTConnectivityErrorFactory.LogTag, hostName);
+                if (IPAddress.TryParse(hostName, out address))
                 {
                     switch (address.AddressFamily)
                     {
@@ -528,10 +647,18 @@ namespace Tizen.Network.IoTConnectivity
                             break;
                     }
                 }
+                else
+                {
+                    Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse hostname " + hostName);
+                }
             }
             return type;
         }
 
+        /// <summary>
+        /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
+        /// </summary>
+        /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
         protected virtual void Dispose(bool disposing)
         {
             if (_disposed)
@@ -569,7 +696,7 @@ namespace Tizen.Network.IoTConnectivity
                         {
                             Representation = repr
                         };
-                        CacheUpdated?.Invoke(null, e);
+                        CacheUpdated?.Invoke(this, e);
                     }
                 };
 
@@ -634,19 +761,28 @@ namespace Tizen.Network.IoTConnectivity
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get remote resource");
                 throw IoTConnectivityErrorFactory.GetException(ret);
             }
+
+            /*IntPtr deviceName;
+            ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceName(_remoteResourceHandle, out deviceName);
+            if (ret != (int)IoTConnectivityError.None)
+            {
+                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device name of remote resource");
+                throw IoTConnectivityErrorFactory.GetException(ret);
+            }
+            DeviceName = Marshal.PtrToStringAnsi(deviceName);*/
         }
 
         private void SetRemoteResource()
         {
-            string hostAddress, uriPath;
-            int ret = Interop.IoTConnectivity.Client.RemoteResource.GetHostAddress(_remoteResourceHandle, out hostAddress);
+            IntPtr hostAddressPtr, uriPathPtr;
+            int ret = Interop.IoTConnectivity.Client.RemoteResource.GetHostAddress(_remoteResourceHandle, out hostAddressPtr);
             if (ret != (int)IoTConnectivityError.None)
             {
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get host address");
                 throw IoTConnectivityErrorFactory.GetException(ret);
             }
 
-            ret = Interop.IoTConnectivity.Client.RemoteResource.GetUriPath(_remoteResourceHandle, out uriPath);
+            ret = Interop.IoTConnectivity.Client.RemoteResource.GetUriPath(_remoteResourceHandle, out uriPathPtr);
             if (ret != (int)IoTConnectivityError.None)
             {
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
@@ -654,7 +790,7 @@ namespace Tizen.Network.IoTConnectivity
             }
 
             int policy = (int)ResourcePolicy.NoProperty;
-            ret = Interop.IoTConnectivity.Client.RemoteResource.GetProperties(_remoteResourceHandle, out policy);
+            ret = Interop.IoTConnectivity.Client.RemoteResource.GetPolicies(_remoteResourceHandle, out policy);
             if (ret != (int)IoTConnectivityError.None)
             {
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
@@ -676,17 +812,24 @@ namespace Tizen.Network.IoTConnectivity
                 throw IoTConnectivityErrorFactory.GetException(ret);
             }
 
-            string deviceId;
-            ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceId(_remoteResourceHandle, out deviceId);
+            IntPtr deviceIdPtr;
+            ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceId(_remoteResourceHandle, out deviceIdPtr);
             if (ret != (int)IoTConnectivityError.None)
             {
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
                 throw IoTConnectivityErrorFactory.GetException(ret);
             }
-
-            DeviceId = deviceId;
-            HostAddress = hostAddress;
-            UriPath = uriPath;
+            IntPtr deviceName;
+            ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceName(_remoteResourceHandle, out deviceName);
+            if (ret != (int)IoTConnectivityError.None)
+            {
+                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device name of remote resource");
+                throw IoTConnectivityErrorFactory.GetException(ret);
+            }
+            DeviceName = Marshal.PtrToStringAnsi(deviceName);
+            DeviceId = Marshal.PtrToStringAnsi(deviceIdPtr);
+            HostAddress = Marshal.PtrToStringAnsi(hostAddressPtr);
+            UriPath = Marshal.PtrToStringAnsi(uriPathPtr);
             Types = new ResourceTypes(typesHandle);
             Interfaces = new ResourceInterfaces(interfacesHandle);
             Policy = (ResourcePolicy)policy;
@@ -716,12 +859,11 @@ namespace Tizen.Network.IoTConnectivity
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get options");
                 throw IoTConnectivityErrorFactory.GetException(ret);
             }
-
             return new RemoteResponse()
             {
                 Result = (ResponseCode)result,
                 Representation = new Representation(representationHandle),
-                Options = new ResourceOptions(optionsHandle)
+                Options = (optionsHandle == IntPtr.Zero)? null : new ResourceOptions(optionsHandle)
             };
         }
     }