/* * 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.Collections.ObjectModel; using System.Runtime.InteropServices; namespace Tizen.Network.IoTConnectivity { /// /// Abstract class respresenting a resource. /// All resources need to inherit from this class. /// public abstract class Resource : IDisposable { private IntPtr _resourceHandle = IntPtr.Zero; private bool _disposed = false; private ObservableCollection _children = new ObservableCollection(); private IntPtr _observerHandle = IntPtr.Zero; /// /// The constructor /// /// /// @a uri format would be relative URI path like '/a/light' /// and its length must be less than 128. /// /// /// http://tizen.org/privilege/internet /// /// The URI path of the resource /// Resource types /// Resource interfaces /// The policies of the resoruce ///
        /// IoTConnectivityServerManager.Initialize() should be called to initialize
        /// 
/// /// /// /// /// // Create a class which inherits from Resource /// public class DoorResource : Resource /// { /// public DoorResource(string uri, ResourceTypes types, ResourceInterfaces interfaces, ResourcePolicy policy) /// : base(uri, types, interfaces, policy) { /// } /// protected override Response OnDelete(Request request) { /// // Do something /// } /// protected override Response OnGet(Request request) { /// // Do something /// } /// // Override other abstract methods of Resource class /// } /// /// // Use it like below /// ResourceInterfaces ifaces = new ResourceInterfaces(new List(){ ResourceInterfaces.DefaultInterface }); /// ResourceTypes types = new ResourceTypes(new List(){ "oic.iot.door.new" }); /// Resource resource = new DoorResource("/door/uri1", types, ifaces, ResourcePolicy.Discoverable | ResourcePolicy.Observable); /// protected Resource(string uri, ResourceTypes types, ResourceInterfaces interfaces, ResourcePolicy policy) { UriPath = uri; Types = types; Interfaces = interfaces; Policy = policy; _children.CollectionChanged += ChildrenCollectionChanged; int ret = Interop.IoTConnectivity.Server.Observers.Create(out _observerHandle); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to create obsever handle"); throw IoTConnectivityErrorFactory.GetException(ret); } } /// /// Destructor of the Resource class. /// ~Resource() { Dispose(false); } /// /// Type details of the resource /// public ResourceTypes Types { get; internal set; } /// /// Interface details of the resource /// public ResourceInterfaces Interfaces { get; internal set; } /// /// The policies of the resource /// public ResourcePolicy Policy { get; internal set; } /// /// URI path of the resource /// public string UriPath { get; internal set; } /// /// List of Child resources /// public ICollection Children { get { return _children; } } internal IntPtr ResourceHandle { get { return _resourceHandle; } set { _resourceHandle = value; } } /// /// Notify the specified representation and qos. /// /// /// http://tizen.org/privilege/internet /// /// Representation. /// The quality of service for message transfer. ///
        /// IoTConnectivityServerManager.Initialize() should be called to initialize
        /// 
/// /// /// /// ResourceInterfaces ifaces = new ResourceInterfaces(new List(){ ResourceInterfaces.DefaultInterface }); /// ResourceTypes types = new ResourceTypes(new List(){ "oic.iot.door.new.notify" }); /// Resource resource = new DoorResource("/door/uri/new/notify", types, ifaces, ResourcePolicy.Discoverable | ResourcePolicy.Observable); /// IoTConnectivityServerManager.RegisterResource(resource); /// /// Representation repr = new Representation(); /// repr.UriPath = "/door/uri/new/notify"; /// repr.Type = new ResourceTypes(new List(){ "oic.iot.door.new.notify" }); /// repr.Attributes = new Attributes() { /// _attribute, 1 } /// }; /// resource.Notify(repr, QualityOfService.High); /// public void Notify(Representation representation, QualityOfService qos) { int ret = (int)IoTConnectivityError.None; ret = Interop.IoTConnectivity.Server.Resource.Notify(_resourceHandle, representation._representationHandle, _observerHandle, (int)qos); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to send notification"); throw IoTConnectivityErrorFactory.GetException(ret); } } /// /// This is Called when the client performs get operation on this resource. /// /// A request from client /// A response having the representation and the result protected abstract Response OnGet(Request request); /// /// This is Called when the client performs put operation on this resource. /// /// A request from client /// A response protected abstract Response OnPut(Request request); /// /// This is Called when the client performs post operation on this resource. /// /// A request from client /// A response having the representation and the result protected abstract Response OnPost(Request request); /// /// This is Called when the client performs delete operation on this resource. /// /// A request from client /// A response protected abstract Response OnDelete(Request request); /// /// Called on the observing event. /// /// A request from client /// Observer type /// Observe identifier. /// Returns true if it wants to be observed, else false. protected abstract bool OnObserving(Request request, ObserveType type, int observeId); /// /// Releases any unmanaged resources used by this object. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects. /// /// If true, disposes any disposable objects. If false, does not dispose disposable objects. protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { Types?.Dispose(); Interfaces?.Dispose(); } if (_resourceHandle != IntPtr.Zero) Interop.IoTConnectivity.Server.Resource.Destroy(_resourceHandle); if (_observerHandle != IntPtr.Zero) Interop.IoTConnectivity.Server.Observers.Destroy(_observerHandle); _disposed = true; } // This method is used as callback for Resource internal void OnRequest(IntPtr resourceHandle, IntPtr requestHandle, IntPtr userData) { Request request = GetRequest(requestHandle); Response response = null; if (request == null) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get Request"); return; } try { int observeType; int ret = Interop.IoTConnectivity.Server.Request.GetObserveType(requestHandle, out observeType); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get observe type"); return; } if ((ObserveType)observeType != ObserveType.NoType) { int observeId; ret = Interop.IoTConnectivity.Server.Request.GetObserveId(requestHandle, out observeId); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get observe id"); return; } switch ((ObserveType)observeType) { case ObserveType.Register: { if (OnObserving(request, ObserveType.Register, observeId)) { ret = Interop.IoTConnectivity.Server.Observers.Add(_observerHandle, observeId); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add observer id"); return; } break; } else { // If OnObserving for ObserveType.Register returns false, do not operate for Get operation after Observe operation. return; } } case ObserveType.Deregister: { if (OnObserving(request, ObserveType.Deregister, observeId)) { ret = Interop.IoTConnectivity.Server.Observers.Remove(_observerHandle, observeId); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove observer id"); return; } break; } else { // If OnObserving for ObserveType.Deregister returns false, do not operate for Get operation after Observe operation. return; } } } } int requestType; ret = Interop.IoTConnectivity.Server.Request.GetRequestType(requestHandle, out requestType); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get request type"); return; } switch ((Interop.IoTConnectivity.Server.RequestType)requestType) { case Interop.IoTConnectivity.Server.RequestType.Put: { response = OnPut(request); break; } case Interop.IoTConnectivity.Server.RequestType.Get: { response = OnGet(request); break; } case Interop.IoTConnectivity.Server.RequestType.Post: { response = OnPost(request); break; } case Interop.IoTConnectivity.Server.RequestType.Delete: { response = OnDelete(request); break; } default: break; } if (response == null) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to send Response"); return; } if (!response.Send(requestHandle)) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to send Response"); return; } } finally { request?.Dispose(); response?.Dispose(); } } private Request GetRequest(IntPtr requestHandle) { IntPtr hostAddressPtr; int ret = Interop.IoTConnectivity.Server.Request.GetHostAddress(requestHandle, out hostAddressPtr); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get host address"); return null; } IntPtr optionsHandle = IntPtr.Zero; ret = Interop.IoTConnectivity.Server.Request.GetOptions(requestHandle, out optionsHandle); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get options"); return null; } IntPtr queryHandle = IntPtr.Zero; ret = Interop.IoTConnectivity.Server.Request.GetQuery(requestHandle, out queryHandle); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get Query"); return null; } IntPtr representationHandle = IntPtr.Zero; ret = Interop.IoTConnectivity.Server.Request.GetRepresentation(requestHandle, out representationHandle); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to Get representation"); return null; } ResourceOptions opts = null; ResourceQuery query = null; Representation representation = null; try { opts = (optionsHandle == IntPtr.Zero) ? null : new ResourceOptions(optionsHandle); } catch (Exception exp) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new ResourceOptions: " + exp.Message); return null; } try { query = (queryHandle == IntPtr.Zero) ? null : new ResourceQuery(queryHandle); } catch (Exception exp) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new ResourceQuery: " + exp.Message); return null; } try { representation = (representationHandle == IntPtr.Zero) ? null : new Representation(representationHandle); ; } catch (Exception exp) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new Representation: " + exp.Message); return null; } return new Request() { HostAddress = Marshal.PtrToStringAnsi(hostAddressPtr), Options = opts, Query = query, Representation = representation }; } private void ChildrenCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs eventArgs) { if (eventArgs.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { foreach (Resource r in eventArgs.NewItems) { int ret = Interop.IoTConnectivity.Server.Resource.BindChildResource(_resourceHandle, r._resourceHandle); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to bind resource "); throw IoTConnectivityErrorFactory.GetException(ret); } } } else if (eventArgs.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) { foreach (Resource r in eventArgs.NewItems) { int ret = Interop.IoTConnectivity.Server.Resource.UnbindChildResource(_resourceHandle, r._resourceHandle); if (ret != (int)IoTConnectivityError.None) { Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to unbind resource"); throw IoTConnectivityErrorFactory.GetException(ret); } } } } } }