Adding PdpGroup query & statechange providers
[policy/pap.git] / main / src / main / java / org / onap / policy / pap / main / rest / depundep / SessionData.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP PAP
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. 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.policy.pap.main.rest.depundep;
22
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.stream.Collectors;
29 import org.onap.policy.common.utils.validation.Version;
30 import org.onap.policy.models.base.PfModelException;
31 import org.onap.policy.models.pdp.concepts.PdpGroup;
32 import org.onap.policy.models.pdp.concepts.PdpGroupFilter;
33 import org.onap.policy.models.pdp.concepts.PdpUpdate;
34 import org.onap.policy.models.pdp.enums.PdpState;
35 import org.onap.policy.models.provider.PolicyModelsProvider;
36 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
37 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter;
38 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
39 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
40 import org.onap.policy.pap.main.PolicyPapRuntimeException;
41
42 /**
43  * Data used during a single REST call when updating PDP policies.
44  */
45 public class SessionData {
46     private final PolicyModelsProvider dao;
47
48     /**
49      * Maps a group name to its group data. This accumulates the set of groups to be
50      * created and updated when the REST call completes.
51      */
52     private final Map<String, GroupData> groupCache = new HashMap<>();
53
54     /**
55      * Maps a policy type to the list of matching groups. Every group appearing within
56      * this map has a corresponding entry in {@link #groupCache}.
57      */
58     private final Map<ToscaPolicyTypeIdentifier, List<GroupData>> type2groups = new HashMap<>();
59
60     /**
61      * Maps a PDP name to its most recently generated update request.
62      */
63     private final Map<String, PdpUpdate> pdpUpdates = new HashMap<>();
64
65     /**
66      * Maps a policy's identifier to the policy.
67      */
68     private final Map<ToscaPolicyIdentifier, ToscaPolicy> policyCache = new HashMap<>();
69
70     /**
71      * Maps a policy name to its latest policy. Every policy appearing within this map has
72      * a corresponding entry in {@link #policyCache}.
73      */
74     private final Map<String, ToscaPolicy> latestPolicy = new HashMap<>();
75
76
77     /**
78      * Constructs the object.
79      *
80      * @param dao DAO provider
81      */
82     public SessionData(PolicyModelsProvider dao) {
83         this.dao = dao;
84     }
85
86     /**
87      * Gets the policy, referenced by an identifier. Loads it from the cache, if possible.
88      * Otherwise, gets it from the DB.
89      *
90      * @param ident policy identifier
91      * @return the specified policy
92      * @throws PolicyPapRuntimeException if an error occurs
93      */
94     public ToscaPolicy getPolicy(ToscaPolicyIdentifier ident) {
95
96         return policyCache.computeIfAbsent(ident, key -> {
97
98             try {
99                 List<ToscaPolicy> lst = dao.getPolicyList(ident.getName(), ident.getVersion());
100
101                 if (lst.isEmpty()) {
102                     throw new PolicyPapRuntimeException(
103                                     "cannot find policy: " + ident.getName() + " " + ident.getVersion());
104                 }
105
106                 if (lst.size() > 1) {
107                     throw new PolicyPapRuntimeException(
108                                     "too many policies match: " + ident.getName() + " " + ident.getVersion());
109                 }
110
111                 return lst.get(0);
112
113             } catch (PfModelException e) {
114                 throw new PolicyPapRuntimeException("cannot get policy: " + ident.getName() + " " + ident.getVersion(),
115                                 e);
116             }
117         });
118     }
119
120     /**
121      * Adds an update to the set of updates, replacing any previous entry for the given
122      * PDP.
123      *
124      * @param update the update to be added
125      */
126     public void addUpdate(PdpUpdate update) {
127         pdpUpdates.put(update.getName(), update);
128     }
129
130     /**
131      * Gets the accumulated UPDATE requests.
132      *
133      * @return the UPDATE requests
134      */
135     public Collection<PdpUpdate> getPdpUpdates() {
136         return pdpUpdates.values();
137     }
138
139     /**
140      * Determines if a group has been newly created as part of this REST call.
141      *
142      * @param group name to the group of interest
143      * @return {@code true} if the group has been newly created, {@code false} otherwise
144      */
145     public boolean isNewlyCreated(String group) {
146         GroupData data = groupCache.get(group);
147         return (data != null && data.isNew());
148     }
149
150     /**
151      * Gets the policy having the given name and the maximum version.
152      *
153      * @param name name of the desired policy
154      * @return the desired policy, or {@code null} if there is no policy with given name
155      * @throws PfModelException if an error occurs
156      */
157     public ToscaPolicy getPolicyMaxVersion(String name) throws PfModelException {
158         ToscaPolicy policy = latestPolicy.get(name);
159         if (policy != null) {
160             return policy;
161         }
162
163         ToscaPolicyFilter filter =
164                         ToscaPolicyFilter.builder().name(name).version(ToscaPolicyFilter.LATEST_VERSION).build();
165         List<ToscaPolicy> policies = dao.getFilteredPolicyList(filter);
166         if (policies.isEmpty()) {
167             throw new PolicyPapRuntimeException("cannot find policy: " + name);
168         }
169
170         policy = policies.get(0);
171         policyCache.putIfAbsent(policy.getIdentifier(), policy);
172         latestPolicy.put(name, policy);
173
174         return policy;
175     }
176
177     /**
178      * Adds a new version of a group to the cache.
179      *
180      * @param newGroup the new group to be added
181      * @throws IllegalStateException if the old group has not been loaded into the cache
182      *         yet
183      * @throws PfModelException if an error occurs
184      */
185     public void setNewGroup(PdpGroup newGroup) throws PfModelException {
186         String name = newGroup.getName();
187         GroupData data = groupCache.get(name);
188         if (data == null) {
189             throw new IllegalStateException("group not cached: " + name);
190         }
191
192         if (data.getLatestVersion() != null) {
193             // already have the latest version
194             data.setNewGroup(newGroup);
195             return;
196         }
197
198         // must determine the latest version of this group, regardless of its state
199         PdpGroupFilter filter = PdpGroupFilter.builder().name(name).version(PdpGroupFilter.LATEST_VERSION).build();
200         List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
201         if (groups.isEmpty()) {
202             throw new PolicyPapRuntimeException("cannot find group: " + name);
203         }
204
205         PdpGroup group = groups.get(0);
206         Version vers = Version.makeVersion("PdpGroup", group.getName(), group.getVersion());
207         if (vers == null) {
208             // none of the versions are numeric - start with zero and increment from there
209             vers = new Version(0, 0, 0);
210         }
211
212         data.setLatestVersion(vers);
213         data.setNewGroup(newGroup);
214     }
215
216     /**
217      * Gets the active groups supporting the given policy.
218      *
219      * @param type desired policy type
220      * @return the active groups supporting the given policy
221      * @throws PfModelException if an error occurs
222      */
223     public List<PdpGroup> getActivePdpGroupsByPolicyType(ToscaPolicyTypeIdentifier type) throws PfModelException {
224         List<GroupData> data = type2groups.get(type);
225         if (data != null) {
226             return data.stream().map(GroupData::getCurrentGroup).collect(Collectors.toList());
227         }
228
229         final List<ToscaPolicyTypeIdentifier> policyTypeList = new ArrayList<>(1);
230         policyTypeList.add(type);
231
232         PdpGroupFilter filter = PdpGroupFilter.builder().policyTypeList(policyTypeList).matchPolicyTypesExactly(true)
233                 .groupState(PdpState.ACTIVE).build();
234
235         List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
236
237         data = groups.stream().map(this::addGroup).collect(Collectors.toList());
238         type2groups.put(type, data);
239
240         return groups;
241     }
242
243     /**
244      * Adds a group to the group cache, if it isn't already in the cache.
245      *
246      * @param group the group to be added
247      * @return the cache entry
248      */
249     private GroupData addGroup(PdpGroup group) {
250         GroupData data = groupCache.get(group.getName());
251         if (data != null) {
252             return data;
253         }
254
255         data = new GroupData(group);
256         groupCache.put(group.getName(), data);
257
258         return data;
259     }
260
261     /**
262      * Update the DB with the changes.
263      *
264      * @throws PfModelException if an error occurs
265      */
266     public void updateDb() throws PfModelException {
267         List<GroupData> updatedGroups =
268                         groupCache.values().stream().filter(GroupData::isNew).collect(Collectors.toList());
269         if (updatedGroups.isEmpty()) {
270             return;
271         }
272
273         // create new groups BEFORE we deactivate the old groups
274         dao.createPdpGroups(updatedGroups.stream().map(GroupData::getCurrentGroup).collect(Collectors.toList()));
275         dao.updatePdpGroups(updatedGroups.stream().map(GroupData::getOldGroup).collect(Collectors.toList()));
276     }
277 }