ef924748b3e85f3676de8fb6a4624a7757a88090
[ccsdk/oran.git] /
1 /*-
2  * ========================LICENSE_START=================================
3  * ONAP : ccsdk oran
4  * ======================================================================
5  * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
6  * ======================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 package org.onap.ccsdk.oran.a1policymanagementservice.repository;
22
23 import com.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25
26 import java.io.File;
27 import java.io.FileOutputStream;
28 import java.io.PrintStream;
29 import java.lang.invoke.MethodHandles;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.time.Instant;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.Vector;
40
41 import lombok.Builder;
42 import lombok.Getter;
43
44 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
45 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.EntityNotFoundException;
46 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import org.springframework.beans.factory.annotation.Autowired;
50 import org.springframework.context.annotation.Configuration;
51 import org.springframework.util.FileSystemUtils;
52 import reactor.util.annotation.Nullable;
53
54 @SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally
55 @Configuration
56 public class Policies {
57
58     @Getter
59     @Builder
60     private static class PersistentPolicyInfo {
61         private String id;
62         private String json;
63         private String ownerServiceId;
64         private String ricId;
65         private String typeId;
66         private String statusNotificationUri;
67         private boolean isTransient;
68         private String lastModified;
69     }
70
71     private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
72     private Map<String, Policy> policiesId = new HashMap<>();
73     private MultiMap<Policy> policiesRic = new MultiMap<>();
74     private MultiMap<Policy> policiesService = new MultiMap<>();
75     private MultiMap<Policy> policiesType = new MultiMap<>();
76
77     private final ApplicationConfig appConfig;
78     private static Gson gson = new GsonBuilder().create();
79
80     public Policies(@Autowired ApplicationConfig appConfig) {
81         this.appConfig = appConfig;
82     }
83
84     public synchronized void put(Policy policy) {
85         policiesId.put(policy.getId(), policy);
86         policiesRic.put(policy.getRic().id(), policy.getId(), policy);
87         policiesService.put(policy.getOwnerServiceId(), policy.getId(), policy);
88         policiesType.put(policy.getType().getId(), policy.getId(), policy);
89         if (this.appConfig.getVardataDirectory() != null && !policy.isTransient()) {
90             store(policy);
91         }
92     }
93
94     public synchronized boolean containsPolicy(String id) {
95         return policiesId.containsKey(id);
96     }
97
98     public synchronized Policy get(String id) {
99         return policiesId.get(id);
100     }
101
102     public synchronized Policy getPolicy(String id) throws EntityNotFoundException {
103         Policy p = policiesId.get(id);
104         if (p == null) {
105             throw new EntityNotFoundException("Could not find policy: " + id);
106         }
107         return p;
108     }
109
110     public synchronized Collection<Policy> getAll() {
111         return new Vector<>(policiesId.values());
112     }
113
114     public synchronized Collection<Policy> getForService(String service) {
115         return policiesService.get(service);
116     }
117
118     public synchronized Collection<Policy> getForRic(String ric) {
119         return policiesRic.get(ric);
120     }
121
122     public synchronized Collection<Policy> getForType(String type) {
123         return policiesType.get(type);
124     }
125
126     public synchronized Policy removeId(String id) {
127         Policy p = policiesId.get(id);
128         if (p != null) {
129             remove(p);
130         }
131         return p;
132     }
133
134     public synchronized void remove(Policy policy) {
135         if (!policy.isTransient()) {
136             try {
137                 Files.delete(getPath(policy));
138             } catch (Exception e) {
139                 logger.debug("Could not delete policy from database: {}", e.getMessage());
140             }
141         }
142         policiesId.remove(policy.getId());
143         policiesRic.remove(policy.getRic().id(), policy.getId());
144         policiesService.remove(policy.getOwnerServiceId(), policy.getId());
145         policiesType.remove(policy.getType().getId(), policy.getId());
146     }
147
148     public synchronized void removePoliciesForRic(String ricId) {
149         Collection<Policy> policiesForRic = getForRic(ricId);
150         for (Policy policy : policiesForRic) {
151             remove(policy);
152         }
153     }
154
155     public Collection<Policy> filterPolicies(@Nullable String typeId, @Nullable String ricId,
156             @Nullable String serviceId, @Nullable String typeName) {
157
158         if (typeId != null) {
159             return filter(this.getForType(typeId), null, ricId, serviceId, typeName);
160         } else if (serviceId != null) {
161             return filter(this.getForService(serviceId), typeId, ricId, null, typeName);
162         } else if (ricId != null) {
163             return filter(this.getForRic(ricId), typeId, null, serviceId, typeName);
164         } else {
165             return filter(this.getAll(), typeId, ricId, serviceId, typeName);
166         }
167     }
168
169     public synchronized int size() {
170         return policiesId.size();
171     }
172
173     public synchronized void clear() {
174         while (policiesId.size() > 0) {
175             Set<String> keys = policiesId.keySet();
176             removeId(keys.iterator().next());
177         }
178         try {
179             if (this.appConfig.getVardataDirectory() != null) {
180                 FileSystemUtils.deleteRecursively(getDatabasePath());
181             }
182         } catch (Exception e) {
183             logger.warn("Could not delete policy database : {}", e.getMessage());
184         }
185     }
186
187     public void store(Policy policy) {
188         try {
189             Files.createDirectories(getDatabasePath(policy.getRic()));
190             try (PrintStream out = new PrintStream(new FileOutputStream(getFile(policy)))) {
191                 out.print(gson.toJson(toStorageObject(policy)));
192             }
193         } catch (Exception e) {
194             logger.warn("Could not store policy: {} {}", policy.getId(), e.getMessage());
195         }
196     }
197
198     private boolean isMatch(String filterValue, String actualValue) {
199         return filterValue == null || actualValue.equals(filterValue);
200     }
201
202     private boolean isTypeMatch(Policy policy, @Nullable String typeName) {
203         return (typeName == null) || policy.getType().getTypeId().getName().equals(typeName);
204     }
205
206     private Collection<Policy> filter(Collection<Policy> collection, String typeId, String ricId, String serviceId,
207             String typeName) {
208         if (typeId == null && ricId == null && serviceId == null && typeName == null) {
209             return collection;
210         }
211         List<Policy> filtered = new ArrayList<>(collection.size());
212         for (Policy p : collection) {
213             if (isMatch(typeId, p.getType().getId()) && isMatch(ricId, p.getRic().id())
214                     && isMatch(serviceId, p.getOwnerServiceId()) && isTypeMatch(p, typeName)) {
215                 filtered.add(p);
216             }
217         }
218         return filtered;
219     }
220
221     private File getFile(Policy policy) throws ServiceException {
222         return getPath(policy).toFile();
223     }
224
225     private Path getPath(Policy policy) throws ServiceException {
226         return Path.of(getDatabaseDirectory(policy.getRic()), policy.getId() + ".json");
227     }
228
229     public synchronized void restoreFromDatabase(Ric ric, PolicyTypes types) {
230         try {
231             Files.createDirectories(getDatabasePath(ric));
232             for (File file : getDatabasePath(ric).toFile().listFiles()) {
233                 String json = Files.readString(file.toPath());
234                 PersistentPolicyInfo policyStorage = gson.fromJson(json, PersistentPolicyInfo.class);
235                 this.put(toPolicy(policyStorage, ric, types));
236             }
237             logger.debug("Restored policy database for RIC: {}, number of policies: {}", ric.id(),
238                     this.policiesRic.get(ric.id()).size());
239         } catch (Exception e) {
240             logger.warn("Could not restore policy database for RIC: {}, reason : {}", ric.id(), e.getMessage());
241         }
242     }
243
244     private PersistentPolicyInfo toStorageObject(Policy p) {
245         return PersistentPolicyInfo.builder() //
246                 .id(p.getId()) //
247                 .json(p.getJson()) //
248                 .ownerServiceId(p.getOwnerServiceId()) //
249                 .ricId(p.getRic().id()) //
250                 .statusNotificationUri(p.getStatusNotificationUri()) //
251                 .typeId(p.getType().getId()) //
252                 .isTransient(p.isTransient()) //
253                 .lastModified(p.getLastModified().toString()) //
254                 .build();
255     }
256
257     Policy toPolicy(PersistentPolicyInfo p, Ric ric, PolicyTypes types) throws EntityNotFoundException {
258         return Policy.builder() //
259                 .id(p.getId()) //
260                 .isTransient(p.isTransient()) //
261                 .json(p.getJson()) //
262                 .lastModified(Instant.parse(p.lastModified)) //
263                 .ownerServiceId(p.getOwnerServiceId()) //
264                 .ric(ric) //
265                 .statusNotificationUri(p.getStatusNotificationUri()) //
266                 .type(types.getType(p.getTypeId())) //
267                 .build();
268     }
269
270     private Path getDatabasePath(Ric ric) throws ServiceException {
271         return Path.of(getDatabaseDirectory(ric));
272     }
273
274     private String getDatabaseDirectory(Ric ric) throws ServiceException {
275         return getDatabaseDirectory() + "/" + ric.id();
276     }
277
278     private String getDatabaseDirectory() throws ServiceException {
279         if (appConfig.getVardataDirectory() == null) {
280             throw new ServiceException("No database storage provided");
281         }
282         return appConfig.getVardataDirectory() + "/database/policyInstances";
283     }
284
285     private Path getDatabasePath() throws ServiceException {
286         return Path.of(getDatabaseDirectory());
287     }
288 }