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