0d24434d87a559b3c04d896dcff4e326c1711a89
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.IoTConnectivity / Tizen.Network.IoTConnectivity / ResourceQuery.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;
20 using System.Collections.Generic;
21 using System.Runtime.InteropServices;
22
23 namespace Tizen.Network.IoTConnectivity
24 {
25     /// <summary>
26     /// This class provides APIs to manage query of request.
27     /// </summary>
28     public class ResourceQuery : IDictionary<string, string>, IDisposable
29     {
30         internal const int QueryMaxLenth = 64;
31         internal IntPtr _resourceQueryHandle = IntPtr.Zero;
32         private readonly IDictionary<string, string> _query = new Dictionary<string, string>();
33         private bool _disposed = false;
34
35         /// <summary>
36         /// The resource query constructor
37         /// </summary>
38         /// <seealso cref="Add()"/>
39         /// <seealso cref="Remove()"/>
40         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
41         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
42         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
43         /// <code>
44         /// ResourceQuery query = new ResourceQuery();
45         /// </code>
46         public ResourceQuery()
47         {
48             int ret = Interop.IoTConnectivity.Common.Query.Create(out _resourceQueryHandle);
49             if (ret != (int)IoTConnectivityError.None)
50             {
51                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to create query");
52                 throw IoTConnectivityErrorFactory.GetException(ret);
53             }
54         }
55
56         internal ResourceQuery(IntPtr resourceQueryHandleToClone)
57         {
58             int ret = Interop.IoTConnectivity.Common.Query.Create(out _resourceQueryHandle);
59             if (ret != (int)IoTConnectivityError.None)
60             {
61                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to create query");
62                 throw IoTConnectivityErrorFactory.GetException(ret);
63             }
64
65             Interop.IoTConnectivity.Common.Query.QueryCallback forEachCallback = (string key, string value, IntPtr userData) =>
66             {
67                 Add(key, value);
68                 return true;
69             };
70
71             ret = Interop.IoTConnectivity.Common.Query.Foreach(resourceQueryHandleToClone, forEachCallback, IntPtr.Zero);
72             if (ret != (int)IoTConnectivityError.None)
73             {
74                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to iterate query");
75                 throw IoTConnectivityErrorFactory.GetException(ret);
76             }
77         }
78
79         /// <summary>
80         /// Destructor of the ResourceQuery class.
81         /// </summary>
82         ~ResourceQuery()
83         {
84             Dispose(false);
85         }
86
87         /// <summary>
88         /// Gets and sets the resource type of the query
89         /// </summary>
90         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
91         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
92         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
93         /// <code>
94         /// ResourceQuery query = new ResourceQuery();
95         /// query.Type = "org.tizen.light";
96         /// Console.WriteLine("Type of query : {0}", query.Type);
97         /// </code>
98         public string Type
99         {
100             get
101             {
102                 IntPtr type;
103                 int ret = Interop.IoTConnectivity.Common.Query.GetResourceType(_resourceQueryHandle, out type);
104                 if (ret != (int)IoTConnectivityError.None)
105                 {
106                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get type");
107                     return "";
108                 }
109                 return Marshal.PtrToStringAnsi(type);
110             }
111             set
112             {
113                 int ret = (int)IoTConnectivityError.InvalidParameter;
114                 if (ResourceTypes.IsValid(value))
115                     ret = Interop.IoTConnectivity.Common.Query.SetResourceType(_resourceQueryHandle, value);
116
117                 if (ret != (int)IoTConnectivityError.None)
118                 {
119                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set type");
120                     throw IoTConnectivityErrorFactory.GetException(ret);
121                 }
122             }
123         }
124
125         /// <summary>
126         /// Gets and sets the resource interface of the query
127         /// </summary>
128         /// <remarks>
129         /// Setter value could be a value such as <see cref="ResourceInterfaces.DefaultInterface"/>
130         /// </remarks>
131         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
132         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
133         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
134         /// <code>
135         /// ResourceQuery query = new ResourceQuery();
136         /// query.Interface = ResourceInterfaces.LinkInterface;
137         /// </code>
138         public string Interface
139         {
140             get
141             {
142                 IntPtr iface;
143                 int ret = Interop.IoTConnectivity.Common.Query.GetInterface(_resourceQueryHandle, out iface);
144                 if (ret != (int)IoTConnectivityError.None)
145                 {
146                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get interface");
147                     return "";
148                 }
149                 return Marshal.PtrToStringAnsi(iface);
150             }
151             set
152             {
153                 int ret = (int)IoTConnectivityError.InvalidParameter;
154                 if (ResourceInterfaces.IsValid(value))
155                     ret = Interop.IoTConnectivity.Common.Query.SetInterface(_resourceQueryHandle, value);
156
157                 if (ret != (int)IoTConnectivityError.None)
158                 {
159                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set interface");
160                     throw IoTConnectivityErrorFactory.GetException(ret);
161                 }
162             }
163         }
164
165         /// <summary>
166         /// Contains all the query keys
167         /// </summary>
168         /// <code>
169         /// ResourceQuery query = new ResourceQuery();
170         /// query.Add("key", "value");
171         /// query.Add("newKey", "sample value");
172         /// var keys = query.Keys;
173         /// Console.WriteLine("Resource query contains keys {0} and {1}", keys.ElementAt(0), keys.ElementAt(1));
174         /// </code>
175         public ICollection<string> Keys
176         {
177             get
178             {
179                 return _query.Keys;
180             }
181         }
182
183         /// <summary>
184         /// Contains all the query values
185         /// </summary>
186         /// <code>
187         /// ResourceQuery query = new ResourceQuery();
188         /// query.Add("key", "value");
189         /// query.Add("newKey", "sample value");
190         /// var values = query.Values;
191         /// Console.WriteLine("Resource query contains values {0} and {1}", values.ElementAt(0), values.ElementAt(1));
192         /// </code>
193         public ICollection<string> Values
194         {
195             get
196             {
197                 return _query.Values;
198             }
199         }
200
201         /// <summary>
202         /// Gets the number of query elements
203         /// </summary>
204         /// <code>
205         /// ResourceQuery query = new ResourceQuery();
206         /// query.Add("key", "value");
207         /// query.Add("newKey", "sample value");
208         /// var count = query.Count;
209         /// Console.WriteLine("There are {0} keys in the query object", count);
210         /// </code>
211         public int Count
212         {
213             get
214             {
215                 return _query.Count;
216             }
217         }
218
219         /// <summary>
220         /// Gets or sets the query data
221         /// </summary>
222         /// <param name="key">The query key to get or set.</param>
223         /// <returns>The query with the specified key.</returns>
224         /// <code>
225         /// ResourceQuery query = new ResourceQuery();
226         /// query["key1"] = "sample-data";
227         /// Console.WriteLine("query has : {0}", query["key1"]);
228         /// </code>
229         public string this[string key]
230         {
231             get
232             {
233                 return _query[key];
234             }
235
236             set
237             {
238                 Add(key, value);
239             }
240         }
241
242         /// <summary>
243         /// Checks whether the given key exists in Query collection
244         /// </summary>
245         /// <param name="key">The key to look for</param>
246         /// <returns>true if exists. Otherwise, false</returns>
247         /// <code>
248         /// ResourceQuery query = new ResourceQuery();
249         /// query.Add("key1", "value1");
250         /// if (query.ContainsKey("key1"))
251         ///     Console.WriteLine("query conatins key : key1");
252         /// </code>
253         public bool ContainsKey(string key)
254         {
255             return _query.ContainsKey(key);
256         }
257
258         /// <summary>
259         /// Adds a new key and correspoding value into the query.
260         /// </summary>
261         /// <remarks>
262         /// The full length of query should be less than or equal to 64.
263         /// </remarks>
264         /// <param name="key">The key of the query to insert</param>
265         /// <param name="value">The string data to insert into the query</param>
266         /// <seealso cref="Remove()"/>
267         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
268         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
269         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
270         /// <code>
271         /// ResourceQuery query = new ResourceQuery();
272         /// query.Add("key1", "value1");
273         /// </code>
274         public void Add(string key, string value)
275         {
276             if (CanAddQuery(key, value))
277             {
278                 int ret = Interop.IoTConnectivity.Common.Query.Add(_resourceQueryHandle, key, value);
279                 if (ret != (int)IoTConnectivityError.None)
280                 {
281                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add query");
282                     throw IoTConnectivityErrorFactory.GetException(ret);
283                 }
284                 _query.Add(key, value);
285             }
286             else
287             {
288                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Query cannot be added");
289                 throw IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.InvalidParameter);
290             }
291         }
292
293         /// <summary>
294         /// Removes the key and its associated value from the query.
295         /// </summary>
296         /// <param name="key">The id of the query to delete</param>
297         /// <returns>True if operation is successful. Otherwise, false</returns>
298         /// <seealso cref="Add()"/>
299         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
300         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
301         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
302         /// <code>
303         /// ResourceQuery query = new ResourceQuery();
304         /// query.Add("key1", "value1");
305         /// var result = query.Remove("key1");
306         /// </code>
307         public bool Remove(string key)
308         {
309             bool isRemoved = _query.Remove(key);
310             if (isRemoved)
311             {
312                 int ret = Interop.IoTConnectivity.Common.Query.Remove(_resourceQueryHandle, key);
313                 if (ret != (int)IoTConnectivityError.None)
314                 {
315                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove query");
316                     throw IoTConnectivityErrorFactory.GetException(ret);
317                 }
318             }
319             return isRemoved;
320         }
321
322         /// <summary>
323         /// Gets the value associated with the specified key.
324         /// </summary>
325         /// <param name="key">The query key</param>
326         /// <param name="value">Value corresponding to query key</param>
327         /// <returns>True if the key exists, false otherwise</returns>
328         /// <code>
329         /// ResourceQuery query = new ResourceQuery();
330         /// query.Add("key1", "value1");
331         /// string value;
332         /// var isPresent = query.TryGetValue("key1", out value);
333         /// if (isPresent)
334         ///     Console.WriteLine("value : {0}", value);
335         /// </code>
336         public bool TryGetValue(string key, out string value)
337         {
338             return _query.TryGetValue(key, out value);
339         }
340
341         /// <summary>
342         ///  Adds query key and value as a key value pair
343         /// </summary>
344         /// <param name="item">The key value pair</param>
345         /// <seealso cref="Remove()"/>
346         /// <code>
347         /// ResourceQuery query = new ResourceQuery();
348         /// query.Add(new KeyValuePair<string, string>("key1", "value1"));
349         /// </code>
350         public void Add(KeyValuePair<string, string> item)
351         {
352             Add(item.Key, item.Value);
353         }
354
355         /// <summary>
356         /// Clears the Query collection
357         /// </summary>
358         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
359         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
360         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
361         /// <code>
362         /// ResourceQuery query = new ResourceQuery();
363         /// query.Add("key1", "value1");
364         /// query.Add("key2", "value2");
365         /// query.Clear();
366         /// </code>
367         public void Clear()
368         {
369             foreach (string key in _query.Keys)
370             {
371                 int ret = Interop.IoTConnectivity.Common.Query.Remove(_resourceQueryHandle, key);
372                 if (ret != (int)IoTConnectivityError.None)
373                 {
374                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to clear query");
375                     throw IoTConnectivityErrorFactory.GetException(ret);
376                 }
377             }
378             _query.Clear();
379         }
380
381         /// <summary>
382         /// Checks if the given query pair exists
383         /// </summary>
384         /// <param name="item">The key value pair</param>
385         /// <returns>True if exists. Otherwise, false</returns>
386         /// <code>
387         /// ResourceQuery query = new ResourceQuery();
388         /// query.Add(new KeyValuePair<string, string>("key1", "value1"));
389         /// var isPresent = query.Contains(new KeyValuePair<string, string>("key1", "value1"));
390         /// if (isPresent)
391         ///     Console.WriteLine("Key value pair is present");
392         /// </code>
393         public bool Contains(KeyValuePair<string, string> item)
394         {
395             return _query.Contains(item);
396         }
397
398         /// <summary>
399         /// Copies the elements of the query collection to an Array, starting at a particular index.
400         /// </summary>
401         /// <param name="array">The destination array</param>
402         /// <param name="arrayIndex">Index parameter</param>
403         /// <code>
404         /// ResourceQuery query = new ResourceQuery();
405         /// query.Add(new KeyValuePair<string, string>("key1", "value1"));
406         /// KeyValuePair<string, string>[] dest = new KeyValuePair<string, string>[query.Count];
407         /// query.CopyTo(dest, 0);
408         /// Console.WriteLine("Dest conatins ({0}, {1})", dest[0].Key, dest[0].Value);
409         /// </code>
410         public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
411         {
412             _query.CopyTo(array, arrayIndex);
413         }
414
415         /// <summary>
416         /// Remove the given key value pair from the query
417         /// </summary>
418         /// <param name="item">The key value pair to remove</param>
419         /// <returns>True if operation is successful. Otherwise, false</returns>
420         /// <seealso cref="Add()"/>
421         /// <code>
422         /// ResourceQuery query = new ResourceQuery();
423         /// query.Add(new KeyValuePair<string, string>("key1", "value1"));
424         /// var result = query.Remove(new KeyValuePair<string, string>("key1", "value1"));
425         /// </code>
426         public bool Remove(KeyValuePair<string, string> item)
427         {
428             return Remove(item.Key);
429         }
430
431         /// <summary>
432         /// Get the enumerator to query collection
433         /// </summary>
434         /// <returns>Enumerator to query pairs</returns>
435         /// <code>
436         /// ResourceQuery query = new ResourceQuery();
437         /// query.Add(new KeyValuePair<string, string>("key1", "value1"));
438         /// query.Add(new KeyValuePair<string, string>("key2", "value2"));
439         /// foreach (KeyValuePair<string, string> pair in query)
440         /// {
441         ///     Console.WriteLine("key : {0}, value : {1}", pair.Key, pair.Value);
442         /// }
443         /// </code>
444         public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
445         {
446             return _query.GetEnumerator();
447         }
448
449         /// <summary>
450         /// Get the enumerator to query collection
451         /// </summary>
452         /// <returns>Enumerator to query pairs</returns>
453         /// <code>
454         /// ResourceQuery query = new ResourceQuery();
455         /// query.Add(new KeyValuePair<string, string>("key1", "value1"));
456         /// query.Add(new KeyValuePair<string, string>("key2", "value2"));
457         /// foreach (KeyValuePair<string, string> pair in query)
458         /// {
459         ///     Console.WriteLine("key : {0}, value : {1}", pair.Key, pair.Value);
460         /// }
461         /// </code>
462         IEnumerator IEnumerable.GetEnumerator()
463         {
464             return _query.GetEnumerator();
465         }
466
467         /// <summary>
468         /// Releases any unmanaged resources used by this object.
469         /// </summary>
470         public void Dispose()
471         {
472             Dispose(true);
473             GC.SuppressFinalize(this);
474         }
475
476         /// <summary>
477         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
478         /// </summary>
479         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
480         protected virtual void Dispose(bool disposing)
481         {
482             if (_disposed)
483                 return;
484
485             if (disposing)
486             {
487                 // Free managed objects
488             }
489
490             Interop.IoTConnectivity.Common.Query.Destroy(_resourceQueryHandle);
491             _disposed = true;
492         }
493
494         private bool CanAddQuery(string newKey, string newValue)
495         {
496             int queryLenth = 0;
497             foreach (string key in Keys)
498             {
499                 queryLenth += key.Length + 2;
500             }
501             foreach (string value in Values)
502             {
503                 queryLenth += value.Length;
504             }
505
506             if ((newKey.Length + newValue.Length + queryLenth + 2) < QueryMaxLenth)
507                 return true;
508
509             return false;
510         }
511     }
512 }