Move PAP database provider to spring boot default
[policy/pap.git] / main / src / main / java / org / onap / policy / pap / main / rest / ProviderBase.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP PAP
4  * ================================================================================
5  * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2020-2021 Nordix Foundation.
7  * Modifications Copyright (C) 2020,2022 Bell Canada. All rights reserved.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.pap.main.rest;
24
25 import java.util.Collection;
26 import javax.ws.rs.core.Response.Status;
27 import org.onap.policy.common.utils.services.Registry;
28 import org.onap.policy.models.base.PfModelException;
29 import org.onap.policy.models.base.PfModelRuntimeException;
30 import org.onap.policy.models.pap.concepts.PolicyNotification;
31 import org.onap.policy.models.pdp.concepts.Pdp;
32 import org.onap.policy.models.pdp.concepts.PdpGroup;
33 import org.onap.policy.models.pdp.concepts.PdpSubGroup;
34 import org.onap.policy.models.pdp.concepts.PdpUpdate;
35 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
36 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifierOptVersion;
37 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
38 import org.onap.policy.pap.main.PapConstants;
39 import org.onap.policy.pap.main.comm.PdpModifyRequestMap;
40 import org.onap.policy.pap.main.notification.PolicyNotifier;
41 import org.onap.policy.pap.main.service.PdpGroupService;
42 import org.onap.policy.pap.main.service.PolicyAuditService;
43 import org.onap.policy.pap.main.service.PolicyStatusService;
44 import org.onap.policy.pap.main.service.ToscaServiceTemplateService;
45 import org.springframework.beans.factory.annotation.Autowired;
46 import org.springframework.boot.context.event.ApplicationReadyEvent;
47 import org.springframework.context.event.EventListener;
48
49 /**
50  * Super class of providers that deploy and undeploy PDP groups. The following items must
51  * be in the {@link Registry}:
52  * <ul>
53  * <li>PDP Modification Lock</li>
54  * <li>PDP Modify Request Map</li>
55  * <li>PAP DAO Factory</li>
56  * </ul>
57  */
58 public abstract class ProviderBase {
59     public static final String DB_ERROR_MSG = "DB error";
60     public static final String DEFAULT_USER = "PAP";
61
62     /**
63      * Lock used when updating PDPs.
64      */
65     private Object updateLock;
66
67     /**
68      * Used to send UPDATE and STATE-CHANGE requests to the PDPs.
69      */
70     private PdpModifyRequestMap requestMap;
71
72     /**
73      * Generates policy notifications based on responses from PDPs.
74      */
75     private PolicyNotifier notifier;
76
77     private ToscaServiceTemplateService toscaService;
78
79     private PdpGroupService pdpGroupService;
80
81     private PolicyStatusService policyStatusService;
82
83     private PolicyAuditService policyAuditService;
84
85     /**
86      * The setter method for injecting into Spring context.
87      *
88      * @param toscaService the toscaService to set
89      */
90     @Autowired
91     public final void setToscaService(ToscaServiceTemplateService toscaService) {
92         this.toscaService = toscaService;
93     }
94
95     /**
96      * The setter method for injecting into Spring context.
97      *
98      * @param pdpGroupService the pdpGroupService to set
99      */
100     @Autowired
101     public final void setPdpGroupService(PdpGroupService pdpGroupService) {
102         this.pdpGroupService = pdpGroupService;
103     }
104
105     /**
106      * The setter method for injecting into Spring context.
107      *
108      * @param policyStatusService the policyStatusService to set
109      */
110     @Autowired
111     public final void setPolicyStatusService(PolicyStatusService policyStatusService) {
112         this.policyStatusService = policyStatusService;
113     }
114
115     /**
116      * The setter method for injecting into Spring context.
117      *
118      * @param policyAuditService the policyAuditService to set
119      */
120     @Autowired
121     public final void setPolicyAuditService(PolicyAuditService policyAuditService) {
122         this.policyAuditService = policyAuditService;
123     }
124
125     /**
126      * The setter method for injecting into Spring context.
127      *
128      * @param policyNotifier the policyNotifier to set
129      */
130     @Autowired
131     public final void setPolicyNotifier(PolicyNotifier policyNotifier) {
132         this.notifier = policyNotifier;
133     }
134
135     /**
136      * Initializes the parameters..
137      */
138     @EventListener(ApplicationReadyEvent.class)
139     public void initialize() {
140         this.updateLock = Registry.get(PapConstants.REG_PDP_MODIFY_LOCK, Object.class);
141         this.requestMap = Registry.get(PapConstants.REG_PDP_MODIFY_MAP, PdpModifyRequestMap.class);
142     }
143
144     /**
145      * Processes a policy request.
146      *
147      * @param user user triggering request
148      * @param request PDP policy request
149      * @param processor function that processes the request
150      * @throws PfModelException if an error occurred
151      */
152     protected <T> void process(String user, T request, BiConsumerWithEx<SessionData, T> processor)
153             throws PfModelException {
154
155         synchronized (updateLock) {
156             SessionData data;
157             var notif = new PolicyNotification();
158
159             try {
160
161                 data = new SessionData(user, toscaService, pdpGroupService, policyStatusService, policyAuditService);
162                 processor.accept(data, request);
163
164                 // make all of the DB updates
165                 data.updateDb(notif);
166
167             } catch (PfModelRuntimeException e) {
168                 throw e;
169
170             } catch (RuntimeException e) {
171                 throw new PfModelException(Status.INTERNAL_SERVER_ERROR, "request failed", e);
172             }
173
174             // publish the requests
175             data.getPdpRequests().forEach(pair -> requestMap.addRequest(pair.getLeft(), pair.getRight()));
176
177             // publish the notifications
178             notifier.publish(notif);
179         }
180     }
181
182     /**
183      * Processes a policy request.
184      *
185      * @param request PDP policy request
186      * @param processor function that processes the request
187      * @throws PfModelException if an error occurred
188      */
189     protected <T> void process(T request, BiConsumerWithEx<SessionData, T> processor) throws PfModelException {
190         this.process(DEFAULT_USER, request, processor);
191     }
192
193     /**
194      * Process a single policy from the request.
195      *
196      * @param data session data
197      * @param desiredPolicy request policy
198      * @throws PfModelException if an error occurred
199      */
200     protected void processPolicy(SessionData data, ToscaConceptIdentifierOptVersion desiredPolicy)
201             throws PfModelException {
202
203         ToscaPolicy policy = getPolicy(data, desiredPolicy);
204
205         Collection<PdpGroup> groups = getGroups(data, policy.getTypeIdentifier());
206         if (groups.isEmpty()) {
207             throw new PfModelException(Status.BAD_REQUEST, "policy not supported by any PDP group: "
208                     + desiredPolicy.getName() + " " + desiredPolicy.getVersion());
209         }
210
211         var updater = makeUpdater(data, policy, desiredPolicy);
212
213         for (PdpGroup group : groups) {
214             upgradeGroup(data, group, updater);
215         }
216     }
217
218     /**
219      * Makes a function to update a subgroup. The function is expected to return
220      * {@code true} if the subgroup was updated, {@code false} if no update was
221      * necessary/appropriate.
222      *
223      * @param data session data
224      * @param policy policy to be added to or removed from each subgroup
225      * @param desiredPolicy request policy
226      * @return a function to update a subgroup
227      */
228     protected abstract Updater makeUpdater(SessionData data, ToscaPolicy policy,
229             ToscaConceptIdentifierOptVersion desiredPolicy);
230
231     /**
232      * Finds the active PDP group(s) that supports the given policy type.
233      *
234      * @param data session data
235      * @param policyType the policy type of interest
236      * @return the matching PDP group, or {@code null} if no active group supports the
237      *         given PDP types
238      * @throws PfModelException if an error occurred
239      */
240     private Collection<PdpGroup> getGroups(SessionData data, ToscaConceptIdentifier policyType)
241             throws PfModelException {
242
243         return data.getActivePdpGroupsByPolicyType(policyType);
244     }
245
246     /**
247      * Updates a group, assigning a new version number, if it actually changes.
248      *
249      * @param data session data
250      * @param group the original group, to be updated
251      * @param updater function to update a group
252      * @throws PfModelException if an error occurred
253      */
254     private void upgradeGroup(SessionData data, PdpGroup group, Updater updater) throws PfModelException {
255
256         var updated = false;
257
258         for (PdpSubGroup subgroup : group.getPdpSubgroups()) {
259
260             if (!updater.apply(group, subgroup)) {
261                 continue;
262             }
263
264             updated = true;
265
266             makeUpdates(data, group, subgroup);
267         }
268
269         if (updated) {
270             // something changed
271             data.update(group);
272         }
273     }
274
275     /**
276      * Makes UPDATE messages for each PDP in a subgroup.
277      *
278      * @param data session data
279      * @param group group containing the subgroup
280      * @param subgroup subgroup whose PDPs should receive messages
281      */
282     protected void makeUpdates(SessionData data, PdpGroup group, PdpSubGroup subgroup) {
283         for (Pdp pdp : subgroup.getPdpInstances()) {
284             data.addUpdate(makeUpdate(data, group, subgroup, pdp));
285         }
286     }
287
288     /**
289      * Makes an UPDATE message for a particular PDP.
290      *
291      * @param data session data
292      * @param group group to which the PDP should belong
293      * @param subgroup subgroup to which the PDP should belong
294      * @param pdp the PDP of interest
295      * @return a new UPDATE message
296      */
297     private PdpUpdate makeUpdate(SessionData data, PdpGroup group, PdpSubGroup subgroup, Pdp pdp) {
298
299         var update = new PdpUpdate();
300
301         update.setSource(PapConstants.PAP_NAME);
302         update.setName(pdp.getInstanceId());
303         update.setDescription(group.getDescription());
304         update.setPdpGroup(group.getName());
305         update.setPdpSubgroup(subgroup.getPdpType());
306         update.setPoliciesToBeDeployed(data.getPoliciesToBeDeployed());
307         update.setPoliciesToBeUndeployed(data.getPoliciesToBeUndeployed());
308
309         return update;
310     }
311
312     /**
313      * Gets the specified policy.
314      *
315      * @param data session data
316      * @param ident policy identifier, with an optional version
317      * @return the policy of interest
318      * @throws PfModelRuntimeException if an error occurred or the policy was not found
319      */
320     private ToscaPolicy getPolicy(SessionData data, ToscaConceptIdentifierOptVersion ident) {
321         try {
322             ToscaPolicy policy = data.getPolicy(ident);
323             if (policy == null) {
324                 throw new PfModelRuntimeException(Status.NOT_FOUND,
325                         "cannot find policy: " + ident.getName() + " " + ident.getVersion());
326             }
327
328             return policy;
329
330         } catch (PfModelException e) {
331             throw new PfModelRuntimeException(e.getErrorResponse().getResponseCode(),
332                     e.getErrorResponse().getErrorMessage(), e);
333         }
334     }
335
336     @FunctionalInterface
337     public static interface BiConsumerWithEx<F, S> {
338         /**
339          * Performs this operation on the given arguments.
340          *
341          * @param firstArg the first input argument
342          * @param secondArg the second input argument
343          * @throws PfModelException if an error occurred
344          */
345         void accept(F firstArg, S secondArg) throws PfModelException;
346     }
347
348     @FunctionalInterface
349     public static interface Updater {
350         boolean apply(PdpGroup group, PdpSubGroup subgroup) throws PfModelException;
351     }
352 }