31545b3f2035e5636cabeacc0a892f88d60f18f8
[policy/apex-pdp.git] / model / policy-model / src / main / java / org / onap / policy / apex / model / policymodel / concepts / AxTask.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.model.policymodel.concepts;
23
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Set;
28 import java.util.TreeMap;
29 import java.util.TreeSet;
30
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;
46
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;
59
60 /**
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.
64  *
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.
68  *
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.
72  *
73  * <p>During validation of a task, the validation checks listed below are executed:
74  * <ol>
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}
87  * </ol>
88  */
89
90 @Entity
91 @Table(name = "AxTask")
92
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"})
97
98 public class AxTask extends AxConcept {
99     private static final String DOES_NOT_EQUAL_TASK_KEY = " does not equal task key";
100
101     private static final long serialVersionUID = 5374237330697362762L;
102
103     @EmbeddedId
104     @XmlElement(name = "key", required = true)
105     private AxArtifactKey key;
106
107     @OneToMany(cascade = CascadeType.ALL)
108     @XmlElement(name = "inputFields", required = true)
109     private Map<String, AxInputField> inputFields;
110
111     @OneToMany(cascade = CascadeType.ALL)
112     @XmlElement(name = "outputFields", required = true)
113     private Map<String, AxOutputField> outputFields;
114
115     @OneToMany(cascade = CascadeType.ALL)
116     @XmlElement(name = "taskParameters", required = true)
117     private Map<String, AxTaskParameter> taskParameters;
118
119     // @formatter:off
120     @ElementCollection
121     @CollectionTable(joinColumns = {@JoinColumn(name = "contextAlbumName", referencedColumnName = "name"),
122             @JoinColumn(name = "contextAlbumVersion", referencedColumnName = "version")})
123     @XmlElement(name = "contextAlbumReference")
124     private Set<AxArtifactKey> contextAlbumReferenceSet;
125     // @formatter:on
126
127     @OneToOne(cascade = CascadeType.ALL)
128     @XmlElement(required = true)
129     private AxTaskLogic taskLogic;
130
131     /**
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.
134      */
135     public AxTask() {
136         this(new AxArtifactKey());
137         contextAlbumReferenceSet = new TreeSet<>();
138     }
139
140     /**
141      * Copy constructor.
142      *
143      * @param copyConcept the concept to copy from
144      */
145     public AxTask(final AxTask copyConcept) {
146         super(copyConcept);
147     }
148
149     /**
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.
152      *
153      * @param key the key of the task
154      */
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
162         );
163     }
164
165     /**
166      * This Constructor defines all the fields of the task.
167      *
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
175      */
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) {
179         super();
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");
186
187         this.key = key;
188         this.inputFields = inputFields;
189         this.outputFields = outputFields;
190         this.taskParameters = taskParameters;
191         this.contextAlbumReferenceSet = contextAlbumReferenceSet;
192         this.taskLogic = taskLogic;
193     }
194
195     /**
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.
200      *
201      * @param unmarshaler the unmarshaler that is unmarshaling the model
202      * @param parent the parent object of this object in the unmarshaler
203      */
204     public void afterUnmarshal(final Unmarshaller unmarshaler, final Object parent) {
205         taskLogic.getKey().setParentArtifactKey(key);
206
207         for (final AxInputField inputField : inputFields.values()) {
208             inputField.getKey().setParentArtifactKey(key);
209             inputField.getKey().setParentLocalName("InField");
210         }
211         for (final AxOutputField outputField : outputFields.values()) {
212             outputField.getKey().setParentArtifactKey(key);
213             outputField.getKey().setParentLocalName("OutField");
214         }
215         for (final AxTaskParameter parameter : taskParameters.values()) {
216             parameter.getKey().setParentArtifactKey(key);
217         }
218     }
219
220     /**
221      * {@inheritDoc}.
222      */
223     @Override
224     public AxArtifactKey getKey() {
225         return key;
226     }
227
228     /**
229      * {@inheritDoc}.
230      */
231     @Override
232     public List<AxKey> getKeys() {
233         final List<AxKey> keyList = key.getKeys();
234         for (final AxInputField inputField : inputFields.values()) {
235             keyList.addAll(inputField.getKeys());
236         }
237         for (final AxOutputField outputField : outputFields.values()) {
238             keyList.addAll(outputField.getKeys());
239         }
240         for (final AxTaskParameter taskParameter : taskParameters.values()) {
241             keyList.addAll(taskParameter.getKeys());
242         }
243         for (final AxArtifactKey contextAlbumKey : contextAlbumReferenceSet) {
244             keyList.add(new AxKeyUse(contextAlbumKey));
245         }
246         keyList.addAll(taskLogic.getKeys());
247         return keyList;
248     }
249
250     /**
251      * Sets the key of the task.
252      *
253      * @param key the key of the task
254      */
255     public void setKey(final AxArtifactKey key) {
256         Assertions.argumentNotNull(key, "key may not be null");
257         this.key = key;
258     }
259
260     /**
261      * Gets the input fields that the task expects.
262      *
263      * @return the input fields that the task expects
264      */
265     public Map<String, AxInputField> getInputFields() {
266         return inputFields;
267     }
268
269     /**
270      * Gets the raw input fields that the task expects as a tree map.
271      *
272      * @return the raw input fields that the task expects
273      */
274     public Map<String, AxField> getRawInputFields() {
275         return new TreeMap<>(inputFields);
276     }
277
278     /**
279      * Convenience method to get the input fields as a set.
280      *
281      * @return the input fields as a set
282      */
283     public Set<AxField> getInputFieldSet() {
284         final Set<AxField> inputFieldSet = new TreeSet<>();
285         for (final AxInputField field : inputFields.values()) {
286             inputFieldSet.add(field);
287         }
288         return inputFieldSet;
289     }
290
291     /**
292      * Sets the input fields that the task expects.
293      *
294      * @param inputFields the input fields that the task expects
295      */
296     public void setInputFields(final Map<String, AxInputField> inputFields) {
297         Assertions.argumentNotNull(inputFields, "inputFields may not be null");
298         this.inputFields = inputFields;
299     }
300
301     /**
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.
304      *
305      * @param fields the fields to copy into the task
306      */
307     public void duplicateInputFields(final Map<String, AxField> fields) {
308         Assertions.argumentNotNull(fields, "fields may not be null");
309
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);
315         }
316     }
317
318     /**
319      * Gets the output fields that the task emits.
320      *
321      * @return the output fields that the task emits
322      */
323     public Map<String, AxOutputField> getOutputFields() {
324         return outputFields;
325     }
326
327     /**
328      * Gets the raw output fields that the task emits as a tree map.
329      *
330      * @return the raw output fields as a tree map
331      */
332     public Map<String, AxField> getRawOutputFields() {
333         return new TreeMap<>(outputFields);
334     }
335
336     /**
337      * Gets the output fields that the task emits as a set.
338      *
339      * @return the output fields as a set
340      */
341     public Set<AxField> getOutputFieldSet() {
342         final Set<AxField> outputFieldSet = new TreeSet<>();
343         for (final AxOutputField field : outputFields.values()) {
344             outputFieldSet.add(field);
345         }
346         return outputFieldSet;
347     }
348
349     /**
350      * Sets the output fields that the task emits.
351      *
352      * @param outputFields the output fields that the task emits
353      */
354     public void setOutputFields(final Map<String, AxOutputField> outputFields) {
355         Assertions.argumentNotNull(outputFields, "outputFields may not be null");
356         this.outputFields = outputFields;
357     }
358
359     /**
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.
362      *
363      * @param fields the fields to copy into the task
364      */
365     public void duplicateOutputFields(final Map<String, AxField> fields) {
366         Assertions.argumentNotNull(fields, "fields may not be null");
367
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);
373         }
374     }
375
376     /**
377      * Gets the task parameters that are used to initialize tasks of this type.
378      *
379      * @return the task parameters that are used to initialize tasks of this type
380      */
381     public Map<String, AxTaskParameter> getTaskParameters() {
382         return taskParameters;
383     }
384
385     /**
386      * Sets the task parameters that are used to initialize tasks of this type.
387      *
388      * @param taskParameters the task parameters that are used to initialize tasks of this type
389      */
390     public void setTaskParameters(final Map<String, AxTaskParameter> taskParameters) {
391         Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
392         this.taskParameters = taskParameters;
393     }
394
395     /**
396      * Gets the context album reference set defines the context that may be used by Task Logic in
397      * the state.
398      *
399      * @return the context album reference set defines the context that may be used by Task Logic in
400      *         the state
401      */
402     public Set<AxArtifactKey> getContextAlbumReferences() {
403         return contextAlbumReferenceSet;
404     }
405
406     /**
407      * Sets the context album reference set defines the context that may be used by Task Logic in
408      * the state.
409      *
410      * @param contextAlbumReferences the context album reference set defines the context that may be
411      *        used by Task Logic in the state
412      */
413     public void setContextAlbumReferences(final Set<AxArtifactKey> contextAlbumReferences) {
414         Assertions.argumentNotNull(contextAlbumReferences, "contextAlbumReferences may not be null");
415         this.contextAlbumReferenceSet = contextAlbumReferences;
416     }
417
418     /**
419      * Gets the task logic that performs the domain specific work of the task.
420      *
421      * @return the task logic that performs the domain specific work of the task
422      */
423     public AxTaskLogic getTaskLogic() {
424         return taskLogic;
425     }
426
427     /**
428      * Sets the task logic that performs the domain specific work of the task.
429      *
430      * @param taskLogic the task logic that performs the domain specific work of the task
431      */
432     public void setTaskLogic(final AxTaskLogic taskLogic) {
433         Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
434         this.taskLogic = taskLogic;
435     }
436
437     /**
438      * {@inheritDoc}.
439      */
440     @Override
441     public AxValidationResult validate(final AxValidationResult resultIn) {
442         AxValidationResult result = resultIn;
443
444         if (key.equals(AxArtifactKey.getNullKey())) {
445             result.addValidationMessage(
446                     new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
447         }
448
449         result = key.validate(result);
450
451         if (inputFields.size() == 0) {
452             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
453                     "inputFields may not be empty"));
454         } else {
455             for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
456                 result = validateField(inputFieldEntry.getKey(), inputFieldEntry.getValue(), "input", result);
457             }
458         }
459
460         if (outputFields.size() == 0) {
461             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
462                     "outputFields may not be empty"));
463         } else {
464             for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
465                 result = validateField(outputFieldEntry.getKey(), outputFieldEntry.getValue(), "input", result);
466             }
467         }
468
469         for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
470             result = vaildateTaskParameterEntry(taskParameterEntry, result);
471         }
472
473         for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
474             result = vaildateContextAlbumReference(contextAlbumReference, result);
475         }
476
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));
480         }
481
482         return taskLogic.validate(result);
483     }
484
485     /**
486      * Validate a field.
487      *
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
493      */
494     private AxValidationResult validateField(final String fieldKey, final AxField field, final String direction,
495             AxValidationResult result) {
496         if (field == null) {
497             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
498                     "null " + direction + " field value found on " + direction + " field " + fieldKey));
499         } else {
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));
503             }
504
505             result = field.validate(result);
506         }
507
508         return result;
509     }
510
511     /**
512      * Validate a task parameter entry.
513      *
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
517      */
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()));
523         } else {
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));
527             }
528
529             result = taskParameterEntry.getValue().validate(result);
530         }
531
532         return result;
533     }
534
535     /**
536      * Validate a context album reference entry.
537      *
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
541      */
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"));
548         }
549
550         return contextAlbumReference.validate(result);
551     }
552
553     /**
554      * {@inheritDoc}.
555      */
556     @Override
557     public void clean() {
558         key.clean();
559         for (final AxInputField inputField : inputFields.values()) {
560             inputField.clean();
561         }
562         for (final AxOutputField outputField : outputFields.values()) {
563             outputField.clean();
564         }
565         for (final AxTaskParameter parameter : taskParameters.values()) {
566             parameter.clean();
567         }
568         for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
569             contextAlbumReference.clean();
570         }
571         taskLogic.clean();
572     }
573
574     /**
575      * {@inheritDoc}.
576      */
577     @Override
578     public String toString() {
579         final StringBuilder builder = new StringBuilder();
580         builder.append(this.getClass().getSimpleName());
581         builder.append(":(");
582         builder.append("key=");
583         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);
594         builder.append(")");
595         return builder.toString();
596     }
597
598     /**
599      * {@inheritDoc}.
600      */
601     @Override
602     public AxConcept copyTo(final AxConcept targetObject) {
603         Assertions.argumentNotNull(targetObject, "target may not be null");
604
605         final Object copyObject = targetObject;
606         Assertions.instanceOf(copyObject, AxTask.class);
607
608         final AxTask copy = ((AxTask) copyObject);
609         copy.setKey(key);
610
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()));
614         }
615         copy.setInputFields(newInputFields);
616
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()));
620         }
621         copy.setOutputFields(newOutputFields);
622
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()));
626         }
627         copy.setTaskParameters(newTaskParameter);
628
629         final Set<AxArtifactKey> newContextUsage = new TreeSet<>();
630         for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
631             newContextUsage.add(new AxArtifactKey(contextAlbumReference));
632         }
633         copy.setContextAlbumReferences(newContextUsage);
634
635         copy.setTaskLogic(new AxTaskLogic(taskLogic));
636
637         return copy;
638     }
639
640     /**
641      * {@inheritDoc}.
642      */
643     @Override
644     public int hashCode() {
645         final int prime = 31;
646         int result = 1;
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();
653         return result;
654     }
655
656     /**
657      * {@inheritDoc}.
658      */
659     @Override
660     public boolean equals(final Object obj) {
661         if (obj == null) {
662             return false;
663         }
664         if (this == obj) {
665             return true;
666         }
667
668         if (getClass() != obj.getClass()) {
669             return false;
670         }
671
672         final AxTask other = (AxTask) obj;
673         if (!key.equals(other.key)) {
674             return false;
675         }
676         if (!inputFields.equals(other.inputFields)) {
677             return false;
678         }
679         if (!outputFields.equals(other.outputFields)) {
680             return false;
681         }
682         if (!taskParameters.equals(other.taskParameters)) {
683             return false;
684         }
685         if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
686             return false;
687         }
688         return taskLogic.equals(other.taskLogic);
689     }
690
691     /**
692      * {@inheritDoc}.
693      */
694     @Override
695     public int compareTo(final AxConcept otherObj) {
696         if (otherObj == null) {
697             return -1;
698         }
699         if (this == otherObj) {
700             return 0;
701         }
702         if (getClass() != otherObj.getClass()) {
703             return this.hashCode() - otherObj.hashCode();
704         }
705
706         final AxTask other = (AxTask) otherObj;
707         if (!key.equals(other.key)) {
708             return key.compareTo(other.key);
709         }
710         if (!inputFields.equals(other.inputFields)) {
711             return (inputFields.hashCode() - other.inputFields.hashCode());
712         }
713         if (!outputFields.equals(other.outputFields)) {
714             return (outputFields.hashCode() - other.outputFields.hashCode());
715         }
716         if (!taskParameters.equals(other.taskParameters)) {
717             return (taskParameters.hashCode() - other.taskParameters.hashCode());
718         }
719         if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
720             return (contextAlbumReferenceSet.hashCode() - other.contextAlbumReferenceSet.hashCode());
721         }
722         return taskLogic.compareTo(other.taskLogic);
723     }
724 }