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