de03469122994cfa613c086ce90d86afd1dfd22b
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.DataControl / Tizen.Applications.DataControl / Provider.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.IO;
18 using System.Text;
19 using System.Collections.Generic;
20 using Tizen.Applications.DataControl;
21 using System.Runtime.InteropServices;
22 using System.Threading;
23
24 namespace Tizen.Applications.DataControl
25 {
26     /// <summary>
27     /// Represents the Provider class for the DataControl provider application.
28     /// </summary>
29     /// <since_tizen> 3 </since_tizen>
30     public abstract class Provider : IDisposable
31     {
32         private const string LogTag = "Tizen.Applications.DataControl";
33         private static IDictionary<string, Provider> _providerDict = new Dictionary<string, Provider>();
34         private static Interop.DataControl.SqlRequestCallbacks _sqlRequestCallbacks;
35         private static Interop.DataControl.MapRequestCallbacks _mapRequestCallbacks;
36         private IntPtr _nativeHandle;
37         private static Interop.DataControl.DataChangeConsumerFilterCb _filterCallback;
38         private static int _filterCallbackID;
39         private static bool _filterRegistered;
40         private static Interop.DataControl.SqlBulkInsertRequestCallback _sqlBulkCallback;
41         private static Interop.DataControl.MapBulkAddRequestCallback _mapBulkCallback;
42         private static Mutex _lock = new Mutex();
43         private bool _disposed = false;
44         private bool _isRunning = false;
45
46         /// <summary>
47         /// Gets the data ID.
48         /// </summary>
49         /// <since_tizen> 3 </since_tizen>
50         public string DataID
51         {
52             get;
53             private set;
54         }
55
56         private static bool DataChangeListenFilter(IntPtr handlePtr, string consumerAppid, IntPtr userData)
57         {
58             Provider provider;
59             DataChangeListenResult result;
60
61             provider = GetProvider(handlePtr);
62             if (provider == null)
63             {
64                 Log.Error(LogTag, "Provider not exist ");
65                 return false;
66             }
67
68             result = provider.OnDataChangeListenRequest(consumerAppid);
69             if (result == null || result.Result != ResultType.Success)
70             {
71                 return false;
72             }
73             else
74             {
75                 return true;
76             }
77         }
78
79         private enum OperationType : short
80         {
81             Select,
82             Update,
83             Insert,
84             Delete
85         }
86
87         private static string CreateSelectQuery(IntPtr handlePtr, string[] columnList, int columnCount, string where, string order, int pageNum, int countPerPage)
88         {
89             Interop.DataControl.SafeDataControlHandle handle = new Interop.DataControl.SafeDataControlHandle(handlePtr, false);
90             string query = "SELECT";
91             string dataId;
92             if (columnList == null)
93             {
94                 query += " * ";
95             }
96             else
97             {
98                 for (int i = 0; i < columnCount; i++)
99                 {
100                     if (i != 0)
101                     {
102                         query += ",";
103                     }
104
105                     query += " " + columnList[i];
106                 }
107             }
108
109             Interop.DataControl.DataControlGetDataId(handle, out dataId);
110             query += " FROM " + dataId;
111             if (where != null)
112             {
113                 query += " WHERE " + where;
114             }
115
116             if (order != null)
117             {
118                 query += " ORDER BY " + order;
119             }
120
121             if (pageNum != 0)
122             {
123                 query += " LIMIT " + countPerPage + " OFFSET " + (countPerPage * (pageNum - 1));
124             }
125             handle.Dispose();
126             return query;
127         }
128
129         private static void InsertRequest(int requestId, IntPtr handlePtr, IntPtr insertData, IntPtr userData)
130         {
131             Provider provider;
132             InsertResult result;
133             SafeBundleHandle sbh = new SafeBundleHandle(insertData, false);
134             string query = GetQuery(handlePtr, sbh, null, OperationType.Update);
135             ResultType ret;
136
137             provider = GetProvider(handlePtr);
138             if (provider == null)
139             {
140                 Log.Error(LogTag, "Provider not exist ");
141                 return;
142             }
143
144             result = provider.OnInsert(query, new Bundle(sbh));
145             if (result != null)
146             {
147                 if (result.Result)
148                 {
149                     ret = Interop.DataControl.SendInsertResult(requestId, result.RowID);
150                     if (ret != ResultType.Success)
151                     {
152                         Log.Error(LogTag, "SendInsertResult fail " + ret.ToString());
153                     }
154                 }
155                 else
156                 {
157                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
158                     if (ret != ResultType.Success)
159                     {
160                         Log.Error(LogTag, "SendError fail " + ret.ToString());
161                     }
162                 }
163             }
164             else
165             {
166                 Log.Info(LogTag, $"InsertResult is null : {requestId.ToString()}");
167             }
168         }
169
170         private static void BulkInsertRequest(int requestId, IntPtr handlePtr, IntPtr bulk_data, IntPtr userData)
171         {
172             Provider provider;
173             BulkInsertResult result;
174             BulkData bulkData = new BulkData(new Interop.DataControl.SafeBulkDataHandle(bulk_data, false));
175             Interop.DataControl.SafeBulkDataHandle sbdh = bulkData.SafeBulkDataHandle;
176             IntPtr bundleHandel;
177             ResultType ret;
178
179             int count = bulkData.GetCount();
180             List<string> queryList = new List<string>();
181
182             for (int i = 0; i < count; i++)
183             {
184                 Interop.DataControl.BulkGetData(sbdh, i, out bundleHandel);
185                 queryList.Add(GetQuery(handlePtr, new SafeBundleHandle(bundleHandel, false), null, OperationType.Insert));
186             }
187
188             provider = GetProvider(handlePtr);
189             if (provider == null)
190             {
191                 Log.Error(LogTag, "Provider not exist ");
192                 return;
193             }
194
195             result = provider.OnBulkInsert(queryList, bulkData);
196             if (result != null)
197             {
198                 if (result.Result)
199                 {
200                     ret = Interop.DataControl.SendBulkInsertResult(requestId, result.BulkResultData.SafeBulkDataHandle);
201                     if (ret != ResultType.Success)
202                     {
203                         Log.Error(LogTag, "SendBulkInsertResult fail " + ret.ToString());
204                     }
205                 }
206                 else
207                 {
208                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
209                     if (ret != ResultType.Success)
210                     {
211                         Log.Error(LogTag, "SendError fail " + ret.ToString());
212                     }
213                 }
214
215                 if (result.BulkResultData != null)
216                 {
217                     result.BulkResultData.Dispose();
218                 }
219             }
220             else
221             {
222                 Log.Info(LogTag, $"BulkInsertResult is null : {requestId.ToString()}");
223             }
224         }
225
226         private static void SendNativeProtocol(int socketFd, ICursor cursor, int requestId)
227         {
228             uint write_len;
229             int DATACONTROL_RESULT_NO_DATA = -1;
230             int COLUMN_TYPE_NULL = 5;
231             int column_count, i, rowcount, size = 0, total_len_of_column_names = 0;
232             byte[] type_array, length_array, string_array, int_tmp, value_array = null;
233             string txt;
234             ResultType result;
235             MemoryStream ms;
236
237             if (cursor.Reset() == false)
238             {
239                 Log.Error(LogTag, "Reset is failed  :  " + requestId.ToString());
240                 return;
241             }
242
243             if (cursor.GetRowCount() <= 0)
244             {
245                 Log.Error(LogTag, "The DB does not have another row : " + requestId.ToString());
246                 int_tmp = BitConverter.GetBytes(DATACONTROL_RESULT_NO_DATA);
247                 result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, int_tmp, int_tmp.Length, out write_len);
248                 return;
249             }
250
251             /* 1. column count */
252             column_count = cursor.GetColumnCount();
253             int_tmp = BitConverter.GetBytes(column_count);
254             result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, int_tmp, int_tmp.Length, out write_len);
255             if (result != ResultType.Success)
256             {
257                 Log.Error(LogTag, "Writing a column_count to a file descriptor is failed.");
258                 return;
259             }
260
261             Log.Info(LogTag, "Writing a column_count " + column_count.ToString());
262
263             /* 2.column type x column_count */
264             for (i = 0; i < column_count; i++)
265             {
266                 type_array = BitConverter.GetBytes((int)cursor.GetColumnType(i));
267                 result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, type_array, type_array.Length, out write_len);
268                 if (result != ResultType.Success)
269                 {
270                     Log.Error(LogTag, "Writing a type to a file descriptor is failed.");
271                     return;
272                 }
273
274                 Log.Info(LogTag, "Writing a column_type " + cursor.GetColumnType(i).ToString());
275             }
276
277             /* 3. column name x column_count */
278             for (i = 0; i < column_count; i++)
279             {
280                 Log.Info(LogTag, "Writing a name " + cursor.GetColumnName(i));
281
282                 total_len_of_column_names += cursor.GetColumnName(i).Length;
283                 string_array = Encoding.UTF8.GetBytes(cursor.GetColumnName(i));
284                 value_array = new byte[string_array.Length + 1];/*insert null */
285                 string_array.CopyTo(value_array, 0);
286                 length_array = BitConverter.GetBytes(value_array.Length);
287
288                 result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, length_array, length_array.Length, out write_len);
289                 if (result != ResultType.Success)
290                 {
291                     Log.Error(LogTag, "Writing a type to a file descriptor is failed.");
292                     return;
293                 }
294
295                 result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, value_array, value_array.Length, out write_len);
296                 if (result != ResultType.Success)
297                 {
298                     Log.Error(LogTag, "Writing a type to a file descriptor is failed.");
299                     return;
300                 }
301
302             }
303
304             /* 4. total length of column names */
305             length_array = BitConverter.GetBytes(total_len_of_column_names);
306             result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, length_array, length_array.Length, out write_len);
307             if (result != ResultType.Success)
308             {
309                 Log.Error(LogTag, "Writing a total_len_of_column_names to a file descriptor is failed");
310                 return;
311             }
312
313             Log.Info(LogTag, "Writing  total length of column namese " + total_len_of_column_names.ToString());
314
315             /* 5. row count */
316             length_array = BitConverter.GetBytes(cursor.GetRowCount());
317             Log.Error(LogTag, "=========================== select rowcount " + cursor.GetRowCount().ToString());
318             result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, length_array, length_array.Length, out write_len);
319             if (result != ResultType.Success)
320             {
321                 Log.Error(LogTag, "Writing a row count to a file descriptor is failed");
322                 return;
323             }
324
325             Log.Error(LogTag, "Writing a row count " + cursor.GetRowCount().ToString());
326
327             rowcount = 0;
328             do
329             {
330                 ms = new MemoryStream();
331
332                 for (i = 0; i < column_count; i++)
333                 {
334                     type_array = BitConverter.GetBytes((int)cursor.GetColumnType(i));
335                     switch (cursor.GetColumnType(i))
336                     {
337                         case ColumnType.ColumnTypeInt:
338                             value_array = BitConverter.GetBytes(cursor.GetInt64Value(i));
339                             size = value_array.Length;
340                             break;
341
342                         case ColumnType.ColumnTypeDouble:
343                             value_array = BitConverter.GetBytes(cursor.GetDoubleValue(i));
344                             size = value_array.Length;
345                             break;
346
347                         case ColumnType.ColumnTypeString:
348                             txt = cursor.GetStringValue(i);
349                             if (txt == null)
350                             {
351                                 type_array = BitConverter.GetBytes(COLUMN_TYPE_NULL);
352                                 size = 0;
353                                 break;
354                             }
355
356                             string_array = Encoding.UTF8.GetBytes(txt);
357                             value_array = new byte[string_array.Length + 1];/*insert null */
358                             string_array.CopyTo(value_array, 0);
359                             size = value_array.Length;
360                             break;
361
362                         case ColumnType.ColumnTypeBlob:
363                             int_tmp = cursor.GetBlobValue(i);
364                             if (int_tmp == null)
365                             {
366                                 type_array = BitConverter.GetBytes(COLUMN_TYPE_NULL);
367                                 size = 0;
368                                 break;
369                             }
370
371                             value_array = int_tmp;
372                             size = value_array.Length;
373                             break;
374                     }
375
376                     ms.Write(type_array, 0, type_array.Length);
377
378                     length_array = BitConverter.GetBytes(size);
379                     ms.Write(length_array, 0, length_array.Length);
380                     if (size > 0)
381                     {
382                         ms.Write(value_array, 0, value_array.Length);
383                     }
384                 }
385
386                 value_array = ms.ToArray();
387
388                 result = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, value_array, value_array.Length, out write_len);
389                 if (result != ResultType.Success)
390                 {
391                     Log.Error(LogTag, "Writing a row to a file descriptor is failed");
392                     ms.Dispose();
393                     return;
394                 }
395
396                 ms.Dispose();
397                 Log.Info(LogTag, "row_count ~~~~ ", rowcount.ToString());
398
399             }
400             while (cursor.Next());
401         }
402
403         private static void SelectRequest(int requestId,
404             IntPtr handlePtr, IntPtr columnList, int columnCount, string where, string order, IntPtr userData)
405         {
406             Provider provider;
407             SelectResult result;
408             int pageNum = 0;
409             int countPerPage = 0;
410             int MAX_WRITE_SIZE = 1024;  /* 1kbyte */
411             string query = null;
412             int socketFd, write_size, i;
413             uint write_len;
414             ResultType ret;
415             string[] _columnList = new string[columnCount];
416             byte[] buffer;
417
418             unsafe
419             {
420                 byte** _sbyte_columnList = (byte**)columnList;
421
422                 for (i = 0; i < columnCount; i++)
423                 {
424                     _columnList[i] = Marshal.PtrToStringAnsi((IntPtr)_sbyte_columnList[i]);
425                 }
426             }
427
428             Interop.DataControl.GetSelectPageInfo(requestId, out pageNum, out countPerPage);
429             query = CreateSelectQuery(handlePtr, _columnList, _columnList.Length, where, order, pageNum, countPerPage);
430             provider = GetProvider(handlePtr);
431             if (provider == null)
432             {
433                 Log.Error(LogTag, "Provider not exist ");
434                 return;
435             }
436
437             result = provider.OnSelect(query, where, _columnList, _columnList.Length, order, pageNum, countPerPage);
438             if (result != null)
439             {
440                 if (result.Result)
441                 {
442                     Interop.DataControl.SendSelectResult(requestId, out socketFd);
443
444                     MatrixCursor mc = result.ResultCursor as MatrixCursor;
445
446                     if (mc == null)
447                     {
448                         SendNativeProtocol(socketFd, result.ResultCursor, requestId);
449                     }
450                     else
451                     {
452                         FileStream fs = mc.GetFileStream();
453                         fs.Seek(0, SeekOrigin.Begin);
454
455                         buffer = new byte[MAX_WRITE_SIZE];
456
457                         do
458                         {
459                             write_size = fs.Read(buffer, 0, MAX_WRITE_SIZE);
460
461                             if (write_size > 0)
462                             {
463                                 ret = (ResultType)Interop.DataControl.UnsafeCode.WriteResult(socketFd, buffer, write_size, out write_len);
464                                 if (ret != ResultType.Success)
465                                 {
466                                     Log.Error(LogTag, "Writing a row to a file descriptor is failed");
467                                     mc.Dispose();
468                                     return;
469                                 }
470                             }
471                         }
472                         while (write_size > 0);
473                         mc.Dispose();
474                     }
475
476                 }
477                 else
478                 {
479                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
480                     if (ret != ResultType.Success)
481                     {
482                         Log.Error(LogTag, "SendError fail " + ret.ToString());
483                     }
484                 }
485             }
486             else
487             {
488                 Log.Info(LogTag, $"SelectResult is null : {requestId.ToString()}");
489             }
490         }
491
492         private static void UpdateRequest(int requestId,
493             IntPtr handlePtr, IntPtr updateData, string where, IntPtr userData)
494         {
495             Provider provider;
496             UpdateResult result;
497             SafeBundleHandle sbh = new SafeBundleHandle(updateData, false);
498             string query = GetQuery(handlePtr, sbh, where, OperationType.Update);
499             ResultType ret;
500
501             provider = GetProvider(handlePtr);
502             if (provider == null)
503             {
504                 Log.Error(LogTag, "Provider not exist ");
505                 return;
506             }
507
508             result = provider.OnUpdate(query, where, new Bundle(sbh));
509             if (result != null)
510             {
511                 if (result.Result)
512                 {
513                     ret = Interop.DataControl.SendUpdateResult(requestId);
514                     if (ret != ResultType.Success)
515                     {
516                         Log.Error(LogTag, "SendUpdateResult fail " + ret.ToString());
517                     }
518                 }
519                 else
520                 {
521                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
522                     if (ret != ResultType.Success)
523                     {
524                         Log.Error(LogTag, "SendError fail " + ret.ToString());
525                     }
526                 }
527             }
528             else
529             {
530                 Log.Info(LogTag, $"UpdateResult is null : {requestId.ToString()}");
531             }
532         }
533
534         private static void DeleteRequest(int requestId,
535             IntPtr handlePtr, string where, IntPtr userData)
536         {
537             Provider provider;
538             DeleteResult result;
539             string query = GetQuery(handlePtr, null, where, OperationType.Delete);
540             ResultType ret;
541
542             provider = GetProvider(handlePtr);
543             if (provider == null)
544             {
545                 Log.Error(LogTag, "Provider not exist ");
546                 return;
547             }
548
549             result = provider.OnDelete(query, where);
550             if (result != null)
551             {
552                 if (result.Result)
553                 {
554                    ret = Interop.DataControl.SendDeleteResult(requestId);
555                     if (ret != ResultType.Success)
556                     {
557                         Log.Error(LogTag, "SendDeleteResult fail " + ret.ToString());
558                     }
559
560                 }
561                 else
562                 {
563                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
564                     if (ret != ResultType.Success)
565                     {
566                         Log.Error(LogTag, "SendError fail " + ret.ToString());
567                     }
568                 }
569             }
570             else
571             {
572                 Log.Info(LogTag, $"DeleteResult is null : {requestId.ToString()}");
573             }
574         }
575
576         private static void MapAddRequest(int requestId, IntPtr handlePtr, string key, string value, IntPtr userData)
577         {
578             Provider provider;
579             MapAddResult result;
580             ResultType ret;
581
582             provider = GetProvider(handlePtr);
583             if (provider == null)
584             {
585                 Log.Error(LogTag, "Provider not exist");
586                 return;
587             }
588
589             result = provider.OnMapAdd(key, value);
590             if (result != null)
591             {
592                 if (result.Result)
593                 {
594                     ret = Interop.DataControl.SendMapResult(requestId);
595                     if (ret != ResultType.Success)
596                     {
597                         Log.Error(LogTag, "SendMapResult fail " + ret.ToString());
598                     }
599                 }
600                 else
601                 {
602                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
603                     if (ret != ResultType.Success)
604                     {
605                         Log.Error(LogTag, "SendError fail " + ret.ToString());
606                     }
607                 }
608             }
609             else
610             {
611                 Log.Info(LogTag, $"MapAddResult is null : {requestId.ToString()}");
612             }
613         }
614
615         private static void MapSetRequest(int requestId, IntPtr handlePtr, string key, string oldValue, string newValue, IntPtr userData)
616         {
617             Provider provider;
618             MapSetResult result;
619             ResultType ret;
620
621             provider = GetProvider(handlePtr);
622             if (provider == null)
623             {
624                 Log.Error(LogTag, "Provider not exist");
625                 return;
626             }
627
628             result = provider.OnMapSet(key, oldValue, newValue);
629             if (result != null)
630             {
631                 if (result.Result)
632                 {
633                     ret = Interop.DataControl.SendMapResult(requestId);
634                     if (ret != ResultType.Success)
635                     {
636                         Log.Error(LogTag, "SendMapResult fail " + ret.ToString());
637                     }
638                 }
639                 else
640                 {
641                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
642                     if (ret != ResultType.Success)
643                     {
644                         Log.Error(LogTag, "SendError fail " + ret.ToString());
645                     }
646                 }
647             }
648             else
649             {
650                 Log.Info(LogTag, $"MapSetResult is null : {requestId.ToString()}");
651             }
652         }
653
654         private static void MapRemoveRequest(int requestId, IntPtr handlePtr, string key, string value, IntPtr userData)
655         {
656             Provider provider;
657             MapRemoveResult result;
658             ResultType ret;
659
660             provider = GetProvider(handlePtr);
661             if (provider == null)
662             {
663                 Log.Error(LogTag, "Provider not exist");
664                 return;
665             }
666
667             result = provider.OnMapRemove(key, value);
668             if (result != null)
669             {
670                 if (result.Result)
671                 {
672                     ret = Interop.DataControl.SendMapResult(requestId);
673                     if (ret != ResultType.Success)
674                     {
675                         Log.Error(LogTag, "SendMapResult fail " + ret.ToString());
676                     }
677
678                 }
679                 else
680                 {
681                     ret = Interop.DataControl.SendError(requestId, result.Result.ToString());
682                     if (ret != ResultType.Success)
683                     {
684                         Log.Error(LogTag, "SendError fail " + ret.ToString());
685                     }
686                 }
687             }
688             else
689             {
690                 Log.Info(LogTag, $"MapRemoveRequest is null : {requestId.ToString()}");
691             }
692         }
693
694         private static void MapGetRequest(int requestID, IntPtr handlePtr, string key, IntPtr userData)
695         {
696             Provider provider;
697             MapGetResult result;
698             ResultType ret;
699
700             provider = GetProvider(handlePtr);
701             if (provider == null)
702             {
703                 Log.Error(LogTag, "Provider not exist");
704                 return;
705             }
706
707             result = provider.OnMapGet(key);
708             if (result != null)
709             {
710                 if (result.Result)
711                 {
712                     int valueCount = 0;
713                     if (result.ValueList != null)
714                         valueCount = result.ValueList.Length;
715                     ret = Interop.DataControl.SendMapGetResult(requestID, result.ValueList, valueCount);
716                     if (ret != ResultType.Success)
717                     {
718                         Log.Error(LogTag, "SendMapGetResult fail " + ret.ToString());
719                     }
720
721                 }
722                 else
723                 {
724                     ret = Interop.DataControl.SendError(requestID, result.Result.ToString());
725                     if (ret != ResultType.Success)
726                     {
727                         Log.Error(LogTag, "SendError fail " + ret.ToString());
728                     }
729                 }
730             }
731             else
732             {
733                 Log.Info(LogTag, $"MapRemoveRequest is null : {requestID.ToString()}");
734             }
735         }
736
737         private static void MapBulkAddRequest(int requestID, IntPtr handlePtr, IntPtr bulkDataPtr, IntPtr userData)
738         {
739             Provider provider;
740             MapBulkAddResult result;
741             BulkData bulkData = new BulkData(new Interop.DataControl.SafeBulkDataHandle(bulkDataPtr, false));
742             Interop.DataControl.SafeBulkDataHandle sbdh = bulkData.SafeBulkDataHandle;
743             IntPtr bundleHandel;
744             int count = bulkData.GetCount();
745             List<string> queryList = new List<string>();
746             ResultType ret;
747
748             for (int i = 0; i < count; i++)
749             {
750                 Interop.DataControl.BulkGetData(sbdh, i, out bundleHandel);
751                 queryList.Add(GetQuery(handlePtr, new SafeBundleHandle(bundleHandel, false), null, OperationType.Insert));
752             }
753
754             provider = GetProvider(handlePtr);
755             if (provider == null)
756             {
757                 Log.Error(LogTag, "Provider not exist");
758                 return;
759             }
760
761             result = provider.OnMapBulkAdd(bulkData);
762             if (result != null)
763             {
764                 if (result.Result)
765                 {
766                     ret = Interop.DataControl.SendMapBulkAddResult(requestID, result.BulkResultData.SafeBulkDataHandle);
767                     if (ret != ResultType.Success)
768                     {
769                         Log.Error(LogTag, "SendMapBulkAddResult fail " + ret.ToString());
770                     }
771                 }
772                 else
773                 {
774                     ret = Interop.DataControl.SendError(requestID, result.Result.ToString());
775                     if (ret != ResultType.Success)
776                     {
777                         Log.Error(LogTag, "SendError fail " + ret.ToString());
778                     }
779                 }
780
781                 if (result.BulkResultData != null)
782                 {
783                     result.BulkResultData.Dispose();
784                 }
785             }
786             else
787             {
788                 Log.Info(LogTag, $"MapBulkAddRequest is null : {requestID.ToString()}");
789             }
790         }
791
792         private static string GetQuery(IntPtr handlePtr, SafeBundleHandle data, string where, OperationType type)
793         {
794             Interop.DataControl.SafeDataControlHandle handle = new Interop.DataControl.SafeDataControlHandle(handlePtr, false);
795             string query = null;
796
797             switch (type)
798             {
799                 case OperationType.Select:
800                     break;
801                 case OperationType.Update:
802                     query = Interop.DataControl.CreateUpdateStatement(handle, data, where);
803                     break;
804                 case OperationType.Delete:
805                     query = Interop.DataControl.CreateDeleteStatement(handle, where);
806                     break;
807                 case OperationType.Insert:
808                     query = Interop.DataControl.CreateInsertStatement(handle, data);
809                     break;
810                 default:
811                     break;
812             }
813             handle.Dispose();
814
815             return query;
816         }
817
818         private static Provider GetProvider(IntPtr handlePtr)
819         {
820             Interop.DataControl.SafeDataControlHandle handle = new Interop.DataControl.SafeDataControlHandle(handlePtr, false);
821             Provider provider = null;
822             string dataID;
823
824             Interop.DataControl.DataControlGetDataId(handle, out dataID);
825             if (dataID != null && _providerDict.ContainsKey(dataID))
826             {
827                 provider = _providerDict[dataID];
828                 provider._nativeHandle = handlePtr;
829                 Log.Info(LogTag, "DataID :" + dataID + ", hash code : " + provider.GetHashCode().ToString());
830             }
831             handle.Dispose();
832
833             return provider;
834         }
835
836         /// <summary>
837         /// Sends a data change notification to consumer applications which have successfully added a data change listen.
838         /// </summary>
839         /// <param name="type">The changed data type.</param>
840         /// <param name="changedData">Customized information about the changed data.</param>
841         /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
842         /// <exception cref="UnauthorizedAccessException">Thrown in case a permission is denied.</exception>
843         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
844         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
845         /// <since_tizen> 3 </since_tizen>
846         public void SendDataChange(ChangeType type, Bundle changedData)
847         {
848             ResultType ret;
849
850             if (changedData == null || changedData.SafeBundleHandle.IsInvalid)
851             {
852                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "changedData");
853             }
854
855             if (this._nativeHandle == IntPtr.Zero)
856             {
857                 return;
858             }
859
860             ret = Interop.DataControl.SendDataChange(this._nativeHandle, type, changedData.SafeBundleHandle);
861             if (ret != ResultType.Success)
862             {
863                 ErrorFactory.ThrowException(ret, false);
864             }
865         }
866
867         /// <summary>
868         /// Initializes the Provider class with the dataID.
869         /// </summary>
870         /// <param name="dataID">The DataControl Data ID.</param>
871         /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
872         /// <since_tizen> 3 </since_tizen>
873         public Provider(string dataID)
874         {
875             if (string.IsNullOrEmpty(dataID))
876             {
877                 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "dataID");
878             }
879
880             DataID = dataID;
881         }
882
883         /// <summary>
884         /// Starts the Provider service.
885         /// </summary>
886         /// <remarks>Only one Provider service can be run for each process.</remarks>
887         /// <exception cref="UnauthorizedAccessException">Thrown in case a permission is denied.</exception>
888         /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
889         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
890         /// <since_tizen> 3 </since_tizen>
891         public void Run()
892         {
893             ResultType ret;
894             _lock.WaitOne();
895             if (_providerDict.ContainsKey(DataID))
896             {
897                 _lock.ReleaseMutex();
898                 ErrorFactory.ThrowException((ResultType)1, true, "The provider is already running");
899                 return;
900             }
901
902             if (_providerDict.Count == 0)
903             {
904                 Log.Debug(LogTag, "Provider create");
905
906                 _sqlRequestCallbacks.Insert = new Interop.DataControl.SqlInsertRequestCallback(InsertRequest);
907                 _sqlRequestCallbacks.Select = new Interop.DataControl.SqlSelectRequestCallback(SelectRequest);
908                 _sqlRequestCallbacks.Update = new Interop.DataControl.SqlUpdateRequestCallback(UpdateRequest);
909                 _sqlRequestCallbacks.Delete = new Interop.DataControl.SqlDeleteRequestCallback(DeleteRequest);
910
911                 ret = Interop.DataControl.RegisterSqlRequest(ref _sqlRequestCallbacks, IntPtr.Zero);
912                 if (ret != ResultType.Success)
913                 {
914                     _lock.ReleaseMutex();
915                     ErrorFactory.ThrowException(ret, false);
916                 }
917
918                 _sqlBulkCallback = new Interop.DataControl.SqlBulkInsertRequestCallback(BulkInsertRequest);
919                 ret = Interop.DataControl.RegisterSqlBulkRequest(_sqlBulkCallback, IntPtr.Zero);
920                 if (ret != ResultType.Success)
921                 {
922                     _lock.ReleaseMutex();
923                     ErrorFactory.ThrowException(ret, false);
924                 }
925
926                 _mapRequestCallbacks.Add = new Interop.DataControl.MapAddRequestCallback(MapAddRequest);
927                 _mapRequestCallbacks.Remove = new Interop.DataControl.MapRemoveRequestCallback(MapRemoveRequest);
928                 _mapRequestCallbacks.Set = new Interop.DataControl.MapSetRequestCallback(MapSetRequest);
929                 _mapRequestCallbacks.Get = new Interop.DataControl.MapGetRequestCallback(MapGetRequest);
930                 ret = Interop.DataControl.RegisterMapRequest(ref _mapRequestCallbacks, IntPtr.Zero);
931                 if (ret != ResultType.Success)
932                 {
933                     _lock.ReleaseMutex();
934                     ErrorFactory.ThrowException(ret, false);
935                 }
936
937                 _mapBulkCallback = new Interop.DataControl.MapBulkAddRequestCallback(MapBulkAddRequest);
938                 ret = Interop.DataControl.RegisterMapBulkRequest(_mapBulkCallback, IntPtr.Zero);
939                 if (ret != ResultType.Success)
940                 {
941                     _lock.ReleaseMutex();
942                     ErrorFactory.ThrowException(ret, false);
943                 }
944
945                 if (_filterRegistered == false)
946                 {
947                     if (_filterCallback == null)
948                         _filterCallback = new Interop.DataControl.DataChangeConsumerFilterCb(DataChangeListenFilter);
949
950                     ret = Interop.DataControl.AddDataChangeConsumerFilterCallback(
951                          _filterCallback,
952                          IntPtr.Zero, out _filterCallbackID);
953
954                     if (ret != ResultType.Success)
955                     {
956                         _lock.ReleaseMutex();
957                         ErrorFactory.ThrowException(ret, false);
958                     }
959                 }
960
961                 _filterRegistered = true;
962             }
963
964             _providerDict.Add(DataID, this);
965             Log.Info(LogTag, "DataID :" + DataID + ", hash code : " + this.GetHashCode().ToString());
966             _isRunning = true;
967             _lock.ReleaseMutex();
968         }
969
970         /// <summary>
971         /// Stops the Provider service.
972         /// </summary>
973         /// <since_tizen> 3 </since_tizen>
974         public void Stop()
975         {
976             if (_isRunning == true)
977             {
978                 Log.Info(LogTag, "DataID :" + DataID);
979                 _isRunning = false;
980                 _providerDict.Remove(DataID);
981             }
982         }
983
984         /// <summary>
985         /// Destructor of the Provider class.
986         /// </summary>
987         ~Provider()
988         {
989             Dispose(false);
990         }
991
992         /// <summary>
993         /// Overrides this method if you want to handle the behavior when the select request is received.
994         /// </summary>
995         /// <since_tizen> 3 </since_tizen>
996         protected abstract SelectResult OnSelect(string query, string where, string[] columList, int columnCount, string order, int pageNum, int countPerPage);
997
998         /// <summary>
999         /// Overrides this method if you want to handle the behavior when the insert request is received.
1000         /// </summary>
1001         /// <since_tizen> 3 </since_tizen>
1002         protected abstract InsertResult OnInsert(string query, Bundle insertData);
1003
1004         /// <summary>
1005         /// Overrides this method if you want to handle the behavior when the update request is received.
1006         /// </summary>
1007         /// <since_tizen> 3 </since_tizen>
1008         protected abstract UpdateResult OnUpdate(string query, string where, Bundle updateData);
1009
1010         /// <summary>
1011         /// Overrides this method if you want to handle the behavior when the delete request is received.
1012         /// </summary>
1013         /// <since_tizen> 3 </since_tizen>
1014         protected abstract DeleteResult OnDelete(string query, string where);
1015
1016         /// <summary>
1017         /// Overrides this method if you want to handle the behavior when the bulk insert request is received.
1018         /// </summary>
1019         /// <since_tizen> 3 </since_tizen>
1020         protected virtual BulkInsertResult OnBulkInsert(IEnumerable<string> query, BulkData bulkInsertData)
1021         {
1022             Log.Info(LogTag, "The OnBulkInsert is not implemented.");
1023             return null;
1024         }
1025
1026         /// <summary>
1027         /// Overrides this method if you want to handle the behavior when the map get request is received.
1028         /// </summary>
1029         /// <since_tizen> 3 </since_tizen>
1030         protected virtual MapGetResult OnMapGet(string key)
1031         {
1032             Log.Info(LogTag, "The OnMapGet is not implemented.");
1033             return null;
1034         }
1035
1036         /// <summary>
1037         /// Overrides this method if you want to handle the behavior when the map add request is received.
1038         /// </summary>
1039         /// <since_tizen> 3 </since_tizen>
1040         protected virtual MapAddResult OnMapAdd(string key, string value)
1041         {
1042             Log.Info(LogTag, "The OnMapAdd is not implemented.");
1043             return null;
1044         }
1045
1046         /// <summary>
1047         /// Overrides this method if you want to handle the behavior when the update request is received.
1048         /// </summary>
1049         /// <since_tizen> 3 </since_tizen>
1050         protected virtual MapSetResult OnMapSet(string key, string oldValue, string newValue)
1051         {
1052             Log.Info(LogTag, "The OnMapSet is not implemented.");
1053             return null;
1054         }
1055
1056         /// <summary>
1057         /// Overrides this method if you want to handle the behavior when the delete request is received.
1058         /// </summary>
1059         /// <since_tizen> 3 </since_tizen>
1060         protected virtual MapRemoveResult OnMapRemove(string key, string value)
1061         {
1062             Log.Info(LogTag, "The OnMapRemove is not implemented.");
1063             return null;
1064         }
1065
1066         /// <summary>
1067         /// Overrides this method if you want to handle the behavior when the bulk add request is received.
1068         /// </summary>
1069         /// <since_tizen> 3 </since_tizen>
1070         protected virtual MapBulkAddResult OnMapBulkAdd(BulkData bulkAddData)
1071         {
1072             Log.Info(LogTag, "The OnMapBulkAdd is not implemented.");
1073             return null;
1074         }
1075
1076         /// <summary>
1077         /// Overrides this method if you want to handle the behavior when the data change listen request is received.
1078         /// </summary>
1079         /// <since_tizen> 3 </since_tizen>
1080         protected virtual DataChangeListenResult OnDataChangeListenRequest(string requestAppID)
1081         {
1082             Log.Info(LogTag, "The OnDataChangeListenRequest is not implemented.");
1083             return null;
1084         }
1085
1086         /// <summary>
1087         /// Releases unmanaged resources used by the Provider class specifying whether to perform a normal dispose operation.
1088         /// </summary>
1089         /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
1090         /// <since_tizen> 3 </since_tizen>
1091         protected virtual void Dispose(bool disposing)
1092         {
1093             if (!_disposed)
1094             {
1095                 Stop();
1096                 _disposed = true;
1097             }
1098             if (disposing)
1099             {
1100                 GC.SuppressFinalize(this);
1101             }
1102         }
1103
1104         /// <summary>
1105         /// Releases all the resources used by the Provider class.
1106         /// </summary>
1107         /// <since_tizen> 3 </since_tizen>
1108         public void Dispose()
1109         {
1110             Dispose(true);
1111         }
1112     }
1113 }