ecc0bec2178137c3674a413702b7ec27191e885a
[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.shutdown();
166             }
167             apexEngineHandler = new ApexEngineHandler(pdpUpdateMsg.getPolicies());
168             Registry.registerOrReplace(ApexStarterConstants.REG_APEX_ENGINE_HANDLER, apexEngineHandler);
169             if (apexEngineHandler.isApexEngineRunning()) {
170                 List<ToscaPolicyIdentifier> runningPolicies = apexEngineHandler.getRunningPolicies();
171                 if (new HashSet<>(runningPolicies)
172                     .equals(new HashSet<>(pdpMessageHandler.getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies())))) {
173                     pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
174                         PdpResponseStatus.SUCCESS, "Apex engine started and policies are running.");
175                 } else {
176                     StringBuilder message =
177                         new StringBuilder("Apex engine started. But, only the following polices are running - ");
178                     for (ToscaPolicyIdentifier policy : runningPolicies) {
179                         message.append(policy.getName()).append(":").append(policy.getVersion()).append("  ");
180                     }
181                     message.append(". Other policies failed execution. Please see the logs for more details.");
182                     pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
183                         PdpResponseStatus.SUCCESS, message.toString());
184                 }
185             } else {
186                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
187                     PdpResponseStatus.FAIL, "Apex engine failed to start.");
188             }
189         } catch (final ApexStarterException e) {
190             LOGGER.error("Apex engine service running failed. ", e);
191             pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
192                     PdpResponseStatus.FAIL, "Apex engine service running failed. " + e.getMessage());
193         }
194         return pdpResponseDetails;
195     }
196
197     /**
198      * Method checks if the Pdp update message is already handled by checking the values in the context.
199      *
200      * @param pdpUpdateMsg pdp update message received from pap
201      * @param pdpStatusContext values saved in context memory
202      * @return boolean flag which tells if the information is same or not
203      */
204     private boolean checkIfAlreadyHandled(final PdpUpdate pdpUpdateMsg, final PdpStatus pdpStatusContext) {
205         return null != pdpStatusContext.getPdpGroup()
206                 && pdpStatusContext.getPdpGroup().equals(pdpUpdateMsg.getPdpGroup())
207                 && null != pdpStatusContext.getPdpSubgroup()
208                 && pdpStatusContext.getPdpSubgroup().equals(pdpUpdateMsg.getPdpSubgroup())
209                 && null != pdpStatusContext.getPolicies() && new PdpMessageHandler()
210                         .getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies()).equals(pdpStatusContext.getPolicies());
211     }
212
213     /**
214      * Method to update the time interval used by the timer task.
215      *
216      * @param interval time interval received in the pdp update message from pap
217      */
218     public void updateInterval(final long interval) {
219         final PdpStatusPublisher pdpStatusPublisher = Registry.get(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER);
220         pdpStatusPublisher.terminate();
221         final List<TopicSink> topicSinks = Registry.get(ApexStarterConstants.REG_APEX_PDP_TOPIC_SINKS);
222         Registry.registerOrReplace(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER,
223                 new PdpStatusPublisher(topicSinks, interval));
224     }
225 }