f7680a7725b64365b95a8b5fea34c2f5978f51d9
[policy/apex-pdp.git] / model / policy-model / src / main / java / org / onap / policy / apex / model / policymodel / concepts / AxLogic.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019 Nordix Foundation.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.model.policymodel.concepts;
23
24 import java.util.List;
25
26 import javax.persistence.Column;
27 import javax.persistence.Convert;
28 import javax.persistence.EmbeddedId;
29 import javax.persistence.Entity;
30 import javax.persistence.Inheritance;
31 import javax.persistence.InheritanceType;
32 import javax.persistence.Table;
33 import javax.xml.bind.annotation.XmlAccessType;
34 import javax.xml.bind.annotation.XmlAccessorType;
35 import javax.xml.bind.annotation.XmlElement;
36 import javax.xml.bind.annotation.XmlRootElement;
37 import javax.xml.bind.annotation.XmlType;
38 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
39
40 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
41 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
42 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
43 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
44 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
45 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
46 import org.onap.policy.apex.model.basicmodel.dao.converters.CDataConditioner;
47 import org.onap.policy.apex.model.basicmodel.xml.AxReferenceKeyAdapter;
48 import org.onap.policy.common.utils.validation.Assertions;
49
50 /**
51  * This class holds Logic for executing a task or task selection on an Apex policy state. The flavour of the logic
52  * describes the type of logic being used and it may be a language identifier such as "Javascript" or "Jython". The
53  * logic itself is held as a string. The {@link AxLogic} instance is used by the Apex engine to start an executor with
54  * the required flavour. Once the executor is started, the Apex engine passes the logic to the executor and the executor
55  * executes it. In the Apex engine, executors are deployed as plugins. Apex also provides the executor with run-time
56  * context, which makes context such as input fields, output fields, and context albums available to the task at
57  * runtime.
58  *
59  * <p>Validation checks that the logic key is valid, that the logic flavour is defined and is valid when checked against
60  * the {@code LOGIC_FLAVOUR_REGEXP} regular expression, and that the specified logic string is not null or blank.
61  */
62
63 @Entity
64 @Table(name = "AxLogic")
65 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
66
67 @XmlAccessorType(XmlAccessType.FIELD)
68 @XmlRootElement(name = "apexLogic", namespace = "http://www.onap.org/policy/apex-pdp")
69 @XmlType(name = "AxLogic", namespace = "http://www.onap.org/policy/apex-pdp", propOrder =
70     { "key", "logicFlavour", "logic" })
71
72 public class AxLogic extends AxConcept {
73     private static final long serialVersionUID = -4260562004005697328L;
74
75     private static final String WHITESPACE_REGEXP = "\\s+$";
76
77     private static final String LOGIC_FLAVOUR_TOKEN = "logicFlavour";
78     private static final String KEY_NULL_MESSAGE = "key may not be null";
79     private static final String LOGIC_FLAVOUR_NULL_MESSAGE = "logicFlavour may not be null";
80     private static final String LOGIC_NULL_MESSAGE = "logic may not be null";
81
82     /** Regular expression that specifies the allowed characters in logic flavour tokens. */
83     public static final String LOGIC_FLAVOUR_REGEXP = "[A-Za-z0-9\\-_]+";
84
85     /** When logic flavour is undefined, it has this value. */
86     public static final String LOGIC_FLAVOUR_UNDEFINED = "UNDEFINED";
87
88     /** The maximum permissible size of a logic definition. */
89     public static final int MAX_LOGIC_SIZE = 32672; // The maximum size supported by Apache Derby
90
91     @EmbeddedId()
92     @XmlElement(name = "key", required = true)
93     @XmlJavaTypeAdapter(AxReferenceKeyAdapter.class)
94     private AxReferenceKey key;
95
96     @Column(name = LOGIC_FLAVOUR_TOKEN)
97     @XmlElement(required = true)
98     private String logicFlavour;
99
100     @Column(name = "logic", length = MAX_LOGIC_SIZE)
101     @Convert(converter = CDataConditioner.class)
102     @XmlJavaTypeAdapter(value = CDataConditioner.class)
103     @XmlElement(required = true)
104     private String logic;
105
106     /**
107      * The Default Constructor creates a logic instance with a null key, undefined logic flavour and a null logic
108      * string.
109      */
110     public AxLogic() {
111         this(new AxReferenceKey());
112         logicFlavour = LOGIC_FLAVOUR_UNDEFINED;
113     }
114
115     /**
116      * Copy constructor.
117      *
118      * @param copyConcept the concept to copy from
119      */
120     public AxLogic(final AxLogic copyConcept) {
121         super(copyConcept);
122     }
123
124     /**
125      * The Key Constructor creates a logic instance with the given reference key, undefined logic flavour and a null
126      * logic string.
127      *
128      * @param key the reference key of the logic
129      */
130     public AxLogic(final AxReferenceKey key) {
131         this(key, LOGIC_FLAVOUR_UNDEFINED, "");
132     }
133
134     /**
135      * This Constructor creates a logic instance with a reference key constructed from the parents key and the logic
136      * local name and all of its fields defined.
137      *
138      * @param parentKey the reference key of the parent of this logic
139      * @param logicName the logic name, held as the local name of the reference key of this logic
140      * @param logicFlavour the flavour of this logic
141      * @param logic the actual logic as a string
142      */
143     public AxLogic(final AxReferenceKey parentKey, final String logicName, final String logicFlavour,
144                     final String logic) {
145         this(new AxReferenceKey(parentKey, logicName), logicFlavour, logic);
146     }
147
148     /**
149      * This Constructor creates a logic instance with the given reference key and all of its fields defined.
150      *
151      * @param key the reference key of this logic
152      * @param logicFlavour the flavour of this logic
153      * @param logic the actual logic as a string
154      */
155     public AxLogic(final AxReferenceKey key, final String logicFlavour, final String logic) {
156         super();
157         Assertions.argumentNotNull(key, KEY_NULL_MESSAGE);
158         Assertions.argumentNotNull(logicFlavour, LOGIC_FLAVOUR_NULL_MESSAGE);
159         Assertions.argumentNotNull(logic, LOGIC_NULL_MESSAGE);
160
161         this.key = key;
162         this.logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
163         this.logic = logic.replaceAll(WHITESPACE_REGEXP, "");
164     }
165
166     /**
167      * This Constructor creates a logic instance with the given reference key and logic flavour, the logic is provided
168      * by the given logic reader instance.
169      *
170      * @param key the reference key of this logic
171      * @param logicFlavour the flavour of this logic
172      * @param logicReader the logic reader to use to read the logic for this logic instance
173      */
174     public AxLogic(final AxReferenceKey key, final String logicFlavour, final AxLogicReader logicReader) {
175         super();
176         Assertions.argumentNotNull(key, KEY_NULL_MESSAGE);
177         Assertions.argumentNotNull(logicFlavour, LOGIC_FLAVOUR_NULL_MESSAGE);
178         Assertions.argumentNotNull(logicReader, "logicReader may not be null");
179
180         this.key = key;
181         this.logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
182         logic = logicReader.readLogic(this);
183     }
184
185     /**
186      * {@inheritDoc}.
187      */
188     @Override
189     public AxReferenceKey getKey() {
190         return key;
191     }
192
193     /**
194      * {@inheritDoc}.
195      */
196     @Override
197     public List<AxKey> getKeys() {
198         return key.getKeys();
199     }
200
201     /**
202      * Sets the key.
203      *
204      * @param key the key
205      */
206     public void setKey(final AxReferenceKey key) {
207         Assertions.argumentNotNull(key, KEY_NULL_MESSAGE);
208         this.key = key;
209     }
210
211     /**
212      * Gets the logic flavour.
213      *
214      * @return the logic flavour
215      */
216     public String getLogicFlavour() {
217         return logicFlavour;
218     }
219
220     /**
221      * Sets the logic flavour.
222      *
223      * @param logicFlavour the logic flavour
224      */
225     public void setLogicFlavour(final String logicFlavour) {
226         this.logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
227     }
228
229     /**
230      * Gets the logic.
231      *
232      * @return the logic
233      */
234     public String getLogic() {
235         return logic;
236     }
237
238     /**
239      * Sets the logic.
240      *
241      * @param logic the logic
242      */
243     public void setLogic(final String logic) {
244         Assertions.argumentNotNull(logic, LOGIC_NULL_MESSAGE);
245         this.logic = logic.replaceAll(WHITESPACE_REGEXP, "");
246     }
247
248     /**
249      * {@inheritDoc}.
250      */
251     @Override
252     public AxValidationResult validate(final AxValidationResult resultIn) {
253         AxValidationResult result = resultIn;
254
255         if (key.equals(AxReferenceKey.getNullKey())) {
256             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
257                             "key is a null key"));
258         }
259
260         result = key.validate(result);
261
262         if (logicFlavour.replaceAll(WHITESPACE_REGEXP, "").length() == 0
263                         || logicFlavour.equals(LOGIC_FLAVOUR_UNDEFINED)) {
264             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
265                             "logic flavour is not defined"));
266         }
267
268         String flavourValidationString = Assertions.getStringParameterValidationMessage(LOGIC_FLAVOUR_TOKEN,
269                         logicFlavour, LOGIC_FLAVOUR_REGEXP);
270         if (flavourValidationString != null) {
271             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
272                             "logic flavour invalid-" + flavourValidationString));
273         }
274
275         if (logic.replaceAll(WHITESPACE_REGEXP, "").length() == 0) {
276             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
277                             "no logic specified, logic may not be blank"));
278         }
279
280         return result;
281     }
282
283     /**
284      * {@inheritDoc}.
285      */
286     @Override
287     public void clean() {
288         if (key != null) {
289             key.clean();
290         }
291         logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
292         logic = logic.replaceAll(WHITESPACE_REGEXP, "");
293     }
294
295     /**
296      * {@inheritDoc}.
297      */
298     @Override
299     public String toString() {
300         final StringBuilder builder = new StringBuilder();
301         builder.append(this.getClass().getSimpleName());
302         builder.append(":(");
303         builder.append("key=");
304         builder.append(key);
305         builder.append(",logicFlavour=");
306         builder.append(logicFlavour);
307         builder.append(",logic=");
308         builder.append(logic);
309         builder.append(")");
310         return builder.toString();
311     }
312
313     /**
314      * {@inheritDoc}.
315      */
316     @Override
317     public AxConcept copyTo(final AxConcept targetObject) {
318         Assertions.argumentNotNull(targetObject, "target may not be null");
319
320         final Object copyObject = targetObject;
321         Assertions.instanceOf(copyObject, AxLogic.class);
322
323         final AxLogic copy = ((AxLogic) copyObject);
324         copy.setKey(new AxReferenceKey(key));
325         copy.setLogicFlavour(logicFlavour);
326         copy.setLogic(logic);
327
328         return copy;
329     }
330
331     /**
332      * {@inheritDoc}.
333      */
334     @Override
335     public int hashCode() {
336         final int prime = 31;
337         int result = 1;
338         result = prime * result + key.hashCode();
339         result = prime * result + logicFlavour.hashCode();
340         result = prime * result + logic.hashCode();
341         return result;
342     }
343
344     /**
345      * {@inheritDoc}.
346      */
347     @Override
348     public boolean equals(final Object obj) {
349         if (obj == null) {
350             return false;
351         }
352         if (this == obj) {
353             return true;
354         }
355         if (getClass() != obj.getClass()) {
356             return false;
357         }
358
359         final AxLogic other = (AxLogic) obj;
360         if (!key.equals(other.key)) {
361             return false;
362         }
363         if (!logicFlavour.equals(other.logicFlavour)) {
364             return false;
365         }
366         final String thislogic = CDataConditioner.clean(logic).replaceAll("\n", "");
367         final String otherlogic = CDataConditioner.clean(other.logic).replaceAll("\n", "");
368         return thislogic.equals(otherlogic);
369     }
370
371     /**
372      * {@inheritDoc}.
373      */
374     @Override
375     public int compareTo(final AxConcept otherObj) {
376         if (otherObj == null) {
377             return -1;
378         }
379         if (this == otherObj) {
380             return 0;
381         }
382         if (getClass() != otherObj.getClass()) {
383             return this.hashCode() - otherObj.hashCode();
384         }
385
386         final AxLogic other = (AxLogic) otherObj;
387         if (!key.equals(other.key)) {
388             return key.compareTo(other.key);
389         }
390         if (!logicFlavour.equals(other.logicFlavour)) {
391             return logicFlavour.compareTo(other.logicFlavour);
392         }
393         return logic.compareTo(other.logic);
394     }
395 }