Fix building the package with GCC-4.8
[platform/framework/web/wrt-commons.git] / modules / 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(m_widgetHandle);
131
132         //save all properties read from config.xml
133         FOREACH(prop, existing) {
134             std::string key = DPL::ToUTF8String(prop->key_name);
135             if (key != KEY_WIDGET_ARG) {
136                 std::string value;
137                 if (!prop->key_value.IsNull()) {
138                     value = DPL::ToUTF8String(*(prop->key_value));
139                 }
140                 bool readonly = !prop->readonly.IsNull() && (*prop->readonly);
141                 setItem(key, value, readonly, true);
142             }
143         }
144     }
145     SQL_CONNECTION_EXCEPTION_HANDLER_END(
146         "Cannot copy properties read from config.xml");
147
148     WrtDB::WrtDatabase::detachFromThread();
149     m_databaseInterface.DetachFromThread();
150 }
151
152 void WidgetInterfaceDAO::setItem(const std::string& key,
153                                  const std::string& value,
154                                  bool readOnly)
155 {
156     setItem(key, value, readOnly, false);
157 }
158
159 void WidgetInterfaceDAO::setItem(const std::string& key,
160                                  const std::string& value,
161                                  bool readOnly,
162                                  bool fromConfigXml)
163 {
164     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
165     {
166         ScopedTransaction tran(&m_databaseInterface);
167         //check if key exists
168         Properties::Select select(&m_databaseInterface);
169         select.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
170         std::list<Properties::Row> rows = select.GetRowList();
171
172         if (rows.empty()) {
173             Properties::Insert insert(&m_databaseInterface);
174             Properties::Row row;
175             row.Set_key(DPL::FromUTF8String(key));
176             row.Set_value(DPL::FromUTF8String(value));
177             row.Set_readonly(readOnly ? 1 : 0);
178             row.Set_configxml(fromConfigXml ? 1 : 0);
179             insert.Values(row);
180             insert.Execute();
181         } else {
182             Assert(rows.size() == 1);
183             Properties::Row row = rows.front();
184             if (row.Get_readonly() != 0) {
185                 Throw(Exception::LocalStorageValueNoModifableException);
186             }
187             row.Set_value(DPL::FromUTF8String(value));
188             row.Set_readonly(readOnly ? 1 : 0);
189             Properties::Update update(&m_databaseInterface);
190             update.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
191             update.Values(row);
192             update.Execute();
193         }
194         tran.Commit();
195     }
196     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot set item");
197 }
198
199 void WidgetInterfaceDAO::removeItem(const std::string& key)
200 {
201     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
202     {
203         Properties::Select select(&m_databaseInterface);
204         select.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
205         bool readonly = select.GetSingleValue<Properties::readonly>();
206         if (readonly) {
207             ThrowMsg(Exception::LocalStorageValueNoModifableException,
208                      "Cannot delete item. Item is readonly");
209         }
210         Properties::Delete deleteItem(&m_databaseInterface);
211         deleteItem.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
212         deleteItem.Execute();
213     }
214     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot delete item");
215 }
216
217 DPL::Optional<std::string> WidgetInterfaceDAO::getValue(
218     const std::string& key) const
219 {
220     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
221     {
222         Properties::Select select(&m_databaseInterface);
223         select.Where(Equals<Properties::key>(DPL::FromUTF8String(key)));
224         std::list<DPL::String> value =
225             select.GetValueList<Properties::value>();
226         if (value.empty()) {
227             return DPL::Optional<std::string>();
228         }
229         return DPL::Optional<std::string>(DPL::ToUTF8String(value.front()));
230     }
231     SQL_CONNECTION_EXCEPTION_HANDLER_END("Not found item");
232 }
233
234 void WidgetInterfaceDAO::clear(bool removeReadOnly)
235 {
236     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
237     {
238         Properties::Delete deleteItem(&m_databaseInterface);
239         if (!removeReadOnly) {
240             deleteItem.Where(Equals<Properties::readonly>(0));
241         }
242         deleteItem.Execute();
243     }
244     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot delete all items");
245 }
246
247 size_t WidgetInterfaceDAO::getStorageSize() const
248 {
249     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
250     {
251         Properties::Select select(&m_databaseInterface);
252         std::list<DPL::String> list =
253             select.GetValueList<Properties::key>();
254         return list.size();
255     }
256     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count");
257 }
258
259 std::string WidgetInterfaceDAO::getKeyByIndex(size_t index) const
260 {
261     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
262     {
263         Properties::Select select(&m_databaseInterface);
264         select.OrderBy("key");
265         std::list<DPL::String> list = select.GetValueList<Properties::key>();
266         if (index >= list.size()) {
267             Throw(Exception::InvalidArgumentException);
268         }
269         for (size_t i = 0; i < index; ++i) {
270             list.pop_front();
271         }
272         return DPL::ToUTF8String(list.front());
273     }
274     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count");
275 }
276
277 std::string WidgetInterfaceDAO::databaseFileName(int widgetHandle)
278 {
279     using namespace DPL::DB::ORM;
280     using namespace WrtDB::WidgetConfig;
281
282     WrtDB::WrtDatabase::attachToThreadRO();
283     std::stringstream filename;
284     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
285     {
286         WrtDB::WidgetDAOReadOnly widgetDAO(widgetHandle);
287         WrtDB::TizenPkgId pkgid = widgetDAO.getTizenPkgId();
288
289         filename << GetWidgetPersistentStoragePath(pkgid)
290                  << "/"
291                  << DATABASE_NAME;
292     }
293     SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count");
294     WrtDB::WrtDatabase::detachFromThread();
295     return filename.str();
296 }
297 } // namespace WidgetInterfaceDB