Changes for checkstyle 8.32
[policy/apex-pdp.git] / services / services-engine / src / main / java / org / onap / policy / apex / service / engine / event / ApexEvent.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.service.engine.event;
22
23 import java.io.Serializable;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.Properties;
27 import java.util.concurrent.atomic.AtomicLong;
28 import lombok.EqualsAndHashCode;
29 import lombok.Getter;
30 import lombok.ToString;
31 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * The Class ApexEvent is an event class that external systems use to send events to and receive
37  * events from Apex engines. The event itself is a hash map of string keys and object values, used
38  * to pass data.
39  *
40  * @author Liam Fallon (liam.fallon@ericsson.com)
41  */
42 @Getter
43 @ToString
44 @EqualsAndHashCode(callSuper = false)
45 public class ApexEvent extends HashMap<String, Object> implements Serializable {
46     private static final long serialVersionUID = -4451918242101961685L;
47
48     // Get a reference to the logger
49     private static final Logger LOGGER = LoggerFactory.getLogger(ApexEvent.class);
50
51     // Recurring string constants
52     private static final String EVENT_PREAMBLE = "event \"";
53
54     // Holds the next identifier for event execution.
55     private static AtomicLong nextExecutionID = new AtomicLong(0L);
56
57     /**
58      * The name of the Apex event, a mandatory field. All Apex events must have a name so that the
59      * event can be looked up in the Apex policy model.
60      */
61     public static final String NAME_HEADER_FIELD = "name";
62
63     /**
64      * The version of the Apex event, an optional field. If a version is specified on an Apex event,
65      * the definition of that version of the event is taken from the Apex policy model. If no
66      * version is specified, the latest version of the event is used.
67      */
68     public static final String VERSION_HEADER_FIELD = "version";
69
70     /**
71      * The name space of the Apex event, an optional field. If a name space is specified on an Apex
72      * event it must match the name space on the event definition taken from the Apex policy model.
73      * If no name space is specified, the name space from the event definition in the Apex policy
74      * model is used.
75      */
76     public static final String NAMESPACE_HEADER_FIELD = "nameSpace";
77
78     /**
79      * The source of the Apex event, an optional field. It specifies where the Apex event has come
80      * from and its use is reserved for now. If no source is specified, the source from the event
81      * definition in the Apex policy model is used.
82      */
83     public static final String SOURCE_HEADER_FIELD = "source";
84
85     /**
86      * The target of the Apex event, an optional field. It specifies where the Apex event is going
87      * to and its use is reserved for now. If no target is specified, the target from the event
88      * definition in the Apex policy model is used.
89      */
90     public static final String TARGET_HEADER_FIELD = "target";
91
92     /**
93      * The exception message field of an Apex event is an exception message indicating that an event
94      * failed.
95      */
96     public static final String EXCEPTION_MESSAGE_HEADER_FIELD = "exceptionMessage";
97
98     /** The name of an Apex event must match this regular expression. */
99     public static final String NAME_REGEXP = "[A-Za-z0-9\\-_.]+";
100
101     /** The version of an Apex event must match this regular expression. */
102     public static final String VERSION_REGEXP = "[A-Za-z0-9.]+";
103
104     /** The name space of an Apex event must match this regular expression. */
105     public static final String NAMESPACE_REGEXP = "([a-zA_Z_][\\.\\w]*)";
106
107     /** The source of an Apex event must match this regular expression. */
108     public static final String SOURCE_REGEXP = "^$|[A-Za-z0-9\\.\\-_:]+";
109
110     /** The target of an Apex event must match this regular expression. */
111     public static final String TARGET_REGEXP = SOURCE_REGEXP;
112
113     // The standard fields of the event
114     private final String name;
115     private final String version;
116     private final String nameSpace;
117     private final String source;
118     private final String target;
119
120     // An identifier for the current event execution. The default value here will always be unique
121     // in a single JVM
122     private long executionId = ApexEvent.getNextExecutionId();
123
124     // Event related properties used during processing of this event
125     private Properties executionProperties = new Properties();
126
127     // A string holding a message that indicates why processing of this event threw an exception
128     private String exceptionMessage;
129
130     /**
131      * Instantiates a new apex event.
132      *
133      * @param name the name of the event
134      * @param version the version of the event
135      * @param nameSpace the name space (java package) of the event
136      * @param source the source of the event
137      * @param target the target of the event
138      * @throws ApexEventException thrown on validation errors on event names and versions
139      */
140     public ApexEvent(final String name, final String version, final String nameSpace, final String source,
141             final String target) throws ApexEventException {
142         // @formatter:off
143         this.name      = validateField(NAME_HEADER_FIELD,      name,      NAME_REGEXP);
144         this.version   = validateField(VERSION_HEADER_FIELD,   version,   VERSION_REGEXP);
145         this.nameSpace = validateField(NAMESPACE_HEADER_FIELD, nameSpace, NAMESPACE_REGEXP);
146         this.source    = validateField(SOURCE_HEADER_FIELD,    source,    SOURCE_REGEXP);
147         this.target    = validateField(TARGET_HEADER_FIELD,    target,    TARGET_REGEXP);
148         // @formatter:on
149     }
150
151     /**
152      * Private utility to get the next candidate value for a Execution ID. This value will always be
153      * unique in a single JVM
154      *
155      * @return the next candidate value for a Execution ID
156      */
157     private static synchronized long getNextExecutionId() {
158         return nextExecutionID.getAndIncrement();
159     }
160
161     /**
162      * Check that a field of the event is valid.
163      *
164      * @param fieldName the name of the field to check
165      * @param fieldValue the value of the field to check
166      * @param fieldRegexp the regular expression to check the field against
167      * @return the validated field value
168      * @throws ApexEventException thrown if the field is invalid
169      */
170     private String validateField(final String fieldName, final String fieldValue, final String fieldRegexp)
171             throws ApexEventException {
172         if (fieldValue.matches(fieldRegexp)) {
173             return fieldValue;
174         } else {
175             String message = EVENT_PREAMBLE + name + ": field \"" + fieldName + "=" + fieldValue
176                     + "\"  is illegal. It doesn't match regex '" + fieldRegexp + "'";
177             LOGGER.warn(message);
178             throw new ApexEventException(message);
179         }
180     }
181
182     /**
183      * Check that the key of an event is valid.
184      *
185      * @param key the key
186      * @return the string
187      * @throws ApexEventException the apex event exception
188      */
189     private String validKey(final String key) throws ApexEventException {
190         if (key.matches(AxReferenceKey.LOCAL_NAME_REGEXP)) {
191             return key;
192         } else {
193             String message = EVENT_PREAMBLE + name + ": key \"" + key + "\" is illegal";
194             LOGGER.warn(message);
195             throw new ApexEventException(message);
196         }
197     }
198
199     /**
200      * Sets the pass-thru executionID for this event.
201      *
202      * <p>The default value for executionID is unique in the current JVM. For some applications/deployments this
203      * executionID may need to be globally unique
204      *
205      * @param executionId the executionID
206      */
207     public void setExecutionId(final long executionId) {
208         this.executionId = executionId;
209     }
210
211     /**
212      * Set the execution properties for this event.
213      *
214      * @param executionProperties the execution properties to set
215      */
216     public void setExecutionProperties(Properties executionProperties) {
217         this.executionProperties = executionProperties;
218     }
219
220     /**
221      * Sets the exception message explaining why processing of this event to fail.
222      *
223      * @param exceptionMessage the exception message
224      */
225     public void setExceptionMessage(final String exceptionMessage) {
226         this.exceptionMessage = exceptionMessage;
227     }
228
229     /*
230      * Map overrides from here
231      */
232
233     /**
234      * {@inheritDoc}.
235      */
236     @Override
237     public Object put(final String key, final Object value) {
238         // Check if the key is valid
239         try {
240             return super.put(validKey(key), value);
241         } catch (final ApexEventException e) {
242             if (LOGGER.isTraceEnabled()) {
243                 LOGGER.trace("put failed", e);
244             }
245             return null;
246         }
247     }
248
249     /**
250      * {@inheritDoc}.
251      */
252     @Override
253     public void putAll(final Map<? extends String, ? extends Object> incomingMap) {
254         // Check the keys are valid
255         try {
256             for (final String key : incomingMap.keySet()) {
257                 validKey(key);
258             }
259         } catch (final ApexEventException e) {
260             if (LOGGER.isTraceEnabled()) {
261                 LOGGER.trace("putAll failed", e);
262             }
263
264             // One of the keys is invalid
265             return;
266         }
267
268         // Go ahead and put everything
269         super.putAll(incomingMap);
270     }
271 }