Changes for checkstyle 8.32
[policy/apex-pdp.git] / model / event-model / src / main / java / org / onap / policy / apex / model / eventmodel / concepts / AxEvent.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.eventmodel.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.SortedMap;
29 import java.util.TreeMap;
30 import java.util.TreeSet;
31 import javax.persistence.CascadeType;
32 import javax.persistence.Column;
33 import javax.persistence.EmbeddedId;
34 import javax.persistence.Entity;
35 import javax.persistence.OneToMany;
36 import javax.persistence.Table;
37 import javax.xml.bind.Unmarshaller;
38 import javax.xml.bind.annotation.XmlAccessType;
39 import javax.xml.bind.annotation.XmlAccessorType;
40 import javax.xml.bind.annotation.XmlElement;
41 import javax.xml.bind.annotation.XmlRootElement;
42 import javax.xml.bind.annotation.XmlType;
43 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
44 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
45 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
46 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
47 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
48 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
49 import org.onap.policy.common.utils.validation.Assertions;
50
51 /**
52  * This class defines an Apex event. An {@link AxEvent} is used to kick off execution of policies in Apex and is emitted
53  * by policies when they completer execution. In addition, Apex uses {@link AxEvent} instances internally to pass
54  * control from one Apex state to the next during execution.
55  *
56  * <p>The {@link AxArtifactKey} of an event uniquely identifies it in an Apex system and the name field in the key is
57  * the name of the event.
58  *
59  * <p>Each {@link AxEvent} has a name space, which is usually set to identify the domain of application of an event. For
60  * example a 4G cell power event might have the name space {@code org.onap.radio.4g} and the name {@code PowerEvent}.
61  * The source and target of the event are reserved to hold an identifier that defines the sender and receiver of an
62  * event respectively. The definition and structure of these fields is reserved for future use and their use by
63  * applications is currently not recommended.
64  *
65  * <p>The parameters that an event has are defined as a map of {@link AxField} instances.
66  *
67  * <p>Validation checks that the event key is valid. If name space is a blank string, a warning is issued. Blank source
68  * or target fields result in observations being issued. An event may not have any parameters. If it has parameters, the
69  * name and value of each parameter entry is checked to ensure they are not null. Then the local name of each parameter
70  * is checked to ensure it matches the event parameter key on the event. Finally, the parent key of each parameter is
71  * checked to ensure it matches the event key.
72  */
73 @Entity
74 @Table(name = "AxEvent")
75
76 @XmlAccessorType(XmlAccessType.FIELD)
77 @XmlRootElement(name = "apexEvent", namespace = "http://www.onap.org/policy/apex-pdp")
78 @XmlType(name = "AxEvent", namespace = "http://www.onap.org/policy/apex-pdp", propOrder =
79     { "key", "nameSpace", "source", "target", "parameterMap" })
80
81 public class AxEvent extends AxConcept {
82     private static final long serialVersionUID = -1460388382582984269L;
83
84     private static final String WHITESPACE_REGEXP = "\\s+$";
85
86     /** The key of the event, unique in the Apex system. */
87     @EmbeddedId
88     @XmlElement(name = "key", required = true)
89     // CHECKSTYLE:OFF: checkstyle:VisibilityMonitor
90     protected AxArtifactKey key;
91     // CHECKSTYLE:ON: checkstyle:VisibilityMonitor
92
93     @Column(name = "nameSpace")
94     @XmlElement(required = true)
95     private String nameSpace;
96
97     @Column(name = "source")
98     @XmlElement(required = true)
99     private String source;
100
101     @Column(name = "target")
102     @XmlElement(required = true)
103     private String target;
104
105     @OneToMany(cascade = CascadeType.ALL)
106     @XmlElement(name = "parameter", required = true)
107     private Map<String, AxField> parameterMap;
108
109     /**
110      * The default constructor creates an event with a null artifact key. The event name space, source, and target are
111      * all defined as empty strings and the parameter map is initialized as an empty map.
112      */
113     public AxEvent() {
114         this(new AxArtifactKey());
115     }
116
117     /**
118      * Copy constructor.
119      *
120      * @param copyConcept the concept to copy from
121      */
122     public AxEvent(final AxEvent copyConcept) {
123         super(copyConcept);
124     }
125
126     /**
127      * The default constructor creates an event with the given artifact key. The event name space, source, and target
128      * are all defined as empty strings and the parameter map is initialized as an empty map.
129      *
130      * @param key the key of the event
131      */
132     public AxEvent(final AxArtifactKey key) {
133         this(key, "", "", "", new TreeMap<String, AxField>());
134     }
135
136     /**
137      * This constructor creates an event with the given artifact key and name space. The event source, and target are
138      * all defined as empty strings and the parameter map is initialized as an empty map.
139      *
140      * @param key the key of the event
141      * @param nameSpace the name space of the event
142      */
143     public AxEvent(final AxArtifactKey key, final String nameSpace) {
144         this(key, nameSpace, "", "", new TreeMap<String, AxField>());
145     }
146
147     /**
148      * This constructor creates an event with the given artifact key, name space, source and target. The parameter map
149      * is initialized as an empty map.
150      *
151      * @param key the key of the event
152      * @param nameSpace the name space of the event
153      * @param source the source of the event
154      * @param target the target of the event
155      */
156     public AxEvent(final AxArtifactKey key, final String nameSpace, final String source, final String target) {
157         this(key, nameSpace, source, target, new TreeMap<String, AxField>());
158     }
159
160     /**
161      * This constructor creates an event with all its fields defined.
162      *
163      * @param key the key of the event
164      * @param nameSpace the name space of the event
165      * @param source the source of the event
166      * @param target the target of the event
167      * @param parameterMap the map of parameters that the event has
168      */
169     public AxEvent(final AxArtifactKey key, final String nameSpace, final String source, final String target,
170                     final SortedMap<String, AxField> parameterMap) {
171         super();
172         Assertions.argumentNotNull(key, "key may not be null");
173         Assertions.argumentNotNull(nameSpace, "nameSpace may not be null");
174         Assertions.argumentNotNull(source, "source may not be null");
175         Assertions.argumentNotNull(target, "target may not be null");
176         Assertions.argumentNotNull(parameterMap, "parameterMap may not be null");
177
178         this.key = key;
179         this.nameSpace = nameSpace;
180         this.source = source;
181         this.target = target;
182         this.parameterMap = parameterMap;
183     }
184
185     /**
186      * This method checks that an event has all the fields in the {@code otherFieldSet} set defined on it.
187      *
188      * @param otherFieldSet the set of fields to check for existence on this event
189      * @return true, if all the {@code otherFieldSet} fields are defined on this event
190      */
191     public boolean hasFields(final Set<AxField> otherFieldSet) {
192         return parameterMap.values().containsAll(otherFieldSet);
193     }
194
195     /**
196      * When an event is unmarshalled from disk or from the database, the parent key in the reference keys in its
197      * parameter map are not set. This method is called by JAXB after unmarshaling and is used to set the parent key of
198      * the {@link AxField} instances in the parameter map to be the key of the event that contains them.
199      *
200      * @param unmarshaler the unmarshaler that is unmarshaling the model
201      * @param parent the parent object of this object in the unmarshaler
202      */
203     public void afterUnmarshal(final Unmarshaller unmarshaler, final Object parent) {
204         for (final AxField parameter : parameterMap.values()) {
205             parameter.getKey().setParentArtifactKey(key);
206         }
207     }
208
209     /**
210      * {@inheritDoc}.
211      */
212     @Override
213     public AxArtifactKey getKey() {
214         return key;
215     }
216
217     /**
218      * {@inheritDoc}.
219      */
220     @Override
221     public List<AxKey> getKeys() {
222         final List<AxKey> keyList = key.getKeys();
223
224         for (final AxField field : parameterMap.values()) {
225             keyList.addAll(field.getKeys());
226         }
227         return keyList;
228     }
229
230     /**
231      * Sets the key of the event.
232      *
233      * @param key the key of the event
234      */
235     public void setKey(final AxArtifactKey key) {
236         Assertions.argumentNotNull(key, "key may not be null");
237         this.key = key;
238
239         for (final AxField parameter : parameterMap.values()) {
240             parameter.getKey().setParentArtifactKey(key);
241         }
242     }
243
244     /**
245      * Gets the name space of the event.
246      *
247      * @return the name space of the event
248      */
249     public String getNameSpace() {
250         return nameSpace;
251     }
252
253     /**
254      * Sets the name space of the event.
255      *
256      * @param nameSpace the name space of the event
257      */
258     public void setNameSpace(final String nameSpace) {
259         Assertions.argumentNotNull(nameSpace, "nameSpace may not be null");
260         this.nameSpace = nameSpace.trim();
261     }
262
263     /**
264      * Gets the source of the event.
265      *
266      * @return the source of the event
267      */
268     public String getSource() {
269         return source;
270     }
271
272     /**
273      * Sets the source of the event.
274      *
275      * @param source the source of the event
276      */
277     public void setSource(final String source) {
278         Assertions.argumentNotNull(source, "source may not be null");
279         this.source = source.trim();
280     }
281
282     /**
283      * Gets the target of the event.
284      *
285      * @return the target of the event
286      */
287     public String getTarget() {
288         return target;
289     }
290
291     /**
292      * Sets the target of the event.
293      *
294      * @param target the target of the event
295      */
296     public void setTarget(final String target) {
297         Assertions.argumentNotNull(target, "target may not be null");
298         this.target = target.trim();
299     }
300
301     /**
302      * Gets the event parameter map.
303      *
304      * @return the event parameter map
305      */
306     public Map<String, AxField> getParameterMap() {
307         return parameterMap;
308     }
309
310     /**
311      * Gets the fields defined on the event as a set.
312      *
313      * @return the fields defined on the event as a set
314      */
315     public Set<AxField> getFields() {
316         return new TreeSet<>(parameterMap.values());
317     }
318
319     /**
320      * Sets the event parameter map, containing all the fields of the event.
321      *
322      * @param parameterMap the event parameter map
323      */
324     public void setParameterMap(final Map<String, AxField> parameterMap) {
325         Assertions.argumentNotNull(parameterMap, "parameterMap may not be null");
326         this.parameterMap = parameterMap;
327     }
328
329     /**
330      * {@inheritDoc}.
331      */
332     @Override
333     public AxValidationResult validate(final AxValidationResult resultIn) {
334         AxValidationResult result = resultIn;
335
336         if (key.equals(AxArtifactKey.getNullKey())) {
337             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
338                             "key is a null key"));
339         }
340
341         result = key.validate(result);
342
343         if (nameSpace.replaceAll(WHITESPACE_REGEXP, "").length() == 0) {
344             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.WARNING,
345                             "nameSpace on event is blank"));
346         }
347
348         if (source.replaceAll(WHITESPACE_REGEXP, "").length() == 0) {
349             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION,
350                             "source on event is blank"));
351         }
352
353         if (target.replaceAll(WHITESPACE_REGEXP, "").length() == 0) {
354             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION,
355                             "target on event is blank"));
356         }
357
358         for (final Entry<String, AxField> eventParameterEntry : parameterMap.entrySet()) {
359             if (eventParameterEntry.getKey() == null || eventParameterEntry.getKey().equals(AxKey.NULL_KEY_NAME)) {
360                 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
361                                 "key on parameter " + eventParameterEntry.getKey() + " may not be the null key"));
362             } else if (eventParameterEntry.getValue() == null) {
363                 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
364                                 "value on parameter " + eventParameterEntry.getKey() + " may not be null"));
365             } else {
366                 result = vaidateEventParameters(eventParameterEntry, result);
367             }
368         }
369
370         return result;
371     }
372
373     /**
374      * Validate an event parameter entry.
375      *
376      * @param eventParameterEntry the event parameter entry
377      * @param result the validation result to append to
378      * @return The validation result
379      */
380     private AxValidationResult vaidateEventParameters(final Entry<String, AxField> eventParameterEntry,
381                     final AxValidationResult result) {
382         if (!eventParameterEntry.getKey().equals(eventParameterEntry.getValue().getKey().getLocalName())) {
383             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
384                             "key on parameter " + eventParameterEntry.getKey()
385                                             + " does not equal parameter field local name "
386                                             + eventParameterEntry.getValue().getKey().getLocalName()));
387         }
388
389         if (!eventParameterEntry.getValue().getKey().getParentArtifactKey().equals(key)) {
390             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
391                             "parent key on parameter field " + eventParameterEntry.getValue().getKey()
392                                             + " does not equal event key"));
393         }
394
395         return eventParameterEntry.getValue().validate(result);
396     }
397
398     /**
399      * {@inheritDoc}.
400      */
401     @Override
402     public void clean() {
403         key.clean();
404         nameSpace = nameSpace.trim();
405         source = source.trim();
406         target = target.trim();
407     }
408
409     /**
410      * {@inheritDoc}.
411      */
412     @Override
413     public String toString() {
414         final StringBuilder builder = new StringBuilder();
415         builder.append(this.getClass().getSimpleName());
416         builder.append(":(");
417         builder.append("key=");
418         builder.append(key);
419         builder.append(",nameSpace=");
420         builder.append(nameSpace);
421         builder.append(",source=");
422         builder.append(source);
423         builder.append(",target=");
424         builder.append(target);
425         builder.append(",parameter=");
426         builder.append(parameterMap);
427         builder.append(")");
428         return builder.toString();
429     }
430
431     /**
432      * {@inheritDoc}.
433      */
434     @Override
435     public AxConcept copyTo(final AxConcept targetObject) {
436         Assertions.argumentNotNull(targetObject, "targetObject may not be null");
437
438         final Object copyObject = targetObject;
439         Assertions.instanceOf(copyObject, AxEvent.class);
440
441         final AxEvent copy = (AxEvent) copyObject;
442
443         final Map<String, AxField> newParameterMap = new TreeMap<>();
444         for (final Entry<String, AxField> eventParameterMapEntry : parameterMap.entrySet()) {
445             newParameterMap.put(eventParameterMapEntry.getKey(), new AxField(eventParameterMapEntry.getValue()));
446         }
447         copy.setParameterMap(newParameterMap);
448
449         copy.setKey(new AxArtifactKey(key));
450         copy.setNameSpace(nameSpace);
451         copy.setSource(source);
452         copy.setTarget(target);
453
454         return copy;
455     }
456
457     /**
458      * {@inheritDoc}.
459      */
460     @Override
461     public int hashCode() {
462         final int prime = 31;
463         int result = 1;
464         result = prime * result + key.hashCode();
465         result = prime * result + nameSpace.hashCode();
466         result = prime * result + source.hashCode();
467         result = prime * result + target.hashCode();
468         result = prime * result + parameterMap.hashCode();
469         return result;
470     }
471
472     /**
473      * {@inheritDoc}.
474      */
475     @Override
476     public boolean equals(final Object obj) {
477         if (obj == null) {
478             return false;
479         }
480         if (this == obj) {
481             return true;
482         }
483
484         if (getClass() != obj.getClass()) {
485             return false;
486         }
487
488         final AxEvent other = (AxEvent) obj;
489         if (!key.equals(other.key)) {
490             return false;
491         }
492         if (!nameSpace.equals(other.nameSpace)) {
493             return false;
494         }
495         if (!source.equals(other.source)) {
496             return false;
497         }
498         if (!target.equals(other.target)) {
499             return false;
500         }
501         return parameterMap.equals(other.parameterMap);
502     }
503
504     /**
505      * {@inheritDoc}.
506      */
507     @Override
508     public int compareTo(final AxConcept otherObj) {
509         if (otherObj == null) {
510             return -1;
511         }
512         if (this == otherObj) {
513             return 0;
514         }
515         if (getClass() != otherObj.getClass()) {
516             return this.hashCode() - otherObj.hashCode();
517         }
518
519         final AxEvent other = (AxEvent) otherObj;
520         if (!key.equals(other.key)) {
521             return key.compareTo(other.key);
522         }
523         if (!nameSpace.equals(other.nameSpace)) {
524             return nameSpace.compareTo(other.nameSpace);
525         }
526         if (!source.equals(other.source)) {
527             return source.compareTo(other.source);
528         }
529         if (!target.equals(other.target)) {
530             return target.compareTo(other.target);
531         }
532         if (!parameterMap.equals(other.parameterMap)) {
533             return (parameterMap.hashCode() - other.parameterMap.hashCode());
534         }
535
536         return 0;
537     }
538 }