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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.apex.model.policymodel.concepts;
24 import java.util.List;
26 import java.util.Map.Entry;
28 import java.util.TreeMap;
29 import java.util.TreeSet;
31 import javax.persistence.CascadeType;
32 import javax.persistence.CollectionTable;
33 import javax.persistence.ElementCollection;
34 import javax.persistence.EmbeddedId;
35 import javax.persistence.Entity;
36 import javax.persistence.JoinColumn;
37 import javax.persistence.OneToMany;
38 import javax.persistence.OneToOne;
39 import javax.persistence.Table;
40 import javax.xml.bind.Unmarshaller;
41 import javax.xml.bind.annotation.XmlAccessType;
42 import javax.xml.bind.annotation.XmlAccessorType;
43 import javax.xml.bind.annotation.XmlElement;
44 import javax.xml.bind.annotation.XmlRootElement;
45 import javax.xml.bind.annotation.XmlType;
47 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
48 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
49 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
50 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyUse;
51 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
52 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
53 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
54 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
55 import org.onap.policy.apex.model.eventmodel.concepts.AxField;
56 import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
57 import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
58 import org.onap.policy.common.utils.validation.Assertions;
61 * This class holds the definition of a task in Apex. A task is executed by a state and performs
62 * some domain specific logic to carry out work required to be done by a policy. The Task Logic that
63 * is executed by a task is held in a {@link AxTaskLogic} instance.
65 * <p>A task has a set of input fields and output fields, which are passed to and are emitted from the
66 * task during a task execution cycle. A task may have task parameters {@link AxTaskParameter},
67 * which are configuration values passed to a task at initialization time.
69 * <p>The Task Logic in a task may use information in context albums to perform their domain specific
70 * work. The context albums that the task uses and that should be made available to the task by Apex
71 * policy distribution are held as a set of references to context albums in the task.
73 * <p>During validation of a task, the validation checks listed below are executed:
75 * <li>The task key must not be a null key and must be valid, see validation in
76 * {@link AxArtifactKey}
77 * <li>The task must have at least one input field
78 * <li>The parent of each input field of a task must be that task
79 * <li>Each input field must be valid, see validation in {@link AxInputField}
80 * <li>The task must have at least one output field
81 * <li>The parent of each output field of a task must be that task
82 * <li>Each output field must be valid, see validation in {@link AxOutputField}
83 * <li>The parent of each task parameter of a task must be that task
84 * <li>Each task parameter must be valid, see validation in {@link AxTaskParameter}
85 * <li>The parent of the task logic in a task must be that task
86 * <li>The task logic must be valid, see validation in {@link AxTaskLogic}
91 @Table(name = "AxTask")
93 @XmlAccessorType(XmlAccessType.FIELD)
94 @XmlRootElement(name = "apexTask", namespace = "http://www.onap.org/policy/apex-pdp")
95 @XmlType(name = "AxTask", namespace = "http://www.onap.org/policy/apex-pdp",
96 propOrder = {"key", "inputFields", "outputFields", "taskParameters", "contextAlbumReferenceSet", "taskLogic"})
98 public class AxTask extends AxConcept {
99 private static final String DOES_NOT_EQUAL_TASK_KEY = " does not equal task key";
101 private static final long serialVersionUID = 5374237330697362762L;
104 @XmlElement(name = "key", required = true)
105 private AxArtifactKey key;
107 @OneToMany(cascade = CascadeType.ALL)
108 @XmlElement(name = "inputFields", required = true)
109 private Map<String, AxInputField> inputFields;
111 @OneToMany(cascade = CascadeType.ALL)
112 @XmlElement(name = "outputFields", required = true)
113 private Map<String, AxOutputField> outputFields;
115 @OneToMany(cascade = CascadeType.ALL)
116 @XmlElement(name = "taskParameters", required = true)
117 private Map<String, AxTaskParameter> taskParameters;
121 @CollectionTable(joinColumns = {@JoinColumn(name = "contextAlbumName", referencedColumnName = "name"),
122 @JoinColumn(name = "contextAlbumVersion", referencedColumnName = "version")})
123 @XmlElement(name = "contextAlbumReference")
124 private Set<AxArtifactKey> contextAlbumReferenceSet;
127 @OneToOne(cascade = CascadeType.ALL)
128 @XmlElement(required = true)
129 private AxTaskLogic taskLogic;
132 * The Default Constructor creates a task with a null key no input or output fields, no task
133 * parameters, no context album references and no logic.
136 this(new AxArtifactKey());
137 contextAlbumReferenceSet = new TreeSet<>();
143 * @param copyConcept the concept to copy from
145 public AxTask(final AxTask copyConcept) {
150 * The Keyed Constructor creates a task with the given key no input or output fields, no task
151 * parameters, no context album references and no logic.
153 * @param key the key of the task
155 public AxTask(final AxArtifactKey key) {
156 this(key, // Task Key
157 new TreeMap<String, AxInputField>(), // Input fields
158 new TreeMap<String, AxOutputField>(), // Output Fields
159 new TreeMap<String, AxTaskParameter>(), // Task Parameters
160 new TreeSet<AxArtifactKey>(), // Context Album References
161 new AxTaskLogic(new AxReferenceKey(key)) // Task Logic
166 * This Constructor defines all the fields of the task.
168 * @param key the key of the task
169 * @param inputFields the input fields that the task expects
170 * @param outputFields the output fields that the task emits
171 * @param taskParameters the task parameters that are used to initialize tasks of this type
172 * @param contextAlbumReferenceSet the context album reference set defines the context that may
173 * be used by Task Logic in the state
174 * @param taskLogic the task logic that performs the domain specific work of the task
176 public AxTask(final AxArtifactKey key, final Map<String, AxInputField> inputFields,
177 final Map<String, AxOutputField> outputFields, final Map<String, AxTaskParameter> taskParameters,
178 final Set<AxArtifactKey> contextAlbumReferenceSet, final AxTaskLogic taskLogic) {
180 Assertions.argumentNotNull(key, "key may not be null");
181 Assertions.argumentNotNull(inputFields, "inputFields may not be null");
182 Assertions.argumentNotNull(outputFields, "outputFields may not be null");
183 Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
184 Assertions.argumentNotNull(contextAlbumReferenceSet, "contextAlbumReferenceSet may not be null");
185 Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
188 this.inputFields = inputFields;
189 this.outputFields = outputFields;
190 this.taskParameters = taskParameters;
191 this.contextAlbumReferenceSet = contextAlbumReferenceSet;
192 this.taskLogic = taskLogic;
196 * When a task is unmarshalled from disk or from the database, the parent of contained objects
197 * is not defined. This method is called by JAXB after unmarshaling and is used to set the
198 * parent keys of all {@link AxInputField}, {@link AxOutputField}, and {@link AxTaskParameter}
199 * instance in the task.
201 * @param unmarshaler the unmarshaler that is unmarshaling the model
202 * @param parent the parent object of this object in the unmarshaler
204 public void afterUnmarshal(final Unmarshaller unmarshaler, final Object parent) {
205 taskLogic.getKey().setParentArtifactKey(key);
207 for (final AxInputField inputField : inputFields.values()) {
208 inputField.getKey().setParentArtifactKey(key);
209 inputField.getKey().setParentLocalName("InField");
211 for (final AxOutputField outputField : outputFields.values()) {
212 outputField.getKey().setParentArtifactKey(key);
213 outputField.getKey().setParentLocalName("OutField");
215 for (final AxTaskParameter parameter : taskParameters.values()) {
216 parameter.getKey().setParentArtifactKey(key);
224 public AxArtifactKey getKey() {
232 public List<AxKey> getKeys() {
233 final List<AxKey> keyList = key.getKeys();
234 for (final AxInputField inputField : inputFields.values()) {
235 keyList.addAll(inputField.getKeys());
237 for (final AxOutputField outputField : outputFields.values()) {
238 keyList.addAll(outputField.getKeys());
240 for (final AxTaskParameter taskParameter : taskParameters.values()) {
241 keyList.addAll(taskParameter.getKeys());
243 for (final AxArtifactKey contextAlbumKey : contextAlbumReferenceSet) {
244 keyList.add(new AxKeyUse(contextAlbumKey));
246 keyList.addAll(taskLogic.getKeys());
251 * Sets the key of the task.
253 * @param key the key of the task
255 public void setKey(final AxArtifactKey key) {
256 Assertions.argumentNotNull(key, "key may not be null");
261 * Gets the input fields that the task expects.
263 * @return the input fields that the task expects
265 public Map<String, AxInputField> getInputFields() {
270 * Gets the raw input fields that the task expects as a tree map.
272 * @return the raw input fields that the task expects
274 public Map<String, AxField> getRawInputFields() {
275 return new TreeMap<>(inputFields);
279 * Convenience method to get the input fields as a set.
281 * @return the input fields as a set
283 public Set<AxField> getInputFieldSet() {
284 final Set<AxField> inputFieldSet = new TreeSet<>();
285 for (final AxInputField field : inputFields.values()) {
286 inputFieldSet.add(field);
288 return inputFieldSet;
292 * Sets the input fields that the task expects.
294 * @param inputFields the input fields that the task expects
296 public void setInputFields(final Map<String, AxInputField> inputFields) {
297 Assertions.argumentNotNull(inputFields, "inputFields may not be null");
298 this.inputFields = inputFields;
302 * Copy the input fields from the given map into the task. This method is used to get a copy of
303 * the input fields, which can be useful for unit testing of policies and tasks.
305 * @param fields the fields to copy into the task
307 public void duplicateInputFields(final Map<String, AxField> fields) {
308 Assertions.argumentNotNull(fields, "fields may not be null");
310 for (final AxField field : fields.values()) {
311 final AxReferenceKey fieldKey = new AxReferenceKey(this.getKey().getName(), this.getKey().getVersion(),
312 "inputFields", field.getKey().getLocalName());
313 final AxInputField inputField = new AxInputField(fieldKey, field.getSchema());
314 inputFields.put(inputField.getKey().getLocalName(), inputField);
319 * Gets the output fields that the task emits.
321 * @return the output fields that the task emits
323 public Map<String, AxOutputField> getOutputFields() {
328 * Gets the raw output fields that the task emits as a tree map.
330 * @return the raw output fields as a tree map
332 public Map<String, AxField> getRawOutputFields() {
333 return new TreeMap<>(outputFields);
337 * Gets the output fields that the task emits as a set.
339 * @return the output fields as a set
341 public Set<AxField> getOutputFieldSet() {
342 final Set<AxField> outputFieldSet = new TreeSet<>();
343 for (final AxOutputField field : outputFields.values()) {
344 outputFieldSet.add(field);
346 return outputFieldSet;
350 * Sets the output fields that the task emits.
352 * @param outputFields the output fields that the task emits
354 public void setOutputFields(final Map<String, AxOutputField> outputFields) {
355 Assertions.argumentNotNull(outputFields, "outputFields may not be null");
356 this.outputFields = outputFields;
360 * Copy the output fields from the given map into the task. This method is used to get a copy of
361 * the output fields, which can be useful for unit testing of policies and tasks.
363 * @param fields the fields to copy into the task
365 public void duplicateOutputFields(final Map<String, AxField> fields) {
366 Assertions.argumentNotNull(fields, "fields may not be null");
368 for (final AxField field : fields.values()) {
369 final AxReferenceKey fieldKey = new AxReferenceKey(this.getKey().getName(), this.getKey().getVersion(),
370 "outputFields", field.getKey().getLocalName());
371 final AxOutputField outputField = new AxOutputField(fieldKey, field.getSchema());
372 outputFields.put(outputField.getKey().getLocalName(), outputField);
377 * Gets the task parameters that are used to initialize tasks of this type.
379 * @return the task parameters that are used to initialize tasks of this type
381 public Map<String, AxTaskParameter> getTaskParameters() {
382 return taskParameters;
386 * Sets the task parameters that are used to initialize tasks of this type.
388 * @param taskParameters the task parameters that are used to initialize tasks of this type
390 public void setTaskParameters(final Map<String, AxTaskParameter> taskParameters) {
391 Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
392 this.taskParameters = taskParameters;
396 * Gets the context album reference set defines the context that may be used by Task Logic in
399 * @return the context album reference set defines the context that may be used by Task Logic in
402 public Set<AxArtifactKey> getContextAlbumReferences() {
403 return contextAlbumReferenceSet;
407 * Sets the context album reference set defines the context that may be used by Task Logic in
410 * @param contextAlbumReferences the context album reference set defines the context that may be
411 * used by Task Logic in the state
413 public void setContextAlbumReferences(final Set<AxArtifactKey> contextAlbumReferences) {
414 Assertions.argumentNotNull(contextAlbumReferences, "contextAlbumReferences may not be null");
415 this.contextAlbumReferenceSet = contextAlbumReferences;
419 * Gets the task logic that performs the domain specific work of the task.
421 * @return the task logic that performs the domain specific work of the task
423 public AxTaskLogic getTaskLogic() {
428 * Sets the task logic that performs the domain specific work of the task.
430 * @param taskLogic the task logic that performs the domain specific work of the task
432 public void setTaskLogic(final AxTaskLogic taskLogic) {
433 Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
434 this.taskLogic = taskLogic;
441 public AxValidationResult validate(final AxValidationResult resultIn) {
442 AxValidationResult result = resultIn;
444 if (key.equals(AxArtifactKey.getNullKey())) {
445 result.addValidationMessage(
446 new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
449 result = key.validate(result);
451 if (inputFields.size() == 0) {
452 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
453 "inputFields may not be empty"));
455 for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
456 result = validateField(inputFieldEntry.getKey(), inputFieldEntry.getValue(), "input", result);
460 if (outputFields.size() == 0) {
461 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
462 "outputFields may not be empty"));
464 for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
465 result = validateField(outputFieldEntry.getKey(), outputFieldEntry.getValue(), "input", result);
469 for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
470 result = vaildateTaskParameterEntry(taskParameterEntry, result);
473 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
474 result = vaildateContextAlbumReference(contextAlbumReference, result);
477 if (!taskLogic.getKey().getParentArtifactKey().equals(key)) {
478 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
479 "taskLogic parent key " + taskLogic.getKey().getId() + DOES_NOT_EQUAL_TASK_KEY));
482 return taskLogic.validate(result);
488 * @param key the key of the field to validate
489 * @param field the field to validate
490 * @param direction The direction of the field
491 * @param result The validation result to append to
492 * @return The result of the validation
494 private AxValidationResult validateField(final String fieldKey, final AxField field, final String direction,
495 AxValidationResult result) {
497 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
498 "null " + direction + " field value found on " + direction + " field " + fieldKey));
500 if (!field.getKey().getParentArtifactKey().equals(key)) {
501 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
502 "parent key on " + direction + " field " + fieldKey + DOES_NOT_EQUAL_TASK_KEY));
505 result = field.validate(result);
512 * Validate a task parameter entry.
514 * @param taskParameterEntry the task parameter entry to validate
515 * @param result The validation result to append to
516 * @return The result of the validation
518 private AxValidationResult vaildateTaskParameterEntry(final Entry<String, AxTaskParameter> taskParameterEntry,
519 AxValidationResult result) {
520 if (taskParameterEntry.getValue() == null) {
521 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
522 "null input task parameter value found on task parameter " + taskParameterEntry.getKey()));
524 if (!taskParameterEntry.getValue().getKey().getParentArtifactKey().equals(key)) {
525 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
526 "parent key on task parameter " + taskParameterEntry.getKey() + DOES_NOT_EQUAL_TASK_KEY));
529 result = taskParameterEntry.getValue().validate(result);
536 * Validate a context album reference entry.
538 * @param taskParameterEntry the context album reference entry to validate
539 * @param result The validation result to append to
540 * @return The result of the validation
542 private AxValidationResult vaildateContextAlbumReference(final AxArtifactKey contextAlbumReference,
543 AxValidationResult result) {
544 if (contextAlbumReference.equals(AxArtifactKey.getNullKey())) {
545 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
546 "key on context item reference entry " + contextAlbumReference.getKey()
547 + " may not be the null key"));
550 return contextAlbumReference.validate(result);
557 public void clean() {
559 for (final AxInputField inputField : inputFields.values()) {
562 for (final AxOutputField outputField : outputFields.values()) {
565 for (final AxTaskParameter parameter : taskParameters.values()) {
568 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
569 contextAlbumReference.clean();
578 public String toString() {
579 final StringBuilder builder = new StringBuilder();
580 builder.append(this.getClass().getSimpleName());
581 builder.append(":(");
582 builder.append("key=");
584 builder.append(",inputFields=");
585 builder.append(inputFields);
586 builder.append(",outputFields=");
587 builder.append(outputFields);
588 builder.append(",taskParameters=");
589 builder.append(taskParameters);
590 builder.append(",contextAlbumReferenceSet=");
591 builder.append(contextAlbumReferenceSet);
592 builder.append(",taskLogic=");
593 builder.append(taskLogic);
595 return builder.toString();
602 public AxConcept copyTo(final AxConcept targetObject) {
603 Assertions.argumentNotNull(targetObject, "target may not be null");
605 final Object copyObject = targetObject;
606 Assertions.instanceOf(copyObject, AxTask.class);
608 final AxTask copy = ((AxTask) copyObject);
611 final Map<String, AxInputField> newInputFields = new TreeMap<>();
612 for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
613 newInputFields.put(inputFieldEntry.getKey(), new AxInputField(inputFieldEntry.getValue()));
615 copy.setInputFields(newInputFields);
617 final Map<String, AxOutputField> newOutputFields = new TreeMap<>();
618 for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
619 newOutputFields.put(outputFieldEntry.getKey(), new AxOutputField(outputFieldEntry.getValue()));
621 copy.setOutputFields(newOutputFields);
623 final Map<String, AxTaskParameter> newTaskParameter = new TreeMap<>();
624 for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
625 newTaskParameter.put(taskParameterEntry.getKey(), new AxTaskParameter(taskParameterEntry.getValue()));
627 copy.setTaskParameters(newTaskParameter);
629 final Set<AxArtifactKey> newContextUsage = new TreeSet<>();
630 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
631 newContextUsage.add(new AxArtifactKey(contextAlbumReference));
633 copy.setContextAlbumReferences(newContextUsage);
635 copy.setTaskLogic(new AxTaskLogic(taskLogic));
644 public int hashCode() {
645 final int prime = 31;
647 result = prime * result + key.hashCode();
648 result = prime * result + inputFields.hashCode();
649 result = prime * result + outputFields.hashCode();
650 result = prime * result + taskParameters.hashCode();
651 result = prime * result + contextAlbumReferenceSet.hashCode();
652 result = prime * result + taskLogic.hashCode();
660 public boolean equals(final Object obj) {
668 if (getClass() != obj.getClass()) {
672 final AxTask other = (AxTask) obj;
673 if (!key.equals(other.key)) {
676 if (!inputFields.equals(other.inputFields)) {
679 if (!outputFields.equals(other.outputFields)) {
682 if (!taskParameters.equals(other.taskParameters)) {
685 if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
688 return taskLogic.equals(other.taskLogic);
695 public int compareTo(final AxConcept otherObj) {
696 if (otherObj == null) {
699 if (this == otherObj) {
702 if (getClass() != otherObj.getClass()) {
703 return this.hashCode() - otherObj.hashCode();
706 final AxTask other = (AxTask) otherObj;
707 if (!key.equals(other.key)) {
708 return key.compareTo(other.key);
710 if (!inputFields.equals(other.inputFields)) {
711 return (inputFields.hashCode() - other.inputFields.hashCode());
713 if (!outputFields.equals(other.outputFields)) {
714 return (outputFields.hashCode() - other.outputFields.hashCode());
716 if (!taskParameters.equals(other.taskParameters)) {
717 return (taskParameters.hashCode() - other.taskParameters.hashCode());
719 if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
720 return (contextAlbumReferenceSet.hashCode() - other.contextAlbumReferenceSet.hashCode());
722 return taskLogic.compareTo(other.taskLogic);