2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2016-2018 Ericsson. All rights reserved.
4 * Modifications Copyright (C) 2018 Samsung Electronics Co., Ltd.
5 * Modifications Copyright (C) 2019 Nordix Foundation.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.policy.apex.model.policymodel.concepts;
25 import java.util.List;
27 import java.util.Map.Entry;
29 import java.util.TreeMap;
30 import java.util.TreeSet;
32 import javax.persistence.AttributeOverride;
33 import javax.persistence.AttributeOverrides;
34 import javax.persistence.CascadeType;
35 import javax.persistence.CollectionTable;
36 import javax.persistence.Column;
37 import javax.persistence.ElementCollection;
38 import javax.persistence.Embedded;
39 import javax.persistence.EmbeddedId;
40 import javax.persistence.Entity;
41 import javax.persistence.JoinColumn;
42 import javax.persistence.JoinTable;
43 import javax.persistence.ManyToMany;
44 import javax.persistence.OneToOne;
45 import javax.persistence.Table;
46 import javax.xml.bind.Unmarshaller;
47 import javax.xml.bind.annotation.XmlAccessType;
48 import javax.xml.bind.annotation.XmlAccessorType;
49 import javax.xml.bind.annotation.XmlElement;
50 import javax.xml.bind.annotation.XmlRootElement;
51 import javax.xml.bind.annotation.XmlType;
53 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
54 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
55 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
56 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyUse;
57 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
58 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
59 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
60 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
61 import org.onap.policy.common.utils.validation.Assertions;
64 * This class holds the definition of a single state in a policy. A state is a single stage in a policy. A state has a
65 * single input event, its trigger. A state can output many events, but can only output one event on a single execution.
66 * After it executes, a state can pass control to another state or can simply emit its event to an external system. In
67 * the case where a state passes control to another state, the output event of the state becomes the input event of the
68 * next state. The outputs of a state {@link AxStateOutput} are held as a map in the state. Each state output contains
69 * the outgoing event of the state and optionally the next state to pass control to.
71 * <p>A state uses tasks {@link AxTask} to execute its logic. A state holds its tasks in a map and must have at least
72 * one task. A state uses Task Selection Logic {@link AxTaskSelectionLogic} to select which task should be executed in a
73 * given execution cycle. Optional Task Selection Logic can use fields on the incoming event and information from the
74 * context albums available on the state to decide what task to execute in a given context. The default task of a state
75 * is the task that is executed when task Selection Logic is not specified. In cases where only a single task is
76 * specified on a state, the default task must be that task and the state always executes that task.
78 * <p>What happens when a state completes its execution cycle depends on the task that is selected for execution by the
79 * state. Therefore, the action to be performed a state on execution of each task must be defined in the state as a
80 * {@link AxStateTaskReference} instance for each task defined in the state. The {@link AxStateTaskReference} instance
81 * defines the action to be performed as either a {@link AxStateTaskOutputType} of {@link AxStateTaskOutputType#DIRECT}
82 * or {@link AxStateTaskOutputType#LOGIC} and contains an {@link AxReferenceKey} reference to the instance that will
83 * complete the state output.
85 * <p>In the case of direct output, the {@link AxReferenceKey} reference in the {@link AxStateTaskReference} instance is
86 * a reference to an {@link AxStateOutput} instance. The state output defines the event to be emitted by the state and
87 * the next state to pass control to if any. All fields of the executed task are marshaled onto the outgoing event
88 * automatically by Apex.
90 * <p>In the case of logic output, the {@link AxReferenceKey} reference in the {@link AxStateTaskReference} instance is
91 * a reference to State Finalizer Logic in an {@link AxStateFinalizerLogic} instance, which selects the
92 * {@link AxStateOutput} that the state will use. The state finalizer logic uses fields emitted by the executed task and
93 * information from the context albums available on the state to decide what {@link AxStateOutput} to select in a given
94 * context. The state output defines the event to be emitted by the state and the next state to pass control to if any.
95 * The State Finalizer Logic instances for the state are held in a map in the state. State Finalizer Logic must marshal
96 * the fields of the output event in whatever manner it wishes; Apex does not automatically transfer the output fields
97 * from the task directly to the output event.
99 * <p>The Task Selection Logic instance or State Finalizer Logic instances in a state may use information in context
100 * albums to arrive at their task or state output selections. The context albums that the state uses and that should be
101 * made available to the state by Apex policy distribution are held as a set of references to context albums in the
104 * <p>During validation of a state, the validation checks listed below are executed: <ol> <li>The policy key must not be
105 * a null key and must be valid, see validation in {@link AxReferenceKey} <li>The trigger event key must not be a null
106 * key and must be valid, see validation in {@link AxArtifactKey} <li>At least one state output must be defined <li>Each
107 * state output in a state must have that state as its parent <li>Each state output must be valid, see validation in
108 * {@link AxStateOutput} <li>The next state defined in a state output must be unique in a state <li>The default task key
109 * must not be a null key and must be valid, see validation in {@link AxArtifactKey} <li>The default task must appear in
110 * the task map of the state <li>At least one task must be defined on the state <li>Each task key on the task map for
111 * the state must not be a null key and must be valid, see validation in {@link AxArtifactKey} <li>All state task
112 * references for each task in the state must exist and must be valid, see validation in {@link AxStateTaskReference}
113 * <li>Each state task reference in a state must have that state as its parent <li>For direct state outputs from tasks,
114 * the state output must be defined on the state <li>For logic state outputs from tasks, the State Finalizer Logic must
115 * be defined on the state <li>An observation is issued for each state output defined on the state that is not used as a
116 * direct output on a task <li>An observation is issued for each state finalizer logic instance defined on the state
117 * that is not used as an output on a task <li>Each context album key on the context album set for the state must not be
118 * a null key and must be valid, see validation in {@link AxArtifactKey} <li>Task Selection logic in a state must have
119 * that state as its parent <li>Task Selection logic in a state must be valid, see validation in
120 * {@link AxTaskSelectionLogic} <li>Each State Finalizer logic instance in a state must have that state as its parent
121 * <li>Each State Finalizer logic instance in a state must be valid, see validation in {@link AxStateFinalizerLogic}
126 @Table(name = "AxState")
128 @XmlAccessorType(XmlAccessType.FIELD)
129 @XmlRootElement(name = "apexState", namespace = "http://www.onap.org/policy/apex-pdp")
130 @XmlType(name = "AxState", namespace = "http://www.onap.org/policy/apex-pdp", propOrder =
131 { "key", "trigger", "stateOutputs", "contextAlbumReferenceSet", "taskSelectionLogic", "stateFinalizerLogicMap",
132 "defaultTask", "taskReferenceMap" })
134 public class AxState extends AxConcept {
135 private static final String DOES_NOT_EQUAL_STATE_KEY = " does not equal state key";
137 private static final long serialVersionUID = 8041771382337655535L;
140 @XmlElement(name = "stateKey", required = true)
141 private AxReferenceKey key;
145 @AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "inTriggerName")),
146 @AttributeOverride(name = "version", column = @Column(name = "inTriggerVersion"))})
147 @Column(name = "trigger")
148 @XmlElement(required = true)
149 private AxArtifactKey trigger;
151 @ManyToMany(cascade = CascadeType.ALL)
153 joinColumns = {@JoinColumn(name = "soParentKeyName", referencedColumnName = "parentKeyName"),
154 @JoinColumn(name = "soParentKeyVersion", referencedColumnName = "parentKeyVersion"),
155 @JoinColumn(name = "soParentLocalName", referencedColumnName = "parentLocalName"),
156 @JoinColumn(name = "soLocalName", referencedColumnName = "localName")},
157 inverseJoinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
158 @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
159 @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
160 @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
161 @XmlElement(name = "stateOutputs", required = true)
162 private Map<String, AxStateOutput> stateOutputs;
165 @CollectionTable(joinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
166 @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
167 @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
168 @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
169 @XmlElement(name = "contextAlbumReference")
170 private Set<AxArtifactKey> contextAlbumReferenceSet;
173 @JoinTable(name = "STATE_TSL_JT",
175 @JoinColumn(name = "tslParentKeyName", referencedColumnName = "parentKeyName", updatable = false,
177 @JoinColumn(name = "tslParentKeyVersion", referencedColumnName = "parentKeyVersion",
178 updatable = false, insertable = false),
179 @JoinColumn(name = "tslParentLocalName ", referencedColumnName = "parentLocalName",
180 updatable = false, insertable = false),
181 @JoinColumn(name = "tslLocalName", referencedColumnName = "localName", updatable = false,
182 insertable = false)})
183 @XmlElement(required = true)
184 private AxTaskSelectionLogic taskSelectionLogic;
186 @ManyToMany(cascade = CascadeType.ALL)
188 joinColumns = {@JoinColumn(name = "sflParentKeyName", referencedColumnName = "parentKeyName"),
189 @JoinColumn(name = "sflParentKeyVersion", referencedColumnName = "parentKeyVersion"),
190 @JoinColumn(name = "sflParentLocalName", referencedColumnName = "parentLocalName"),
191 @JoinColumn(name = "sflLocalName", referencedColumnName = "localName")},
192 inverseJoinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
193 @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
194 @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
195 @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
196 @XmlElement(name = "stateFinalizerLogicMap", required = true)
197 private Map<String, AxStateFinalizerLogic> stateFinalizerLogicMap;
200 @AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "defaultTaskName")),
201 @AttributeOverride(name = "version", column = @Column(name = "defaultTaskVersion"))})
202 @Column(name = "defaultTask")
203 @XmlElement(required = true)
204 private AxArtifactKey defaultTask;
206 @ManyToMany(cascade = CascadeType.ALL)
208 joinColumns = {@JoinColumn(name = "trmParentKeyName", referencedColumnName = "parentKeyName"),
209 @JoinColumn(name = "trmParentKeyVersion", referencedColumnName = "parentKeyVersion"),
210 @JoinColumn(name = "trmParentLocalName", referencedColumnName = "parentLocalName"),
211 @JoinColumn(name = "trmLocalName", referencedColumnName = "localName")},
212 inverseJoinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
213 @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
214 @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
215 @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
216 @XmlElement(name = "taskReferences", required = true)
217 private Map<AxArtifactKey, AxStateTaskReference> taskReferenceMap;
221 * The Default Constructor creates a state with a null reference key and with default values for all other fields.
224 this(new AxReferenceKey());
225 contextAlbumReferenceSet = new TreeSet<>();
226 taskReferenceMap = new TreeMap<>();
232 * @param copyConcept the concept to copy from
234 public AxState(final AxState copyConcept) {
239 * The Keyed Constructor creates a state with the given reference key and with default values for all other fields.
241 * @param key the reference key of the state
243 public AxState(final AxReferenceKey key) {
245 this(new AxStateParamsBuilder()
247 .trigger(AxArtifactKey.getNullKey()) // Trigger Reference
248 .stateOutputs(new TreeMap<String, AxStateOutput>()) // State Outputs
249 .contextAlbumReferenceSet(new TreeSet<AxArtifactKey>()) // Context Album Refs
250 .taskSelectionLogic(new AxTaskSelectionLogic()) // Task Selection Logic
251 .stateFinalizerLogicMap(new TreeMap<String, AxStateFinalizerLogic>()) // State Finalizer Logics
252 .defaultTask(AxArtifactKey.getNullKey()) // Default Task
253 .taskReferenceMap(new TreeMap<AxArtifactKey, AxStateTaskReference>()) // Task References
259 * This Constructor creates a state with all its fields defined.
261 * @param axStateParams parameters for state creation
263 // CHECKSTYLE:OFF: checkstyle:parameterNumber
264 public AxState(AxStateParamsBuilder axStateParams) {
266 Assertions.argumentNotNull(axStateParams.getKey(), "key may not be null");
267 Assertions.argumentNotNull(axStateParams.getTrigger(), "trigger may not be null");
268 Assertions.argumentNotNull(axStateParams.getStateOutputs(), "stateOutputs may not be null");
269 Assertions.argumentNotNull(axStateParams.getContextAlbumReferenceSet(),
270 "contextAlbumReferenceSet may not be null");
271 Assertions.argumentNotNull(axStateParams.getTaskSelectionLogic(), "taskSelectionLogic may not be null");
272 Assertions.argumentNotNull(axStateParams.getStateFinalizerLogicMap(), "stateFinalizerLogicMap may not be null");
273 Assertions.argumentNotNull(axStateParams.getDefaultTask(), "defaultTask may not be null");
274 Assertions.argumentNotNull(axStateParams.getTaskReferenceMap(), "taskReferenceMap may not be null");
276 this.key = axStateParams.getKey();
277 this.trigger = axStateParams.getTrigger();
278 this.stateOutputs = axStateParams.getStateOutputs();
279 this.contextAlbumReferenceSet = axStateParams.getContextAlbumReferenceSet();
280 this.taskSelectionLogic = axStateParams.getTaskSelectionLogic();
281 this.stateFinalizerLogicMap = axStateParams.getStateFinalizerLogicMap();
282 this.defaultTask = axStateParams.getDefaultTask();
283 this.taskReferenceMap = axStateParams.getTaskReferenceMap();
285 // CHECKSTYLE:ON: checkstyle:parameterNumber
288 * When a state is unmarshalled from disk or from the database, the parent of contained objects is not defined. This
289 * method is called by JAXB after unmarshaling and is used to set the parent keys of all
290 * {@link AxTaskSelectionLogic}, {@link AxStateOutput}, and {@link AxStateFinalizerLogic} instance in the state.
292 * @param unmarshaler the unmarshaler that is unmarshaling the model
293 * @param parent the parent object of this object in the unmarshaler
295 public void afterUnmarshal(final Unmarshaller unmarshaler, final Object parent) {
296 if (!taskSelectionLogic.getKey().getLocalName().equals(AxKey.NULL_KEY_NAME)) {
297 taskSelectionLogic.getKey().setParentReferenceKey(key);
300 for (final Entry<String, AxStateOutput> soEntry : stateOutputs.entrySet()) {
301 soEntry.getValue().getKey().setParentReferenceKey(key);
304 for (final Entry<String, AxStateFinalizerLogic> sflEntry : stateFinalizerLogicMap.entrySet()) {
305 sflEntry.getValue().getKey().setParentReferenceKey(key);
308 for (final Entry<AxArtifactKey, AxStateTaskReference> trEntry : taskReferenceMap.entrySet()) {
309 trEntry.getValue().getKey().setParentReferenceKey(key);
314 * Gets the names of all the states that this state may pass control to.
316 * @return the list of possible states that may receive control when this state completes execution
318 public Set<String> getNextStateSet() {
319 final Set<String> nextStateSet = new TreeSet<>();
321 for (final AxStateOutput stateOutput : stateOutputs.values()) {
322 nextStateSet.add(stateOutput.getNextState().getLocalName());
330 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
333 public AxReferenceKey getKey() {
340 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
343 public List<AxKey> getKeys() {
344 final List<AxKey> keyList = key.getKeys();
345 keyList.add(new AxKeyUse(trigger.getKey()));
346 for (final AxStateOutput stateOutput : stateOutputs.values()) {
347 keyList.addAll(stateOutput.getKeys());
349 for (final AxArtifactKey contextAlbumReferenceKey : contextAlbumReferenceSet) {
350 keyList.add(new AxKeyUse(contextAlbumReferenceKey));
352 if (!taskSelectionLogic.getKey().equals(AxReferenceKey.getNullKey())) {
353 keyList.addAll(taskSelectionLogic.getKeys());
355 for (final Entry<String, AxStateFinalizerLogic> stateFinalizerLogicEntry : stateFinalizerLogicMap.entrySet()) {
356 keyList.addAll(stateFinalizerLogicEntry.getValue().getKeys());
358 keyList.add(new AxKeyUse(defaultTask.getKey()));
359 for (final Entry<AxArtifactKey, AxStateTaskReference> taskReferenceEntry : taskReferenceMap.entrySet()) {
360 keyList.add(new AxKeyUse(taskReferenceEntry.getKey()));
362 // A state output is allowed to be used more than once but we only return one usage as a
364 for (AxKey referencedKey : taskReferenceEntry.getValue().getKeys()) {
365 if (keyList.contains(referencedKey)) {
366 keyList.add(referencedKey);
374 * Sets the reference key of the state.
376 * @param key the state reference key
378 public void setKey(final AxReferenceKey key) {
379 Assertions.argumentNotNull(key, "key may not be null");
384 * Gets the event that triggers the state.
386 * @return the event that triggers the state
388 public AxArtifactKey getTrigger() {
393 * Sets the event that triggers the state.
395 * @param trigger the event that triggers the state
397 public void setTrigger(final AxArtifactKey trigger) {
398 Assertions.argumentNotNull(trigger, "trigger may not be null");
399 this.trigger = trigger;
403 * Gets the possible state outputs for the state.
405 * @return the the possible state outputs for the state
407 public Map<String, AxStateOutput> getStateOutputs() {
412 * Sets the the possible state outputs for the state.
414 * @param stateOutputs the the possible state outputs for the state
416 public void setStateOutputs(final Map<String, AxStateOutput> stateOutputs) {
417 Assertions.argumentNotNull(stateOutputs, "stateOutputs may not be null");
418 this.stateOutputs = stateOutputs;
422 * Gets the context album reference set defines the context that may be used by Task Selection Logic and State
423 * Finalizer Logic in the state.
425 * @return the context album reference set defines the context that may be used by Task Selection Logic and State
426 * Finalizer Logic in the state
428 public Set<AxArtifactKey> getContextAlbumReferences() {
429 return contextAlbumReferenceSet;
433 * Sets the context album reference set defines the context that may be used by Task Selection Logic and State
434 * Finalizer Logic in the state.
436 * @param contextAlbumReferences the context album reference set defines the context that may be used by Task
437 * Selection Logic and State Finalizer Logic in the state
439 public void setContextAlbumReferences(final Set<AxArtifactKey> contextAlbumReferences) {
440 Assertions.argumentNotNull(contextAlbumReferences, "contextAlbumReferenceSet may not be null");
441 this.contextAlbumReferenceSet = contextAlbumReferences;
445 * Gets the task selection logic that selects the task a state executes in an execution cycle.
447 * @return the task selection logic that selects the task a state executes in an execution cycle
449 public AxTaskSelectionLogic getTaskSelectionLogic() {
450 return taskSelectionLogic;
454 * Sets the task selection logic that selects the task a state executes in an execution cycle.
456 * @param taskSelectionLogic the task selection logic that selects the task a state executes in an execution cycle
458 public void setTaskSelectionLogic(final AxTaskSelectionLogic taskSelectionLogic) {
459 Assertions.argumentNotNull(taskSelectionLogic, "taskSelectionLogic may not be null");
460 this.taskSelectionLogic = taskSelectionLogic;
464 * Check if task selection logic has been specified the state.
466 * @return true, if task selection logic has been specified
468 public boolean checkSetTaskSelectionLogic() {
469 return !taskSelectionLogic.getKey().equals(AxReferenceKey.getNullKey());
473 * Gets the state finalizer logic instances that selects the state output to use after a task executes in a state
476 * @return the state finalizer logic instances that selects the state output to use after a task executes in a state
479 public Map<String, AxStateFinalizerLogic> getStateFinalizerLogicMap() {
480 return stateFinalizerLogicMap;
484 * Sets the state finalizer logic instances that selects the state output to use after a task executes in a state
487 * @param stateFinalizerLogicMap the state finalizer logic instances that selects the state output to use after a
488 * task executes in a state execution cycle
490 public void setStateFinalizerLogicMap(final Map<String, AxStateFinalizerLogic> stateFinalizerLogicMap) {
491 Assertions.argumentNotNull(stateFinalizerLogicMap, "stateFinalizerLogic may not be null");
492 this.stateFinalizerLogicMap = stateFinalizerLogicMap;
496 * Gets the default task that will execute in a state if Task Selection Logic is not specified.
498 * @return the default task that will execute in a state if Task Selection Logic is not specified
500 public AxArtifactKey getDefaultTask() {
505 * Sets the default task that will execute in a state if Task Selection Logic is not specified.
507 * @param defaultTask the default task that will execute in a state if Task Selection Logic is not specified
509 public void setDefaultTask(final AxArtifactKey defaultTask) {
510 Assertions.argumentNotNull(defaultTask, "defaultTask may not be null");
511 this.defaultTask = defaultTask;
515 * Gets the task reference map that defines the tasks for the state and how the task outputs are handled.
517 * @return the task reference map that defines the tasks for the state and how the task outputs are handled
519 public Map<AxArtifactKey, AxStateTaskReference> getTaskReferences() {
520 return taskReferenceMap;
524 * Sets the task reference map that defines the tasks for the state and how the task outputs are handled.
526 * @param taskReferences the task reference map that defines the tasks for the state and how the task outputs are
529 public void setTaskReferences(final Map<AxArtifactKey, AxStateTaskReference> taskReferences) {
530 Assertions.argumentNotNull(taskReferences, "taskReferenceMap may not be null");
531 this.taskReferenceMap = taskReferences;
537 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
538 * basicmodel.concepts.AxValidationResult)
541 public AxValidationResult validate(final AxValidationResult resultIn) {
542 AxValidationResult result = resultIn;
544 if (key.equals(AxReferenceKey.getNullKey())) {
545 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
546 "key is a null key"));
549 result = key.validate(result);
551 if (trigger.equals(AxArtifactKey.getNullKey())) {
552 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
553 "trigger is a null key: " + trigger));
555 result = trigger.validate(result);
557 if (stateOutputs.size() == 0) {
558 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
559 "stateOutputs may not be empty"));
561 validateStateOutputs(result);
564 validateContextAlbumReferences(result);
565 result = validateTaskSelectionLogic(result);
566 validateStateFinalizerLogics(result);
568 if (defaultTask.equals(AxArtifactKey.getNullKey())) {
569 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
570 "default task has a null key: " + defaultTask));
572 result = defaultTask.validate(result);
574 if (taskReferenceMap.size() == 0) {
575 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
576 "taskReferenceMap may not be empty"));
578 validateStateTaskReferences(result);
585 * Validate the state outputs of the state.
587 * @param result the validation result to append to
589 private void validateStateOutputs(AxValidationResult result) {
590 final Set<String> nextStateNameSet = new TreeSet<>();
591 for (final Entry<String, AxStateOutput> stateOutputEntry : stateOutputs.entrySet()) {
592 if (stateOutputEntry.getValue() == null) {
593 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
594 "null state output value found on state output " + stateOutputEntry.getKey()));
596 if (!stateOutputEntry.getValue().getKey().getParentReferenceKey().equals(key)) {
597 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
598 "parent key on state output " + stateOutputEntry.getKey()
599 + DOES_NOT_EQUAL_STATE_KEY));
602 if (stateOutputEntry.getValue().getNextState().getLocalName().equals(key.getLocalName())) {
603 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
604 "state output next state "
605 + stateOutputEntry.getValue().getNextState().getLocalName()
606 + " may not be this state"));
610 if (nextStateNameSet.contains(stateOutputEntry.getValue().getNextState().getLocalName())) {
611 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
612 "duplicate state output next state name "
613 + stateOutputEntry.getValue().getNextState().getLocalName()
616 nextStateNameSet.add(stateOutputEntry.getValue().getNextState().getLocalName());
618 result = stateOutputEntry.getValue().validate(result);
624 * Validate the context album references of the state.
626 * @param result the validation result to append to
628 private void validateContextAlbumReferences(AxValidationResult result) {
629 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
630 if (contextAlbumReference.equals(AxArtifactKey.getNullKey())) {
631 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
632 "key on context album reference entry " + contextAlbumReference.getKey()
633 + " may not be the null key"));
636 result = contextAlbumReference.validate(result);
641 * Validate the task selection logic of the state.
643 * @param result the validation result to append to
644 * @return the result of the validation
646 private AxValidationResult validateTaskSelectionLogic(AxValidationResult result) {
647 if (!taskSelectionLogic.getKey().equals(AxReferenceKey.getNullKey())) {
648 if (!taskSelectionLogic.getKey().getParentReferenceKey().equals(key)) {
649 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
650 "taskSelectionLogic key " + taskSelectionLogic.getKey().getId()
651 + DOES_NOT_EQUAL_STATE_KEY));
653 result = taskSelectionLogic.validate(result);
660 * Validate all the state finalizer logic of the state.
662 * @param result the validation result to append to
664 private void validateStateFinalizerLogics(AxValidationResult result) {
665 for (final Entry<String, AxStateFinalizerLogic> stateFinalizerLogicEntry : stateFinalizerLogicMap.entrySet()) {
666 if (stateFinalizerLogicEntry.getValue() == null) {
667 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
668 "null state finalizer logic value found on state finalizer entry "
669 + stateFinalizerLogicEntry.getKey()));
671 if (!stateFinalizerLogicEntry.getValue().getKey().getParentReferenceKey().equals(key)) {
672 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
673 "stateFinalizerLogic parent key "
674 + stateFinalizerLogicEntry.getValue().getKey().getId()
675 + DOES_NOT_EQUAL_STATE_KEY));
678 result = stateFinalizerLogicEntry.getValue().validate(result);
684 * Validate the tasks used the state.
686 * @param result the validation result to append to
688 private void validateStateTaskReferences(AxValidationResult result) {
689 final Set<String> usedStateOutputNameSet = new TreeSet<>();
690 final Set<String> usedStateFinalizerLogicNameSet = new TreeSet<>();
692 for (final Entry<AxArtifactKey, AxStateTaskReference> taskRefEntry : taskReferenceMap.entrySet()) {
693 if (taskRefEntry.getKey().equals(AxArtifactKey.getNullKey())) {
694 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
695 "task has a null key: " + taskRefEntry.getKey()));
697 result = taskRefEntry.getKey().validate(result);
699 if (taskRefEntry.getValue() == null) {
700 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
701 "null task reference value found on task reference " + taskRefEntry.getKey()));
703 result = validateStateTaskReference(taskRefEntry.getKey(), taskRefEntry.getValue(),
704 usedStateOutputNameSet, usedStateFinalizerLogicNameSet, result);
708 final Set<String> unUsedStateOutputNameSet = new TreeSet<>(stateOutputs.keySet());
709 unUsedStateOutputNameSet.removeAll(usedStateOutputNameSet);
710 for (final String unUsedStateOutputName : unUsedStateOutputNameSet) {
711 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION,
712 "state output " + unUsedStateOutputName + " is not used directly by any task"));
715 final Set<String> usnUedStateFinalizerLogicNameSet = new TreeSet<>(stateFinalizerLogicMap.keySet());
716 usnUedStateFinalizerLogicNameSet.removeAll(usedStateFinalizerLogicNameSet);
717 for (final String unusedStateFinalizerLogicName : usnUedStateFinalizerLogicNameSet) {
718 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION,
719 "state finalizer logic " + unusedStateFinalizerLogicName + " is not used by any task"));
722 if (!taskReferenceMap.containsKey(defaultTask)) {
723 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
724 "defaultTask " + defaultTask + " not found in taskReferenceMap"));
729 * Validate the references of a task used in a state.
731 * @param taskKey The key of the task
732 * @param taskReference the task reference of the task
733 * @param stateOutputNameSet State outputs that have been used so far, will be appended for this task reference
734 * @param stateFinalizerLogicNameSet State finalizers that have been used so far, may be appended if this task
735 * reference uses a finalzier
736 * @param result the validation result to append to
737 * @return the result of the validation
739 private AxValidationResult validateStateTaskReference(final AxArtifactKey taskKey,
740 final AxStateTaskReference taskReference, Set<String> stateOutputNameSet,
741 Set<String> stateFinalizerLogicNameSet, AxValidationResult result) {
742 if (!taskReference.getKey().getParentReferenceKey().equals(key)) {
743 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
744 "stateTaskReference parent key " + taskReference.getKey().getId()
745 + DOES_NOT_EQUAL_STATE_KEY));
748 if (taskReference.getStateTaskOutputType().equals(AxStateTaskOutputType.DIRECT)) {
749 if (stateOutputs.containsKey(taskReference.getOutput().getLocalName())) {
750 stateOutputNameSet.add(taskReference.getOutput().getLocalName());
752 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
753 "state output for task " + taskKey + " not found in stateOutputs"));
755 } else if (taskReference.getStateTaskOutputType().equals(AxStateTaskOutputType.LOGIC)) {
756 if (stateFinalizerLogicMap.containsKey(taskReference.getOutput().getLocalName())) {
757 stateFinalizerLogicNameSet.add(taskReference.getOutput().getLocalName());
759 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
760 "state finalizer logic for task " + taskKey + " not found in stateFinalizerLogicMap"));
763 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
764 "stateTaskReference task output type " + taskReference.getStateTaskOutputType()
768 return taskReference.validate(result);
774 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
777 public void clean() {
780 for (final AxStateOutput stateOutput : stateOutputs.values()) {
783 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
784 contextAlbumReference.clean();
786 taskSelectionLogic.clean();
787 for (final AxStateFinalizerLogic stateFinalizerLogic : stateFinalizerLogicMap.values()) {
788 stateFinalizerLogic.clean();
791 for (final AxStateTaskReference taskReference : taskReferenceMap.values()) {
792 taskReference.clean();
799 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
802 public String toString() {
803 final StringBuilder builder = new StringBuilder();
804 builder.append(this.getClass().getSimpleName());
805 builder.append(":(");
806 builder.append("stateKey=");
808 builder.append(",trigger=");
809 builder.append(trigger);
810 builder.append(",stateOutputs=");
811 builder.append(stateOutputs);
812 builder.append(",contextAlbumReferenceSet=");
813 builder.append(contextAlbumReferenceSet);
814 builder.append(",taskSelectionLogic=");
815 builder.append(taskSelectionLogic);
816 builder.append(",stateFinalizerLogicSet=");
817 builder.append(stateFinalizerLogicMap);
818 builder.append(",defaultTask=");
819 builder.append(defaultTask);
820 builder.append(",taskReferenceMap=");
821 builder.append(taskReferenceMap);
823 return builder.toString();
829 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
830 * basicmodel.concepts.AxConcept)
833 public AxConcept copyTo(final AxConcept targetObject) {
834 Assertions.argumentNotNull(targetObject, "target may not be null");
836 final Object copyObject = targetObject;
837 Assertions.instanceOf(copyObject, AxState.class);
839 final AxState copy = ((AxState) copyObject);
840 copy.setKey(new AxReferenceKey(key));
841 copy.setTrigger(new AxArtifactKey(trigger));
843 final Map<String, AxStateOutput> newStateOutputs = new TreeMap<>();
844 for (final Entry<String, AxStateOutput> stateOutputEntry : stateOutputs.entrySet()) {
845 newStateOutputs.put(stateOutputEntry.getKey(), new AxStateOutput(stateOutputEntry.getValue()));
847 copy.setStateOutputs(newStateOutputs);
849 final Set<AxArtifactKey> newContextUsage = new TreeSet<>();
850 for (final AxArtifactKey contextAlbumReferenceItem : contextAlbumReferenceSet) {
851 newContextUsage.add(new AxArtifactKey(contextAlbumReferenceItem));
853 copy.setContextAlbumReferences(newContextUsage);
855 copy.setTaskSelectionLogic(new AxTaskSelectionLogic(taskSelectionLogic));
857 final Map<String, AxStateFinalizerLogic> newStateFinalizerLogicMap = new TreeMap<>();
858 for (final Entry<String, AxStateFinalizerLogic> stateFinalizerLogicEntry : stateFinalizerLogicMap.entrySet()) {
859 newStateFinalizerLogicMap.put(stateFinalizerLogicEntry.getKey(),
860 new AxStateFinalizerLogic(stateFinalizerLogicEntry.getValue()));
862 copy.setStateFinalizerLogicMap(newStateFinalizerLogicMap);
864 copy.setDefaultTask(new AxArtifactKey(defaultTask));
866 final Map<AxArtifactKey, AxStateTaskReference> newTaskReferenceMap = new TreeMap<>();
867 for (final Entry<AxArtifactKey, AxStateTaskReference> taskReferenceEntry : taskReferenceMap.entrySet()) {
868 newTaskReferenceMap.put(new AxArtifactKey(taskReferenceEntry.getKey()),
869 new AxStateTaskReference(taskReferenceEntry.getValue()));
871 copy.setTaskReferences(newTaskReferenceMap);
879 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
882 public int hashCode() {
883 final int prime = 31;
885 result = prime * result + key.hashCode();
886 result = prime * result + trigger.hashCode();
887 result = prime * result + stateOutputs.hashCode();
888 result = prime * result + contextAlbumReferenceSet.hashCode();
889 result = prime * result + taskSelectionLogic.hashCode();
890 result = prime * result + stateFinalizerLogicMap.hashCode();
891 result = prime * result + defaultTask.hashCode();
892 result = prime * result + taskReferenceMap.hashCode();
899 * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
902 public boolean equals(final Object obj) {
910 if (getClass() != obj.getClass()) {
914 final AxState other = (AxState) obj;
915 if (!key.equals(other.key)) {
918 if (!trigger.equals(other.trigger)) {
921 if (!stateOutputs.equals(other.stateOutputs)) {
924 if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
927 if (!taskSelectionLogic.equals(other.taskSelectionLogic)) {
930 if (!stateFinalizerLogicMap.equals(other.stateFinalizerLogicMap)) {
933 if (!defaultTask.equals(other.defaultTask)) {
936 return taskReferenceMap.equals(other.taskReferenceMap);
942 * @see java.lang.Comparable#compareTo(java.lang.Object)
945 public int compareTo(final AxConcept otherObj) {
946 if (otherObj == null) {
949 if (this == otherObj) {
952 if (getClass() != otherObj.getClass()) {
953 return this.hashCode() - otherObj.hashCode();
956 return compareObjectFields((AxState) otherObj);
960 * Compare the object fields on this state to another state.
962 * @param the other state to compare with
963 * @return the result of the comparison
965 private int compareObjectFields(final AxState other) {
966 if (!key.equals(other.key)) {
967 return key.compareTo(other.key);
969 if (!trigger.equals(other.trigger)) {
970 return trigger.compareTo(other.trigger);
972 if (!stateOutputs.equals(other.stateOutputs)) {
973 return stateOutputs.hashCode() - other.stateOutputs.hashCode();
975 if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
976 return (contextAlbumReferenceSet.hashCode() - other.contextAlbumReferenceSet.hashCode());
978 if (!taskSelectionLogic.equals(other.taskSelectionLogic)) {
979 return taskSelectionLogic.compareTo(other.taskSelectionLogic);
981 if (!stateFinalizerLogicMap.equals(other.stateFinalizerLogicMap)) {
982 return stateFinalizerLogicMap.hashCode() - other.stateFinalizerLogicMap.hashCode();
984 if (!defaultTask.equals(other.defaultTask)) {
985 return defaultTask.compareTo(other.defaultTask);
987 if (!taskReferenceMap.equals(other.taskReferenceMap)) {
988 return (taskReferenceMap.hashCode() - other.taskReferenceMap.hashCode());