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