[DataControl] Fix MapGet bug
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.DataControl / Tizen.Applications.DataControl / Consumer.cs
1 /*
2  * Copyright (c) 2017 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 using System;
17 using System.Collections.Generic;
18 using Tizen.Applications.DataControl.Core;
19 using System.Threading;
20 using System.Runtime.InteropServices;
21
22 namespace Tizen.Applications.DataControl
23 {
24     /// <summary>
25     /// Represents the Consumer class for the DataControl consumer application.
26     /// </summary>
27     /// <since_tizen> 3 </since_tizen>
28     public abstract class Consumer : IDisposable
29     {
30
31         private Interop.DataControl.SafeDataControlHandle _handle;
32         private string _dataID, _providerID;
33         private int _changeCallbackID = 0;
34         private const string LogTag = "Tizen.Applications.DataControl";
35         private bool _disposed = false;
36         private static Mutex _lock = new Mutex();
37         private Interop.DataControl.DataChangeCallback _dataChangeCallback;
38         private Interop.DataControl.AddCallbackResultCallback _addCallbackResultCallback;
39
40         private static class CallbackManager
41         {
42             private static IDictionary<string, Interop.DataControl.MapResponseCallbacks> _mapResponseCallbacks = new Dictionary<string, Interop.DataControl.MapResponseCallbacks>();
43             private static IDictionary<string, Interop.DataControl.MapBulkAddResponseCallback> _mapBulkResponseCallback = new Dictionary<string, Interop.DataControl.MapBulkAddResponseCallback>();
44             private static IDictionary<string, Interop.DataControl.SqlResponseCallbacks> _sqlResponseCallbacks = new Dictionary<string, Interop.DataControl.SqlResponseCallbacks>();
45             private static IDictionary<string, Interop.DataControl.SqlBulkInsertResponseCallback> _sqlBulkResponseCallback = new Dictionary<string, Interop.DataControl.SqlBulkInsertResponseCallback>();
46             private static IDictionary<int, Consumer> _reqConsumerDictionary = new Dictionary<int, Consumer>();
47             private static IDictionary<string, int> _reqProviderList = new Dictionary<string, int>();
48             private static void InsertResponse(int reqId, IntPtr provider, long insertedRowId, bool providerResult, string error, IntPtr userData)
49             {
50                 Log.Debug(LogTag, $"InsertResponse {reqId.ToString()}");
51                 if (!_reqConsumerDictionary.ContainsKey(reqId))
52                 {
53                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
54                     return;
55                 }
56
57                 if (!providerResult)
58                 {
59                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}, rowID : {insertedRowId.ToString()}");
60                 }
61
62                 Consumer consumer = _reqConsumerDictionary[reqId];
63                 consumer.OnInsertResult(new InsertResult(insertedRowId, providerResult));
64                 _reqConsumerDictionary.Remove(reqId);
65             }
66
67             private static void BulkInsertResponse(int reqId, IntPtr provider, IntPtr bulkResults, bool providerResult, string error, IntPtr userData)
68             {
69                 BulkResultData brd;
70                 Log.Debug(LogTag, $"BulkInsertResponse {reqId.ToString()}");
71                 if (!_reqConsumerDictionary.ContainsKey(reqId))
72                 {
73                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
74                     return;
75                 }
76
77                 if (!providerResult)
78                 {
79                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
80                 }
81
82                 if (bulkResults != IntPtr.Zero)
83                 {
84                     brd = new BulkResultData(new Interop.DataControl.SafeBulkResultDataHandle(bulkResults, false));
85                 }
86                 else
87                 {
88                     brd = new BulkResultData();
89                     Log.Error(LogTag, $"reqId {reqId.ToString()}, bulkResults is null");
90                 }
91
92                 Consumer consumer = _reqConsumerDictionary[reqId];
93                 consumer.OnBulkInsertResult(new BulkInsertResult(brd, providerResult));
94                 _reqConsumerDictionary.Remove(reqId);
95             }
96
97             private static void SelectResponse(int reqId, IntPtr provider, IntPtr cursor, bool providerResult, string error, IntPtr userData)
98             {
99                 MatrixCursor dmc;
100                 Log.Debug(LogTag, $"SelectResponse {reqId.ToString()}");
101                 if (!_reqConsumerDictionary.ContainsKey(reqId))
102                 {
103                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
104                     return;
105                 }
106
107                 if (!providerResult)
108                 {
109                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
110                 }
111
112                 if (cursor != IntPtr.Zero)
113                 {
114                     try
115                     {
116                         dmc = CloneCursor(new CloneCursorCore(new Interop.DataControl.SafeCursorHandle(cursor, true)));
117                     }
118                     catch (Exception ex)
119                     {
120                         dmc = new MatrixCursor();
121                         Log.Error(LogTag, $"reqId {reqId.ToString()},  {ex.ToString()}");
122                     }
123                 }
124                 else
125                 {
126                     dmc = new MatrixCursor();
127                     Log.Error(LogTag, $"reqId {reqId.ToString()}, cursor is null");
128                 }
129                 Consumer consumer = _reqConsumerDictionary[reqId];
130                 consumer.OnSelectResult(new SelectResult(dmc, providerResult));
131                 _reqConsumerDictionary.Remove(reqId);
132             }
133
134             private static void UpdateResponse(int reqId, IntPtr provider, bool providerResult, string error, IntPtr userData)
135             {
136                 if (!_reqConsumerDictionary.ContainsKey(reqId))
137                 {
138                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
139                     return;
140                 }
141
142                 if (!providerResult)
143                 {
144                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
145                 }
146
147                 Consumer consumer = _reqConsumerDictionary[reqId];
148                 consumer.OnUpdateResult(new UpdateResult(providerResult));
149                 _reqConsumerDictionary.Remove(reqId);
150             }
151
152             private static void DeleteResponse(int reqId, IntPtr provider, bool providerResult, string error, IntPtr userData)
153             {
154                 if (!_reqConsumerDictionary.ContainsKey(reqId))
155                 {
156                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
157                     return;
158                 }
159
160                 if (!providerResult)
161                 {
162                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
163                 }
164
165                 Consumer consumer = _reqConsumerDictionary[reqId];
166                 consumer.OnDeleteResult(new DeleteResult(providerResult));
167                 _reqConsumerDictionary.Remove(reqId);
168             }
169
170             static void IntPtrToStringArray(IntPtr unmanagedArray, int size, out string[] managedArray)
171             {
172                 managedArray = new string[size];
173                 IntPtr[] IntPtrArray = new IntPtr[size];
174                 Marshal.Copy(unmanagedArray, IntPtrArray, 0, size);
175                 for (int iterator = 0; iterator < size; iterator++)
176                 {
177                     managedArray[iterator] = Marshal.PtrToStringAnsi(IntPtrArray[iterator]);
178                 }
179             }
180
181             private static void MapGetResponse(int reqId, IntPtr provider, IntPtr valueList, int valueCount, bool providerResult, string error, IntPtr userData)
182             {
183                 MapGetResult mgr;
184                 Log.Debug(LogTag, $"MapGetResponse {reqId.ToString()}");
185                 if (!_reqConsumerDictionary.ContainsKey(reqId))
186                 {
187                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
188                     return;
189                 }
190
191                 if (!providerResult)
192                 {
193                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
194                 }
195
196                 if (valueList !=null)
197                 {
198                     string[] stringArray;
199                     IntPtrToStringArray(valueList, valueCount, out stringArray);
200                     mgr = new MapGetResult(stringArray, providerResult);
201                 }
202                 else
203                 {
204                     mgr = new MapGetResult(new string[0], providerResult);
205                     Log.Error(LogTag, $"reqId {reqId.ToString()}, valueList is null");
206                 }
207
208                 Consumer consumer = _reqConsumerDictionary[reqId];
209                 consumer.OnMapGetResult(mgr);
210                 _reqConsumerDictionary.Remove(reqId);
211             }
212
213             private static void MapBulkAddResponse(int reqId, IntPtr provider, IntPtr bulkResults, bool providerResult, string error, IntPtr userData)
214             {
215                 BulkResultData brd;
216                 Log.Debug(LogTag, $"MapBulkAddResponse {reqId.ToString()}");
217                 if (!_reqConsumerDictionary.ContainsKey(reqId))
218                 {
219                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
220                     return;
221                 }
222
223                 if (!providerResult)
224                 {
225                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
226                 }
227
228                 if (bulkResults != IntPtr.Zero)
229                 {
230                     brd = new BulkResultData(new Interop.DataControl.SafeBulkResultDataHandle(bulkResults, false));
231                 }
232                 else
233                 {
234                     brd = new BulkResultData();
235                     Log.Error(LogTag, $"reqId {reqId.ToString()}, bulkResults is null");
236                 }
237
238                 Consumer consumer = _reqConsumerDictionary[reqId];
239                 consumer.OnMapBulkAddResult(new MapBulkAddResult(brd, providerResult));
240                 _reqConsumerDictionary.Remove(reqId);
241             }
242
243             private static void MapAddResponse(int reqId, IntPtr provider, bool providerResult, string error, IntPtr userData)
244             {
245                 Log.Debug(LogTag, $"MapAddResponse {reqId.ToString()}");
246                 if (!_reqConsumerDictionary.ContainsKey(reqId))
247                 {
248                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
249                     return;
250                 }
251
252                 if (!providerResult)
253                 {
254                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
255                 }
256
257                 Consumer consumer = _reqConsumerDictionary[reqId];
258                 consumer.OnMapAddResult(new MapAddResult(providerResult));
259                 _reqConsumerDictionary.Remove(reqId);
260             }
261
262             private static void MapSetResponse(int reqId, IntPtr provider, bool providerResult, string error, IntPtr userData)
263             {
264                 Log.Debug(LogTag, $"MapSetResponse {reqId.ToString()}");
265                 if (!_reqConsumerDictionary.ContainsKey(reqId))
266                 {
267                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
268                     return;
269                 }
270
271                 if (!providerResult)
272                 {
273                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
274                 }
275
276                 Consumer consumer = _reqConsumerDictionary[reqId];
277                 consumer.OnMapSetResult(new MapSetResult(providerResult));
278                 _reqConsumerDictionary.Remove(reqId);
279             }
280
281             private static void MapRemoveResponse(int reqId, IntPtr provider, bool providerResult, string error, IntPtr userData)
282             {
283                 if (!_reqConsumerDictionary.ContainsKey(reqId))
284                 {
285                     Log.Error(LogTag, $"Invalid reqId {reqId.ToString()}");
286                     return;
287                 }
288
289                 if (!providerResult)
290                 {
291                     Log.Error(LogTag, $"reqId {reqId.ToString()}, error : {error}");
292                 }
293
294                 Consumer consumer = _reqConsumerDictionary[reqId];
295                 consumer.OnMapRemoveResult(new MapRemoveResult(providerResult));
296                 _reqConsumerDictionary.Remove(reqId);
297             }
298
299             private static MatrixCursor CloneCursor(CloneCursorCore coreCursor)
300             {
301                 int size = coreCursor.GetColumnCount();
302                 int i;
303                 string[] name = new string[size];
304                 object[] newRow = new object[size];
305                 ColumnType[] type = new ColumnType[size];
306
307                 for (i = 0; i < size; i++)
308                 {
309                     name[i] = coreCursor.GetColumnName(i);
310                     type[i] = coreCursor.GetColumnType(i);
311                 }
312
313                 MatrixCursor dmc = new MatrixCursor(name, type);
314
315                 if (coreCursor.GetRowCount() <= 0)
316                 {
317                     return dmc;
318                 }
319
320                 coreCursor.Reset();
321                 do
322                 {
323                     for (i = 0; i < size; i++)
324                     {
325                         switch (type[i])
326                         {
327                             case ColumnType.ColumnTypeInt:
328                                 newRow[i] = coreCursor.GetInt64Value(i);
329                                 break;
330                             case ColumnType.ColumnTypeDouble:
331                                 newRow[i] = coreCursor.GetDoubleValue(i);
332                                 break;
333                             case ColumnType.ColumnTypeBlob:
334                                 newRow[i] = coreCursor.GetBlobValue(i);
335                                 break;
336                             case ColumnType.ColumnTypeString:
337                                 newRow[i] = coreCursor.GetStringValue(i);
338                                 break;
339                         }
340                     }
341
342                     dmc.AddRow(newRow);
343                 }
344                 while (coreCursor.Next());
345
346                 return dmc;
347             }
348
349             internal static void RegisterReqId(int reqId, Consumer consumer)
350             {
351                 _lock.WaitOne();
352                 _reqConsumerDictionary.Add(reqId, consumer);
353                 _lock.ReleaseMutex();
354             }
355
356             internal static void RegisterCallback(Interop.DataControl.SafeDataControlHandle handle, string providerId)
357             {
358                 ResultType ret;
359                 Interop.DataControl.SqlResponseCallbacks sqlCallbacks;
360                 Interop.DataControl.SqlBulkInsertResponseCallback sqlBulkCallbacks;
361                 Interop.DataControl.MapResponseCallbacks mapCallbacks;
362                 Interop.DataControl.MapBulkAddResponseCallback mapBulkCallbacks;
363                 bool sqlRegistered = false;
364                 bool mapRegistered = false;
365
366                 if (_reqProviderList.ContainsKey(providerId))
367                 {
368                     _reqProviderList[providerId]++;
369                     Log.Error(LogTag, "The data control is already set");
370                     return;
371                 }
372
373                 sqlCallbacks.Insert = new Interop.DataControl.SqlInsertResponseCallback(InsertResponse);
374                 sqlCallbacks.Select = new Interop.DataControl.SqlSelectResponseCallback(SelectResponse);
375                 sqlCallbacks.Update = new Interop.DataControl.SqlUpdateResponseCallback(UpdateResponse);
376                 sqlCallbacks.Delete = new Interop.DataControl.SqlDeleteResponseCallback(DeleteResponse);
377                 ret = Interop.DataControl.RegisterSqlResponseCallback(handle, ref sqlCallbacks, IntPtr.Zero);
378                 if (ret != ResultType.Success)
379                 {
380                     Log.Error(LogTag, "Registering the sql callback function is failed : " + ret);
381                 }
382                 else
383                 {
384                     _sqlResponseCallbacks.Add(providerId, sqlCallbacks);
385                     sqlRegistered = true;
386                 }
387
388                 sqlBulkCallbacks = new Interop.DataControl.SqlBulkInsertResponseCallback(BulkInsertResponse);
389                 ret = Interop.DataControl.RegisterSqlBulkResponseCallback(handle, sqlBulkCallbacks, IntPtr.Zero);
390                 if (ret != ResultType.Success)
391                 {
392                     Log.Error(LogTag, "Registering the sql bulk callback function is failed : " + ret);
393                 }
394                 else
395                 {
396                     _sqlBulkResponseCallback.Add(providerId, sqlBulkCallbacks);
397                 }
398
399                 mapCallbacks.Add = new Interop.DataControl.MapAddResponseCallback(MapAddResponse);
400                 mapCallbacks.Set = new Interop.DataControl.MapSetResponseCallback(MapSetResponse);
401                 mapCallbacks.Get = new Interop.DataControl.MapGetResponseCallback(MapGetResponse);
402                 mapCallbacks.Remove = new Interop.DataControl.MapRemoveResponseCallback(MapRemoveResponse);
403                 ret = Interop.DataControl.RegisterMapResponse(handle, ref mapCallbacks, IntPtr.Zero);
404
405                 if (ret != ResultType.Success)
406                 {
407                     Log.Error(LogTag, "Registering the map callback function is failed : " + ret);
408                 }
409                 else
410                 {
411                     _mapResponseCallbacks.Add(providerId, mapCallbacks);
412                     mapRegistered = true;
413                 }
414
415                 mapBulkCallbacks = new Interop.DataControl.MapBulkAddResponseCallback(MapBulkAddResponse);
416                 ret = Interop.DataControl.RegisterMapBulkResponseCallback(handle, mapBulkCallbacks, IntPtr.Zero);
417                 if (ret != ResultType.Success)
418                 {
419                     Log.Error(LogTag, "Registering the map bulk callback function is failed : " + ret);
420                 }
421                 else
422                 {
423                     _mapBulkResponseCallback.Add(providerId, mapBulkCallbacks);
424                 }
425
426                 if (!mapRegistered && !sqlRegistered)
427                 {
428                     ErrorFactory.ThrowException(ret, true, "Registering the response callback function is failed");
429                 }
430
431                 _reqProviderList.Add(providerId, 1);
432             }
433
434             internal static void UnregisterCallback(Interop.DataControl.SafeDataControlHandle handle, string providerId)
435             {
436                 int count;
437
438                 _reqProviderList[providerId]--;
439                 count = _reqProviderList[providerId];
440                 if (count <= 0)
441                 {
442                     _reqProviderList.Remove(providerId);
443
444                     _mapResponseCallbacks.Remove(providerId);
445                     Interop.DataControl.UnregisterMapResponse(handle);
446
447                     _mapBulkResponseCallback.Remove(providerId);
448                     Interop.DataControl.UnregisterMapBulkResponseCallback(handle);
449
450                     _sqlResponseCallbacks.Remove(providerId);
451                     Interop.DataControl.UnregisterSqlResponseCallback(handle);
452
453                     _sqlBulkResponseCallback.Remove(providerId);
454                     Interop.DataControl.UnregisterSqlBulkResponseCallback(handle);
455                 }
456
457             }
458         }
459
460         /// <summary>
461         /// Sends the insert request to the provider application.
462         /// </summary>
463         /// <remarks>The OnInsertResult will recieve the result of this API.</remarks>
464         /// <param name="insertData">The insert data.</param>
465         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
466         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
467         /// <exception cref="ArgumentOutOfRangeException">Thrown when the message has exceeded the maximum limit (1MB).</exception>
468         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
469         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
470         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
471         /// <since_tizen> 3 </since_tizen>
472         public void Insert(Bundle insertData)
473         {
474             int reqId;
475             ResultType ret;
476
477             if (insertData == null || insertData.SafeBundleHandle.IsInvalid)
478             {
479                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "insertData");
480             }
481
482             _lock.WaitOne();
483             ret = Interop.DataControl.Insert(_handle, insertData.SafeBundleHandle, out reqId);
484             _lock.ReleaseMutex();
485             if (ret != ResultType.Success)
486             {
487                 ErrorFactory.ThrowException(ret, false, "Insert");
488             }
489
490             CallbackManager.RegisterReqId(reqId, this);
491         }
492
493         /// <summary>
494         /// Sends the select request to the provider application.
495         /// </summary>
496         /// <remarks>The OnSelectResult will recieve the result of this API.</remarks>
497         /// <param name="columnList">Select the target column list.</param>
498         /// <param name="where">The Where statement for the select query.</param>
499         /// <param name="order">The Order statement for the select query.</param>
500         /// <param name="pageNumber">Select the target page number.</param>
501         /// <param name="countPerPage">Select the row count per page.</param>
502         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
503         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied..</exception>
504         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
505         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
506         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
507         /// <since_tizen> 3 </since_tizen>
508         public void Select(string[] columnList, string where, string order, int pageNumber = 1, int countPerPage = 20)
509         {
510             int reqId, i;
511             ResultType ret;
512             if (columnList == null || columnList.Length == 0)
513             {
514                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "column_list");
515             }
516
517             for (i = 0; i < columnList.Length; i++)
518             {
519                 if (string.IsNullOrEmpty(columnList[i]))
520                 {
521                     ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "column_list index " + i.ToString());
522                 }
523             }
524
525             _lock.WaitOne();
526             ret = Interop.DataControl.Select(_handle, columnList, columnList.Length, where, order, pageNumber, countPerPage, out reqId);
527             _lock.ReleaseMutex();
528             if (ret != ResultType.Success)
529             {
530                 ErrorFactory.ThrowException(ret, false, "Select");
531             }
532             Log.Info(LogTag, "select end. " + reqId.ToString());
533
534             CallbackManager.RegisterReqId(reqId, this);
535         }
536
537         /// <summary>
538         /// Sends the delete request to the provider application.
539         /// </summary>
540         /// <remarks>The OnDeleteResult will recieve the result of this API</remarks>
541         /// <param name="where">The Where statement for the delete query.</param>
542         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
543         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
544         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
545         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
546         /// <since_tizen> 3 </since_tizen>
547         public void Delete(string where)
548         {
549             int reqId;
550             ResultType ret;
551
552             _lock.WaitOne();
553             ret = Interop.DataControl.Delete(_handle, where, out reqId);
554             _lock.ReleaseMutex();
555             if (ret != ResultType.Success)
556             {
557                 ErrorFactory.ThrowException(ret, false, "Delete");
558             }
559
560             CallbackManager.RegisterReqId(reqId, this);
561         }
562
563         /// <summary>
564         /// Sends the update request to the provider application.
565         /// </summary>
566         /// <remarks>The OnUpdateResult will recieve result of this API.</remarks>
567         /// <param name="updateData">The update data.</param>
568         /// <param name="where">The Where statement for the query.</param>
569         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
570         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
571         /// <exception cref="ArgumentOutOfRangeException">Thrown when the message has exceeded the maximum limit (1MB).</exception>
572         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
573         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
574         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
575         /// <since_tizen> 3 </since_tizen>
576         public void Update(Bundle updateData, string where)
577         {
578             int reqId;
579             ResultType ret;
580
581             if (updateData == null || updateData.SafeBundleHandle.IsInvalid)
582             {
583                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "insertData");
584             }
585
586             if (string.IsNullOrEmpty(where))
587             {
588                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "where");
589             }
590
591             _lock.WaitOne();
592             ret = Interop.DataControl.Update(_handle, updateData.SafeBundleHandle, where, out reqId);
593             _lock.ReleaseMutex();
594             if (ret != ResultType.Success)
595             {
596                 ErrorFactory.ThrowException(ret, false, "Update");
597             }
598
599             CallbackManager.RegisterReqId(reqId, this);
600         }
601
602         /// <summary>
603         /// Sends the bulk insert request to the provider application.
604         /// </summary>
605         /// <remarks>The OnBulkInsertResult will recieve the result of this API.</remarks>
606         /// <param name="insertData">The bulk insert data.</param>
607         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
608         /// <exception cref="UnauthorizedAccessException">Thrown in case oif a permission is denied.</exception>
609         /// <exception cref="ArgumentOutOfRangeException">Thrown when the message has exceeded the maximum limit (1MB).</exception>
610         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
611         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
612         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
613         /// <since_tizen> 3 </since_tizen>
614         public void BulkInsert(BulkData insertData)
615         {
616             int reqId;
617             ResultType ret;
618
619             if (insertData == null || insertData.SafeBulkDataHandle.IsInvalid)
620             {
621                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "insertData");
622             }
623
624             _lock.WaitOne();
625             ret = Interop.DataControl.BulkInsert(_handle, insertData.SafeBulkDataHandle, out reqId);
626             _lock.ReleaseMutex();
627             if (ret != ResultType.Success)
628             {
629                 ErrorFactory.ThrowException(ret, false, "BulkInsert");
630             }
631
632             CallbackManager.RegisterReqId(reqId, this);
633         }
634
635         /// <summary>
636         /// Sends the map add request to the provider application.
637         /// </summary>
638         /// <remarks>The OnMapAddResult will recieve the result of this API.</remarks>
639         /// <param name="key">The key of the value to add.</param>
640         /// <param name="value">The value to add.</param>
641         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
642         /// <exception cref="UnauthorizedAccessException">Thrown in case of if a permission is denied.</exception>
643         /// <exception cref="ArgumentOutOfRangeException">Thrown when the message has exceeded the maximum limit (1MB).</exception>
644         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
645         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
646         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
647         /// <since_tizen> 3 </since_tizen>
648         public void MapAdd(string key, string value)
649         {
650             int reqId;
651             ResultType ret;
652
653             if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
654             {
655                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
656             }
657
658             _lock.WaitOne();
659             ret = Interop.DataControl.MapAdd(_handle, key, value, out reqId);
660             _lock.ReleaseMutex();
661             if (ret != ResultType.Success)
662             {
663                 ErrorFactory.ThrowException(ret, false, "MapAdd");
664             }
665
666             CallbackManager.RegisterReqId(reqId, this);
667         }
668
669         /// <summary>
670         /// Sends the map get request to the provider application.
671         /// </summary>
672         /// <remarks>The OnMapGetResult will recieve the result of this API.</remarks>
673         /// <param name="key">The key of the value list to obtain.</param>
674         /// <param name="pageNumber">The page number of the value set.</param>
675         /// <param name="countPerPage">The desired maximum count of the data items per page.</param>
676         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
677         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
678         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
679         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
680         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
681         /// <since_tizen> 3 </since_tizen>
682         public void MapGet(string key, int pageNumber = 1, int countPerPage = 20)
683         {
684             int reqId;
685             ResultType ret;
686
687             if (string.IsNullOrEmpty(key) || pageNumber <= 0 || countPerPage <= 0)
688             {
689                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
690             }
691
692             _lock.WaitOne();
693             ret = Interop.DataControl.MapGet(_handle, key, out reqId, pageNumber, countPerPage);
694             _lock.ReleaseMutex();
695             if (ret != ResultType.Success)
696             {
697                 ErrorFactory.ThrowException(ret, false, "MapGet");
698             }
699
700             CallbackManager.RegisterReqId(reqId, this);
701         }
702
703         /// <summary>
704         /// Sends the map remove request to the provider application.
705         /// </summary>
706         /// <remarks>The OnMapRemoveResult will recieve the result of this API.</remarks>
707         /// <param name="key">The key of the value to remove.</param>
708         /// <param name="value">The value to remove.</param>
709         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
710         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
711         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
712         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
713         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
714         /// <since_tizen> 3 </since_tizen>
715         public void MapRemove(string key, string value)
716         {
717             int reqId;
718             ResultType ret;
719
720             if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
721             {
722                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
723             }
724
725             _lock.WaitOne();
726             ret = Interop.DataControl.MapRemove(_handle, key, value, out reqId);
727             _lock.ReleaseMutex();
728             if (ret != ResultType.Success)
729             {
730                 ErrorFactory.ThrowException(ret, false, "MapRemove");
731             }
732
733             CallbackManager.RegisterReqId(reqId, this);
734         }
735
736         /// <summary>
737         /// Sends the map set request to the provider application.
738         /// </summary>
739         /// <remarks>The OnMapSetResult will recieve the result of this API.</remarks>
740         /// <param name="key">The key of the value to replace.</param>
741         /// <param name="oldValue">The value to be replaced.</param>
742         /// <param name="newValue"> The new value that replaces the existing value.</param>
743         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
744         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
745         /// <exception cref="ArgumentOutOfRangeException">Thrown when message has exceeded the maximum limit (1MB).</exception>
746         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
747         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
748         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
749         /// <since_tizen> 3 </since_tizen>
750         public void MapSet(string key, string oldValue, string newValue)
751         {
752             int reqId;
753             ResultType ret;
754
755             if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(oldValue) || string.IsNullOrEmpty(newValue))
756             {
757                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
758             }
759
760             _lock.WaitOne();
761             ret = Interop.DataControl.MapSet(_handle, key, oldValue, newValue, out reqId);
762             _lock.ReleaseMutex();
763             if (ret != ResultType.Success)
764             {
765                 ErrorFactory.ThrowException(ret, false, "MapSet");
766             }
767
768             CallbackManager.RegisterReqId(reqId, this);
769         }
770
771         /// <summary>
772         /// Sends the map bulk add request to the provider application.
773         /// </summary>
774         /// <remarks>The OnMapBulkAddResult will recieve the result of this API.</remarks>
775         /// <param name="addData">The map bulk add data.</param>
776         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
777         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
778         /// <exception cref="ArgumentOutOfRangeException">Thrown when the message has exceeded the maximum limit (1MB).</exception>
779         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
780         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
781         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
782         /// <since_tizen> 3 </since_tizen>
783         public void MapBulkAdd(BulkData addData)
784         {
785             int reqId;
786             ResultType ret;
787
788             if (addData == null || addData.SafeBulkDataHandle.IsInvalid)
789             {
790                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "addData");
791             }
792
793             _lock.WaitOne();
794             ret = Interop.DataControl.BulkAdd(_handle, addData.SafeBulkDataHandle, out reqId);
795             _lock.ReleaseMutex();
796             if (ret != ResultType.Success)
797             {
798                 ErrorFactory.ThrowException(ret, false, "BulkAdd");
799             }
800
801             CallbackManager.RegisterReqId(reqId, this);
802         }
803
804         private void DataChange(IntPtr handle, ChangeType type, IntPtr data, IntPtr userData)
805         {
806             OnDataChange(type, new Bundle(new SafeBundleHandle(data, false)));
807         }
808
809         private void DataChangeListenResult(IntPtr handle, ResultType type, int callbackId, IntPtr userData)
810         {
811             OnDataChangeListenResult(new DataChangeListenResult(type));
812         }
813
814         /// <summary>
815         /// Listens the DataChange event.
816         /// </summary>
817         /// <remarks>The OnDataChangeListenResult will recieve the result of this API.</remarks>
818         /// <remarks>If success, the OnDataChange will recieve the DataChange event.</remarks>
819         /// <exception cref="UnauthorizedAccessException">Thrown in case if a permission is denied.</exception>
820         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
821         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
822         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
823         /// <since_tizen> 3 </since_tizen>
824         public void DataChangeListen()
825         {
826             ResultType ret;
827             _lock.WaitOne();
828             /* Only one callback is allowed for every obejct */
829             if (_changeCallbackID > 0)
830             {
831                 _lock.ReleaseMutex();
832                 return;
833             }
834             _dataChangeCallback = new Interop.DataControl.DataChangeCallback(DataChange);
835             _addCallbackResultCallback = new Interop.DataControl.AddCallbackResultCallback(DataChangeListenResult);
836             ret = Interop.DataControl.AddDataChangeCallback(_handle, _dataChangeCallback, IntPtr.Zero,
837                       _addCallbackResultCallback , IntPtr.Zero, out _changeCallbackID);
838             _lock.ReleaseMutex();
839             if (ret != ResultType.Success)
840             {
841                 ErrorFactory.ThrowException(ret, false, "DataChangeListen");
842             }
843         }
844
845         /// <summary>
846         /// Initializes the Consumer class with the providerId and the ataId.
847         /// </summary>
848         /// <param name="providerId">The DataControl Provider ID.</param>
849         /// <param name="dataId">The DataControl Data ID.</param>
850         /// <exception cref="ArgumentException">Thrown in case of an invalid parmaeter.</exception>
851         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
852         /// <since_tizen> 3 </since_tizen>
853         public Consumer(string providerId, string dataId)
854         {
855             ResultType ret;
856
857             if (string.IsNullOrEmpty(providerId))
858             {
859                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "providerId");
860             }
861
862             if (string.IsNullOrEmpty(dataId))
863             {
864                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "dataId");
865             }
866
867             ret = Interop.DataControl.DataControlCreate(out _handle);
868             if (ret != ResultType.Success)
869             {
870                 ErrorFactory.ThrowException(ret, false, "Creating data control handle is failed");
871             }
872
873             Interop.DataControl.DataControlSetProviderId(_handle, providerId);
874             Interop.DataControl.DataControlSetDataId(_handle, dataId);
875             CallbackManager.RegisterCallback(_handle, providerId);
876             _dataID = dataId;
877             _providerID = providerId;
878         }
879
880         /// <summary>
881         /// Destructor of the Consumer class.
882         /// </summary>
883         ~Consumer()
884         {
885             Dispose(false);
886         }
887
888         /// <summary>
889         /// Overrides this method if you want to handle the behavior when the DataChangeListen result is received.
890         /// </summary>
891         /// <since_tizen> 3 </since_tizen>
892         protected virtual void OnDataChangeListenResult(DataChangeListenResult result)
893         {
894             Log.Info(LogTag, "The OnDataChangeListenResult is not implemented.");
895         }
896
897         /// <summary>
898         /// Overrides this method if you want to handle the behavior when the data change event is received.
899         /// </summary>
900         /// <since_tizen> 3 </since_tizen>
901         protected virtual void OnDataChange(ChangeType type, Bundle data)
902         {
903             Log.Info(LogTag, "The OnDataChange is not implemented.");
904         }
905
906         /// <summary>
907         /// Overrides this method if you want to handle the behavior when the select response is received.
908         /// </summary>
909         /// <since_tizen> 3 </since_tizen>
910         protected abstract void OnSelectResult(SelectResult result);
911
912         /// <summary>
913         /// Overrides this method if you want to handle the behavior when the insert response is received.
914         /// </summary>
915         /// <since_tizen> 3 </since_tizen>
916         protected abstract void OnInsertResult(InsertResult result);
917
918         /// <summary>
919         /// Overrides this method if you want to handle the behavior when the update response is received.
920         /// </summary>
921         /// <since_tizen> 3 </since_tizen>
922         protected abstract void OnUpdateResult(UpdateResult result);
923
924         /// <summary>
925         /// Overrides this method if want to handle the behavior when the delete response is received.
926         /// </summary>
927         /// <since_tizen> 3 </since_tizen>
928         protected abstract void OnDeleteResult(DeleteResult result);
929         /// <summary>
930         /// Overrides this method if you want to handle the behavior when the BulkInsert response is received.
931         /// </summary>
932         /// <since_tizen> 3 </since_tizen>
933         protected virtual void OnBulkInsertResult(BulkInsertResult result)
934         {
935             Log.Info(LogTag, "The OnBulkInsertResult is not implemented.");
936         }
937
938         /// <summary>
939         /// Overrides this method if you want to handle the behavior when the map get response is received.
940         /// </summary>
941         /// <since_tizen> 3 </since_tizen>
942         protected virtual void OnMapGetResult(MapGetResult result)
943         {
944             Log.Info(LogTag, "The OnMapGetResult is not implemented.");
945         }
946
947         /// <summary>
948         /// Overrides this method if you want to handle the behavior when the map add response is received.
949         /// </summary>
950         /// <since_tizen> 3 </since_tizen>
951         protected virtual void OnMapAddResult(MapAddResult result)
952         {
953             Log.Info(LogTag, "The OnMapAddResult is not implemented.");
954         }
955
956         /// <summary>
957         /// Overrides this method if you want to handle the behavior when the map set response is received.
958         /// </summary>
959         /// <since_tizen> 3 </since_tizen>
960         protected virtual void OnMapSetResult(MapSetResult result)
961         {
962             Log.Info(LogTag, "The OnMapSetResult is not implemented.");
963         }
964
965         /// <summary>
966         /// Overrides this method if you want to handle the behavior when the map remove response is received.
967         /// </summary>
968         /// <since_tizen> 3 </since_tizen>
969         protected virtual void OnMapRemoveResult(MapRemoveResult result)
970         {
971             Log.Info(LogTag, "The OnMapRemoveResult is not implemented.");
972         }
973
974         /// <summary>
975         /// Overrides this method if you want to handle the behavior when the BulkAdd response is received.
976         /// </summary>
977         /// <since_tizen> 3 </since_tizen>
978         protected virtual void OnMapBulkAddResult(MapBulkAddResult result)
979         {
980             Log.Info(LogTag, "The OnMapBulkAddResult is not implemented.");
981         }
982
983         /// <summary>
984         /// Releases the unmanaged resources used by the Consumer class specifying whether to perform a normal dispose operation.
985         /// </summary>
986         /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
987         /// <since_tizen> 3 </since_tizen>
988         protected virtual void Dispose(bool disposing)
989         {
990             if (!_disposed)
991             {
992                 if (_changeCallbackID > 0)
993                 {
994                     Interop.DataControl.RemoveDataChangeCallback(_handle, _changeCallbackID);
995                 }
996
997                 CallbackManager.UnregisterCallback(_handle, _providerID);
998                 _handle.Dispose();
999                 _disposed = true;
1000             }
1001
1002             if (disposing)
1003             {
1004                 GC.SuppressFinalize(this);
1005             }
1006         }
1007
1008         /// <summary>
1009         /// Releases all resources used by the Consumer class.
1010         /// </summary>
1011         /// <since_tizen> 3 </since_tizen>
1012         public void Dispose()
1013         {
1014             Dispose(true);
1015         }
1016     }
1017 }