73ace3de21e4710e8c18b7573a33df1c416d2aa9
[policy/apex-pdp.git] / core / core-engine / src / main / java / org / onap / policy / apex / core / engine / executor / StateMachineExecutor.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019 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.core.engine.executor;
23
24 import java.util.Map;
25 import java.util.Properties;
26 import java.util.TreeMap;
27
28 import org.onap.policy.apex.context.ContextException;
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.event.EnEvent;
32 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
33 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
34 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
35 import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
36 import org.onap.policy.apex.model.policymodel.concepts.AxState;
37 import org.onap.policy.apex.model.policymodel.concepts.AxStateOutput;
38
39 /**
40  * This class is the executor for a state machine built from a policy.
41  *
42  * @author Sven van der Meer (sven.van.der.meer@ericsson.com)
43  * @author Liam Fallon (liam.fallon@ericsson.com)
44  */
45 public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> {
46     // The Apex Policy and context for this state machine
47     private AxPolicy axPolicy = null;
48     private Executor<?, ?, ?, ?> parent = null;
49     private ApexInternalContext internalContext = null;
50
51     // The list of state executors for this state machine
52     private final Map<AxReferenceKey, StateExecutor> stateExecutorMap = new TreeMap<>();
53
54     // The first executor
55     private StateExecutor firstExecutor = null;
56
57     // The next state machine executor
58     private Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> nextExecutor = null;
59
60     // The executor factory
61     private ExecutorFactory executorFactory = null;
62
63     /**
64      * Constructor, save the executor factory that will give us executors for task selection logic and task logic.
65      *
66      * @param executorFactory the executor factory
67      * @param owner the artifact key of the owner of this state machine
68      */
69     public StateMachineExecutor(final ExecutorFactory executorFactory, final AxArtifactKey owner) {
70         this.executorFactory = executorFactory;
71     }
72
73     /**
74      * {@inheritDoc}.
75      */
76     @Override
77     public void setContext(final Executor<?, ?, ?, ?> newParent, final AxPolicy newAxPolicy,
78             final ApexInternalContext newInternalContext) {
79         // Save the policy and context for this state machine
80         this.parent = newParent;
81         this.axPolicy = newAxPolicy;
82         this.internalContext = newInternalContext;
83
84         // Clear the first executor, setContext can be called multiple times
85         firstExecutor = null;
86
87         // Create the state executors for this state machine
88         StateExecutor lastExecutor = null;
89         for (final AxState state : axPolicy.getStateMap().values()) {
90             // Create a state executor for this state and add its context (the state)
91             final StateExecutor stateExecutor = new StateExecutor(executorFactory);
92             stateExecutor.setContext(this, state, internalContext);
93
94             // Update the next executor on the last executor
95             if (lastExecutor != null) {
96                 lastExecutor.setNext(stateExecutor);
97             }
98             lastExecutor = stateExecutor;
99
100             // Add the state executor to the executor list
101             stateExecutorMap.put(state.getKey(), stateExecutor);
102
103             // Set the first executor if it is not set
104             if (state.getKey().getLocalName().equals(axPolicy.getFirstState())) {
105                 firstExecutor = stateExecutor;
106             }
107         }
108     }
109
110     /**
111      * {@inheritDoc}.
112      */
113     @Override
114     public void prepare() throws StateMachineException {
115         for (final StateExecutor stateExecutor : stateExecutorMap.values()) {
116             stateExecutor.prepare();
117         }
118     }
119
120     /**
121      * {@inheritDoc}.
122      */
123     @Override
124     public EnEvent execute(final long executionId, final Properties executionProperties, final EnEvent incomingEvent)
125             throws StateMachineException, ContextException {
126         // Check if there are any states on the state machine
127         if (stateExecutorMap.size() == 0) {
128             throw new StateMachineException("no states defined on state machine");
129         }
130
131         // Check if the first state of the machine is defined
132         if (firstExecutor == null) {
133             throw new StateMachineException("first state not defined on state machine");
134         }
135
136         // Get the first state of the state machine and define a state output that starts state
137         // execution
138         StateExecutor stateExecutor = firstExecutor;
139         StateOutput stateOutput = new StateOutput(new AxStateOutput(firstExecutor.getSubject().getKey(),
140                 incomingEvent.getKey(), firstExecutor.getSubject().getKey()), incomingEvent);
141
142         while (true) {
143             // Execute the state, it returns an output or throws an exception
144             stateOutput = stateExecutor.execute(executionId, executionProperties, stateOutput.getOutputEvent());
145
146             // Use the next state of the state output to find if all the states have executed
147             if (stateOutput.getNextState().equals(AxReferenceKey.getNullKey())) {
148                 break;
149             }
150
151             // Use the next state of the state output to find the next state
152             stateExecutor = stateExecutorMap.get(stateOutput.getNextState());
153             if (stateExecutor == null) {
154                 throw new StateMachineException(
155                         "state execution failed, next state \"" + stateOutput.getNextState().getId() + "\" not found");
156             }
157         }
158
159         return stateOutput.getOutputEvent();
160     }
161
162     /**
163      * {@inheritDoc}.
164      */
165     @Override
166     public final void executePre(final long executionId, final Properties executionProperties,
167             final EnEvent incomingEntity) throws StateMachineException {
168         throw new StateMachineException("execution pre work not implemented on class");
169     }
170
171     /**
172      * {@inheritDoc}.
173      */
174     @Override
175     public final void executePost(final boolean returnValue) throws StateMachineException {
176         throw new StateMachineException("execution post work not implemented on class");
177     }
178
179     /**
180      * {@inheritDoc}.
181      */
182     @Override
183     public void cleanUp() throws StateMachineException {
184         for (final StateExecutor stateExecutor : stateExecutorMap.values()) {
185             stateExecutor.cleanUp();
186         }
187     }
188
189     /**
190      * {@inheritDoc}.
191      */
192     @Override
193     public AxArtifactKey getKey() {
194         return axPolicy.getKey();
195     }
196
197     /**
198      * {@inheritDoc}.
199      */
200     @Override
201     public final Executor<?, ?, ?, ?> getParent() {
202         return parent;
203     }
204
205     /**
206      * {@inheritDoc}.
207      */
208     @Override
209     public final AxPolicy getSubject() {
210         return axPolicy;
211     }
212
213     /**
214      * {@inheritDoc}.
215      */
216     @Override
217     public final ApexInternalContext getContext() {
218         return internalContext;
219     }
220
221     /**
222      * {@inheritDoc}.
223      */
224     @Override
225     public final EnEvent getIncoming() {
226         return null;
227     }
228
229     /**
230      * {@inheritDoc}.
231      */
232     @Override
233     public final EnEvent getOutgoing() {
234         return null;
235     }
236
237     /**
238      * {@inheritDoc}.
239      */
240     @Override
241     public final void setNext(final Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> newNextExecutor) {
242         this.nextExecutor = newNextExecutor;
243     }
244
245     /**
246      * {@inheritDoc}.
247      */
248     @Override
249     public final Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> getNext() {
250         return nextExecutor;
251     }
252
253     /**
254      * {@inheritDoc}.
255      */
256     @Override
257     public void setParameters(final ExecutorParameters parameters) {
258         // Not implemented in this class
259     }
260 }