Merge "Unit test for Apex engine"
[policy/apex-pdp.git] / core / core-engine / src / main / java / org / onap / policy / apex / core / engine / executor / impl / ExecutorFactoryImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
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.core.engine.executor.impl;
22
23 import java.util.Map;
24 import java.util.Map.Entry;
25 import java.util.TreeMap;
26
27 import org.onap.policy.apex.core.engine.EngineParameterConstants;
28 import org.onap.policy.apex.core.engine.EngineParameters;
29 import org.onap.policy.apex.core.engine.ExecutorParameters;
30 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
31 import org.onap.policy.apex.core.engine.executor.Executor;
32 import org.onap.policy.apex.core.engine.executor.ExecutorFactory;
33 import org.onap.policy.apex.core.engine.executor.StateFinalizerExecutor;
34 import org.onap.policy.apex.core.engine.executor.TaskExecutor;
35 import org.onap.policy.apex.core.engine.executor.TaskSelectExecutor;
36 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
37 import org.onap.policy.apex.core.engine.executor.exception.StateMachineRuntimeException;
38 import org.onap.policy.apex.model.policymodel.concepts.AxState;
39 import org.onap.policy.apex.model.policymodel.concepts.AxStateFinalizerLogic;
40 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
41 import org.onap.policy.apex.model.utilities.Assertions;
42 import org.onap.policy.common.parameters.ParameterService;
43 import org.slf4j.ext.XLogger;
44 import org.slf4j.ext.XLoggerFactory;
45
46 /**
47  * The Class ExecutorFactoryImpl is a factory class that returns task selection logic and task logic executors depending
48  * on the type of logic executor has been specified for the task selection logic in a state or task logic in a task.
49  *
50  * @author Liam Fallon (liam.fallon@ericsson.com)
51  */
52 public class ExecutorFactoryImpl implements ExecutorFactory {
53     // Get a reference to the logger
54     private static final XLogger LOGGER = XLoggerFactory.getXLogger(ExecutorFactoryImpl.class);
55
56     // A map of logic flavours mapped to executor classes for plugins to executors for those logic flavours
57     private Map<String, Class<Executor<?, ?, ?, ?>>> taskExecutorPluginClassMap = new TreeMap<>();
58     private Map<String, Class<Executor<?, ?, ?, ?>>> taskSelectionExecutorPluginClassMap = new TreeMap<>();
59     private Map<String, Class<Executor<?, ?, ?, ?>>> stateFinalizerExecutorPluginClassMap = new TreeMap<>();
60
61     // A map of parameters for executors
62     private final Map<String, ExecutorParameters> implementationParameterMap = new TreeMap<>();
63
64     /**
65      * Constructor, builds the class map for executors.
66      *
67      * @throws StateMachineException on plugin creation errors
68      */
69     public ExecutorFactoryImpl() throws StateMachineException {
70         final EngineParameters engineParameters = ParameterService.get(EngineParameterConstants.MAIN_GROUP_NAME);
71
72         Assertions.argumentOfClassNotNull(engineParameters, StateMachineException.class,
73                         "Parameter \"engineParameters\" may not be null");
74
75         // Instantiate each executor class map entry
76         for (final Entry<String, ExecutorParameters> executorParameterEntry : engineParameters.getExecutorParameterMap()
77                         .entrySet()) {
78             // Get classes for all types of executors for this logic type
79             taskExecutorPluginClassMap.put(executorParameterEntry.getKey(),
80                             getExecutorPluginClass(executorParameterEntry.getValue().getTaskExecutorPluginClass()));
81             taskSelectionExecutorPluginClassMap.put(executorParameterEntry.getKey(), getExecutorPluginClass(
82                             executorParameterEntry.getValue().getTaskSelectionExecutorPluginClass()));
83             stateFinalizerExecutorPluginClassMap.put(executorParameterEntry.getKey(), getExecutorPluginClass(
84                             executorParameterEntry.getValue().getStateFinalizerExecutorPluginClass()));
85
86             // Save the executor implementation parameters
87             implementationParameterMap.put(executorParameterEntry.getKey(), executorParameterEntry.getValue());
88         }
89     }
90
91     /*
92      * (non-Javadoc)
93      *
94      * @see
95      * org.onap.policy.apex.core.engine.executor.ExecutorFactory#getTaskSelectionExecutor(org.onap.policy.apex.core.
96      * model. concepts.AxState, org.onap.policy.apex.core.engine.context.Context)
97      */
98     @Override
99     public TaskSelectExecutor getTaskSelectionExecutor(final Executor<?, ?, ?, ?> parentExecutor, final AxState state,
100                     final ApexInternalContext context) {
101         if (!state.checkSetTaskSelectionLogic()) {
102             return null;
103         }
104
105         // Create task selection executor
106         final TaskSelectExecutor tsExecutor = (TaskSelectExecutor) createExecutor(
107                         state.getTaskSelectionLogic().getLogicFlavour(),
108                         taskSelectionExecutorPluginClassMap.get(state.getTaskSelectionLogic().getLogicFlavour()),
109                         TaskSelectExecutor.class);
110         tsExecutor.setParameters(implementationParameterMap.get(state.getTaskSelectionLogic().getLogicFlavour()));
111         tsExecutor.setContext(parentExecutor, state, context);
112
113         return tsExecutor;
114     }
115
116     /*
117      * (non-Javadoc)
118      *
119      * @see org.onap.policy.apex.core.engine.executor.ExecutorFactory#getTaskExecutor(org.onap.policy.apex.core.model.
120      * concepts. AxTask, org.onap.policy.apex.core.engine.context.Context)
121      */
122     @Override
123     public TaskExecutor getTaskExecutor(final Executor<?, ?, ?, ?> parentExecutor, final AxTask task,
124                     final ApexInternalContext context) {
125         // Create task executor
126         final TaskExecutor taskExecutor = (TaskExecutor) createExecutor(task.getTaskLogic().getLogicFlavour(),
127                         taskExecutorPluginClassMap.get(task.getTaskLogic().getLogicFlavour()), TaskExecutor.class);
128         taskExecutor.setParameters(implementationParameterMap.get(task.getTaskLogic().getLogicFlavour()));
129         taskExecutor.setContext(parentExecutor, task, context);
130
131         return taskExecutor;
132     }
133
134     /*
135      * (non-Javadoc)
136      *
137      * @see
138      * org.onap.policy.apex.core.engine.executor.ExecutorFactory#getStateFinalizerExecutor(org.onap.policy.apex.core.
139      * engine. executor.Executor, org.onap.policy.apex.core.policymodel.concepts.AxStateFinalizerLogic,
140      * org.onap.policy.apex.core.engine.context.ApexInternalContext)
141      */
142     @Override
143     public StateFinalizerExecutor getStateFinalizerExecutor(final Executor<?, ?, ?, ?> parentExecutor,
144                     final AxStateFinalizerLogic logic, final ApexInternalContext context) {
145         // Create state finalizer executor
146         final StateFinalizerExecutor sfExecutor = (StateFinalizerExecutor) createExecutor(logic.getLogicFlavour(),
147                         stateFinalizerExecutorPluginClassMap.get(logic.getLogicFlavour()),
148                         StateFinalizerExecutor.class);
149         sfExecutor.setParameters(implementationParameterMap.get(logic.getLogicFlavour()));
150         sfExecutor.setContext(parentExecutor, logic, context);
151
152         return sfExecutor;
153     }
154
155     /**
156      * Get an executor class for a given executor plugin class name.
157      *
158      * @param executorClassName The name of the executor plugin class
159      * @return an executor class
160      * @throws StateMachineException on plugin instantiation errors
161      */
162     @SuppressWarnings("unchecked")
163     private Class<Executor<?, ?, ?, ?>> getExecutorPluginClass(final String executorClassName)
164                     throws StateMachineException {
165         // It's OK for an executor class not to be defined as long as it's not called
166         if (executorClassName == null) {
167             return null;
168         }
169
170         // Get the class for the executor using reflection
171         Class<? extends Object> executorPluginClass = null;
172         try {
173             executorPluginClass = Class.forName(executorClassName);
174         } catch (final ClassNotFoundException e) {
175             LOGGER.error("Apex executor class not found for executor plugin \"" + executorClassName + "\"", e);
176             throw new StateMachineException(
177                             "Apex executor class not found for executor plugin \"" + executorClassName + "\"", e);
178         }
179
180         // Check the class is an executor
181         if (!Executor.class.isAssignableFrom(executorPluginClass)) {
182             LOGGER.error("Specified Apex executor plugin class \"{}\" does not implment the Executor interface",
183                             executorClassName);
184             throw new StateMachineException("Specified Apex executor plugin class \"" + executorClassName
185                             + "\" does not implment the Executor interface");
186         }
187
188         return (Class<Executor<?, ?, ?, ?>>) executorPluginClass;
189     }
190
191     /**
192      * Get an instance of an executor plugin class of the specified type and super type.
193      *
194      * @param logicFlavour The logic flavour of the logic
195      * @param executorClass The sub-class of the executor type to be instantiated
196      * @param executorSuperClass The super type of the class of executor to be instantiated
197      * @return The instantiated class
198      */
199     private Executor<?, ?, ?, ?> createExecutor(final String logicFlavour,
200                     final Class<Executor<?, ?, ?, ?>> executorClass,
201                     final Class<? extends Executor<?, ?, ?, ?>> executorSuperClass) {
202         // It's OK for an executor class not to be defined but it's not all right to try and create
203         // a non-defined
204         // executor class
205         if (executorClass == null) {
206             final String errorMessage = "Executor plugin class not defined for \"" + logicFlavour
207                             + "\" executor of type \"" + executorSuperClass.getCanonicalName() + "\"";
208             LOGGER.error(errorMessage);
209             throw new StateMachineRuntimeException(errorMessage);
210         }
211
212         // Create an executor for the specified logic flavour
213         Object executorObject = null;
214         try {
215             executorObject = executorClass.newInstance();
216         } catch (InstantiationException | IllegalAccessException e) {
217             final String errorMessage = "Instantiation error on \"" + logicFlavour + "\" executor of type \""
218                             + executorClass.getCanonicalName() + "\"";
219             LOGGER.error(errorMessage, e);
220             throw new StateMachineRuntimeException(errorMessage, e);
221         }
222
223         // Check the class is the correct type of executor
224         if (!(executorSuperClass.isAssignableFrom(executorObject.getClass()))) {
225             final String errorMessage = "Executor on \"" + logicFlavour + "\" of type \"" + executorClass
226                             + "\" is not an instance of \"" + executorSuperClass.getCanonicalName() + "\"";
227
228             LOGGER.error(errorMessage);
229             throw new StateMachineRuntimeException(errorMessage);
230         }
231
232         return (Executor<?, ?, ?, ?>) executorObject;
233     }
234 }