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