Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_wearable / widget_interface_dao / dao / widget_interface_dao.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @author      Lukasz Marek (l.marek@samsung.com)
18  * @version     0.1
19  * @brief
20  */
21
22 #include <wrt-commons/widget-interface-dao/widget_interface_dao.h>
23 #include <string>
24 #include <sstream>
25 #include <fstream>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <dpl/db/sql_connection.h>
29 #include <dpl/log/log.h>
30 #include <dpl/foreach.h>
31 #include <dpl/string.h>
32 #include <dpl/wrt-dao-ro/property_dao_read_only.h>
33 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
34 #include <dpl/wrt-dao-ro/WrtDatabase.h>
35 #include <dpl/wrt-dao-ro/widget_config.h>
36 #include "orm_generator_widget_interface.h"
37
38 namespace WidgetInterfaceDB {
39 using namespace DPL::DB::ORM;
40 using namespace DPL::DB::ORM::widget_interface;
41
42 #define SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN          Try
43 #define SQL_CONNECTION_EXCEPTION_HANDLER_END(message)            \
44     Catch(DPL::DB::SqlConnection::Exception::Base) {             \
45         LogError(message);                                       \
46         ReThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError, \
47                    message);                                     \
48     }
49
50 namespace {
51 DPL::DB::SqlConnection::Flag::Type DATABASE_FLAG =
52     DPL::DB::SqlConnection::Flag::UseLucene;
53 DPL::DB::SqlConnection::Flag::Option DATABASE_OPTION =
54     DPL::DB::SqlConnection::Flag::RW;
55 const char *KEY_WIDGET_ARG = "widget_arg";
56
57 const char* const DATABASE_NAME = ".widget_interface.db";
58 const char* const DATABASE_FILE_PATH =
59     "/usr/share/wrt-engine/widget_interface_db.sql";
60 const char* const DATABASE_JOURNAL_FILENAME = "-journal";
61
62 const int APP_UID = 5000;
63 const int APP_GUID = 5000;
64 } // anonymous namespace
65
66 WidgetInterfaceDAO::WidgetInterfaceDAO(int widgetHandle) :
67     m_widgetHandle(widgetHandle),
68     m_databaseInterface(databaseFileName(widgetHandle), DATABASE_FLAG)
69 {
70     checkDatabase();
71     m_databaseInterface.AttachToThread(DATABASE_OPTION);
72 }
73
74 WidgetInterfaceDAO::~WidgetInterfaceDAO()
75 {
76     m_databaseInterface.DetachFromThread();
77 }
78
79 void WidgetInterfaceDAO::checkDatabase()
80 {
81     std::string databaseFile = databaseFileName(m_widgetHandle);
82     struct stat buffer;
83     if (stat(databaseFile.c_str(), &buffer) != 0) {
84         //Create fresh database
85         LogDebug("Creating database " << databaseFile);
86
87         std::fstream file;
88         file.open(DATABASE_FILE_PATH, std::ios_base::in);
89         if (!file) {
90             ThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError,
91                      "Cannot create database. SQL file is missing.");
92         }
93
94         std::stringstream stream;
95         stream << file.rdbuf();
96
97         file.close();
98
99         SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
100         {
101             DPL::DB::SqlConnection con(databaseFile,
102                                        DATABASE_FLAG,
103                                        DATABASE_OPTION);
104             con.ExecCommand(stream.str().c_str());
105             copyPropertiesFromWrtDatabase();
106         }
107         SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot create database")
108
109         if(chown(databaseFile.c_str(), APP_UID, APP_GUID) != 0) {
110             ThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError,
111                      "Fail to change uid/guid");
112         }
113         std::string databaseJournal =
114             databaseFile + DATABASE_JOURNAL_FILENAME;
115         if(chown(databaseJournal.c_str(), APP_UID, APP_GUID) != 0) {
116             ThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError,
117                      "Fail to change uid/guid");
118         }
119     }
120 }
121
122 void WidgetInterfaceDAO::copyPropertiesFromWrtDatabase()
123 {
124     WrtDB::WrtDatabase::attachToThreadRO();
125     m_databaseInterface.AttachToThread(DPL::DB::SqlConnection::Flag::RW);
126
127     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
128     {
129         WrtDB::PropertyDAOReadOnly::WidgetPreferenceList existing =
130             WrtDB::PropertyDAOReadOnly::GetPropertyList(
131                     WrtDB::WidgetDAOReadOnly::getTizenAppId(m_widgetHandle)
132         );
133
134         //save all properties read from config.xml
135         FOREACH(prop, existing) {
136             std::string key = DPL::ToUTF8String(prop->key_name);
137             if (key != KEY_WIDGET_ARG) {
138                 std::string value;
139                 if (!prop->key_value.IsNull()) {
140                     value = DPL::ToUTF8String(*(prop->key_value));
141                 }
142                 bool readonly = !prop->readonly.IsNull() && (*prop->readonly);
143                 setItem(key, value, readonly, true);
144             }
145         }
146     }
147     SQL_CONNECTION_EXCEPTION_HANDLER_END(
148         "Cannot copy properties read from config.xml");
149
150     WrtDB::WrtDatabase::detachFromThread();
151     m_databaseInterface.DetachFromThread();
152 }
153
154 void WidgetInterfaceDAO::setItem(const std::string& key,
155                                  const std::string& value,
156                                  bool readOnly)
157 {
158     setItem(key, value, readOnly, false);
159 }
160
161 void WidgetInterfaceDAO::setItem(const std::string& key,
162                                  const std::string& value,
163                                  bool readOnly,
164                                  bool fromConfigXml)
165 {
166     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
167     {
168         ScopedTransaction tran(&m_databaseInterface);
169         //check if key exists
170         Properties::Select select(&m_databaseInterface);
171         select.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
172         std::list<Properties::Row> rows = select.GetRowList();
173
174         if (rows.empty()) {
175             Properties::Insert insert(&m_databaseInterface);
176             Properties::Row row;
177             row.Set_key(DPL::FromUTF8String(key));
178             row.Set_value(DPL::FromUTF8String(value));
179             row.Set_readonly(readOnly ? 1 : 0);
180             row.Set_configxml(fromConfigXml ? 1 : 0);
181             insert.Values(row);
182             insert.Execute();
183         } else {
184             Assert(rows.size() == 1);
185             Properties::Row row = rows.front();
186             if (row.Get_readonly() != 0) {
187                 Throw(Exception::LocalStorageValueNoModifableException);
188             }
189             row.Set_value(DPL::FromUTF8String(value));
190             row.Set_readonly(readOnly ? 1 : 0);
191             Properties::Update update(&m_databaseInterface);
192             update.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
193             update.Values(row);
194             update.Execute();
195         }
196         tran.Commit();
197     }
198     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot set item");
199 }
200
201 void WidgetInterfaceDAO::removeItem(const std::string& key)
202 {
203     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
204     {
205         Properties::Select select(&m_databaseInterface);
206         select.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
207         bool readonly = select.GetSingleValue<Properties::readonly>();
208         if (readonly) {
209             ThrowMsg(Exception::LocalStorageValueNoModifableException,
210                      "Cannot delete item. Item is readonly");
211         }
212         Properties::Delete deleteItem(&m_databaseInterface);
213         deleteItem.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
214         deleteItem.Execute();
215     }
216     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot delete item");
217 }
218
219 DPL::Optional<std::string> WidgetInterfaceDAO::getValue(
220     const std::string& key) const
221 {
222     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
223     {
224         Properties::Select select(&m_databaseInterface);
225         select.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
226         std::list<DPL::String> value =
227             select.GetValueList<Properties::value>();
228         if (value.empty()) {
229             return DPL::Optional<std::string>();
230         }
231         return DPL::Optional<std::string>(DPL::ToUTF8String(value.front()));
232     }
233     SQL_CONNECTION_EXCEPTION_HANDLER_END("Not found item");
234 }
235
236 void WidgetInterfaceDAO::clear(bool removeReadOnly)
237 {
238     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
239     {
240         Properties::Delete deleteItem(&m_databaseInterface);
241         if (!removeReadOnly) {
242             deleteItem.Where(Equals<Properties::readonly>(0));
243         }
244         deleteItem.Execute();
245     }
246     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot delete all items");
247 }
248
249 size_t WidgetInterfaceDAO::getStorageSize() const
250 {
251     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
252     {
253         Properties::Select select(&m_databaseInterface);
254         std::list<DPL::String> list =
255             select.GetValueList<Properties::key>();
256         return list.size();
257     }
258     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count");
259 }
260
261 std::string WidgetInterfaceDAO::getKeyByIndex(size_t index) const
262 {
263     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
264     {
265         Properties::Select select(&m_databaseInterface);
266         select.OrderBy("key");
267         std::list<DPL::String> list = select.GetValueList<Properties::key>();
268         if (index >= list.size()) {
269             Throw(Exception::InvalidArgumentException);
270         }
271         for (size_t i = 0; i < index; ++i) {
272             list.pop_front();
273         }
274         return DPL::ToUTF8String(list.front());
275     }
276     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count");
277 }
278
279 std::string WidgetInterfaceDAO::databaseFileName(int widgetHandle)
280 {
281     using namespace DPL::DB::ORM;
282     using namespace WrtDB::WidgetConfig;
283
284     WrtDB::WrtDatabase::attachToThreadRO();
285     std::stringstream filename;
286     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
287     {
288         WrtDB::WidgetDAOReadOnly widgetDAO(widgetHandle);
289         WrtDB::TizenPkgId pkgid = widgetDAO.getTizenPkgId();
290
291         filename << GetWidgetPersistentStoragePath(pkgid)
292                  << "/"
293                  << DATABASE_NAME;
294     }
295     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count");
296     WrtDB::WrtDatabase::detachFromThread();
297     return filename.str();
298 }
299 } // namespace WidgetInterfaceDB