61434ca67c98bbcf30a30c1de0657155c6d3fceb
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019-2022 Nordix Foundation.
5  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.apex.model.contextmodel.concepts;
24
25 import java.util.List;
26 import lombok.AccessLevel;
27 import lombok.Getter;
28 import lombok.ToString;
29 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
30 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
31 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
32 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
33 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
34 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
35 import org.onap.policy.common.utils.validation.Assertions;
36
37 /**
38  * This class holds a data schema definition in Apex. A data schema describes the structure of a single atom of data
39  * handled by Apex. This atom of data can be a primitive type such as an integer or a string, or it can be a more
40  * complex data type such as a Java object or an object described using a data definition language such as Avro. The
41  * schema flavour defines the type of schema being defined and the schema itself defines the schema. The schema flavour
42  * is used by Apex to look up and load a plugin class that understands and interprets the schema definition and can
43  * create instances of classes for the schema.
44  *
45  * <p>An {@link AxContextSchema} is used to define each parameter in Apex events, the messages that enter, exit, and are
46  * passed internally in Apex. In addition, an Apex {@link AxContextAlbum} instances hold a map of
47  * {@link AxContextSchema} instances to represent the context being managed as an {@link AxContextAlbum}. For example,
48  * the state of all cells in a mobile network might be represented as an {@link AxContextAlbum} with its
49  * {@link AxContextSchema} being defined as @code cell} objects.
50  *
51  * <p>Validation checks that the schema key is not null. It also checks that the schema flavour is defined and matches
52  * the regular expression SCHEMA_FLAVOUR_REGEXP. Finally, validation checks that the defined schema is not a blank or
53  * empty string.
54  */
55 @Getter
56 @ToString
57 public class AxContextSchema extends AxConcept {
58     private static final String SCHEMA_FLAVOUR = "schemaFlavour";
59     private static final String WHITESPACE_REGEXP = "\\s+$";
60
61     private static final long serialVersionUID = -6443016863162692288L;
62
63     /** Regular expression that constrains what values a schema flavour can have. */
64     public static final String SCHEMA_FLAVOUR_REGEXP = "[A-Za-z0-9\\-_]+";
65
66     /** An undefined schema flavour has this value. */
67     public static final String SCHEMA_FLAVOUR_UNDEFINED = "UNDEFINED";
68
69     /** The maximum permissible size of a schema definition. */
70     public static final int MAX_SCHEMA_SIZE = 32672; // The maximum size supported by Apache Derby
71
72     private AxArtifactKey key;
73     private String schemaFlavour;
74
75     @Getter(AccessLevel.NONE)
76     private String schemaDefinition;
77
78     /**
79      * The default constructor creates a context schema with a null artifact key. The flavour of the context album is
80      * set as SCHEMA_FLAVOUR_UNDEFINED and the schema itself is defined as an empty string.
81      */
82     public AxContextSchema() {
83         this(new AxArtifactKey());
84         schemaFlavour = SCHEMA_FLAVOUR_UNDEFINED;
85     }
86
87     /**
88      * Copy constructor.
89      *
90      * @param copyConcept the concept to copy from
91      */
92     public AxContextSchema(final AxContextSchema copyConcept) {
93         super(copyConcept);
94     }
95
96     /**
97      * The key constructor creates a context schema with the given artifact key. The flavour of the context album is set
98      * as SCHEMA_FLAVOUR_UNDEFINED and the schema itself is defined as an empty string.
99      *
100      * @param key the key
101      */
102     public AxContextSchema(final AxArtifactKey key) {
103         this(key, SCHEMA_FLAVOUR_UNDEFINED, "");
104     }
105
106     /**
107      * This Constructor creates a context schema with all of its fields defined.
108      *
109      * @param key the key
110      * @param schemaFlavour the schema flavour
111      * @param schemaDefinition the schema definition
112      */
113     public AxContextSchema(final AxArtifactKey key, final String schemaFlavour, final String schemaDefinition) {
114         super();
115         Assertions.argumentNotNull(key, "key may not be null");
116         Assertions.argumentNotNull(schemaFlavour, "schemaFlavour may not be null");
117         Assertions.argumentNotNull(schemaDefinition, "schemaDefinition may not be null");
118
119         this.key = key;
120         this.schemaFlavour = Assertions.validateStringParameter(SCHEMA_FLAVOUR, schemaFlavour, SCHEMA_FLAVOUR_REGEXP);
121         this.schemaDefinition = schemaDefinition.replaceAll(WHITESPACE_REGEXP, "");
122     }
123
124     /**
125      * {@inheritDoc}.
126      */
127     @Override
128     public List<AxKey> getKeys() {
129         return key.getKeys();
130     }
131
132     /**
133      * Sets the key of the context schema.
134      *
135      * @param key the key of the context schema
136      */
137     public void setKey(final AxArtifactKey key) {
138         Assertions.argumentNotNull(key, "key may not be null");
139         this.key = key;
140     }
141
142     /**
143      * Sets the schema flavour, which defines the type of schema definition being used.
144      *
145      * @param schemaFlavour the schema flavour
146      */
147     public void setSchemaFlavour(final String schemaFlavour) {
148         this.schemaFlavour = Assertions.validateStringParameter(SCHEMA_FLAVOUR, schemaFlavour, SCHEMA_FLAVOUR_REGEXP);
149     }
150
151     /**
152      * Gets the schema, which defines the structure of this data schema atom.
153      *
154      * @return the schema definition
155      */
156     public String getSchema() {
157         return schemaDefinition;
158     }
159
160     /**
161      * Sets the schema, which defines the structure of this data schema atom.
162      *
163      * @param schema the schema definition
164      */
165     public void setSchema(final String schema) {
166         Assertions.argumentNotNull(schema, "schema may not be null");
167         this.schemaDefinition = schema.replaceAll(WHITESPACE_REGEXP, "");
168     }
169
170     /**
171      * {@inheritDoc}.
172      */
173     @Override
174     public AxValidationResult validate(final AxValidationResult resultIn) {
175         AxValidationResult result = resultIn;
176
177         if (key.equals(AxArtifactKey.getNullKey())) {
178             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
179                             "key is a null key"));
180         }
181
182         result = key.validate(result);
183
184         if (schemaFlavour.replaceAll(WHITESPACE_REGEXP, "").length() == 0
185                         || schemaFlavour.equals(SCHEMA_FLAVOUR_UNDEFINED)) {
186             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
187                             "schema flavour is not defined"));
188         }
189
190         var flavourValidationResult = Assertions.getStringParameterValidationMessage(SCHEMA_FLAVOUR, schemaFlavour,
191                         SCHEMA_FLAVOUR_REGEXP);
192         if (flavourValidationResult != null) {
193             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
194                             "schema flavour invalid-" + flavourValidationResult));
195         }
196
197         if (schemaDefinition.replaceAll(WHITESPACE_REGEXP, "").length() == 0) {
198             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
199                             "no schemaDefinition specified, schemaDefinition may not be blank"));
200         }
201
202         return result;
203     }
204
205     /**
206      * {@inheritDoc}.
207      */
208     @Override
209     public void clean() {
210         key.clean();
211         schemaFlavour = Assertions.validateStringParameter(SCHEMA_FLAVOUR, schemaFlavour, SCHEMA_FLAVOUR_REGEXP);
212         schemaDefinition = schemaDefinition.replaceAll(WHITESPACE_REGEXP, "");
213     }
214
215     /**
216      * {@inheritDoc}.
217      */
218     @Override
219     public AxConcept copyTo(final AxConcept target) {
220         Assertions.argumentNotNull(target, "target may not be null");
221
222         final Object copyObject = target;
223         Assertions.instanceOf(copyObject, AxContextSchema.class);
224
225         final AxContextSchema copy = ((AxContextSchema) copyObject);
226         copy.setKey(new AxArtifactKey(key));
227         copy.setSchemaFlavour(schemaFlavour);
228         copy.setSchema(schemaDefinition);
229
230         return copy;
231     }
232
233     /**
234      * {@inheritDoc}.
235      */
236     @Override
237     public int hashCode() {
238         final var prime = 31;
239         var result = 1;
240         result = prime * result + key.hashCode();
241         result = prime * result + schemaFlavour.hashCode();
242
243         final String thisSchema = schemaDefinition.replace("\n", "");
244         result = prime * result + thisSchema.hashCode();
245         return result;
246     }
247
248     /**
249      * {@inheritDoc}.
250      */
251     @Override
252     public boolean equals(final Object obj) {
253         if (obj == null) {
254             return false;
255         }
256         if (this == obj) {
257             return true;
258         }
259
260         if (getClass() != obj.getClass()) {
261             return false;
262         }
263
264         final AxContextSchema other = (AxContextSchema) obj;
265
266         if (!key.equals(other.key)) {
267             return false;
268         }
269         if (!schemaFlavour.equals(other.schemaFlavour)) {
270             return false;
271         }
272         return schemaDefinition.equals(other.schemaDefinition);
273     }
274
275     /**
276      * {@inheritDoc}.
277      */
278     @Override
279     public int compareTo(final AxConcept otherObj) {
280         if (otherObj == null) {
281             return -1;
282         }
283         if (this == otherObj) {
284             return 0;
285         }
286         if (getClass() != otherObj.getClass()) {
287             return this.hashCode() - otherObj.hashCode();
288         }
289
290         final AxContextSchema other = (AxContextSchema) otherObj;
291         if (!key.equals(other.key)) {
292             return key.compareTo(other.key);
293         }
294         if (!schemaFlavour.equals(other.schemaFlavour)) {
295             return schemaFlavour.compareTo(other.schemaFlavour);
296         }
297         return schemaDefinition.compareTo(other.schemaDefinition);
298     }
299 }