2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file InMemoryStorageBackend.cpp
18 * @author Aleksander Zdyb <a.zdyb@partner.samsung.com>
20 * @brief Implementation of InMemoryStorageBackend
29 #include <sys/types.h>
30 #include <unordered_map>
34 #include <exceptions/BucketNotExistsException.h>
35 #include <exceptions/CannotCreateFileException.h>
36 #include <exceptions/FileNotFoundException.h>
37 #include <exceptions/UnexpectedErrorException.h>
38 #include <types/PolicyBucket.h>
39 #include <types/PolicyResult.h>
40 #include <types/PolicyType.h>
42 #include <storage/BucketDeserializer.h>
43 #include <storage/StorageDeserializer.h>
44 #include <storage/StorageSerializer.h>
46 #include "InMemoryStorageBackend.h"
50 void InMemoryStorageBackend::load(void) {
51 std::string indexFilename = m_dbPath + m_indexFileName;
54 std::shared_ptr<std::ifstream> indexStream = std::make_shared<std::ifstream>();
55 openFileStream(indexStream, indexFilename);
57 StorageDeserializer storageDeserializer(indexStream,
58 std::bind(&InMemoryStorageBackend::bucketStreamOpener, this, std::placeholders::_1));
60 storageDeserializer.initBuckets(buckets());
61 storageDeserializer.loadBuckets(buckets());
62 } catch (const FileNotFoundException &) {
63 LOGE("Reading cynara database failed.");
66 if (!hasBucket(defaultPolicyBucketId)) {
67 LOGN("Creating defaultBucket.");
68 this->buckets().insert({ defaultPolicyBucketId, PolicyBucket() });
72 void InMemoryStorageBackend::save(void) {
75 int ret = mkdir(m_dbPath.c_str(), S_IRWXU);
79 LOGE("Cannot create directory <%s>. Error [%d] : <%s>.",
80 m_dbPath.c_str(), err, strerror(err));
81 throw UnexpectedErrorException(err, strerror(err));
85 std::shared_ptr<std::ofstream> indexStream = std::make_shared<std::ofstream>();
86 openDumpFileStream(indexStream, m_dbPath + m_indexFileName);
88 StorageSerializer storageSerializer(indexStream);
89 storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
90 this, std::placeholders::_1));
93 PolicyBucket InMemoryStorageBackend::searchDefaultBucket(const PolicyKey &key) {
94 return searchBucket(defaultPolicyBucketId, key);
97 PolicyBucket InMemoryStorageBackend::searchBucket(const PolicyBucketId &bucketId,
98 const PolicyKey &key) {
100 const auto &bucket = this->buckets().at(bucketId);
101 return bucket.filtered(key);
102 } catch (const std::out_of_range &) {
103 throw BucketNotExistsException(bucketId);
107 void InMemoryStorageBackend::insertPolicy(const PolicyBucketId &bucketId, PolicyPtr policy) {
109 auto &bucket = buckets().at(bucketId);
110 auto &policies = bucket.policyCollection();
111 policies.push_back(policy);
112 } catch (const std::out_of_range &) {
113 throw BucketNotExistsException(bucketId);
117 void InMemoryStorageBackend::createBucket(const PolicyBucketId &bucketId,
118 const PolicyResult &defaultPolicy) {
119 PolicyBucket newBucket;
120 newBucket.setDefaultPolicy(defaultPolicy);
121 buckets().insert({ bucketId, newBucket });
124 void InMemoryStorageBackend::updateBucket(const PolicyBucketId &bucketId,
125 const PolicyResult &defaultPolicy) {
127 auto &bucket = buckets().at(bucketId);
128 bucket.setDefaultPolicy(defaultPolicy);
129 } catch (const std::out_of_range &) {
130 throw BucketNotExistsException(bucketId);
134 void InMemoryStorageBackend::deleteBucket(const PolicyBucketId &bucketId) {
135 auto bucketErased = buckets().erase(bucketId);
136 if (bucketErased == 0) {
137 throw BucketNotExistsException(bucketId);
141 bool InMemoryStorageBackend::hasBucket(const PolicyBucketId &bucketId) {
142 return buckets().find(bucketId) != buckets().end();
145 void InMemoryStorageBackend::deletePolicy(const PolicyBucketId &bucketId, const PolicyKey &key) {
147 // TODO: Move the erase code to PolicyCollection maybe?
148 auto &bucket = buckets().at(bucketId);
149 auto &policies = bucket.policyCollection();
150 policies.erase(remove_if(policies.begin(), policies.end(),
151 [key](PolicyPtr policy) -> bool {
152 return policy->key() == key;
154 } catch (const std::out_of_range &) {
155 throw BucketNotExistsException(bucketId);
159 void InMemoryStorageBackend::deleteLinking(const PolicyBucketId &bucketId) {
160 auto bucketIdMatches = [&bucketId] (PolicyPtr policy) -> bool {
161 auto policyResult = policy->result();
163 // Check bucket id only if policy is a bucket policy
164 // TODO: Maybe move the test to PolicyResult
165 if (policyResult.policyType() == PredefinedPolicyType::BUCKET) {
166 return policyResult.metadata() == bucketId;
171 for (auto &bucketIter : buckets()) {
172 // TODO: Move the erase code to PolicyCollection maybe?
173 auto &bucket = bucketIter.second;
174 auto &policies = bucket.policyCollection();
175 policies.erase(remove_if(policies.begin(), policies.end(), bucketIdMatches),
180 void InMemoryStorageBackend::openFileStream(std::shared_ptr<std::ifstream> stream,
181 const std::string &filename) {
182 // TODO: Consider adding exceptions to streams and handling them:
183 // stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
184 stream->open(filename);
186 if (!stream->is_open())
187 throw FileNotFoundException(filename);
190 void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr<std::ofstream> stream,
191 const std::string &filename) {
192 stream->open(filename, std::ofstream::out | std::ofstream::trunc);
194 if (!stream->is_open()) {
195 throw CannotCreateFileException(filename);
199 std::shared_ptr<BucketDeserializer> InMemoryStorageBackend::bucketStreamOpener(
200 const PolicyBucketId &bucketId) {
201 std::string bucketFilename = m_dbPath + "_" + bucketId;
202 std::shared_ptr<std::ifstream> bucketStream = std::make_shared<std::ifstream>();
204 openFileStream(bucketStream, bucketFilename);
205 return std::make_shared<BucketDeserializer>(bucketStream);
206 } catch (const FileNotFoundException &) {
211 std::shared_ptr<StorageSerializer> InMemoryStorageBackend::bucketDumpStreamOpener(
212 const PolicyBucketId &bucketId) {
213 std::string bucketFilename = m_dbPath + "_" + bucketId;
214 std::shared_ptr<std::ofstream> bucketStream = std::make_shared<std::ofstream>();
216 openDumpFileStream(bucketStream, bucketFilename);
217 return std::make_shared<StorageSerializer>(bucketStream);
220 } /* namespace Cynara */