pull in new policy updates
[profile/ivi/smartdevicelink.git] / src / components / policy / src / policy / src / sql_pt_representation.cc
1 /*
2  Copyright (c) 2013, Ford Motor Company
3  All rights reserved.
4
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7
8  Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10
11  Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following
13  disclaimer in the documentation and/or other materials provided with the
14  distribution.
15
16  Neither the name of the Ford Motor Company nor the names of its contributors
17  may be used to endorse or promote products derived from this software
18  without specific prior written permission.
19
20  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sstream>
34 #include "utils/logger.h"
35 #include "policy/sql_pt_representation.h"
36 #include "policy/sql_wrapper.h"
37 #include "policy/sql_pt_queries.h"
38 #ifndef __QNX__
39 #  include "config_profile/profile.h"
40 #endif  // __QNX__
41
42 namespace policy {
43
44 CREATE_LOGGERPTR_GLOBAL(logger_, "SQLPTRepresentation")
45
46 namespace {
47 template<typename T, typename K> void InsertUnique(K value, T* array) {
48   int i = 0;
49   for (; i < array->size() && array->at(i) != value; ++i) {
50     continue;
51   }
52   if (array->size() == i) {
53     array->push_back(value);
54   }
55 }
56 }  //  namespace
57
58
59 const std::string SQLPTRepresentation::kDatabaseName = "policy";
60
61 SQLPTRepresentation::SQLPTRepresentation()
62   : db_(new dbms::SQLDatabase(kDatabaseName)) {
63 #ifndef __QNX__
64   std::string path = profile::Profile::instance()->app_storage_folder();
65   if (!path.empty()) {
66     db_->set_path(path + "/");
67   }
68 #endif  // __QNX__
69 }
70
71 SQLPTRepresentation::~SQLPTRepresentation() {
72   db_->Close();
73   delete db_;
74 }
75
76 CheckPermissionResult SQLPTRepresentation::CheckPermissions(
77   const PTString& app_id, const PTString& hmi_level, const PTString& rpc) {
78   CheckPermissionResult result;
79   dbms::SQLQuery query(db());
80
81   if (!query.Prepare(sql_pt::kSelectRpc)) {
82     LOG4CXX_WARN(
83       logger_,
84       "Incorrect select statement from rpcs" << query.LastError().text());
85     return result;
86   }
87   query.Bind(0, app_id);
88   query.Bind(1, hmi_level);
89   query.Bind(2, rpc);
90
91   bool ret = query.Next();
92   result.hmi_level_permitted = ret ? kRpcAllowed : kRpcDisallowed;
93   LOG4CXX_INFO(
94     logger_,
95     "Level is "
96     << (result.hmi_level_permitted == kRpcAllowed ? "permitted" : "not permitted"));
97   std::string parameter;
98   while (ret) {
99     if (!query.IsNull(0)) {
100       if (!result.list_of_allowed_params) {
101         result.list_of_allowed_params = new std::vector<PTString>();
102       }
103       parameter = query.GetString(0);
104       result.list_of_allowed_params->push_back(parameter);
105     }
106     ret = query.Next();
107   }
108
109   return result;
110 }
111
112 bool SQLPTRepresentation::IsPTPreloaded() {
113   dbms::SQLQuery query(db());
114   return query.Prepare(sql_pt::kSelectPreloaded) && query.Next();
115 }
116
117 int SQLPTRepresentation::IgnitionCyclesBeforeExchange() {
118   dbms::SQLQuery query(db());
119   if (!query.Prepare(sql_pt::kSelectIgnitionCycles) || !query.Exec()) {
120     LOG4CXX_WARN(logger_, "Can not select ignition cycles");
121     return 0;
122   }
123   int limit = query.GetInteger(0);
124   int current = query.GetInteger(1);
125
126   if (limit < 0 || current < 0 || current > limit) {
127     return 0;
128   }
129
130   return limit - current;
131 }
132
133 int SQLPTRepresentation::KilometersBeforeExchange(int current) {
134   dbms::SQLQuery query(db());
135   if (!query.Prepare(sql_pt::kSelectKilometers) || !query.Exec()) {
136     LOG4CXX_WARN(logger_, "Can not select kilometers");
137     return 0;
138   }
139   int limit = query.GetInteger(0);
140   int last = query.GetInteger(1);
141
142   if (limit < 0 || last < 0 || current < 0 || current < last
143       || limit < (current - last)) {
144     return 0;
145   }
146
147   return limit - (current - last);
148 }
149
150 bool SQLPTRepresentation::SetCountersPassedForSuccessfulUpdate(
151   int kilometers, int days_after_epoch) {
152   LOG4CXX_INFO(logger_,
153                "SQLPTRepresentation::SetCountersPassedForSuccessfulUpdate");
154   dbms::SQLQuery query(db());
155   if (!query.Prepare(sql_pt::kUpdateCountersSuccessfulUpdate)) {
156     LOG4CXX_WARN(logger_,
157                  "Wrong update query for counters on successful update.");
158     return false;
159   }
160   query.Bind(0, kilometers);
161   query.Bind(1, days_after_epoch);
162   if (!query.Exec()) {
163     LOG4CXX_WARN(logger_, "Failed to update counters on successful update.");
164     return false;
165   }
166   return true;
167 }
168
169 int SQLPTRepresentation::DaysBeforeExchange(int current) {
170   dbms::SQLQuery query(db());
171   if (!query.Prepare(sql_pt::kSelectDays) || !query.Exec()) {
172     LOG4CXX_WARN(logger_, "Can not select days");
173     return 0;
174   }
175   int limit = query.GetInteger(0);
176   int last = query.GetInteger(1);
177
178   if (0 == last) {
179     return limit;
180   }
181
182   if (limit < 0 || last < 0 || current < 0 || current < last
183       || limit < (current - last)) {
184     return 0;
185   }
186
187   return limit - (current - last);
188 }
189
190 int SQLPTRepresentation::TimeoutResponse() {
191   dbms::SQLQuery query(db());
192   if (!query.Prepare(sql_pt::kSelectTimeoutResponse) || !query.Exec()) {
193     LOG4CXX_INFO(logger_, "Can not select timeout response for retry sequence");
194     const int kDefault = 30;
195     return kDefault;
196   }
197   return query.GetInteger(0);
198 }
199
200 bool SQLPTRepresentation::SecondsBetweenRetries(std::vector<int>* seconds) {
201   dbms::SQLQuery query(db());
202   if (!query.Prepare(sql_pt::kSelectSecondsBetweenRetries)) {
203     LOG4CXX_INFO(logger_,
204                  "Incorrect select statement from seconds between retries");
205     return false;
206   }
207   while (query.Next()) {
208     seconds->push_back(query.GetInteger(0));
209   }
210   return true;
211 }
212
213 std::vector<UserFriendlyMessage> SQLPTRepresentation::GetUserFriendlyMsg(
214   const std::vector<std::string>& msg_codes, const std::string& language) {
215   std::vector<UserFriendlyMessage> result;
216   std::vector<std::string>::const_iterator it = msg_codes.begin();
217   std::vector<std::string>::const_iterator it_end = msg_codes.end();
218   for (; it != it_end; ++it) {
219     UserFriendlyMessage msg;
220     msg.message_code = *it;
221     result.push_back(msg);
222   }
223   return result;
224 }
225
226 EndpointUrls SQLPTRepresentation::GetUpdateUrls(int service_type) {
227   LOG4CXX_INFO(logger_, "SQLPTRepresentation::GetUpdateUrls for " << service_type);
228   dbms::SQLQuery query(db());
229   EndpointUrls ret;
230   if (query.Prepare(sql_pt::kSelectEndpoint)) {
231     query.Bind(0, service_type);
232     while (query.Next()) {
233       EndpointData data;
234
235       data.url = query.GetString(0);
236       if (!query.IsNull(1)) {
237         data.app_id = query.GetString(1);
238       }
239       ret.push_back(data);
240     }
241   } else {
242     LOG4CXX_WARN(logger_, "Invalid select endpoints statement.");
243   }
244   return ret;
245 }
246
247 int SQLPTRepresentation::GetNotificationsNumber(
248   policy_table::Priority priority) {
249   return 0;
250 }
251
252 InitResult SQLPTRepresentation::Init() {
253   LOG4CXX_INFO(logger_, "SQLPTRepresentation::Init");
254
255   if (!db_->Open()) {
256     LOG4CXX_ERROR(logger_, "Failed opening database");
257     return InitResult::FAIL;
258   }
259   dbms::SQLQuery check_pages(db());
260   if (!check_pages.Prepare(sql_pt::kCheckPgNumber) || !check_pages.Next()) {
261     LOG4CXX_WARN(logger_, "Incorrect pragma for page counting.");
262   } else {
263     if (0 < check_pages.GetInteger(0)) {
264       dbms::SQLQuery db_check(db());
265       if (!db_check.Prepare(sql_pt::kCheckDBIntegrity)) {
266         LOG4CXX_WARN(logger_, "Incorrect pragma for integrity check.");
267       } else {
268         while (db_check.Next()) {
269           if (db_check.GetString(0).compare("ok") == 0) {
270             return InitResult::EXISTS;
271           } else {
272             LOG4CXX_ERROR(logger_,
273                           "Existing policy table representation is invlaid.");
274             // TODO(PV): add handle
275             return InitResult::FAIL;
276           }
277         }
278       }
279     }
280   }
281   dbms::SQLQuery query(db());
282   if (!query.Exec(sql_pt::kCreateSchema)) {
283     LOG4CXX_ERROR(
284       logger_,
285       "Failed creating schema of database: " << query.LastError().text());
286     return InitResult::FAIL;
287   }
288   if (!query.Exec(sql_pt::kInsertInitData)) {
289     LOG4CXX_ERROR(
290       logger_,
291       "Failed insert init data to database: " << query.LastError().text());
292     return InitResult::FAIL;
293   }
294   return InitResult::SUCCESS;
295 }
296
297 bool SQLPTRepresentation::Close() {
298   db_->Close();
299   return db_->LastError().number() == dbms::OK;
300 }
301
302 VehicleData SQLPTRepresentation::GetVehicleData() {
303   return VehicleData();
304 }
305
306 bool SQLPTRepresentation::Drop() {
307   dbms::SQLQuery query(db());
308   if (!query.Exec(sql_pt::kDropSchema)) {
309     LOG4CXX_WARN(logger_,
310                  "Failed dropping database: " << query.LastError().text());
311     return false;
312   }
313   return true;
314 }
315
316 bool SQLPTRepresentation::Clear() {
317   dbms::SQLQuery query(db());
318   if (!query.Exec(sql_pt::kDeleteData)) {
319     LOG4CXX_ERROR(logger_,
320                  "Failed clearing database: " << query.LastError().text());
321     return false;
322   }
323   if (!query.Exec(sql_pt::kInsertInitData)) {
324     LOG4CXX_ERROR(
325       logger_,
326       "Failed insert init data to database: " << query.LastError().text());
327     return false;
328   }
329   return true;
330 }
331
332 utils::SharedPtr<policy_table::Table> SQLPTRepresentation::GenerateSnapshot() const {
333   LOG4CXX_INFO(logger_, "GenerateSnapshot");
334   utils::SharedPtr<policy_table::Table> table = new policy_table::Table();
335   GatherModuleMeta(&*table->policy_table.module_meta);
336   GatherModuleConfig(&table->policy_table.module_config);
337   GatherUsageAndErrorCounts(&*table->policy_table.usage_and_error_counts);
338   GatherDeviceData(&*table->policy_table.device_data);
339   GatherFunctionalGroupings(&table->policy_table.functional_groupings);
340   GatherConsumerFriendlyMessages(
341     &*table->policy_table.consumer_friendly_messages);
342   GatherApplicationPolicies(&table->policy_table.app_policies);
343   return table;
344 }
345
346 void SQLPTRepresentation::GatherModuleMeta(
347   policy_table::ModuleMeta* meta) const {
348   LOG4CXX_INFO(logger_, "Gather Module Meta Info");
349   meta->mark_initialized();
350   // Section Module Meta is empty for SDL specific
351 }
352
353 void SQLPTRepresentation::GatherModuleConfig(
354   policy_table::ModuleConfig* config) const {
355   LOG4CXX_INFO(logger_, "Gather Configuration Info");
356   dbms::SQLQuery query(db());
357   if (!query.Prepare(sql_pt::kSelectModuleConfig) || !query.Next()) {
358     LOG4CXX_WARN(logger_, "Incorrect select statement for module config");
359   } else {
360     *config->preloaded_pt = query.GetBoolean(0);
361     config->exchange_after_x_ignition_cycles = query.GetInteger(1);
362     config->exchange_after_x_kilometers = query.GetInteger(2);
363     config->exchange_after_x_days = query.GetInteger(3);
364     config->timeout_after_x_seconds = query.GetInteger(4);
365     *config->vehicle_make = query.GetString(5);
366     *config->vehicle_model = query.GetString(6);
367     *config->vehicle_year = query.GetString(7);
368   }
369
370   dbms::SQLQuery endpoints(db());
371   if (!endpoints.Prepare(sql_pt::kSelectEndpoints)) {
372     LOG4CXX_WARN(logger_, "Incorrect select statement for endpoints");
373   } else {
374     while (endpoints.Next()) {
375       std::stringstream stream;
376       stream << "0x0" << endpoints.GetInteger(1);
377       config->endpoints[stream.str()][endpoints.GetString(2)]
378       .push_back(endpoints.GetString(0));
379     }
380   }
381
382   dbms::SQLQuery notifications(db());
383   if (!notifications.Prepare(sql_pt::kSelectNotificationsPerMin)) {
384     LOG4CXX_WARN(logger_, "Incorrect select statement for notifications");
385   } else {
386     while (notifications.Next()) {
387       config->notifications_per_minute_by_priority[notifications.GetString(0)] =
388         notifications.GetInteger(1);
389     }
390   }
391   dbms::SQLQuery seconds(db());
392   if (!seconds.Prepare(sql_pt::kSelectSecondsBetweenRetries)) {
393     LOG4CXX_INFO(logger_,
394                  "Incorrect select statement from seconds between retries");
395   } else {
396     while (seconds.Next()) {
397       config->seconds_between_retries.push_back(seconds.GetInteger(0));
398     }
399   }
400 }
401
402 bool SQLPTRepresentation::GatherUsageAndErrorCounts(
403   policy_table::UsageAndErrorCounts* counts) const {
404   LOG4CXX_INFO(logger_, "Gather Usage and Error Counts.");
405   dbms::SQLQuery query(db());
406   if (query.Prepare(sql_pt::kSelectAppLevels)) {
407     policy_table::AppLevel app_level_empty;
408     app_level_empty.mark_initialized();
409     while (query.Next()) {
410       (*counts->app_level)[query.GetString(0)] = app_level_empty;
411     }
412   }
413   return true;
414 }
415
416 void SQLPTRepresentation::GatherDeviceData(
417   policy_table::DeviceData* data) const {
418   LOG4CXX_INFO(logger_, "Gather device data.");
419   dbms::SQLQuery query(db());
420   if (query.Prepare(sql_pt::kSelectDeviceData)) {
421     policy_table::DeviceParams device_data_empty;
422     device_data_empty.mark_initialized();
423     while (query.Next()) {
424       (*data)[query.GetString(0)] = device_data_empty;
425     }
426   }
427 }
428
429 bool SQLPTRepresentation::GatherFunctionalGroupings(
430   policy_table::FunctionalGroupings* groups) const {
431   LOG4CXX_INFO(logger_, "Gather Functional Groupings info");
432   dbms::SQLQuery func_group(db());
433   if (!func_group.Prepare(sql_pt::kSelectFunctionalGroups)) {
434     LOG4CXX_WARN(logger_, "Incorrect select from functional_groupings");
435     return false;
436   }
437   dbms::SQLQuery rpcs(db());
438   if (!rpcs.Prepare(sql_pt::kSelectAllRpcs)) {
439     LOG4CXX_WARN(logger_, "Incorrect select all from rpc");
440     return false;
441   }
442   while (func_group.Next()) {
443     policy_table::Rpcs rpcs_tbl;
444     if (!func_group.IsNull(2)) {
445       *rpcs_tbl.user_consent_prompt = func_group.GetString(2);
446     }
447     int func_id = func_group.GetInteger(0);
448     rpcs.Bind(0, func_id);
449     while (rpcs.Next()) {
450       if (!rpcs.IsNull(1)) {
451         policy_table::HmiLevel level;
452         if (policy_table::EnumFromJsonString(rpcs.GetString(1), &level)) {
453           InsertUnique(level, &rpcs_tbl.rpcs[rpcs.GetString(0)].hmi_levels);
454         }
455       }
456       if (!rpcs.IsNull(2)) {
457         policy_table::Parameter param;
458         if (policy_table::EnumFromJsonString(rpcs.GetString(2), &param)) {
459           // TODO(IKozyrenko): Check logic if optional container is missing
460           InsertUnique(param, &(*rpcs_tbl.rpcs[rpcs.GetString(0)].parameters));
461         }
462       }
463     }
464     rpcs.Reset();
465     (*groups)[func_group.GetString(1)] = rpcs_tbl;
466   }
467   return true;
468 }
469
470 bool SQLPTRepresentation::GatherConsumerFriendlyMessages(
471   policy_table::ConsumerFriendlyMessages* messages) const {
472   LOG4CXX_INFO(logger_, "Gather Consumer Friendly Messages");
473   dbms::SQLQuery query(db());
474   if (!query.Prepare(sql_pt::kSelectUserMsgsVersion) || !query.Next()) {
475     LOG4CXX_WARN(logger_, "Incorrect select from consumer_friendly_messages");
476     return false;
477   }
478   messages->version = query.GetString(0);
479   return true;
480 }
481
482 bool SQLPTRepresentation::GatherApplicationPolicies(
483   policy_table::ApplicationPolicies* apps) const {
484   LOG4CXX_INFO(logger_, "Gather applications policies");
485   dbms::SQLQuery query(db());
486   if (!query.Prepare(sql_pt::kSelectAppPolicies)) {
487     LOG4CXX_WARN(logger_, "Incorrect select from app_policies");
488     return false;
489   }
490
491   while (query.Next()) {
492     rpc::Nullable<policy_table::ApplicationParams> params;
493     const std::string& app_id = query.GetString(0);
494     if (IsApplicationRevoked(app_id)) {
495       params.set_to_null();
496       (*apps)[app_id] = params;
497       continue;
498     }
499     *params.memory_kb = query.GetInteger(1);
500     *params.heart_beat_timeout_ms = query.GetInteger(2);
501     if (!query.IsNull(3)) {
502       *params.certificate = query.GetString(3);
503     }
504     if (!GatherAppGroup(app_id, &params.groups)) {
505       return false;
506     }
507     // TODO(IKozyrenko): Check logic if optional container is missing
508     if (!GatherNickName(app_id, &*params.nicknames)) {
509       return false;
510     }
511     // TODO(IKozyrenko): Check logic if optional container is missing
512     if (!GatherAppType(app_id, &*params.AppHMIType)) {
513       return false;
514     }
515     (*apps)[app_id] = params;
516   }
517   return true;
518 }
519
520 bool SQLPTRepresentation::Save(const policy_table::Table& table) {
521   LOG4CXX_INFO(logger_, "SQLPTRepresentation::Save");
522   db_->BeginTransaction();
523   if (!SaveFunctionalGroupings(table.policy_table.functional_groupings)) {
524     db_->RollbackTransaction();
525     return false;
526   }
527   if (!SaveApplicationPolicies(table.policy_table.app_policies)) {
528     db_->RollbackTransaction();
529     return false;
530   }
531   if (!SaveModuleConfig(table.policy_table.module_config)) {
532     db_->RollbackTransaction();
533     return false;
534   }
535   if (!SaveConsumerFriendlyMessages(
536         *table.policy_table.consumer_friendly_messages)) {
537     db_->RollbackTransaction();
538     return false;
539   }
540   if (!SaveDeviceData(*table.policy_table.device_data)) {
541     db_->RollbackTransaction();
542     return false;
543   }
544   if (!SaveUsageAndErrorCounts(*table.policy_table.usage_and_error_counts)) {
545     db_->RollbackTransaction();
546     return false;
547   }
548   if (!SaveModuleMeta(*table.policy_table.module_meta)) {
549     db_->RollbackTransaction();
550     return false;
551   }
552   db_->CommitTransaction();
553   return true;
554 }
555
556 bool SQLPTRepresentation::SaveFunctionalGroupings(
557   const policy_table::FunctionalGroupings& groups) {
558   LOG4CXX_INFO(logger_, "SaveFunctionalGroupings");
559   dbms::SQLQuery query_delete(db());
560   if (!query_delete.Exec(sql_pt::kDeleteRpc)) {
561     LOG4CXX_WARN(logger_, "Incorrect delete from rpc.");
562     return false;
563   }
564
565   dbms::SQLQuery query(db());
566   if (!query.Exec(sql_pt::kDeleteFunctionalGroup)) {
567     LOG4CXX_WARN(logger_, "Incorrect delete from seconds between retries.");
568     return false;
569   }
570   if (!query.Prepare(sql_pt::kInsertFunctionalGroup)) {
571     LOG4CXX_WARN(logger_, "Incorrect insert statement for functional groups");
572     return false;
573   }
574
575   policy_table::FunctionalGroupings::const_iterator it;
576   for (it = groups.begin(); it != groups.end(); ++it) {
577     query.Bind(0, it->first);
578     it->second.user_consent_prompt.is_initialized() ?
579     query.Bind(1, *(it->second.user_consent_prompt)) : query.Bind(1);
580
581     if (!query.Exec() || !query.Reset()) {
582       LOG4CXX_WARN(logger_, "Incorrect insert into functional groups");
583       return false;
584     }
585
586     if (!SaveRpcs(query.LastInsertId(), it->second.rpcs)) {
587       return false;
588     }
589   }
590   return true;
591 }
592
593 bool SQLPTRepresentation::SaveRpcs(int64_t group_id,
594                                    const policy_table::Rpc& rpcs) {
595   dbms::SQLQuery query(db());
596   dbms::SQLQuery query_parameter(db());
597   if (!query.Prepare(sql_pt::kInsertRpc)
598       || !query_parameter.Prepare(sql_pt::kInsertRpcWithParameter)) {
599     LOG4CXX_WARN(logger_, "Incorrect insert statement for rpc");
600     return false;
601   }
602
603   policy_table::Rpc::const_iterator it;
604   for (it = rpcs.begin(); it != rpcs.end(); ++it) {
605     const policy_table::HmiLevels& hmi_levels = it->second.hmi_levels;
606     // TODO(IKozyrenko): Check logic if optional container is missing
607     const policy_table::Parameters& parameters = *it->second.parameters;
608     policy_table::HmiLevels::const_iterator hmi_it;
609     policy_table::Parameters::const_iterator ps_it;
610     for (hmi_it = hmi_levels.begin(); hmi_it != hmi_levels.end(); ++hmi_it) {
611       if (!parameters.empty()) {
612         for (ps_it = parameters.begin(); ps_it != parameters.end(); ++ps_it) {
613           query_parameter.Bind(0, it->first);
614           query_parameter.Bind(
615             1, std::string(policy_table::EnumToJsonString(*hmi_it)));
616           query_parameter.Bind(
617             2, std::string(policy_table::EnumToJsonString(*ps_it)));
618           query_parameter.Bind(3, group_id);
619           if (!query_parameter.Exec() || !query_parameter.Reset()) {
620             LOG4CXX_WARN(logger_, "Incorrect insert into rpc with parameter");
621             return false;
622           }
623         }
624       } else {
625         query.Bind(0, it->first);
626         query.Bind(1, std::string(policy_table::EnumToJsonString(*hmi_it)));
627         query.Bind(2, group_id);
628         if (!query.Exec() || !query.Reset()) {
629           LOG4CXX_WARN(logger_, "Incorrect insert into rpc");
630           return false;
631         }
632       }
633     }
634   }
635
636   return true;
637 }
638
639 bool SQLPTRepresentation::SaveApplicationPolicies(
640   const policy_table::ApplicationPolicies& apps) {
641   LOG4CXX_INFO(logger_, "SaveApplicationPolicies");
642   dbms::SQLQuery query_delete(db());
643   if (!query_delete.Exec(sql_pt::kDeleteAppGroup)) {
644     LOG4CXX_WARN(logger_, "Incorrect delete from app_group.");
645     return false;
646   }
647   if (!query_delete.Exec(sql_pt::kDeleteApplication)) {
648     LOG4CXX_WARN(logger_, "Incorrect delete from application.");
649     return false;
650   }
651   policy_table::ApplicationPolicies::const_iterator it;
652   dbms::SQLQuery app_query(db());
653   if (!app_query.Prepare(sql_pt::kInsertApplication)) {
654     LOG4CXX_WARN(logger_, "Incorrect insert statement into application.");
655     return false;
656   }
657   for (it = apps.begin(); it != apps.end(); ++it) {
658     app_query.Bind(0, it->first);
659     app_query.Bind(1, it->second.is_null());
660     app_query.Bind(2, it->second.memory_kb);
661     app_query.Bind(3, it->second.heart_beat_timeout_ms);
662     it->second.certificate.is_initialized() ?
663     app_query.Bind(4, *it->second.certificate) : app_query.Bind(4);
664
665     if (!app_query.Exec() || !app_query.Reset()) {
666       LOG4CXX_WARN(logger_, "Incorrect insert into application.");
667       return false;
668     }
669
670     LOG4CXX_INFO(logger_, "Saving data for application: " << it->first);
671     if (it->second.is_string()) {
672       if (kDefaultId.compare(it->second.get_string()) == 0) {
673         if (!SetDefaultPolicy(it->first)) {
674           return false;
675         }
676       }
677       continue;
678     }
679
680     if (!SaveAppGroup(it->first, it->second.groups)) {
681       return false;
682     }
683     // TODO(IKozyrenko): Check logic if optional container is missing
684     if (!SaveNickname(it->first, *it->second.nicknames)) {
685       return false;
686     }
687     // TODO(IKozyrenko): Check logic if optional container is missing
688     if (!SaveAppType(it->first, *it->second.AppHMIType)) {
689       return false;
690     }
691   }
692
693   return true;
694 }
695
696 bool SQLPTRepresentation::SaveAppGroup(
697   const std::string& app_id, const policy_table::Strings& app_groups) {
698   dbms::SQLQuery query(db());
699   if (!query.Prepare(sql_pt::kInsertAppGroup)) {
700     LOG4CXX_WARN(logger_, "Incorrect insert statement for app group");
701     return false;
702   }
703   LOG4CXX_INFO(logger_, "SaveAppGroup");
704   policy_table::Strings::const_iterator it;
705   for (it = app_groups.begin(); it != app_groups.end(); ++it) {
706     std::string ssss = *it;
707     LOG4CXX_INFO(logger_, "Group: " << ssss);
708     query.Bind(0, app_id);
709     query.Bind(1, *it);
710     if (!query.Exec() || !query.Reset()) {
711       LOG4CXX_WARN(
712         logger_,
713         "Incorrect insert into app group." << query.LastError().text());
714       return false;
715     }
716   }
717
718   return true;
719 }
720
721 bool SQLPTRepresentation::SaveNickname(const std::string& app_id,
722                                        const policy_table::Strings& nicknames) {
723   dbms::SQLQuery query(db());
724   if (!query.Prepare(sql_pt::kInsertNickname)) {
725     LOG4CXX_WARN(logger_, "Incorrect insert statement for nickname");
726     return false;
727   }
728
729   policy_table::Strings::const_iterator it;
730   for (it = nicknames.begin(); it != nicknames.end(); ++it) {
731     query.Bind(0, app_id);
732     query.Bind(1, *it);
733     if (!query.Exec() || !query.Reset()) {
734       LOG4CXX_WARN(logger_, "Incorrect insert into nickname.");
735       return false;
736     }
737   }
738
739   return true;
740 }
741
742 bool SQLPTRepresentation::SaveAppType(const std::string& app_id,
743                                       const policy_table::AppHMITypes& types) {
744   dbms::SQLQuery query(db());
745   if (!query.Prepare(sql_pt::kInsertAppType)) {
746     LOG4CXX_WARN(logger_, "Incorrect insert statement for app type");
747     return false;
748   }
749
750   policy_table::AppHMITypes::const_iterator it;
751   for (it = types.begin(); it != types.end(); ++it) {
752     query.Bind(0, app_id);
753     query.Bind(1, std::string(policy_table::EnumToJsonString(*it)));
754     if (!query.Exec() || !query.Reset()) {
755       LOG4CXX_WARN(logger_, "Incorrect insert into app type.");
756       return false;
757     }
758   }
759
760   return true;
761 }
762
763 bool SQLPTRepresentation::SaveModuleMeta(const policy_table::ModuleMeta& meta) {
764   LOG4CXX_INFO(logger_, "SaveModuleMeta");
765   // Section Module Meta is empty for SDL specific
766   return true;
767 }
768
769 bool SQLPTRepresentation::SaveModuleConfig(
770   const policy_table::ModuleConfig& config) {
771   LOG4CXX_INFO(logger_, "SaveModuleConfig");
772   dbms::SQLQuery query(db());
773   if (!query.Prepare(sql_pt::kUpdateModuleConfig)) {
774     LOG4CXX_WARN(logger_, "Incorrect update statement for module config");
775     return false;
776   }
777
778   config.preloaded_pt.is_initialized() ?
779   query.Bind(0, config.preloaded_pt) : query.Bind(0, false);
780   query.Bind(1, config.exchange_after_x_ignition_cycles);
781   query.Bind(2, config.exchange_after_x_kilometers);
782   query.Bind(3, config.exchange_after_x_days);
783   query.Bind(4, config.timeout_after_x_seconds);
784   config.vehicle_make.is_initialized() ?
785   query.Bind(5, *(config.vehicle_make)) : query.Bind(5);
786   config.vehicle_model.is_initialized() ?
787   query.Bind(6, *(config.vehicle_model)) : query.Bind(6);
788   config.vehicle_year.is_initialized() ?
789   query.Bind(7, *(config.vehicle_year)) : query.Bind(7);
790
791   if (!query.Exec()) {
792     LOG4CXX_WARN(logger_, "Incorrect update module config");
793     return false;
794   }
795
796   if (!SaveSecondsBetweenRetries(config.seconds_between_retries)) {
797     return false;
798   }
799
800   if (!SaveNumberOfNotificationsPerMinute(
801         config.notifications_per_minute_by_priority)) {
802     return false;
803   }
804
805   if (!SaveServiceEndpoints(config.endpoints)) {
806     return false;
807   }
808
809   return true;
810 }
811
812 bool SQLPTRepresentation::SaveServiceEndpoints(
813   const policy_table::ServiceEndpoints& endpoints) {
814   dbms::SQLQuery query(db());
815   if (!query.Exec(sql_pt::kDeleteEndpoint)) {
816     LOG4CXX_WARN(logger_, "Incorrect delete from endpoint.");
817     return false;
818   }
819
820   if (!query.Prepare(sql_pt::kInsertEndpoint)) {
821     LOG4CXX_WARN(logger_, "Incorrect insert statement for endpoint");
822     return false;
823   }
824
825   policy_table::ServiceEndpoints::const_iterator it;
826   for (it = endpoints.begin(); it != endpoints.end(); ++it) {
827     const policy_table::URLList& apps = it->second;
828     policy_table::URLList::const_iterator app_it;
829     for (app_it = apps.begin(); app_it != apps.end(); ++app_it) {
830       const policy_table::URL& urls = app_it->second;
831       policy_table::URL::const_iterator url_it;
832       for (url_it = urls.begin(); url_it != urls.end(); ++url_it) {
833         std::stringstream temp_stream(it->first);
834         int service;
835         temp_stream.seekg(3);
836         temp_stream >> service;
837         query.Bind(0, service);
838         query.Bind(1, *url_it);
839         query.Bind(2, app_it->first);
840         if (!query.Exec()) {
841           LOG4CXX_WARN(logger_, "Incorrect insert into endpoint");
842           return false;
843         }
844       }
845     }
846   }
847
848   return true;
849 }
850
851 bool SQLPTRepresentation::SaveConsumerFriendlyMessages(
852   const policy_table::ConsumerFriendlyMessages& messages) {
853   LOG4CXX_INFO(logger_, "SaveConsumerFriendlyMessages");
854
855   dbms::SQLQuery query(db());
856   if (!query.Exec(sql_pt::kDeleteMessageString)) {
857     LOG4CXX_WARN(logger_, "Incorrect delete from message.");
858     return false;
859   }
860
861   if (query.Prepare(sql_pt::kUpdateVersion)) {
862     query.Bind(0, messages.version);
863     if (!query.Exec()) {
864       LOG4CXX_WARN(logger_, "Incorrect update into version.");
865       return false;
866     }
867   } else {
868     LOG4CXX_WARN(logger_, "Incorrect update statement for version.");
869     return false;
870   }
871
872   policy_table::Messages::const_iterator it;
873   // TODO(IKozyrenko): Check logic if optional container is missing
874   for (it = messages.messages->begin(); it != messages.messages->end(); ++it) {
875     if (!SaveMessageType(it->first)) {
876       return false;
877     }
878     const policy_table::Languages& langs = it->second.languages;
879     policy_table::Languages::const_iterator lang_it;
880     for (lang_it = langs.begin(); lang_it != langs.end(); ++lang_it) {
881       if (!SaveLanguage(lang_it->first)) {
882         return false;
883       }
884       if (!SaveMessageString(it->first, lang_it->first, lang_it->second)) {
885         return false;
886       }
887     }
888   }
889
890   return true;
891 }
892
893 bool SQLPTRepresentation::SaveMessageType(const std::string& type) {
894   dbms::SQLQuery query(db());
895   if (!query.Prepare(sql_pt::kInsertMessageType)) {
896     LOG4CXX_WARN(logger_, "Incorrect insert statement for message type.");
897     return false;
898   }
899
900   query.Bind(0, type);
901   if (!query.Exec()) {
902     LOG4CXX_WARN(logger_, "Incorrect insert into message type.");
903     return false;
904   }
905
906   return true;
907 }
908
909 bool SQLPTRepresentation::SaveLanguage(const std::string& code) {
910   dbms::SQLQuery query(db());
911   if (!query.Prepare(sql_pt::kInsertLanguage)) {
912     LOG4CXX_WARN(logger_, "Incorrect insert statement for language.");
913     return false;
914   }
915
916   query.Bind(0, code);
917   if (!query.Exec()) {
918     LOG4CXX_WARN(logger_, "Incorrect insert into language.");
919     return false;
920   }
921
922   return true;
923 }
924
925 bool SQLPTRepresentation::SaveMessageString(
926   const std::string& type, const std::string& lang,
927   const policy_table::MessageString& strings) {
928   // Section is empty for SDL specific
929   return true;
930 }
931
932 bool SQLPTRepresentation::SaveSecondsBetweenRetries(
933   const policy_table::SecondsBetweenRetries& seconds) {
934   dbms::SQLQuery query(db());
935   if (!query.Exec(sql_pt::kDeleteSecondsBetweenRetries)) {
936     LOG4CXX_WARN(logger_, "Incorrect delete from seconds between retries.");
937     return false;
938   }
939   if (!query.Prepare(sql_pt::kInsertSecondsBetweenRetry)) {
940     LOG4CXX_WARN(logger_,
941                  "Incorrect insert statement for seconds between retries.");
942     return false;
943   }
944
945   for (int i = 0; i < seconds.size(); ++i) {
946     query.Bind(0, i);
947     query.Bind(1, seconds[i]);
948     if (!query.Exec() || !query.Reset()) {
949       LOG4CXX_WARN(logger_, "Incorrect insert into seconds between retries.");
950       return false;
951     }
952   }
953
954   return true;
955 }
956
957 bool SQLPTRepresentation::SaveNumberOfNotificationsPerMinute(
958   const policy_table::NumberOfNotificationsPerMinute& notifications) {
959   dbms::SQLQuery query(db());
960   if (!query.Prepare(sql_pt::kInsertNotificationsByPriority)) {
961     LOG4CXX_WARN(logger_,
962                  "Incorrect insert statement for notifications by priority.");
963     return false;
964   }
965
966   policy_table::NumberOfNotificationsPerMinute::const_iterator it;
967   for (it = notifications.begin(); it != notifications.end(); ++it) {
968     query.Bind(0, it->first);
969     query.Bind(1, it->second);
970     if (!query.Exec() || !query.Reset()) {
971       LOG4CXX_WARN(logger_, "Incorrect insert into notifications by priority.");
972       return false;
973     }
974   }
975
976   return true;
977 }
978
979 bool SQLPTRepresentation::SaveDeviceData(
980   const policy_table::DeviceData& devices) {
981   LOG4CXX_INFO(logger_, "SaveDeviceData");
982   dbms::SQLQuery query(db());
983   if (!query.Prepare(sql_pt::kInsertDeviceData)) {
984     LOG4CXX_WARN(logger_, "Incorrect insert statement for device data.");
985     return false;
986   }
987
988   policy_table::DeviceData::const_iterator it;
989   for (it = devices.begin(); it != devices.end(); ++it) {
990     query.Bind(0, it->first);
991     if (!query.Exec()) {
992       LOG4CXX_WARN(logger_, "Incorrect insert into device data.");
993       return false;
994     }
995   }
996
997   return true;
998 }
999
1000 bool SQLPTRepresentation::SaveUsageAndErrorCounts(
1001   const policy_table::UsageAndErrorCounts& counts) {
1002   LOG4CXX_INFO(logger_, "SaveUsageAndErrorCounts");
1003   dbms::SQLQuery query(db());
1004   if (!query.Exec(sql_pt::kDeleteAppLevel)) {
1005     LOG4CXX_WARN(logger_, "Incorrect delete from app level.");
1006     return false;
1007   }
1008   if (!query.Prepare(sql_pt::kInsertAppLevel)) {
1009     LOG4CXX_WARN(logger_, "Incorrect insert statement for app level.");
1010     return false;
1011   }
1012
1013   policy_table::AppLevels::const_iterator it;
1014   const policy_table::AppLevels& app_levels = *counts.app_level;
1015   for (it = app_levels.begin(); it != app_levels.end(); ++it) {
1016     query.Bind(0, it->first);
1017     if (!query.Exec()) {
1018       LOG4CXX_WARN(logger_, "Incorrect insert into app level.");
1019       return false;
1020     }
1021   }
1022
1023   return true;
1024 }
1025
1026 void SQLPTRepresentation::IncrementIgnitionCycles() {
1027   dbms::SQLQuery query(db());
1028   if (!query.Exec(sql_pt::kIncrementIgnitionCycles)) {
1029     LOG4CXX_WARN(logger_, "Failed incrementing ignition cycles");
1030   }
1031 }
1032
1033 void SQLPTRepresentation::ResetIgnitionCycles() {
1034   LOG4CXX_INFO(logger_, "ResetIgnitionCycles");
1035   dbms::SQLQuery query(db());
1036   if (!query.Exec(sql_pt::kResetIgnitionCycles)) {
1037     LOG4CXX_WARN(logger_, "Failed to reset ignition cycles number.");
1038   }
1039 }
1040
1041 bool SQLPTRepresentation::UpdateRequired() const {
1042   dbms::SQLQuery query(db());
1043   if (!query.Prepare(sql_pt::kSelectFlagUpdateRequired) || !query.Exec()) {
1044     LOG4CXX_WARN(logger_,
1045                  "Failed select update required flag from module meta");
1046     return false;
1047   }
1048   return query.GetBoolean(0);
1049 }
1050
1051 void SQLPTRepresentation::SaveUpdateRequired(bool value) {
1052   dbms::SQLQuery query(db());
1053   if (!query.Prepare(sql_pt::kUpdateFlagUpdateRequired)) {
1054     LOG4CXX_WARN(logger_,
1055                  "Incorrect update into module meta (update_required)");
1056     return;
1057   }
1058   query.Bind(0, value);
1059   if (!query.Exec()) {
1060     LOG4CXX_WARN(logger_, "Failed update module meta (update_required)");
1061   }
1062 }
1063
1064 bool SQLPTRepresentation::GetInitialAppData(const std::string& app_id,
1065     StringArray* nicknames,
1066     StringArray* app_types) {
1067   LOG4CXX_INFO(logger_, "Getting initial application data.");
1068   dbms::SQLQuery app_names(db());
1069   if (!app_names.Prepare(sql_pt::kSelectNicknames)) {
1070     LOG4CXX_WARN(logger_, "Incorrect select from app nicknames");
1071     return false;
1072   }
1073   dbms::SQLQuery app_hmi_types(db());
1074   if (!app_hmi_types.Prepare(sql_pt::kSelectAppTypes)) {
1075     LOG4CXX_WARN(logger_, "Incorrect select from app types");
1076     return false;
1077   }
1078   app_names.Bind(0, app_id);
1079   while (app_names.Next()) {
1080     nicknames->push_back(app_names.GetString(0));
1081   }
1082   app_names.Reset();
1083   app_hmi_types.Bind(0, app_id);
1084   while (app_hmi_types.Next()) {
1085     app_types->push_back(app_names.GetString(0));
1086   }
1087   app_hmi_types.Reset();
1088   return true;
1089 }
1090
1091 bool SQLPTRepresentation::GetFunctionalGroupings(
1092   policy_table::FunctionalGroupings& groups) {
1093   LOG4CXX_INFO(logger_, "GetFunctionalGroupings");
1094   return GatherFunctionalGroupings(&groups);
1095 }
1096
1097 bool SQLPTRepresentation::GatherAppType(
1098   const std::string& app_id, policy_table::AppHMITypes* app_types) const {
1099   dbms::SQLQuery query(db());
1100   if (!query.Prepare(sql_pt::kSelectAppTypes)) {
1101     LOG4CXX_WARN(logger_, "Incorrect select from app types");
1102     return false;
1103   }
1104
1105   query.Bind(0, app_id);
1106   while (query.Next()) {
1107     policy_table::AppHMIType type;
1108     if (!policy_table::EnumFromJsonString(query.GetString(0), &type)) {
1109       return false;
1110     }
1111     app_types->push_back(type);
1112   }
1113   return true;
1114 }
1115
1116 bool SQLPTRepresentation::GatherNickName(
1117   const std::string& app_id, policy_table::Strings* nicknames) const {
1118   dbms::SQLQuery query(db());
1119   if (!query.Prepare(sql_pt::kSelectNicknames)) {
1120     LOG4CXX_WARN(logger_, "Incorrect select from app nicknames");
1121     return false;
1122   }
1123
1124   query.Bind(0, app_id);
1125   while (query.Next()) {
1126     nicknames->push_back(query.GetString(0));
1127   }
1128   return true;
1129 }
1130
1131 bool SQLPTRepresentation::GatherAppGroup(
1132   const std::string& app_id, policy_table::Strings* app_groups) const {
1133   dbms::SQLQuery query(db());
1134   if (!query.Prepare(sql_pt::kSelectAppGroups)) {
1135     LOG4CXX_WARN(logger_, "Incorrect select from app groups");
1136     return false;
1137   }
1138
1139   query.Bind(0, app_id);
1140   while (query.Next()) {
1141     app_groups->push_back(query.GetString(0));
1142   }
1143   return true;
1144 }
1145
1146 bool SQLPTRepresentation::IsApplicationRevoked(
1147   const std::string& app_id) const {
1148   dbms::SQLQuery query(db());
1149   if (!query.Prepare(sql_pt::kSelectApplicationRevoked)) {
1150     LOG4CXX_WARN(logger_, "Incorrect select from is_revoked of application");
1151     return false;
1152   }
1153
1154   query.Bind(0, app_id);
1155   if (!query.Exec()) {
1156     LOG4CXX_WARN(logger_, "Failed select is_revoked of application");
1157     return false;
1158   }
1159   return query.IsNull(0) ? false : query.GetBoolean(0);
1160 }
1161
1162 bool SQLPTRepresentation::IsApplicationRepresented(
1163   const std::string& app_id) const {
1164   dbms::SQLQuery query(db());
1165   if (!query.Prepare(sql_pt::kSelectApplicationRepresented)) {
1166     LOG4CXX_WARN(logger_, "Incorrect select application by id");
1167     return false;
1168   }
1169
1170   query.Bind(0, app_id);
1171   if (!query.Exec()) {
1172     LOG4CXX_WARN(logger_, "Failed select application by id");
1173     return false;
1174   }
1175   return query.GetInteger(0) != 0;
1176 }
1177
1178 bool SQLPTRepresentation::IsDefaultPolicy(const std::string& app_id) const {
1179   dbms::SQLQuery query(db());
1180   if (!query.Prepare(sql_pt::kSelectApplicationIsDefault)) {
1181     LOG4CXX_WARN(logger_, "Incorrect select application by id");
1182     return false;
1183   }
1184
1185   query.Bind(0, app_id);
1186   if (!query.Exec()) {
1187     LOG4CXX_WARN(logger_, "Failed select application by id");
1188     return false;
1189   }
1190   return query.IsNull(0) ? false : query.GetBoolean(0);
1191 }
1192
1193 bool SQLPTRepresentation::IsPredataPolicy(const std::string& app_id) const {
1194   return false;
1195 }
1196
1197 bool SQLPTRepresentation::SetDefaultPolicy(const std::string& app_id) {
1198   policy_table::ApplicationPolicies apps;
1199   if (!GatherApplicationPolicies(&apps)) {
1200     LOG4CXX_WARN(logger_, "Failed gathering application policies");
1201     return false;
1202   }
1203   apps[app_id] = apps[kDefaultId];
1204   if (!SaveApplicationPolicies(apps)) {
1205     LOG4CXX_WARN(logger_, "Failed saving application policies");
1206     return false;
1207   }
1208
1209   return SetIsDefault(app_id, true);
1210 }
1211
1212 bool SQLPTRepresentation::SetIsDefault(const std::string& app_id,
1213                                        bool is_default) const {
1214   LOG4CXX_TRACE(logger_, "Set flag is_default of application");
1215   dbms::SQLQuery query(db());
1216   if (!query.Prepare(sql_pt::kUpdateIsDefault)) {
1217     LOG4CXX_WARN(logger_, "Incorect statement for updating is_default");
1218     return false;
1219   }
1220
1221   query.Bind(0, is_default);
1222   query.Bind(1, app_id);
1223   if (!query.Exec()) {
1224     LOG4CXX_WARN(logger_, "Failed update is_default");
1225     return false;
1226   }
1227   return true;
1228 }
1229
1230 dbms::SQLDatabase* SQLPTRepresentation::db() const {
1231 #ifdef __QNX__
1232   dbms::SQLDatabase* db = new dbms::SQLDatabase(kDatabaseName);
1233   db->Open();
1234   return db;
1235 #else
1236   return db_;
1237 #endif
1238 }
1239
1240 }  // namespace policy
1241