Changes for checkstyle 8.32
[policy/apex-pdp.git] / services / services-engine / src / main / java / org / onap / policy / apex / service / engine / main / ApexMain.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modification Copyright (C) 2019-2020 Nordix Foundation.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.service.engine.main;
23
24 import java.util.Arrays;
25 import java.util.Base64;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30 import java.util.TreeMap;
31 import lombok.Getter;
32 import lombok.Setter;
33 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
34 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
35 import org.onap.policy.apex.model.basicmodel.service.ModelService;
36 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
37 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbums;
38 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineModel;
39 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
40 import org.onap.policy.apex.service.parameters.ApexParameterHandler;
41 import org.onap.policy.apex.service.parameters.ApexParameters;
42 import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
44 import org.slf4j.ext.XLogger;
45 import org.slf4j.ext.XLoggerFactory;
46
47 /**
48  * This class initiates Apex as a complete service from the command line.
49  *
50  * @author Liam Fallon (liam.fallon@ericsson.com)
51  */
52 public class ApexMain {
53     private static final String APEX_SERVICE_FAILED_MSG = "start of Apex service failed";
54
55     private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexMain.class);
56
57     // The Apex Activator that activates the Apex engine
58     private ApexActivator activator;
59
60     // The parameters read in from JSON for each policy
61     @Getter
62     private Map<ToscaPolicyIdentifier, ApexParameters> apexParametersMap;
63
64     @Getter
65     @Setter(lombok.AccessLevel.PRIVATE)
66     private volatile boolean alive = false;
67
68     /**
69      * Instantiates the Apex service.
70      *
71      * @param args the command line arguments
72      */
73     public ApexMain(final String[] args) {
74         LOGGER.entry("Starting Apex service with parameters " + Arrays.toString(args) + " . . .");
75         apexParametersMap = new LinkedHashMap<>();
76         try {
77             apexParametersMap.put(new ToscaPolicyIdentifier(), populateApexParameters(args));
78         } catch (ApexException e) {
79             LOGGER.error(APEX_SERVICE_FAILED_MSG, e);
80             return;
81         }
82
83         // Now, create the activator for the Apex service
84         activator = new ApexActivator(apexParametersMap);
85
86         // Start the activator
87         try {
88             activator.initialize();
89             setAlive(true);
90         } catch (final ApexActivatorException e) {
91             LOGGER.error("start of Apex service failed, used parameters are " + Arrays.toString(args), e);
92             return;
93         }
94
95         // Add a shutdown hook to shut everything down in an orderly manner
96         Runtime.getRuntime().addShutdownHook(new ApexMainShutdownHookClass());
97         LOGGER.exit("Started Apex");
98     }
99
100     /**
101      * Instantiates the Apex service for multiple policies.
102      *
103      * @param policyArgumentsMap the map with command line arguments as value and policy-id as key
104      * @throws ApexException on errors
105      */
106     public ApexMain(Map<ToscaPolicyIdentifier, String[]> policyArgumentsMap) throws ApexException {
107         apexParametersMap = new LinkedHashMap<>();
108         for (Entry<ToscaPolicyIdentifier, String[]> policyArgsEntry: policyArgumentsMap.entrySet()) {
109             try {
110                 apexParametersMap.put(policyArgsEntry.getKey(), populateApexParameters(policyArgsEntry.getValue()));
111             } catch (ApexException e) {
112                 LOGGER.error("Invalid arguments specified for policy - " + policyArgsEntry.getKey().getName() + ":"
113                     + policyArgsEntry.getKey().getVersion(), e);
114             }
115         }
116         if (apexParametersMap.isEmpty()) {
117             LOGGER.error(APEX_SERVICE_FAILED_MSG);
118             return;
119         }
120         // Now, create the activator for the Apex service
121         activator = new ApexActivator(apexParametersMap);
122
123         // Start the activator
124         try {
125             activator.initialize();
126             apexParametersMap = activator.getApexParametersMap();
127             setAlive(true);
128         } catch (final ApexActivatorException e) {
129             LOGGER.error(APEX_SERVICE_FAILED_MSG, e);
130             activator.terminate();
131             return;
132         }
133
134         // Add a shutdown hook to shut everything down in an orderly manner
135         Runtime.getRuntime().addShutdownHook(new ApexMainShutdownHookClass());
136         LOGGER.exit("Started Apex");
137     }
138
139     /**
140      * Updates the APEX Engine with the model created from new Policies.
141      *
142      * @param policyArgsMap the map with command line arguments as value and policy-id as key
143      * @throws ApexException on errors
144      */
145     public void updateModel(Map<ToscaPolicyIdentifier, String[]> policyArgsMap) throws ApexException {
146         apexParametersMap.clear();
147         AxContextAlbums albums = ModelService.getModel(AxContextAlbums.class);
148         Map<AxArtifactKey, AxContextAlbum> albumsMap = new TreeMap<>();
149         for (Entry<ToscaPolicyIdentifier, String[]> policyArgsEntry : policyArgsMap.entrySet()) {
150             findAlbumsToHold(albumsMap, policyArgsEntry.getKey());
151             try {
152                 apexParametersMap.put(policyArgsEntry.getKey(), populateApexParameters(policyArgsEntry.getValue()));
153             } catch (ApexException e) {
154                 LOGGER.error("Invalid arguments specified for policy - {}:{}", policyArgsEntry.getKey().getName(),
155                     policyArgsEntry.getKey().getVersion(), e);
156             }
157         }
158         try {
159             if (albumsMap.isEmpty()) {
160                 // clear context since none of the policies' context albums has to be retained
161                 // this could be because all policies have a major version change,
162                 // or a full set of new policies are received in the update message
163                 activator.terminate();
164                 // ParameterService is cleared when activator is terminated. Register the engine parameters in this case
165                 new ApexParameterHandler().registerParameters(apexParametersMap.values().iterator().next());
166                 activator = new ApexActivator(apexParametersMap);
167                 activator.initialize();
168                 setAlive(true);
169             } else {
170                 albums.setAlbumsMap(albumsMap);
171                 activator.setApexParametersMap(apexParametersMap);
172                 activator.updateModel(apexParametersMap);
173             }
174         } catch (final ApexException e) {
175             LOGGER.error(APEX_SERVICE_FAILED_MSG, e);
176             activator.terminate();
177             throw new ApexException(e.getMessage());
178         }
179     }
180
181     /**
182      * Find the context albums which should be retained when updating the policies.
183      *
184      * @param albumsMap the albums which should be kept during model update
185      * @param policyId the policy id of current policy
186      */
187     private void findAlbumsToHold(Map<AxArtifactKey, AxContextAlbum> albumsMap, ToscaPolicyIdentifier policyId) {
188         for (Entry<ToscaPolicyIdentifier, AxPolicyModel> policyModelsEntry : activator.getPolicyModelsMap()
189             .entrySet()) {
190             // If a policy with the same major version is received in PDP_UPDATE,
191             // context for that policy has to be retained. For this, take such policies' albums
192             if (policyModelsEntry.getKey().getName().equals(policyId.getName())
193                 && policyModelsEntry.getKey().getVersion().split("\\.")[0]
194                     .equals(policyId.getVersion().split("\\.")[0])) {
195                 albumsMap.putAll(policyModelsEntry.getValue().getAlbums().getAlbumsMap());
196             }
197         }
198     }
199
200     private ApexParameters populateApexParameters(String[] args) throws ApexException {
201         // Check the arguments
202         final ApexCommandLineArguments arguments = new ApexCommandLineArguments();
203         try {
204             // The arguments return a string if there is a message to print and we should exit
205             final String argumentMessage = arguments.parse(args);
206             if (argumentMessage != null) {
207                 LOGGER.info(argumentMessage);
208                 throw new ApexException(argumentMessage);
209             }
210
211             // Validate that the arguments are sane
212             arguments.validate();
213         } catch (final ApexException e) {
214             LOGGER.error("Arguments validation failed.", e);
215             throw new ApexException("Arguments validation failed.", e);
216         }
217
218         ApexParameters axParameters;
219         // Read the parameters
220         try {
221             ApexParameterHandler apexParameterHandler = new ApexParameterHandler();
222             // In case of multiple policies received from PAP, do not clear ParameterService if parameters of one policy
223             // already registered
224             apexParameterHandler.setKeepParameterServiceFlag(null != apexParametersMap && !apexParametersMap.isEmpty());
225             axParameters = apexParameterHandler.getParameters(arguments);
226         } catch (final Exception e) {
227             LOGGER.error("Cannot create APEX Parameters from the arguments provided.", e);
228             throw new ApexException("Cannot create APEX Parameters from the arguments provided.", e);
229         }
230
231         // Set incoming Java properties
232         setJavaProperties(axParameters);
233
234         // Set the name of the event handler parameters for producers and consumers
235         for (final Entry<String, EventHandlerParameters> ehParameterEntry : axParameters.getEventOutputParameters()
236             .entrySet()) {
237             if (!ehParameterEntry.getValue().checkSetName()) {
238                 ehParameterEntry.getValue().setName(ehParameterEntry.getKey());
239             }
240         }
241         for (final Entry<String, EventHandlerParameters> ehParameterEntry : axParameters.getEventInputParameters()
242             .entrySet()) {
243             if (!ehParameterEntry.getValue().checkSetName()) {
244                 ehParameterEntry.getValue().setName(ehParameterEntry.getKey());
245             }
246         }
247         return axParameters;
248     }
249
250     /**
251      * Shut down Execution.
252      *
253      * @throws ApexException on shutdown errors
254      */
255     public void shutdown() throws ApexException {
256         if (activator != null) {
257             activator.terminate();
258         }
259         setAlive(false);
260     }
261
262     /**
263      * Get the Engine Stats.
264      */
265     public List<AxEngineModel> getEngineStats() {
266         List<AxEngineModel> engineStats = null;
267         if (activator != null) {
268             engineStats = activator.getEngineStats();
269         }
270         return engineStats;
271     }
272
273     /**
274      * The Class ApexMainShutdownHookClass terminates the Apex engine for the Apex service when its run
275      * method is called.
276      */
277     private class ApexMainShutdownHookClass extends Thread {
278         /**
279          * {@inheritDoc}.
280          */
281         @Override
282         public void run() {
283             try {
284                 // Shutdown the Apex engine and wait for everything to stop
285                 activator.terminate();
286                 setAlive(false);
287             } catch (final ApexException e) {
288                 LOGGER.warn("error occured during shut down of the Apex service", e);
289             }
290         }
291     }
292
293     /**
294      * Set the Java properties specified in the parameters.
295      *
296      * @param parameters The incoming parameters
297      */
298     private void setJavaProperties(final ApexParameters parameters) {
299         if (!parameters.checkJavaPropertiesSet()) {
300             return;
301         }
302
303         // Set each Java property
304         for (String[] javaProperty : parameters.getJavaProperties()) {
305             String javaPropertyName = javaProperty[0];
306             String javaPropertyValue = javaProperty[1];
307
308             // Passwords are encoded using base64, better than sending passwords in the clear
309             if (javaPropertyName.toLowerCase().contains("password")) {
310                 javaPropertyValue = new String(Base64.getDecoder().decode(javaPropertyValue.getBytes()));
311             }
312
313             // Set the Java property
314             System.setProperty(javaPropertyName, javaPropertyValue);
315         }
316     }
317
318     /**
319      * The main method.
320      *
321      * @param args the arguments
322      */
323     public static void main(final String[] args) {
324         new ApexMain(args);
325     }
326 }