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