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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.apex.core.engine.engine.impl;
23 import java.util.HashMap;
25 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
26 import org.onap.policy.apex.core.engine.event.EnEvent;
27 import org.onap.policy.apex.core.engine.executor.ExecutorFactory;
28 import org.onap.policy.apex.core.engine.executor.StateMachineExecutor;
29 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
30 import org.onap.policy.apex.core.engine.executor.impl.ExecutorFactoryImpl;
31 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
32 import org.onap.policy.apex.model.basicmodel.service.ModelService;
33 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
34 import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
35 import org.onap.policy.apex.model.policymodel.concepts.AxPolicies;
36 import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
37 import org.slf4j.ext.XLogger;
38 import org.slf4j.ext.XLoggerFactory;
41 * This handler holds and manages state machines for each policy in an Apex engine. When the class
42 * is instantiated, an executor {@link StateMachineExecutor} is created for each policy in the
43 * policy model the state machine handler will execute. The executors for each policy are held in a
44 * map indexed by event.
46 * <p>When an event is received on the policy, the state machine executor to execute that event is
47 * looked up on the executor map and the event is passed to the executor for execution.
52 public class StateMachineHandler {
53 // Logger for this class
54 private static final XLogger LOGGER = XLoggerFactory.getXLogger(StateMachineHandler.class);
56 // The key of the Apex model we are executing
57 private final AxArtifactKey key;
59 // The state machines in this engine
60 private final HashMap<AxEvent, StateMachineExecutor> stateMachineExecutorMap = new HashMap<>();
62 // The executor factory is used to get logic executors for the particular type of executor we
64 // selection logic or task logic
65 private final ExecutorFactory executorFactory;
68 * This constructor builds the state machines for the policies in the apex model.
70 * @param internalContext The internal context we are using
71 * @throws StateMachineException On state machine initiation errors
73 protected StateMachineHandler(final ApexInternalContext internalContext) throws StateMachineException {
74 LOGGER.entry("StateMachineHandler()->" + internalContext.getKey().getID());
76 key = internalContext.getKey();
78 // Create the executor factory to generate executors as the engine runs policies
79 executorFactory = new ExecutorFactoryImpl();
81 // Iterate over the policies in the policy model and create a state machine for each one
82 for (final AxPolicy policy : ModelService.getModel(AxPolicies.class).getPolicyMap().values()) {
83 // Create a state machine for this policy
84 final StateMachineExecutor thisStateMachineExecutor =
85 new StateMachineExecutor(executorFactory, policy.getKey());
87 // This executor is the top executor so has no parent
88 thisStateMachineExecutor.setContext(null, policy, internalContext);
90 // Get the incoming trigger event
91 final AxEvent triggerEvent = ModelService.getModel(AxEvents.class)
92 .get(policy.getStateMap().get(policy.getFirstState()).getTrigger());
94 // Put the state machine executor on the map for this trigger
95 final StateMachineExecutor lastStateMachineExecutor =
96 stateMachineExecutorMap.put(triggerEvent, thisStateMachineExecutor);
97 if (lastStateMachineExecutor != null
98 && lastStateMachineExecutor.getSubject() != thisStateMachineExecutor.getSubject()) {
99 LOGGER.error("No more than one policy in a model can have the same trigger event. In model "
100 + internalContext.getKey().getID() + " Policy ("
101 + lastStateMachineExecutor.getSubject().getKey().getID() + ") and Policy ("
102 + thisStateMachineExecutor.getSubject().getKey().getID() + ") have the same Trigger event ("
103 + triggerEvent.getKey().getID() + ") ");
104 LOGGER.error(" Policy (" + lastStateMachineExecutor.getSubject().getKey() + ") has overwritten Policy ("
105 + thisStateMachineExecutor.getSubject().getKey().getID()
106 + " so this overwritten policy will never be triggered in this engine.");
110 LOGGER.exit("StateMachineHandler()<-" + internalContext.getKey().getID());
114 * This constructor starts the state machines for each policy, carrying out whatever
115 * initialization executors need.
117 * @throws StateMachineException On state machine initiation errors
119 protected void start() throws StateMachineException {
120 LOGGER.entry("start()->" + key.getID());
122 // Iterate over the state machines
123 for (final StateMachineExecutor smExecutor : stateMachineExecutorMap.values()) {
125 smExecutor.prepare();
126 } catch (final StateMachineException e) {
127 final String stateMachineID = smExecutor.getContext().getKey().getID();
128 LOGGER.warn("start()<-" + key.getID() + ", start failed, state machine \"" + stateMachineID + "\"", e);
129 throw new StateMachineException(
130 "start()<-" + key.getID() + ", start failed, state machine \"" + stateMachineID + "\"", e);
134 LOGGER.exit("start()<-" + key.getID());
138 * This method is called to execute an event on the state machines in an engine.
140 * @param event The trigger event for the state machine
141 * @return The result of the state machine execution run
142 * @throws StateMachineException On execution errors in a state machine
144 protected EnEvent execute(final EnEvent event) throws StateMachineException {
145 LOGGER.entry("execute()->" + event.getName());
147 // Try to execute the state machine for the trigger
148 final StateMachineExecutor stateMachineExecutor = stateMachineExecutorMap.get(event.getAxEvent());
149 if (stateMachineExecutor == null) {
150 final String exceptionMessage =
151 "state machine execution not possible, policy not found for trigger event " + event.getName();
152 LOGGER.warn(exceptionMessage);
154 event.setExceptionMessage(exceptionMessage);
158 // Run the state machine
160 LOGGER.debug("execute(): state machine \"{}\" execution starting . . .", stateMachineExecutor);
161 final EnEvent outputObject = stateMachineExecutor.execute(event.getExecutionID(), event);
163 LOGGER.debug("execute()<-: state machine \"{}\" execution completed", stateMachineExecutor);
165 } catch (final Exception e) {
166 LOGGER.warn("execute()<-: state machine \"" + stateMachineExecutor + "\" execution failed", e);
167 throw new StateMachineException("execute()<-: execution failed on state machine " + stateMachineExecutor,
173 * Closes down the state machines of an engine.
175 protected void stop() {
176 LOGGER.entry("stop()->");
178 // Iterate through all state machines and clean them
179 for (final StateMachineExecutor smExecutor : stateMachineExecutorMap.values()) {
181 smExecutor.cleanUp();
182 } catch (final StateMachineException e) {
183 final String smID = smExecutor.getContext().getKey().getID();
184 LOGGER.warn("stop()<-clean up failed, state machine \"" + smID + "\" cleanup failed", e);
187 LOGGER.exit("stop()<-");