33ac81f5dbe146fafb1018390a2c4bfc9a6b0e56
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.services.onappf.handler;
22
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.List;
26 import org.onap.policy.apex.services.onappf.ApexStarterConstants;
27 import org.onap.policy.apex.services.onappf.comm.PdpStatusPublisher;
28 import org.onap.policy.apex.services.onappf.exception.ApexStarterException;
29 import org.onap.policy.common.endpoints.event.comm.TopicSink;
30 import org.onap.policy.common.utils.services.Registry;
31 import org.onap.policy.models.pdp.concepts.PdpResponseDetails;
32 import org.onap.policy.models.pdp.concepts.PdpStatus;
33 import org.onap.policy.models.pdp.concepts.PdpUpdate;
34 import org.onap.policy.models.pdp.enums.PdpResponseStatus;
35 import org.onap.policy.models.pdp.enums.PdpState;
36 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * This class supports the handling of pdp update messages.
42  *
43  * @author Ajith Sreekumar (ajith.sreekumar@est.tech)
44  */
45 public class PdpUpdateMessageHandler {
46
47     private static final Logger LOGGER = LoggerFactory.getLogger(PdpUpdateMessageHandler.class);
48
49     /**
50      * Method which handles a pdp update event from PAP.
51      *
52      * @param pdpUpdateMsg pdp update message
53      */
54     public void handlePdpUpdateEvent(final PdpUpdate pdpUpdateMsg) {
55         final PdpMessageHandler pdpMessageHandler = new PdpMessageHandler();
56         final PdpStatus pdpStatusContext = Registry.get(ApexStarterConstants.REG_PDP_STATUS_OBJECT, PdpStatus.class);
57         PdpResponseDetails pdpResponseDetails = null;
58         if (pdpUpdateMsg.appliesTo(pdpStatusContext.getName(), pdpStatusContext.getPdpGroup(),
59                 pdpStatusContext.getPdpSubgroup())) {
60             if (checkIfAlreadyHandled(pdpUpdateMsg, pdpStatusContext)) {
61                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
62                         PdpResponseStatus.SUCCESS, "Pdp already updated");
63             } else {
64                 pdpResponseDetails = handlePdpUpdate(pdpUpdateMsg, pdpMessageHandler, pdpStatusContext);
65             }
66             final PdpStatusPublisher pdpStatusPublisherTemp =
67                     Registry.get(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER);
68             final PdpStatus pdpStatus = pdpMessageHandler.createPdpStatusFromContext();
69             pdpStatus.setResponse(pdpResponseDetails);
70             pdpStatus.setDescription("Pdp status response message for PdpUpdate");
71             pdpStatusPublisherTemp.send(pdpStatus);
72         }
73     }
74
75     /**
76      * Method to do pdp update.
77      *
78      * @param pdpUpdateMsg the pdp update message
79      * @param pdpMessageHandler the message handler
80      * @param pdpStatusContext the pdp status in memory
81      * @return pdpResponseDetails the pdp response
82      */
83     private PdpResponseDetails handlePdpUpdate(final PdpUpdate pdpUpdateMsg, final PdpMessageHandler pdpMessageHandler,
84         final PdpStatus pdpStatusContext) {
85         PdpResponseDetails pdpResponseDetails = null;
86         final PdpStatusPublisher pdpStatusPublisher = Registry.get(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER);
87         if (null != pdpUpdateMsg.getPdpHeartbeatIntervalMs() && pdpUpdateMsg.getPdpHeartbeatIntervalMs() > 0
88                 && pdpStatusPublisher.getInterval() != pdpUpdateMsg.getPdpHeartbeatIntervalMs()) {
89             updateInterval(pdpUpdateMsg.getPdpHeartbeatIntervalMs());
90         }
91         pdpStatusContext.setPdpGroup(pdpUpdateMsg.getPdpGroup());
92         pdpStatusContext.setPdpSubgroup(pdpUpdateMsg.getPdpSubgroup());
93         pdpStatusContext
94                 .setPolicies(new PdpMessageHandler().getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies()));
95         Registry.registerOrReplace(ApexStarterConstants.REG_APEX_TOSCA_POLICY_LIST, pdpUpdateMsg.getPolicies());
96         if (pdpStatusContext.getState().equals(PdpState.ACTIVE)) {
97             pdpResponseDetails = startOrStopApexEngineBasedOnPolicies(pdpUpdateMsg, pdpMessageHandler);
98
99             ApexEngineHandler apexEngineHandler = Registry.get(ApexStarterConstants.REG_APEX_ENGINE_HANDLER);
100             // in hearbeat while in active state, only the policies which are running should be there.
101             // if some policy fails, that shouldn't go in the heartbeat.
102             // If no policies are running, then the policy list in the heartbeat can be empty
103             if (null != apexEngineHandler && apexEngineHandler.isApexEngineRunning()) {
104                 pdpStatusContext.setPolicies(apexEngineHandler.getRunningPolicies());
105             } else {
106                 pdpStatusContext.setPolicies(Collections.emptyList());
107             }
108         }
109         if (null == pdpResponseDetails) {
110             pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
111                     PdpResponseStatus.SUCCESS, "Pdp update successful.");
112         }
113         return pdpResponseDetails;
114     }
115
116     /**
117      * Method to start or stop apex engine based on the list of policies received from pap. When current state is
118      * active, if PAP sends PdpUpdate with empty policies list, stop apex engine, or, if there is a change in policies,
119      * stop the current running policies and the deploy the new ones.
120      *
121      * @param pdpUpdateMsg the pdp update message from pap
122      * @param pdpMessageHandler pdp message handler
123      * @param pdpStatusContext the pdp status object in memory
124      * @return pdpResponseDetails the pdp response
125      */
126     private PdpResponseDetails startOrStopApexEngineBasedOnPolicies(final PdpUpdate pdpUpdateMsg,
127             final PdpMessageHandler pdpMessageHandler) {
128         PdpResponseDetails pdpResponseDetails = null;
129         ApexEngineHandler apexEngineHandler = null;
130         try {
131             apexEngineHandler = Registry.get(ApexStarterConstants.REG_APEX_ENGINE_HANDLER);
132         } catch (final IllegalArgumentException e) {
133             LOGGER.debug("ApenEngineHandler not in registry.", e);
134         }
135         if (pdpUpdateMsg.getPolicies().isEmpty()) {
136             pdpResponseDetails = stopApexEngineBasedOnPolicies(pdpUpdateMsg, pdpMessageHandler, apexEngineHandler);
137         } else {
138             pdpResponseDetails = startApexEngineBasedOnPolicies(pdpUpdateMsg, pdpMessageHandler, apexEngineHandler);
139         }
140         return pdpResponseDetails;
141     }
142
143     private PdpResponseDetails stopApexEngineBasedOnPolicies(final PdpUpdate pdpUpdateMsg,
144         final PdpMessageHandler pdpMessageHandler, ApexEngineHandler apexEngineHandler) {
145         PdpResponseDetails pdpResponseDetails = null;
146         if (null != apexEngineHandler && apexEngineHandler.isApexEngineRunning()) {
147             try {
148                 apexEngineHandler.shutdown();
149                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
150                     PdpResponseStatus.SUCCESS, "Pdp update successful. No policies are running.");
151             } catch (final ApexStarterException e) {
152                 LOGGER.error("Pdp update failed as the policies couldn't be undeployed.", e);
153                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
154                         PdpResponseStatus.FAIL, "Pdp update failed as the policies couldn't be undeployed.");
155             }
156         }
157         return pdpResponseDetails;
158     }
159
160     private PdpResponseDetails startApexEngineBasedOnPolicies(final PdpUpdate pdpUpdateMsg,
161         final PdpMessageHandler pdpMessageHandler, ApexEngineHandler apexEngineHandler) {
162         PdpResponseDetails pdpResponseDetails = null;
163         try {
164             if (null != apexEngineHandler && apexEngineHandler.isApexEngineRunning()) {
165                 apexEngineHandler.updateApexEngine(pdpUpdateMsg.getPolicies());
166             } else {
167                 apexEngineHandler = new ApexEngineHandler(pdpUpdateMsg.getPolicies());
168                 Registry.registerOrReplace(ApexStarterConstants.REG_APEX_ENGINE_HANDLER, apexEngineHandler);
169             }
170             if (apexEngineHandler.isApexEngineRunning()) {
171                 List<ToscaPolicyIdentifier> runningPolicies = apexEngineHandler.getRunningPolicies();
172                 if (new HashSet<>(runningPolicies)
173                     .equals(new HashSet<>(pdpMessageHandler.getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies())))) {
174                     pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
175                         PdpResponseStatus.SUCCESS, "Apex engine started and policies are running.");
176                 } else {
177                     StringBuilder message =
178                         new StringBuilder("Apex engine started. But, only the following polices are running - ");
179                     for (ToscaPolicyIdentifier policy : runningPolicies) {
180                         message.append(policy.getName()).append(":").append(policy.getVersion()).append("  ");
181                     }
182                     message.append(". Other policies failed execution. Please see the logs for more details.");
183                     pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
184                         PdpResponseStatus.SUCCESS, message.toString());
185                 }
186             } else {
187                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
188                     PdpResponseStatus.FAIL, "Apex engine failed to start.");
189             }
190         } catch (final ApexStarterException e) {
191             LOGGER.error("Apex engine service running failed. ", e);
192             pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
193                     PdpResponseStatus.FAIL, "Apex engine service running failed. " + e.getMessage());
194         }
195         return pdpResponseDetails;
196     }
197
198     /**
199      * Method checks if the Pdp update message is already handled by checking the values in the context.
200      *
201      * @param pdpUpdateMsg pdp update message received from pap
202      * @param pdpStatusContext values saved in context memory
203      * @return boolean flag which tells if the information is same or not
204      */
205     private boolean checkIfAlreadyHandled(final PdpUpdate pdpUpdateMsg, final PdpStatus pdpStatusContext) {
206         return null != pdpStatusContext.getPdpGroup()
207                 && pdpStatusContext.getPdpGroup().equals(pdpUpdateMsg.getPdpGroup())
208                 && null != pdpStatusContext.getPdpSubgroup()
209                 && pdpStatusContext.getPdpSubgroup().equals(pdpUpdateMsg.getPdpSubgroup())
210                 && null != pdpStatusContext.getPolicies() && new PdpMessageHandler()
211                         .getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies()).equals(pdpStatusContext.getPolicies());
212     }
213
214     /**
215      * Method to update the time interval used by the timer task.
216      *
217      * @param interval time interval received in the pdp update message from pap
218      */
219     public void updateInterval(final long interval) {
220         final PdpStatusPublisher pdpStatusPublisher = Registry.get(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER);
221         pdpStatusPublisher.terminate();
222         final List<TopicSink> topicSinks = Registry.get(ApexStarterConstants.REG_APEX_PDP_TOPIC_SINKS);
223         Registry.registerOrReplace(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER,
224                 new PdpStatusPublisher(topicSinks, interval));
225     }
226 }