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;
30 import javax.persistence.CascadeType;
31 import javax.persistence.CollectionTable;
32 import javax.persistence.ElementCollection;
33 import javax.persistence.EmbeddedId;
34 import javax.persistence.Entity;
35 import javax.persistence.JoinColumn;
36 import javax.persistence.OneToMany;
37 import javax.persistence.OneToOne;
38 import javax.persistence.Table;
39 import javax.xml.bind.Unmarshaller;
40 import javax.xml.bind.annotation.XmlAccessType;
41 import javax.xml.bind.annotation.XmlAccessorType;
42 import javax.xml.bind.annotation.XmlElement;
43 import javax.xml.bind.annotation.XmlRootElement;
44 import javax.xml.bind.annotation.XmlType;
45 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
46 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
47 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
48 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyUse;
49 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
50 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
51 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
52 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
53 import org.onap.policy.apex.model.eventmodel.concepts.AxField;
54 import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
55 import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
56 import org.onap.policy.common.utils.validation.Assertions;
59 * This class holds the definition of a task in Apex. A task is executed by a state and performs
60 * some domain specific logic to carry out work required to be done by a policy. The Task Logic that
61 * is executed by a task is held in a {@link AxTaskLogic} instance.
63 * <p>A task has a set of input fields and output fields, which are passed to and are emitted from the
64 * task during a task execution cycle. A task may have task parameters {@link AxTaskParameter},
65 * which are configuration values passed to a task at initialization time.
67 * <p>The Task Logic in a task may use information in context albums to perform their domain specific
68 * work. The context albums that the task uses and that should be made available to the task by Apex
69 * policy distribution are held as a set of references to context albums in the task.
71 * <p>During validation of a task, the validation checks listed below are executed:
73 * <li>The task key must not be a null key and must be valid, see validation in
74 * {@link AxArtifactKey}
75 * <li>The task must have at least one input field
76 * <li>The parent of each input field of a task must be that task
77 * <li>Each input field must be valid, see validation in {@link AxInputField}
78 * <li>The task must have at least one output field
79 * <li>The parent of each output field of a task must be that task
80 * <li>Each output field must be valid, see validation in {@link AxOutputField}
81 * <li>The parent of each task parameter of a task must be that task
82 * <li>Each task parameter must be valid, see validation in {@link AxTaskParameter}
83 * <li>The parent of the task logic in a task must be that task
84 * <li>The task logic must be valid, see validation in {@link AxTaskLogic}
89 @Table(name = "AxTask")
91 @XmlAccessorType(XmlAccessType.FIELD)
92 @XmlRootElement(name = "apexTask", namespace = "http://www.onap.org/policy/apex-pdp")
93 @XmlType(name = "AxTask", namespace = "http://www.onap.org/policy/apex-pdp",
94 propOrder = {"key", "inputFields", "outputFields", "taskParameters", "contextAlbumReferenceSet", "taskLogic"})
96 public class AxTask extends AxConcept {
97 private static final String DOES_NOT_EQUAL_TASK_KEY = " does not equal task key";
99 private static final long serialVersionUID = 5374237330697362762L;
102 @XmlElement(name = "key", required = true)
103 private AxArtifactKey key;
105 @OneToMany(cascade = CascadeType.ALL)
106 @XmlElement(name = "inputFields", required = true)
107 private Map<String, AxInputField> inputFields;
109 @OneToMany(cascade = CascadeType.ALL)
110 @XmlElement(name = "outputFields", required = true)
111 private Map<String, AxOutputField> outputFields;
113 @OneToMany(cascade = CascadeType.ALL)
114 @XmlElement(name = "taskParameters", required = true)
115 private Map<String, AxTaskParameter> taskParameters;
119 @CollectionTable(joinColumns = {@JoinColumn(name = "contextAlbumName", referencedColumnName = "name"),
120 @JoinColumn(name = "contextAlbumVersion", referencedColumnName = "version")})
121 @XmlElement(name = "contextAlbumReference")
122 private Set<AxArtifactKey> contextAlbumReferenceSet;
125 @OneToOne(cascade = CascadeType.ALL)
126 @XmlElement(required = true)
127 private AxTaskLogic taskLogic;
130 * The Default Constructor creates a task with a null key no input or output fields, no task
131 * parameters, no context album references and no logic.
134 this(new AxArtifactKey());
135 contextAlbumReferenceSet = new TreeSet<>();
141 * @param copyConcept the concept to copy from
143 public AxTask(final AxTask copyConcept) {
148 * The Keyed Constructor creates a task with the given key no input or output fields, no task
149 * parameters, no context album references and no logic.
151 * @param key the key of the task
153 public AxTask(final AxArtifactKey key) {
154 this(key, // Task Key
155 new TreeMap<String, AxInputField>(), // Input fields
156 new TreeMap<String, AxOutputField>(), // Output Fields
157 new TreeMap<String, AxTaskParameter>(), // Task Parameters
158 new TreeSet<AxArtifactKey>(), // Context Album References
159 new AxTaskLogic(new AxReferenceKey(key)) // Task Logic
164 * This Constructor defines all the fields of the task.
166 * @param key the key of the task
167 * @param inputFields the input fields that the task expects
168 * @param outputFields the output fields that the task emits
169 * @param taskParameters the task parameters that are used to initialize tasks of this type
170 * @param contextAlbumReferenceSet the context album reference set defines the context that may
171 * be used by Task Logic in the state
172 * @param taskLogic the task logic that performs the domain specific work of the task
174 public AxTask(final AxArtifactKey key, final Map<String, AxInputField> inputFields,
175 final Map<String, AxOutputField> outputFields, final Map<String, AxTaskParameter> taskParameters,
176 final Set<AxArtifactKey> contextAlbumReferenceSet, final AxTaskLogic taskLogic) {
178 Assertions.argumentNotNull(key, "key may not be null");
179 Assertions.argumentNotNull(inputFields, "inputFields may not be null");
180 Assertions.argumentNotNull(outputFields, "outputFields may not be null");
181 Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
182 Assertions.argumentNotNull(contextAlbumReferenceSet, "contextAlbumReferenceSet may not be null");
183 Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
186 this.inputFields = inputFields;
187 this.outputFields = outputFields;
188 this.taskParameters = taskParameters;
189 this.contextAlbumReferenceSet = contextAlbumReferenceSet;
190 this.taskLogic = taskLogic;
194 * When a task is unmarshalled from disk or from the database, the parent of contained objects
195 * is not defined. This method is called by JAXB after unmarshaling and is used to set the
196 * parent keys of all {@link AxInputField}, {@link AxOutputField}, and {@link AxTaskParameter}
197 * instance in the task.
199 * @param unmarshaler the unmarshaler that is unmarshaling the model
200 * @param parent the parent object of this object in the unmarshaler
202 public void afterUnmarshal(final Unmarshaller unmarshaler, final Object parent) {
203 taskLogic.getKey().setParentArtifactKey(key);
205 for (final AxInputField inputField : inputFields.values()) {
206 inputField.getKey().setParentArtifactKey(key);
207 inputField.getKey().setParentLocalName("InField");
209 for (final AxOutputField outputField : outputFields.values()) {
210 outputField.getKey().setParentArtifactKey(key);
211 outputField.getKey().setParentLocalName("OutField");
213 for (final AxTaskParameter parameter : taskParameters.values()) {
214 parameter.getKey().setParentArtifactKey(key);
222 public AxArtifactKey getKey() {
230 public List<AxKey> getKeys() {
231 final List<AxKey> keyList = key.getKeys();
232 for (final AxInputField inputField : inputFields.values()) {
233 keyList.addAll(inputField.getKeys());
235 for (final AxOutputField outputField : outputFields.values()) {
236 keyList.addAll(outputField.getKeys());
238 for (final AxTaskParameter taskParameter : taskParameters.values()) {
239 keyList.addAll(taskParameter.getKeys());
241 for (final AxArtifactKey contextAlbumKey : contextAlbumReferenceSet) {
242 keyList.add(new AxKeyUse(contextAlbumKey));
244 keyList.addAll(taskLogic.getKeys());
249 * Sets the key of the task.
251 * @param key the key of the task
253 public void setKey(final AxArtifactKey key) {
254 Assertions.argumentNotNull(key, "key may not be null");
259 * Gets the input fields that the task expects.
261 * @return the input fields that the task expects
263 public Map<String, AxInputField> getInputFields() {
268 * Gets the raw input fields that the task expects as a tree map.
270 * @return the raw input fields that the task expects
272 public Map<String, AxField> getRawInputFields() {
273 return new TreeMap<>(inputFields);
277 * Convenience method to get the input fields as a set.
279 * @return the input fields as a set
281 public Set<AxField> getInputFieldSet() {
282 final Set<AxField> inputFieldSet = new TreeSet<>();
283 for (final AxInputField field : inputFields.values()) {
284 inputFieldSet.add(field);
286 return inputFieldSet;
290 * Sets the input fields that the task expects.
292 * @param inputFields the input fields that the task expects
294 public void setInputFields(final Map<String, AxInputField> inputFields) {
295 Assertions.argumentNotNull(inputFields, "inputFields may not be null");
296 this.inputFields = inputFields;
300 * Copy the input fields from the given map into the task. This method is used to get a copy of
301 * the input fields, which can be useful for unit testing of policies and tasks.
303 * @param fields the fields to copy into the task
305 public void duplicateInputFields(final Map<String, AxField> fields) {
306 Assertions.argumentNotNull(fields, "fields may not be null");
308 for (final AxField field : fields.values()) {
309 final AxReferenceKey fieldKey = new AxReferenceKey(this.getKey().getName(), this.getKey().getVersion(),
310 "inputFields", field.getKey().getLocalName());
311 final AxInputField inputField = new AxInputField(fieldKey, field.getSchema());
312 inputFields.put(inputField.getKey().getLocalName(), inputField);
317 * Gets the output fields that the task emits.
319 * @return the output fields that the task emits
321 public Map<String, AxOutputField> getOutputFields() {
326 * Gets the raw output fields that the task emits as a tree map.
328 * @return the raw output fields as a tree map
330 public Map<String, AxField> getRawOutputFields() {
331 return new TreeMap<>(outputFields);
335 * Gets the output fields that the task emits as a set.
337 * @return the output fields as a set
339 public Set<AxField> getOutputFieldSet() {
340 final Set<AxField> outputFieldSet = new TreeSet<>();
341 for (final AxOutputField field : outputFields.values()) {
342 outputFieldSet.add(field);
344 return outputFieldSet;
348 * Sets the output fields that the task emits.
350 * @param outputFields the output fields that the task emits
352 public void setOutputFields(final Map<String, AxOutputField> outputFields) {
353 Assertions.argumentNotNull(outputFields, "outputFields may not be null");
354 this.outputFields = outputFields;
358 * Copy the output fields from the given map into the task. This method is used to get a copy of
359 * the output fields, which can be useful for unit testing of policies and tasks.
361 * @param fields the fields to copy into the task
363 public void duplicateOutputFields(final Map<String, AxField> fields) {
364 Assertions.argumentNotNull(fields, "fields may not be null");
366 for (final AxField field : fields.values()) {
367 final AxReferenceKey fieldKey = new AxReferenceKey(this.getKey().getName(), this.getKey().getVersion(),
368 "outputFields", field.getKey().getLocalName());
369 final AxOutputField outputField = new AxOutputField(fieldKey, field.getSchema());
370 outputFields.put(outputField.getKey().getLocalName(), outputField);
375 * Gets the task parameters that are used to initialize tasks of this type.
377 * @return the task parameters that are used to initialize tasks of this type
379 public Map<String, AxTaskParameter> getTaskParameters() {
380 return taskParameters;
384 * Sets the task parameters that are used to initialize tasks of this type.
386 * @param taskParameters the task parameters that are used to initialize tasks of this type
388 public void setTaskParameters(final Map<String, AxTaskParameter> taskParameters) {
389 Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
390 this.taskParameters = taskParameters;
394 * Gets the context album reference set defines the context that may be used by Task Logic in
397 * @return the context album reference set defines the context that may be used by Task Logic in
400 public Set<AxArtifactKey> getContextAlbumReferences() {
401 return contextAlbumReferenceSet;
405 * Sets the context album reference set defines the context that may be used by Task Logic in
408 * @param contextAlbumReferences the context album reference set defines the context that may be
409 * used by Task Logic in the state
411 public void setContextAlbumReferences(final Set<AxArtifactKey> contextAlbumReferences) {
412 Assertions.argumentNotNull(contextAlbumReferences, "contextAlbumReferences may not be null");
413 this.contextAlbumReferenceSet = contextAlbumReferences;
417 * Gets the task logic that performs the domain specific work of the task.
419 * @return the task logic that performs the domain specific work of the task
421 public AxTaskLogic getTaskLogic() {
426 * Sets the task logic that performs the domain specific work of the task.
428 * @param taskLogic the task logic that performs the domain specific work of the task
430 public void setTaskLogic(final AxTaskLogic taskLogic) {
431 Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
432 this.taskLogic = taskLogic;
439 public AxValidationResult validate(final AxValidationResult resultIn) {
440 AxValidationResult result = resultIn;
442 if (key.equals(AxArtifactKey.getNullKey())) {
443 result.addValidationMessage(
444 new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
447 result = key.validate(result);
449 if (inputFields.size() == 0) {
450 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
451 "inputFields may not be empty"));
453 for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
454 result = validateField(inputFieldEntry.getKey(), inputFieldEntry.getValue(), "input", result);
458 if (outputFields.size() == 0) {
459 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
460 "outputFields may not be empty"));
462 for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
463 result = validateField(outputFieldEntry.getKey(), outputFieldEntry.getValue(), "input", result);
467 for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
468 result = vaildateTaskParameterEntry(taskParameterEntry, result);
471 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
472 result = vaildateContextAlbumReference(contextAlbumReference, result);
475 if (!taskLogic.getKey().getParentArtifactKey().equals(key)) {
476 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
477 "taskLogic parent key " + taskLogic.getKey().getId() + DOES_NOT_EQUAL_TASK_KEY));
480 return taskLogic.validate(result);
486 * @param key the key of the field to validate
487 * @param field the field to validate
488 * @param direction The direction of the field
489 * @param result The validation result to append to
490 * @return The result of the validation
492 private AxValidationResult validateField(final String fieldKey, final AxField field, final String direction,
493 AxValidationResult result) {
495 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
496 "null " + direction + " field value found on " + direction + " field " + fieldKey));
498 if (!field.getKey().getParentArtifactKey().equals(key)) {
499 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
500 "parent key on " + direction + " field " + fieldKey + DOES_NOT_EQUAL_TASK_KEY));
503 result = field.validate(result);
510 * Validate a task parameter entry.
512 * @param taskParameterEntry the task parameter entry to validate
513 * @param result The validation result to append to
514 * @return The result of the validation
516 private AxValidationResult vaildateTaskParameterEntry(final Entry<String, AxTaskParameter> taskParameterEntry,
517 AxValidationResult result) {
518 if (taskParameterEntry.getValue() == null) {
519 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
520 "null input task parameter value found on task parameter " + taskParameterEntry.getKey()));
522 if (!taskParameterEntry.getValue().getKey().getParentArtifactKey().equals(key)) {
523 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
524 "parent key on task parameter " + taskParameterEntry.getKey() + DOES_NOT_EQUAL_TASK_KEY));
527 result = taskParameterEntry.getValue().validate(result);
534 * Validate a context album reference entry.
536 * @param taskParameterEntry the context album reference entry to validate
537 * @param result The validation result to append to
538 * @return The result of the validation
540 private AxValidationResult vaildateContextAlbumReference(final AxArtifactKey contextAlbumReference,
541 AxValidationResult result) {
542 if (contextAlbumReference.equals(AxArtifactKey.getNullKey())) {
543 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
544 "key on context item reference entry " + contextAlbumReference.getKey()
545 + " may not be the null key"));
548 return contextAlbumReference.validate(result);
555 public void clean() {
557 for (final AxInputField inputField : inputFields.values()) {
560 for (final AxOutputField outputField : outputFields.values()) {
563 for (final AxTaskParameter parameter : taskParameters.values()) {
566 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
567 contextAlbumReference.clean();
576 public String toString() {
577 final StringBuilder builder = new StringBuilder();
578 builder.append(this.getClass().getSimpleName());
579 builder.append(":(");
580 builder.append("key=");
582 builder.append(",inputFields=");
583 builder.append(inputFields);
584 builder.append(",outputFields=");
585 builder.append(outputFields);
586 builder.append(",taskParameters=");
587 builder.append(taskParameters);
588 builder.append(",contextAlbumReferenceSet=");
589 builder.append(contextAlbumReferenceSet);
590 builder.append(",taskLogic=");
591 builder.append(taskLogic);
593 return builder.toString();
600 public AxConcept copyTo(final AxConcept targetObject) {
601 Assertions.argumentNotNull(targetObject, "target may not be null");
603 final Object copyObject = targetObject;
604 Assertions.instanceOf(copyObject, AxTask.class);
606 final AxTask copy = ((AxTask) copyObject);
609 final Map<String, AxInputField> newInputFields = new TreeMap<>();
610 for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
611 newInputFields.put(inputFieldEntry.getKey(), new AxInputField(inputFieldEntry.getValue()));
613 copy.setInputFields(newInputFields);
615 final Map<String, AxOutputField> newOutputFields = new TreeMap<>();
616 for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
617 newOutputFields.put(outputFieldEntry.getKey(), new AxOutputField(outputFieldEntry.getValue()));
619 copy.setOutputFields(newOutputFields);
621 final Map<String, AxTaskParameter> newTaskParameter = new TreeMap<>();
622 for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
623 newTaskParameter.put(taskParameterEntry.getKey(), new AxTaskParameter(taskParameterEntry.getValue()));
625 copy.setTaskParameters(newTaskParameter);
627 final Set<AxArtifactKey> newContextUsage = new TreeSet<>();
628 for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
629 newContextUsage.add(new AxArtifactKey(contextAlbumReference));
631 copy.setContextAlbumReferences(newContextUsage);
633 copy.setTaskLogic(new AxTaskLogic(taskLogic));
642 public int hashCode() {
643 final int prime = 31;
645 result = prime * result + key.hashCode();
646 result = prime * result + inputFields.hashCode();
647 result = prime * result + outputFields.hashCode();
648 result = prime * result + taskParameters.hashCode();
649 result = prime * result + contextAlbumReferenceSet.hashCode();
650 result = prime * result + taskLogic.hashCode();
658 public boolean equals(final Object obj) {
666 if (getClass() != obj.getClass()) {
670 final AxTask other = (AxTask) obj;
671 if (!key.equals(other.key)) {
674 if (!inputFields.equals(other.inputFields)) {
677 if (!outputFields.equals(other.outputFields)) {
680 if (!taskParameters.equals(other.taskParameters)) {
683 if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
686 return taskLogic.equals(other.taskLogic);
693 public int compareTo(final AxConcept otherObj) {
694 if (otherObj == null) {
697 if (this == otherObj) {
700 if (getClass() != otherObj.getClass()) {
701 return this.hashCode() - otherObj.hashCode();
704 final AxTask other = (AxTask) otherObj;
705 if (!key.equals(other.key)) {
706 return key.compareTo(other.key);
708 if (!inputFields.equals(other.inputFields)) {
709 return (inputFields.hashCode() - other.inputFields.hashCode());
711 if (!outputFields.equals(other.outputFields)) {
712 return (outputFields.hashCode() - other.outputFields.hashCode());
714 if (!taskParameters.equals(other.taskParameters)) {
715 return (taskParameters.hashCode() - other.taskParameters.hashCode());
717 if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
718 return (contextAlbumReferenceSet.hashCode() - other.contextAlbumReferenceSet.hashCode());
720 return taskLogic.compareTo(other.taskLogic);