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