Add bug fixes and tests for filters
[policy/models.git] / models-base / src / main / java / org / onap / policy / models / base / PfReferenceKey.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
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.models.base;
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import javax.persistence.Column;
27 import javax.persistence.Embeddable;
28
29 import lombok.Data;
30 import lombok.EqualsAndHashCode;
31 import lombok.NonNull;
32
33 import org.onap.policy.common.utils.validation.Assertions;
34 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
35
36 /**
37  * A reference key identifies entities in the system that are contained in other entities. Every contained concept in
38  * the system must have an {@link PfReferenceKey} to identify it. Non-contained first order concepts are identified
39  * using an {@link PfConceptKey} key.
40  *
41  * <p>An {@link PfReferenceKey} contains an {@link PfConceptKey} key reference to the first order entity that contains
42  * it. The local name of the reference key must uniquely identify the referenced concept among those concepts contained
43  * in the reference key's parent. In other words, if a parent concept has more than one child, the local name in the key
44  * of all its children must be unique.
45  *
46  * <p>If a reference key's parent is itself a reference key, then the parent's local name must be set in the reference
47  * key. If the parent is a first order concept, then the parent's local name in the key will be set to NULL.
48  *
49  * <p>Key validation checks that the parent name and parent version fields match the NAME_REGEXP and
50  * VERSION_REGEXP regular expressions respectively and that the local name fields match the
51  * LOCAL_NAME_REGEXP regular expression.
52  */
53 @Embeddable
54 @Data
55 @EqualsAndHashCode(callSuper = false)
56 public class PfReferenceKey extends PfKey {
57     private static final String PARENT_KEY_NAME = "parentKeyName";
58     private static final String PARENT_KEY_VERSION = "parentKeyVersion";
59     private static final String PARENT_LOCAL_NAME = "parentLocalName";
60     private static final String LOCAL_NAME = "localName";
61
62     private static final long serialVersionUID = 8932717618579392561L;
63
64     /** Regular expression to specify the structure of local names in reference keys. */
65     public static final String LOCAL_NAME_REGEXP = "[A-Za-z0-9\\-_\\.]+|^$";
66
67     /** Regular expression to specify the structure of IDs in reference keys. */
68     public static final String REFERENCE_KEY_ID_REGEXP =
69                     "[A-Za-z0-9\\-_]+:[0-9].[0-9].[0-9]:[A-Za-z0-9\\-_]+:[A-Za-z0-9\\-_]+";
70
71     private static final int PARENT_NAME_FIELD = 0;
72     private static final int PARENT_VERSION_FIELD = 1;
73     private static final int PARENT_LOCAL_NAME_FIELD = 2;
74     private static final int LOCAL_NAME_FIELD = 3;
75
76     @Column(name = PARENT_KEY_NAME, length = 120)
77     private String parentKeyName;
78
79     @Column(name = PARENT_KEY_VERSION, length = 15)
80     private String parentKeyVersion;
81
82     @Column(name = PARENT_LOCAL_NAME, length = 120)
83     private String parentLocalName;
84
85     @Column(name = LOCAL_NAME, length = 120)
86     private String localName;
87
88     /**
89      * The default constructor creates a null reference key.
90      */
91     public PfReferenceKey() {
92         this(NULL_KEY_NAME, NULL_KEY_VERSION, NULL_KEY_NAME, NULL_KEY_NAME);
93     }
94
95     /**
96      * The Copy Constructor creates a key by copying another key.
97      *
98      * @param referenceKey
99      *        the reference key to copy from
100      */
101     public PfReferenceKey(final PfReferenceKey referenceKey) {
102         this(referenceKey.getParentKeyName(), referenceKey.getParentKeyVersion(), referenceKey.getParentLocalName(),
103                         referenceKey.getLocalName());
104     }
105
106     /**
107      * Constructor to create a null reference key for the specified parent concept key.
108      *
109      * @param pfConceptKey
110      *        the parent concept key of this reference key
111      */
112     public PfReferenceKey(final PfConceptKey pfConceptKey) {
113         this(pfConceptKey.getName(), pfConceptKey.getVersion(), NULL_KEY_NAME, NULL_KEY_NAME);
114     }
115
116     /**
117      * Constructor to create a reference key for the given parent concept key with the given local name.
118      *
119      * @param pfConceptKey
120      *        the parent concept key of this reference key
121      * @param localName
122      *        the local name of this reference key
123      */
124     public PfReferenceKey(final PfConceptKey pfConceptKey, final String localName) {
125         this(pfConceptKey, NULL_KEY_NAME, localName);
126     }
127
128     /**
129      * Constructor to create a reference key for the given parent reference key with the given local name.
130      *
131      * @param parentReferenceKey
132      *        the parent reference key of this reference key
133      * @param localName
134      *        the local name of this reference key
135      */
136     public PfReferenceKey(final PfReferenceKey parentReferenceKey, final String localName) {
137         this(parentReferenceKey.getParentConceptKey(), parentReferenceKey.getLocalName(), localName);
138     }
139
140     /**
141      * Constructor to create a reference key for the given parent reference key (specified by the parent reference key's
142      * concept key and local name) with the given local name.
143      *
144      * @param pfConceptKey
145      *        the concept key of the parent reference key of this reference key
146      * @param parentLocalName
147      *        the local name of the parent reference key of this reference key
148      * @param localName
149      *        the local name of this reference key
150      */
151     public PfReferenceKey(final PfConceptKey pfConceptKey, final String parentLocalName, final String localName) {
152         this(pfConceptKey.getName(), pfConceptKey.getVersion(), parentLocalName, localName);
153     }
154
155     /**
156      * Constructor to create a reference key for the given parent concept key (specified by the parent concept key's
157      * name and version) with the given local name.
158      *
159      * @param parentKeyName
160      *        the name of the parent concept key of this reference key
161      * @param parentKeyVersion
162      *        the version of the parent concept key of this reference key
163      * @param localName
164      *        the local name of this reference key
165      */
166     public PfReferenceKey(final String parentKeyName, final String parentKeyVersion, final String localName) {
167         this(parentKeyName, parentKeyVersion, NULL_KEY_NAME, localName);
168     }
169
170     /**
171      * Constructor to create a reference key for the given parent key (specified by the parent key's name, version nad
172      * local name) with the given local name.
173      *
174      * @param parentKeyName
175      *        the parent key name of this reference key
176      * @param parentKeyVersion
177      *        the parent key version of this reference key
178      * @param parentLocalName
179      *        the parent local name of this reference key
180      * @param localName
181      *        the local name of this reference key
182      */
183     public PfReferenceKey(final String parentKeyName, final String parentKeyVersion, final String parentLocalName,
184                     final String localName) {
185         super();
186         this.parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP);
187         this.parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion,
188                         VERSION_REGEXP);
189         this.parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName,
190                         LOCAL_NAME_REGEXP);
191         this.localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP);
192     }
193
194     /**
195      * Constructor to create a key from the specified key ID.
196      *
197      * @param id
198      *        the key ID in a format that respects the KEY_ID_REGEXP
199      */
200     public PfReferenceKey(final String id) {
201         final String conditionedId = Assertions.validateStringParameter("id", id, REFERENCE_KEY_ID_REGEXP);
202
203         // Split on colon, if the id passes the regular expression test above
204         // it'll have just three colons separating the parent name,
205         // parent version, parent local name, and and local name
206         // No need for range checks or size checks on the array
207         final String[] nameVersionNameArray = conditionedId.split(":");
208
209         // Initiate the new key
210         parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, nameVersionNameArray[PARENT_NAME_FIELD],
211                         NAME_REGEXP);
212         parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION,
213                         nameVersionNameArray[PARENT_VERSION_FIELD], VERSION_REGEXP);
214         parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME,
215                         nameVersionNameArray[PARENT_LOCAL_NAME_FIELD], LOCAL_NAME_REGEXP);
216         localName = Assertions.validateStringParameter(LOCAL_NAME, nameVersionNameArray[LOCAL_NAME_FIELD],
217                         LOCAL_NAME_REGEXP);
218     }
219
220     /**
221      * Get a null reference key.
222      *
223      * @return a null reference key
224      */
225     public static PfReferenceKey getNullKey() {
226         return new PfReferenceKey(PfKey.NULL_KEY_NAME, PfKey.NULL_KEY_VERSION, PfKey.NULL_KEY_NAME,
227                         PfKey.NULL_KEY_NAME);
228     }
229
230     @Override
231     public PfReferenceKey getKey() {
232         return this;
233     }
234
235     @Override
236     public List<PfKey> getKeys() {
237         final List<PfKey> keyList = new ArrayList<>();
238         keyList.add(getKey());
239         return keyList;
240     }
241
242     @Override
243     public String getId() {
244         return parentKeyName + ':' + parentKeyVersion + ':' + parentLocalName + ':' + localName;
245     }
246
247     @Override
248     public boolean isNullKey() {
249         return this.equals(PfReferenceKey.getNullKey());
250     }
251
252     /**
253      * Gets the parent concept key of this reference key.
254      *
255      * @return the parent concept key of this reference key
256      */
257     public PfConceptKey getParentConceptKey() {
258         return new PfConceptKey(parentKeyName, parentKeyVersion);
259     }
260
261     /**
262      * Gets the parent reference key of this reference key.
263      *
264      * @return the parent reference key of this reference key
265      */
266     public PfReferenceKey getParentReferenceKey() {
267         return new PfReferenceKey(parentKeyName, parentKeyVersion, parentLocalName);
268     }
269
270     /**
271      * Sets the parent concept key of this reference key.
272      *
273      * @param parentKey
274      *        the parent concept key of this reference key
275      */
276     public void setParentConceptKey(final PfConceptKey parentKey) {
277         Assertions.argumentNotNull(parentKey, "parentKey may not be null");
278
279         parentKeyName = parentKey.getName();
280         parentKeyVersion = parentKey.getVersion();
281         parentLocalName = NULL_KEY_NAME;
282     }
283
284     /**
285      * Sets the parent reference key of this reference key.
286      *
287      * @param parentKey
288      *        the parent reference key of this reference key
289      */
290     public void setParentReferenceKey(final PfReferenceKey parentKey) {
291         Assertions.argumentNotNull(parentKey, "parentKey may not be null");
292
293         parentKeyName = parentKey.getParentKeyName();
294         parentKeyVersion = parentKey.getParentKeyVersion();
295         parentLocalName = parentKey.getLocalName();
296     }
297
298     @Override
299     public PfKey.Compatibility getCompatibility(final PfKey otherKey) {
300         if (!(otherKey instanceof PfReferenceKey)) {
301             return Compatibility.DIFFERENT;
302         }
303         final PfReferenceKey otherReferenceKey = (PfReferenceKey) otherKey;
304
305         return this.getParentConceptKey().getCompatibility(otherReferenceKey.getParentConceptKey());
306     }
307
308     @Override
309     public boolean isCompatible(@NonNull final PfKey otherKey) {
310         if (!(otherKey instanceof PfReferenceKey)) {
311             return false;
312         }
313         final PfReferenceKey otherReferenceKey = (PfReferenceKey) otherKey;
314
315         return this.getParentConceptKey().isCompatible(otherReferenceKey.getParentConceptKey());
316     }
317
318     @Override
319     public int getMajorVersion() {
320         return this.getParentConceptKey().getMajorVersion();
321     }
322
323     @Override
324     public int getMinorVersion() {
325         return this.getParentConceptKey().getMinorVersion();
326     }
327
328     @Override
329     public int getPatchVersion() {
330         return this.getParentConceptKey().getPatchVersion();
331     }
332
333
334     @Override
335     public boolean isNewerThan(@NonNull final PfKey otherKey) {
336         Assertions.instanceOf(otherKey, PfReferenceKey.class);
337
338         final PfReferenceKey otherReferenceKey = (PfReferenceKey) otherKey;
339
340         return this.getParentConceptKey().isNewerThan(otherReferenceKey.getParentConceptKey());
341     }
342
343     @Override
344     public PfValidationResult validate(final PfValidationResult result) {
345         final String parentNameValidationErrorMessage = Assertions.getStringParameterValidationMessage(PARENT_KEY_NAME,
346                         parentKeyName, NAME_REGEXP);
347         if (parentNameValidationErrorMessage != null) {
348             result.addValidationMessage(new PfValidationMessage(this, this.getClass(), ValidationResult.INVALID,
349                             "parentKeyName invalid-" + parentNameValidationErrorMessage));
350         }
351
352         final String parentKeyVersionValidationErrorMessage = Assertions
353                         .getStringParameterValidationMessage(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP);
354         if (parentKeyVersionValidationErrorMessage != null) {
355             result.addValidationMessage(new PfValidationMessage(this, this.getClass(), ValidationResult.INVALID,
356                             "parentKeyVersion invalid-" + parentKeyVersionValidationErrorMessage));
357         }
358
359         final String parentLocalNameValidationErrorMessage = Assertions
360                         .getStringParameterValidationMessage(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP);
361         if (parentLocalNameValidationErrorMessage != null) {
362             result.addValidationMessage(new PfValidationMessage(this, this.getClass(), ValidationResult.INVALID,
363                             "parentLocalName invalid-" + parentLocalNameValidationErrorMessage));
364         }
365
366         final String localNameValidationErrorMessage = Assertions.getStringParameterValidationMessage(LOCAL_NAME,
367                         localName, LOCAL_NAME_REGEXP);
368         if (localNameValidationErrorMessage != null) {
369             result.addValidationMessage(new PfValidationMessage(this, this.getClass(), ValidationResult.INVALID,
370                             "localName invalid-" + localNameValidationErrorMessage));
371         }
372
373         return result;
374     }
375
376     @Override
377     public void clean() {
378         parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP);
379         parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP);
380         parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP);
381         localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP);
382     }
383
384     @Override
385     public PfConcept copyTo(final PfConcept target) {
386         Assertions.argumentNotNull(target, "target may not be null");
387
388         final Object copyObject = target;
389         Assertions.instanceOf(copyObject, PfReferenceKey.class);
390
391         final PfReferenceKey copy = ((PfReferenceKey) copyObject);
392         copy.setParentKeyName(parentKeyName);
393         copy.setParentKeyVersion(parentKeyVersion);
394         copy.setLocalName(localName);
395         copy.setParentLocalName(parentLocalName);
396
397         return copy;
398     }
399
400     @Override
401     public int compareTo(final PfConcept otherObj) {
402         Assertions.argumentNotNull(otherObj, "comparison object may not be null");
403
404         if (this == otherObj) {
405             return 0;
406         }
407         if (getClass() != otherObj.getClass()) {
408             return this.hashCode() - otherObj.hashCode();
409         }
410
411         final PfReferenceKey other = (PfReferenceKey) otherObj;
412         if (!parentKeyName.equals(other.parentKeyName)) {
413             return parentKeyName.compareTo(other.parentKeyName);
414         }
415         if (!parentKeyVersion.equals(other.parentKeyVersion)) {
416             return parentKeyVersion.compareTo(other.parentKeyVersion);
417         }
418         if (!parentLocalName.equals(other.parentLocalName)) {
419             return parentLocalName.compareTo(other.parentLocalName);
420         }
421         return localName.compareTo(other.localName);
422     }
423 }