summaryrefslogtreecommitdiffstats
path: root/model/policy-model/src/main
diff options
context:
space:
mode:
authorwaqas.ikram <waqas.ikram@ericsson.com>2018-05-28 10:58:07 +0100
committerwaqas.ikram <waqas.ikram@ericsson.com>2018-05-28 14:35:30 +0100
commit55d93a12cc5575c872724f48585304b5eec77fea (patch)
treeac5e44c5670bbcc5e68cceb1694f87348c371e1b /model/policy-model/src/main
parent6029d25f5f3ad43fe02ffe1a4beb1eda0a6ae5e3 (diff)
Adding policy-model, model-api & engine-model
Change-Id: I56702b8f0953457d493f894d155b2a6ddc87b10c Issue-ID: POLICY-856 Signed-off-by: waqas.ikram <waqas.ikram@ericsson.com>
Diffstat (limited to 'model/policy-model/src/main')
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogic.java419
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogicReader.java74
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicies.java429
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicy.java536
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicyModel.java737
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxState.java1020
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateFinalizerLogic.java137
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateOutput.java389
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskOutputType.java48
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskReference.java400
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTree.java157
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTask.java745
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskLogic.java136
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskParameter.java299
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskSelectionLogic.java135
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTasks.java425
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyException.java51
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyRuntimeException.java51
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/package-info.java35
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalyser.java186
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalysisResult.java266
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyComparer.java46
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyLogicReader.java153
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelComparer.java271
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelMerger.java155
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelSplitter.java165
-rw-r--r--model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/package-info.java26
27 files changed, 7491 insertions, 0 deletions
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogic.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogic.java
new file mode 100644
index 000000000..a537d90b9
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogic.java
@@ -0,0 +1,419 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.basicmodel.dao.converters.CDATAConditioner;
+import org.onap.policy.apex.model.basicmodel.xml.AxReferenceKeyAdapter;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class holds Logic for executing a task or task selection on an Apex policy state. The
+ * flavour of the logic describes the type of logic being used and it may be a language identifier
+ * such as "Javascript" or "Jython". The logic itself is held as a string. The {@link AxLogic}
+ * instance is used by the Apex engine to start an executor with the required flavour. Once the
+ * executor is started, the Apex engine passes the logic to the executor and the executor executes
+ * it. In the Apex engine, executors are deployed as plugins. Apex also provides the executor with
+ * run-time context, which makes context such as input fields, output fields, and context albums
+ * available to the task at runtime.
+ * <p>
+ * Validation checks that the logic key is valid, that the logic flavour is defined and is valid
+ * when checked against the {@code LOGIC_FLAVOUR_REGEXP} regular expression, and that the specified
+ * logic string is not null or blank.
+ */
+
+@Entity
+@Table(name = "AxLogic")
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexLogic", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxLogic", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"key", "logicFlavour", "logic"})
+
+public class AxLogic extends AxConcept {
+ private static final long serialVersionUID = -4260562004005697328L;
+
+ private static final String WHITESPACE_REGEXP = "\\s+$";
+
+ private static final String LOGIC_FLAVOUR_TOKEN = "logicFlavour";
+ private static final String KEY_NULL_MESSAGE = "key may not be null";
+ private static final String LOGIC_FLAVOUR_NULL_MESSAGE = "logicFlavour may not be null";
+ private static final String LOGIC_NULL_MESSAGE = "logic may not be null";
+
+ /** Regular expression that specifies the allowed characters in logic flavour tokens. */
+ public static final String LOGIC_FLAVOUR_REGEXP = "[A-Za-z0-9\\-_]+";
+
+ /** When logic flavour is undefined, it has this value. */
+ public static final String LOGIC_FLAVOUR_UNDEFINED = "UNDEFINED";
+
+ /** The maximum permissible size of a logic definition. */
+ public static final int MAX_LOGIC_SIZE = 32672; // The maximum size supported by Apache Derby
+
+ @EmbeddedId()
+ @XmlElement(name = "key", required = true)
+ @XmlJavaTypeAdapter(AxReferenceKeyAdapter.class)
+ private AxReferenceKey key;
+
+ @Column(name = LOGIC_FLAVOUR_TOKEN)
+ @XmlElement(required = true)
+ private String logicFlavour;
+
+ @Column(name = "logic", length = MAX_LOGIC_SIZE)
+ @Convert(converter = CDATAConditioner.class)
+ @XmlJavaTypeAdapter(value = CDATAConditioner.class)
+ @XmlElement(required = true)
+ private String logic;
+
+ /**
+ * The Default Constructor creates a logic instance with a null key, undefined logic flavour and
+ * a null logic string.
+ */
+ public AxLogic() {
+ this(new AxReferenceKey());
+ logicFlavour = LOGIC_FLAVOUR_UNDEFINED;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxLogic(final AxLogic copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Key Constructor creates a logic instance with the given reference key, undefined logic
+ * flavour and a null logic string.
+ *
+ * @param key the reference key of the logic
+ */
+ public AxLogic(final AxReferenceKey key) {
+ this(key, LOGIC_FLAVOUR_UNDEFINED, "");
+ }
+
+ /**
+ * This Constructor creates a logic instance with a reference key constructed from the parents
+ * key and the logic local name and all of its fields defined.
+ *
+ * @param parentKey the reference key of the parent of this logic
+ * @param logicName the logic name, held as the local name of the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxLogic(final AxReferenceKey parentKey, final String logicName, final String logicFlavour,
+ final String logic) {
+ this(new AxReferenceKey(parentKey, logicName), logicFlavour, logic);
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and all of its fields
+ * defined.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxLogic(final AxReferenceKey key, final String logicFlavour, final String logic) {
+ super();
+ Assertions.argumentNotNull(key, KEY_NULL_MESSAGE);
+ Assertions.argumentNotNull(logicFlavour, LOGIC_FLAVOUR_NULL_MESSAGE);
+ Assertions.argumentNotNull(logic, LOGIC_NULL_MESSAGE);
+
+ this.key = key;
+ this.logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
+ this.logic = logic.replaceAll(WHITESPACE_REGEXP, "");
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and logic flavour, the
+ * logic is provided by the given logic reader instance.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logicReader the logic reader to use to read the logic for this logic instance
+ */
+ public AxLogic(final AxReferenceKey key, final String logicFlavour, final AxLogicReader logicReader) {
+ super();
+ Assertions.argumentNotNull(key, KEY_NULL_MESSAGE);
+ Assertions.argumentNotNull(logicFlavour, LOGIC_FLAVOUR_NULL_MESSAGE);
+ Assertions.argumentNotNull(logicReader, "logicReader may not be null");
+
+ this.key = key;
+ this.logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
+ logic = logicReader.readLogic(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxReferenceKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ return key.getKeys();
+ }
+
+ /**
+ * Sets the key.
+ *
+ * @param key the key
+ */
+ public void setKey(final AxReferenceKey key) {
+ Assertions.argumentNotNull(key, KEY_NULL_MESSAGE);
+ this.key = key;
+ }
+
+ /**
+ * Gets the logic flavour.
+ *
+ * @return the logic flavour
+ */
+ public String getLogicFlavour() {
+ return logicFlavour;
+ }
+
+ /**
+ * Sets the logic flavour.
+ *
+ * @param logicFlavour the logic flavour
+ */
+ public void setLogicFlavour(final String logicFlavour) {
+ this.logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
+ }
+
+ /**
+ * Gets the logic.
+ *
+ * @return the logic
+ */
+ public String getLogic() {
+ return logic;
+ }
+
+ /**
+ * Sets the logic.
+ *
+ * @param logic the logic
+ */
+ public void setLogic(final String logic) {
+ Assertions.argumentNotNull(logic, LOGIC_NULL_MESSAGE);
+ this.logic = logic.replaceAll(WHITESPACE_REGEXP, "");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxReferenceKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (logicFlavour.replaceAll(WHITESPACE_REGEXP, "").length() == 0
+ || logicFlavour.equals(LOGIC_FLAVOUR_UNDEFINED)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "logic flavour is not defined"));
+ }
+
+ try {
+ Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
+ } catch (final IllegalArgumentException e) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "logic flavour invalid-" + e.getMessage()));
+ }
+
+ if (logic.replaceAll(WHITESPACE_REGEXP, "").length() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "no logic specified, logic may not be blank"));
+ }
+
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ if (key != null) {
+ key.clean();
+ }
+ logicFlavour = Assertions.validateStringParameter(LOGIC_FLAVOUR_TOKEN, logicFlavour, LOGIC_FLAVOUR_REGEXP);
+ logic = logic.replaceAll(WHITESPACE_REGEXP, "");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("key=");
+ builder.append(key);
+ builder.append(",logicFlavour=");
+ builder.append(logicFlavour);
+ builder.append(",logic=");
+ builder.append(logic);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxLogic.class);
+
+ final AxLogic copy = ((AxLogic) copyObject);
+ copy.setKey(new AxReferenceKey(key));
+ copy.setLogicFlavour(logicFlavour);
+ copy.setLogic(logic);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + logicFlavour.hashCode();
+ result = prime * result + logic.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxLogic other = (AxLogic) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ if (!logicFlavour.equals(other.logicFlavour)) {
+ return false;
+ }
+ final String thislogic = CDATAConditioner.clean(logic).replaceAll("\n", "");
+ final String otherlogic = CDATAConditioner.clean(other.logic).replaceAll("\n", "");
+ return thislogic.equals(otherlogic);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxLogic other = (AxLogic) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!logicFlavour.equals(other.logicFlavour)) {
+ return logicFlavour.compareTo(other.logicFlavour);
+ }
+ return logic.compareTo(other.logic);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogicReader.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogicReader.java
new file mode 100644
index 000000000..7532f9f34
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxLogicReader.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+/**
+ * This interface is used to provide logic to a {@link AxLogic} instance. Implementations usually
+ * store logic on disk in a structure similar to Java package naming conventions. The logic package
+ * gives the package path, a directory where a set of logic is defined. Default logic is logic that
+ * can be used as dummy logic in tasks or states that are filler tasks or states. The actual logic
+ * is returned by the {@code readLogic()} method. The interface is used mainly by unit test classes
+ * that generate test logic.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public interface AxLogicReader {
+
+ /**
+ * Get the logic package path.
+ *
+ * @return the logic package path
+ */
+ String getLogicPackage();
+
+ /**
+ * Set the logic package path.
+ *
+ * @param logicPackage the name of the package that contains the logic for this logic reader
+ * @return the logic reader on which this method was called, used for daisy chaining
+ * configuration
+ */
+ AxLogicReader setLogicPackage(final String logicPackage);
+
+ /**
+ * Get the default logic name.
+ *
+ * @return the default logic name
+ */
+ String getDefaultLogic();
+
+ /**
+ * Set the default logic name.
+ *
+ * @param defaultLogic the default logic name
+ * @return the logic reader on which this method was called, used for daisy chaining
+ * configuration
+ */
+ AxLogicReader setDefaultLogic(final String defaultLogic);
+
+ /**
+ * Read the logic for an AxLogic object.
+ *
+ * @param axLogic the AxLogic object
+ * @return the logic as a string
+ */
+ String readLogic(final AxLogic axLogic);
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicies.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicies.java
new file mode 100644
index 000000000..248e4fdae
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicies.java
@@ -0,0 +1,429 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.persistence.CascadeType;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetterImpl;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class is a policy container and holds a map of the policies for an entire Apex model. All
+ * Apex models that use policies must have an {@link AxPolicies} field. The {@link AxPolicies} class
+ * implements the helper methods of the {@link AxConceptGetter} interface to allow {@link AxPolicy}
+ * instances to be retrieved by calling methods directly on this class without referencing the
+ * contained map.
+ * <p>
+ * Validation checks that the container key is not null. An error is issued if no policies are
+ * defined in the container. Each policy entry is checked to ensure that its key and value are not
+ * null and that the key matches the key in the map value. Each policy entry is then validated
+ * individually.
+ */
+@Entity
+@Table(name = "AxPolicies")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "AxPolicies", namespace = "http://www.onap.org/policy/apex-pdp", propOrder = {"key", "policyMap"})
+
+public class AxPolicies extends AxConcept implements AxConceptGetter<AxPolicy> {
+ private static final long serialVersionUID = 4290442590545820316L;
+
+ @EmbeddedId
+ @XmlElement(name = "key", required = true)
+ private AxArtifactKey key;
+
+ // @formatter:off
+ @ManyToMany(cascade = CascadeType.ALL)
+ @JoinTable(
+ joinColumns = {@JoinColumn(name = "policyMapName", referencedColumnName = "name"),
+ @JoinColumn(name = "policyMapVersion", referencedColumnName = "version")},
+ inverseJoinColumns = {@JoinColumn(name = "policyName", referencedColumnName = "name"),
+ @JoinColumn(name = "policyVersion", referencedColumnName = "version")})
+ @XmlElement(required = true)
+ private Map<AxArtifactKey, AxPolicy> policyMap;
+ // @formatter:on
+
+ /**
+ * The Default Constructor creates a {@link AxPolicies} object with a null artifact key and
+ * creates an empty event map.
+ */
+ public AxPolicies() {
+ this(new AxArtifactKey());
+ }
+
+ /**
+ * The Key Constructor creates a {@link AxPolicies} object with the given artifact key and
+ * creates an empty event map.
+ *
+ * @param key the key
+ */
+ public AxPolicies(final AxArtifactKey key) {
+ this(key, new TreeMap<AxArtifactKey, AxPolicy>());
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxPolicies(final AxPolicies copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * This Constructor creates a policy container with all of its fields defined.
+ *
+ * @param key the policy container key
+ * @param policyMap the policies to be stored in the policy container
+ */
+ public AxPolicies(final AxArtifactKey key, final Map<AxArtifactKey, AxPolicy> policyMap) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(policyMap, "policyMap may not be null");
+
+ this.key = key;
+ this.policyMap = new TreeMap<>();
+ this.policyMap.putAll(policyMap);
+ }
+
+ /**
+ * When a model is unmarshalled from disk or from the database, the policy map is returned as a
+ * raw hash map. This method is called by JAXB after unmarshaling and is used to convert the
+ * hash map to a {@link NavigableMap} so that it will work with the {@link AxConceptGetter}
+ * interface.
+ *
+ * @param u the unmarshaler that is unmarshaling the model
+ * @param parent the parent object of this object in the unmarshaler
+ */
+ public void afterUnmarshal(final Unmarshaller u, final Object parent) {
+ // The map must be navigable to allow name and version searching, unmarshaling returns a
+ // hash map
+ final NavigableMap<AxArtifactKey, AxPolicy> navigablePolicyMap = new TreeMap<>();
+ navigablePolicyMap.putAll(policyMap);
+ policyMap = navigablePolicyMap;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxArtifactKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = key.getKeys();
+
+ for (final AxPolicy policy : policyMap.values()) {
+ keyList.addAll(policy.getKeys());
+ }
+
+ return keyList;
+ }
+
+ /**
+ * Sets the key of the policy container.
+ *
+ * @param key the policy container key
+ */
+ public void setKey(final AxArtifactKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the policy map containing all policies in the policy container.
+ *
+ * @return the policy map with all the policies in the container
+ */
+ public Map<AxArtifactKey, AxPolicy> getPolicyMap() {
+ return policyMap;
+ }
+
+ /**
+ * Sets the policy map containing all policies in the policy container.
+ *
+ * @param policyMap the policy map with all the policies to be put in the container
+ */
+ public void setPolicyMap(final Map<AxArtifactKey, AxPolicy> policyMap) {
+ Assertions.argumentNotNull(policyMap, "policyMap may not be null");
+ this.policyMap = new TreeMap<>();
+ this.policyMap.putAll(policyMap);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (policyMap.size() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "policyMap may not be empty"));
+ } else {
+ for (final Entry<AxArtifactKey, AxPolicy> policyEntry : policyMap.entrySet()) {
+ if (policyEntry.getKey().equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "key on policy entry " + policyEntry.getKey() + " may not be the null key"));
+ } else if (policyEntry.getValue() == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "value on policy entry " + policyEntry.getKey() + " may not be null"));
+ } else {
+ if (!policyEntry.getKey().equals(policyEntry.getValue().getKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(),
+ ValidationResult.INVALID, "key on policy entry key " + policyEntry.getKey()
+ + " does not equal policy value key " + policyEntry.getValue().getKey()));
+ }
+
+ result = policyEntry.getValue().validate(result);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ for (final Entry<AxArtifactKey, AxPolicy> policyEntry : policyMap.entrySet()) {
+ policyEntry.getKey().clean();
+ policyEntry.getValue().clean();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("key=");
+ builder.append(key);
+ builder.append(",policyMap=");
+ builder.append(policyMap);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxPolicies.class);
+
+ final AxPolicies copy = ((AxPolicies) copyObject);
+ copy.setKey(new AxArtifactKey(key));
+
+ final Map<AxArtifactKey, AxPolicy> newPolicyMap = new TreeMap<>();
+ for (final Entry<AxArtifactKey, AxPolicy> policyMapEntry : policyMap.entrySet()) {
+ newPolicyMap.put(new AxArtifactKey(policyMapEntry.getKey()), new AxPolicy(policyMapEntry.getValue()));
+ }
+ copy.setPolicyMap(newPolicyMap);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + policyMap.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxPolicies other = (AxPolicies) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ return policyMap.equals(other.policyMap);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxPolicies other = (AxPolicies) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!policyMap.equals(other.policyMap)) {
+ return (policyMap.hashCode() - other.policyMap.hashCode());
+ }
+
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#get(org.onap.policy.apex.model
+ * .basicmodel.concepts.AxArtifactKey)
+ */
+ @Override
+ public AxPolicy get(final AxArtifactKey conceptKey) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxPolicy>) policyMap).get(conceptKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#get(java.lang.String)
+ */
+ @Override
+ public AxPolicy get(final String conceptKeyName) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxPolicy>) policyMap).get(conceptKeyName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#get(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public AxPolicy get(final String conceptKeyName, final String conceptKeyVersion) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxPolicy>) policyMap).get(conceptKeyName,
+ conceptKeyVersion);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#getAll(java.lang.String)
+ */
+ @Override
+ public Set<AxPolicy> getAll(final String conceptKeyName) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxPolicy>) policyMap).getAll(conceptKeyName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#getAll(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public Set<AxPolicy> getAll(final String conceptKeyName, final String conceptKeyVersion) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxPolicy>) policyMap).getAll(conceptKeyName,
+ conceptKeyVersion);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicy.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicy.java
new file mode 100644
index 000000000..ff7e4a23f
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicy.java
@@ -0,0 +1,536 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class holds the definition of an Apex policy. A policy is made up of a tree of states, each
+ * represented by an {@link AxState} instance. The states of a policy are held in a map in the
+ * policy. The state tree is built up at policy design time by a policy editor and each state is
+ * connected to its next state by an {@link AxStateOutput} instance.
+ * <p>
+ * Execution of a policy is triggered by an event. A policy starts execution from its first state so
+ * the trigger event for the first sate is the trigger event for the entire policy. Execution from
+ * that first state can continue to one or more subsequent states and so on down branches of states.
+ * The state output of the final state in a branch has no next state, indicating the end of
+ * execution of that branch. Therefore, the set of output events from final states in the policy are
+ * the possible set of output events on the policy. A state may only be used once in the state tree
+ * of a policy and recursive execution of states in the same execution branch is not allowed, so the
+ * same state may not execute more than once on a single execution of a policy.
+ * <p>
+ * The template of a policy is a string that can be used by policy editors to store meta information
+ * on the policy that can be used at design time. The policy template string is not used during
+ * policy execution.
+ * <p>
+ * During validation of a policy, the validation checks listed below are executed:
+ * <ol>
+ * <li>The policy key must not be a null key
+ * <li>The policy key must be valid
+ * <li>If the policy template is not set, an observation is issued
+ * <li>At least one state must be defined
+ * <li>Keys and values must all be defined, that is not null
+ * <li>The key on each entry in the state map must match the key in the entry's value
+ * <li>The parent key of each state in the state map of a policy must be the key of that policy
+ * <li>Each state must itself be valid, see validation in {@link AxState}
+ * <li>The next state of the state output of each state must be defined as a state in the policy
+ * <li>The first state of a policy must be set
+ * <li>The first state of a policy must be defined in the policy
+ * <li>If a state is defined but is not used in a policy,a warning is issued
+ * <li>The state tree of the policy must be valid, see validation in {@link AxStateTree}
+ * </ol>
+ */
+
+@Entity
+@Table(name = "AxPolicy")
+@XmlRootElement(name = "apexPolicy", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "AxPolicy", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"key", "template", "stateMap", "firstState"})
+
+public class AxPolicy extends AxConcept {
+ private static final long serialVersionUID = -1775614096390365941L;
+
+ @EmbeddedId
+ @XmlElement(name = "policyKey", required = true)
+ private AxArtifactKey key;
+
+ @Column(name = "template")
+ @XmlElement(required = true)
+ private String template;
+
+ // @formatter:off
+ @OneToMany(cascade = CascadeType.ALL)
+ @JoinTable(joinColumns = {@JoinColumn(name = "parentKeyName", referencedColumnName = "name"),
+ @JoinColumn(name = "parentKeyVersion", referencedColumnName = "version")})
+ @XmlElement(name = "state", required = true)
+ private Map<String, AxState> stateMap;
+ // @formatter:on
+
+ @Column(name = "firstState")
+ @XmlElement(required = true)
+ private String firstState;
+
+ /**
+ * The Default Constructor creates a policy instance with a null key, a blank template and
+ * undefined first state.
+ */
+ public AxPolicy() {
+ this(new AxArtifactKey());
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxPolicy(final AxPolicy copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Key Constructor creates a policy instance with the given key, a blank template and
+ * undefined first state.
+ *
+ * @param key the key of the policy
+ */
+ public AxPolicy(final AxArtifactKey key) {
+ this(key, "", new TreeMap<String, AxState>(), "");
+ }
+
+ /**
+ * This Constructor creates a policy with the given key and all its fields defined.
+ *
+ * @param key the key of the policy
+ * @param template the policy template for policy editor metadata
+ * @param stateMap the state map containing the states of the policy
+ * @param firstState the first state that will execute on this policy
+ */
+ public AxPolicy(final AxArtifactKey key, final String template, final Map<String, AxState> stateMap,
+ final String firstState) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(template, "template may not be null");
+ Assertions.argumentNotNull(stateMap, "stateMap may not be null");
+ Assertions.argumentNotNull(firstState, "firstState may not be null");
+
+ this.key = key;
+ this.template = template;
+ this.stateMap = stateMap;
+ this.firstState = firstState;
+ }
+
+ /**
+ * Gets a tree that holds all the possible execution paths for this policy. This method may be
+ * used for verification of policies, to find the branches of policy execution and the final
+ * states of policies.
+ *
+ * @return the state tree of the policy, a tree representing the execution branches of the
+ * policy
+ */
+ public AxStateTree getStateTree() {
+ return new AxStateTree(this, stateMap.get(firstState), null);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxArtifactKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = key.getKeys();
+ for (final AxState state : stateMap.values()) {
+ keyList.addAll(state.getKeys());
+ }
+ return keyList;
+ }
+
+ /**
+ * Sets the key of the policy.
+ *
+ * @param key the key of the policy
+ */
+ public void setKey(final AxArtifactKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the policy template for policy editor metadata.
+ *
+ * @return the policy template for policy editor metadata
+ */
+ public String getTemplate() {
+ return template;
+ }
+
+ /**
+ * Sets the policy template for policy editor metadata.
+ *
+ * @param template the policy template for policy editor metadata
+ */
+ public void setTemplate(final String template) {
+ Assertions.argumentNotNull(template, "template may not be null");
+ this.template = template;
+ }
+
+ /**
+ * Gets a map containing the states of the policy.
+ *
+ * @return the map of states in the policy
+ */
+ public Map<String, AxState> getStateMap() {
+ return stateMap;
+ }
+
+ /**
+ * Sets a map containing the states of the policy.
+ *
+ * @param stateMap a map of states in the policy
+ */
+ public void setStateMap(final Map<String, AxState> stateMap) {
+ Assertions.argumentNotNull(stateMap, "stateMap may not be null");
+ this.stateMap = stateMap;
+ }
+
+ /**
+ * Gets the first state of the policy.
+ *
+ * @return the first state of the policy
+ */
+ public String getFirstState() {
+ return firstState;
+ }
+
+ /**
+ * Sets the first state of the policy.
+ *
+ * @param firstState the first state of the policy
+ */
+ public void setFirstState(final String firstState) {
+ Assertions.argumentNotNull(firstState, "firstState may not be null");
+ this.firstState = firstState;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (template.trim().length() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION,
+ "a policy template has not been specified"));
+ }
+
+ if (stateMap.size() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "stateMap may not be empty"));
+ } else {
+ for (final Entry<String, AxState> stateEntry : stateMap.entrySet()) {
+ result = validateStateEntry(stateEntry, result);
+ }
+ }
+
+ // Validation continues from this point only if all validation checks this far have been
+ // passed
+ if (!result.isOK()) {
+ return result;
+ }
+
+ // We only check the unused states on models validated this far
+ if (firstState.trim().length() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "no first state specified, first state may not be blank"));
+ } else {
+ if (!stateMap.containsKey(firstState)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "first state not found in stateMap"));
+ } else {
+ validateStateTree(result);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate a state entry
+ *
+ * @param stateEntry the state entry to validate
+ * @param result The validation result to append to
+ * @return The result of the validation
+ */
+ private AxValidationResult validateStateEntry(final Entry<String, AxState> stateEntry, AxValidationResult result) {
+ if (stateEntry.getKey() == null || stateEntry.getKey().equals(AxKey.NULL_KEY_NAME)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "key on state entry key " + stateEntry.getKey() + " may not be the null key"));
+ return result;
+ }
+
+ if (stateEntry.getValue() == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "value on state entry value " + stateEntry.getKey() + " may not be null"));
+ return result;
+ }
+
+ if (!stateEntry.getKey().equals(stateEntry.getValue().getKey().getLocalName())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "key on state entry key " + stateEntry.getKey() + " does not equal state entry value local name "
+ + stateEntry.getValue().getKey().getLocalName()));
+ }
+
+ if (!stateEntry.getValue().getKey().getParentArtifactKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "parent key on state entry key " + stateEntry.getValue().getKey() + " does not equal policy key"));
+ }
+
+ result = stateEntry.getValue().validate(result);
+
+ for (final AxStateOutput stateOutput : stateEntry.getValue().getStateOutputs().values()) {
+ if (!stateOutput.getNextState().equals(AxReferenceKey.getNullKey())
+ && !stateMap.containsKey(stateOutput.getNextState().getLocalName())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ " nextState of state " + stateEntry.getKey() + " not found in StateMap: "
+ + stateOutput.getNextState().getID()));
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate a state tree to ensure there are no circular references in it
+ *
+ * @param result The validation result to append to
+ * @return The result of the validation
+ */
+ private AxValidationResult validateStateTree(AxValidationResult result) {
+ try {
+ // Cpnstructor validates policy state tree
+ AxStateTree policyStateTree = getStateTree();
+
+ // Check for unused states
+ final Set<AxState> referencedStateSet = policyStateTree.getReferencedStateSet();
+ final Set<AxState> unreferencedStateSet = new TreeSet<>(stateMap.values());
+ unreferencedStateSet.removeAll(referencedStateSet);
+
+ for (final AxState unreferencedState : unreferencedStateSet) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.WARNING,
+ "state " + unreferencedState.getKey() + " is not referenced in the policy execution tree"));
+ }
+ } catch (PolicyRuntimeException pre) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.WARNING,
+ "state tree in policy is invalid"));
+ }
+
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ firstState = firstState.trim();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("key=");
+ builder.append(key);
+ builder.append(",template=");
+ builder.append(template);
+ builder.append(",stateMap=");
+ builder.append(stateMap);
+ builder.append(",firstState=");
+ builder.append(firstState);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxPolicy.class);
+
+ final AxPolicy copy = ((AxPolicy) copyObject);
+ copy.setKey(new AxArtifactKey(key));
+ copy.setTemplate(template);
+
+ final Map<String, AxState> newStateMap = new TreeMap<>();
+ for (final Entry<String, AxState> stateMapEntry : stateMap.entrySet()) {
+ newStateMap.put(stateMapEntry.getKey(), new AxState(stateMapEntry.getValue()));
+ }
+ copy.setStateMap(newStateMap);
+
+ copy.setFirstState(firstState);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + template.hashCode();
+ result = prime * result + stateMap.hashCode();
+ result = prime * result + firstState.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxPolicy other = (AxPolicy) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ if (!template.equals(other.template)) {
+ return false;
+ }
+ if (!stateMap.equals(other.stateMap)) {
+ return false;
+ }
+ return firstState.equals(other.firstState);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxPolicy other = (AxPolicy) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!template.equals(other.template)) {
+ return template.compareTo(other.template);
+ }
+ if (!stateMap.equals(other.stateMap)) {
+ return (stateMap.hashCode() - other.stateMap.hashCode());
+ }
+ return firstState.compareTo(other.firstState);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicyModel.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicyModel.java
new file mode 100644
index 000000000..f6000b1f3
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicyModel.java
@@ -0,0 +1,737 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInformation;
+import org.onap.policy.apex.model.basicmodel.concepts.AxModel;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.basicmodel.service.ModelService;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbums;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextModel;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchemas;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * A container class for an Apex policy model. This class is a container class that allows an Apex
+ * model to be constructed that contains definitions of all the context, event, and policy concepts
+ * required to run policies in Apex. The model contains schema definitions, definitions of events
+ * and context albums that use those schemas, definitions of tasks for policies and definitions of
+ * the policies themselves.
+ * <p>
+ * An Apex policy model is an important artifact in Apex. At editing time, an Apex editor creates
+ * and edits a policy model and a policy model is loaded into and is executed by an Apex engine.
+ * Therefore, an Apex model and the set of policies that it holds is the way that the policy domain
+ * that an Apex engine or a group of Apex engines executes across is expressed, both at design time
+ * and run time. The Apex deployment system is responsible for deploying Apex models to and the
+ * context they need the appropriate engines for execution.
+ * <p>
+ * Model registration is carried out by calling the {@code register()} method, which registers the
+ * policy model and all its constituent containers with the model service. The containers for
+ * context schemas, events, context albums, tasks, policies, and key information are all registered.
+ * <p>
+ * Once a policy model is composed, the overall structure of the policy model and all its references
+ * can be validated. During validation of a policy model, the validation checks listed below are
+ * executed:
+ * <ol>
+ * <li>The policy model is validated as an Apex model, which validates the existence, correctness,
+ * and duplication of all keys in the model as well as validating the key information of the keys,
+ * see validation in {@link AxModel}
+ * <li>The schemas in the model must be valid, see validation in {@link AxContextSchemas}
+ * <li>The context albums in the model must be valid, see validation in {@link AxContextAlbums}
+ * <li>The tasks in the model must be valid, see validation in {@link AxTasks}
+ * <li>The policies in the model must be valid, see validation in {@link AxPolicies}
+ * <li>The events in the model must be valid, see validation in {@link AxEvents}
+ * <li>The context schemas referred to in each field in every event must exist
+ * <li>The context schemas referred to in every context album must exist
+ * <li>The context schemas referred to in every task input field and output field must exist
+ * <li>The context albums referred to in every task must exist
+ * <li>The context albums referred to in every state must exist
+ * <li>The trigger event referred to in every state must exist
+ * <li>The default task referred to in every state must exist
+ * <li>In a state, an event that triggers a task must contain all the input fields required by that
+ * task
+ * <li>In a state, an event that is emitted by a task must contain all the output fields produced by
+ * that task
+ * <li>All tasks referred to by a state must exist
+ * <li>All events referred to on direct state outputs must exist
+ * </ol>
+ */
+@Entity
+@Table(name = "AxPolicyModel")
+
+@XmlRootElement(name = "apexPolicyModel", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "AxPolicyModel", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"policies", "tasks", "events", "albums", "schemas"})
+
+public class AxPolicyModel extends AxModel {
+ private static final String DOES_NOT_EXIST = " does not exist";
+
+ private static final long serialVersionUID = 8800599637708309945L;
+
+ // @formatter:off
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumns({@JoinColumn(name = "policiesName", referencedColumnName = "name"),
+ @JoinColumn(name = "policiesVersion", referencedColumnName = "version")})
+ @XmlElement(name = "policies", required = true)
+ private AxPolicies policies;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumns({@JoinColumn(name = "tasksName", referencedColumnName = "name"),
+ @JoinColumn(name = "tasksVersion", referencedColumnName = "version")})
+ @XmlElement(name = "tasks", required = true)
+ private AxTasks tasks;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumns({@JoinColumn(name = "eventsName", referencedColumnName = "name"),
+ @JoinColumn(name = "eventsVersion", referencedColumnName = "version")})
+ @XmlElement(name = "events", required = true)
+ private AxEvents events;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumns({@JoinColumn(name = "albumsName", referencedColumnName = "name"),
+ @JoinColumn(name = "albumsVersion", referencedColumnName = "version")})
+ @XmlElement(name = "albums", required = true)
+ private AxContextAlbums albums;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumns({@JoinColumn(name = "schemasName", referencedColumnName = "name"),
+ @JoinColumn(name = "schemasVersion", referencedColumnName = "version")})
+ @XmlElement(name = "schemas", required = true)
+ private AxContextSchemas schemas;
+ // @formatter:on
+
+ /**
+ * The Default Constructor creates a policy model with a null key and empty containers for
+ * schemas, key information, events, context albums, tasks and policies.
+ */
+ public AxPolicyModel() {
+ this(new AxArtifactKey());
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxPolicyModel(final AxPolicyModel copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Keyed Constructor creates a policy model with the given key and empty containers for
+ * schemas, key information, events, context albums, tasks and policies.
+ *
+ * @param key the key
+ */
+ public AxPolicyModel(final AxArtifactKey key) {
+ this(key, new AxContextSchemas(new AxArtifactKey(key.getName() + "_Schemas", key.getVersion())),
+ new AxKeyInformation(new AxArtifactKey(key.getName() + "_KeyInfo", key.getVersion())),
+ new AxEvents(new AxArtifactKey(key.getName() + "_Events", key.getVersion())),
+ new AxContextAlbums(new AxArtifactKey(key.getName() + "_Albums", key.getVersion())),
+ new AxTasks(new AxArtifactKey(key.getName() + "_Tasks", key.getVersion())),
+ new AxPolicies(new AxArtifactKey(key.getName() + "_Policies", key.getVersion())));
+ }
+
+ /**
+ * This Constructor creates a policy model with all of its fields specified.
+ *
+ * @param key the key of the policy model
+ * @param schemas the context schema container for the policy model
+ * @param keyInformation the key information container for the policy model
+ * @param events the event container for the policy model
+ * @param albums the context album container for the policy model
+ * @param tasks the task container for the policy model
+ * @param policies the policy container for the policy model
+ */
+ public AxPolicyModel(final AxArtifactKey key, final AxContextSchemas schemas, final AxKeyInformation keyInformation,
+ final AxEvents events, final AxContextAlbums albums, final AxTasks tasks, final AxPolicies policies) {
+ super(key, keyInformation);
+ Assertions.argumentNotNull(schemas, "schemas may not be null");
+ Assertions.argumentNotNull(events, "events may not be null");
+ Assertions.argumentNotNull(albums, "albums may not be null");
+ Assertions.argumentNotNull(tasks, "tasks may not be null");
+ Assertions.argumentNotNull(policies, "policies may not be null");
+
+ this.schemas = schemas;
+ this.events = events;
+ this.albums = albums;
+ this.tasks = tasks;
+ this.policies = policies;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxModel#register()
+ */
+ @Override
+ public void register() {
+ super.register();
+ ModelService.registerModel(AxContextSchemas.class, getSchemas());
+ ModelService.registerModel(AxEvents.class, getEvents());
+ ModelService.registerModel(AxContextAlbums.class, getAlbums());
+ ModelService.registerModel(AxTasks.class, getTasks());
+ ModelService.registerModel(AxPolicies.class, getPolicies());
+ ModelService.registerModel(AxPolicyModel.class, this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxModel#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = super.getKeys();
+
+ keyList.addAll(schemas.getKeys());
+ keyList.addAll(events.getKeys());
+ keyList.addAll(albums.getKeys());
+ keyList.addAll(tasks.getKeys());
+ keyList.addAll(policies.getKeys());
+
+ return keyList;
+ }
+
+ /**
+ * Gets a context model from the policy model.
+ *
+ * @return the context model
+ */
+ public AxContextModel getContextModel() {
+ return new AxContextModel(new AxArtifactKey(albums.getKey().getName() + "_Model", albums.getKey().getVersion()),
+ getSchemas(), getAlbums(), getKeyInformation());
+ }
+
+ /**
+ * Gets the policy container from the policy model.
+ *
+ * @return the policy container with all the policies in the model
+ */
+ public AxPolicies getPolicies() {
+ return policies;
+ }
+
+ /**
+ * Sets the policy container for the policy model.
+ *
+ * @param policies the policy container with all the policies in the model
+ */
+ public void setPolicies(final AxPolicies policies) {
+ Assertions.argumentNotNull(policies, "policies may not be null");
+ this.policies = policies;
+ }
+
+ /**
+ * Gets the task container from the policy model.
+ *
+ * @return the task container with all the tasks in the model
+ */
+ public AxTasks getTasks() {
+ return tasks;
+ }
+
+ /**
+ * Sets the task container from the policy model.
+ *
+ * @param tasks the task container with all the tasks in the model
+ */
+ public void setTasks(final AxTasks tasks) {
+ Assertions.argumentNotNull(tasks, "tasks may not be null");
+ this.tasks = tasks;
+ }
+
+ /**
+ * Gets the event container from the policy model.
+ *
+ * @return the event container with all the events in the model
+ */
+ public AxEvents getEvents() {
+ return events;
+ }
+
+ /**
+ * Sets the event container from the policy model.
+ *
+ * @param events the event container with all the events in the model
+ */
+ public void setEvents(final AxEvents events) {
+ Assertions.argumentNotNull(events, "events may not be null");
+ this.events = events;
+ }
+
+ /**
+ * Gets the context album container from the policy model.
+ *
+ * @return the context album container with all the context albums in the model
+ */
+ public AxContextAlbums getAlbums() {
+ return albums;
+ }
+
+ /**
+ * Sets the context album container from the policy model.
+ *
+ * @param albums the context album container with all the context albums in the model
+ */
+ public void setAlbums(final AxContextAlbums albums) {
+ Assertions.argumentNotNull(albums, "albums may not be null");
+ this.albums = albums;
+ }
+
+ /**
+ * Gets the context schema container from the policy model.
+ *
+ * @return the context schema container with all the context schemas in the model
+ */
+ public AxContextSchemas getSchemas() {
+ return schemas;
+ }
+
+ /**
+ * Sets the context schema container from the policy model.
+ *
+ * @param schemas the context schema container with all the context schemas in the model
+ */
+ public void setSchemas(final AxContextSchemas schemas) {
+ Assertions.argumentNotNull(schemas, "schemas may not be null");
+ this.schemas = schemas;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxModel#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ result = super.validate(result);
+ result = schemas.validate(result);
+ result = events.validate(result);
+ result = albums.validate(result);
+ result = tasks.validate(result);
+ result = policies.validate(result);
+
+ validateEventKeys(result);
+ validateContextAlbumKeys(result);
+ result = validateAllTaskKeys(result);
+ validatePolicyKeys(result);
+
+ return result;
+ }
+
+ /**
+ * Validate all fundamental concepts keyed in events exist.
+ *
+ * @param result the validation result to return
+ * @return the result
+ */
+ private AxValidationResult validateEventKeys(final AxValidationResult result) {
+ for (final AxEvent event : events.getAll(null)) {
+ for (final AxField field : event.getFields()) {
+ if (getSchemas().get(field.getSchema()) == null) {
+ result.addValidationMessage(
+ new AxValidationMessage(event.getKey(), this.getClass(), ValidationResult.INVALID,
+ "event field data type " + field.getSchema().getID() + DOES_NOT_EXIST));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Validate all fundamental concepts keyed in concept maps exist.
+ *
+ * @param result the validation result to return
+ * @return the result
+ */
+ private AxValidationResult validateContextAlbumKeys(final AxValidationResult result) {
+ for (final AxContextAlbum contextAlbum : albums.getAll(null)) {
+ if (getSchemas().get(contextAlbum.getItemSchema()) == null) {
+ result.addValidationMessage(
+ new AxValidationMessage(contextAlbum.getKey(), this.getClass(), ValidationResult.INVALID,
+ "context album schema " + contextAlbum.getItemSchema().getID() + DOES_NOT_EXIST));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Validate all fundamental concepts keyed in tasks exist.
+ *
+ * @param result the validation result to return
+ * @return the result
+ */
+ private AxValidationResult validateAllTaskKeys(AxValidationResult result) {
+ for (final AxTask task : tasks.getAll(null)) {
+ result = validateTaskKeys(task, result);
+ }
+ return result;
+ }
+
+ /**
+ * Validate all fundamental concepts keyed in tasks exist.
+ *
+ * @param task The task to validate the keys of
+ * @param result the validation result to return
+ * @return the result
+ */
+ private AxValidationResult validateTaskKeys(final AxTask task, AxValidationResult result) {
+ for (final AxField field : task.getInputFieldSet()) {
+ if (getSchemas().get(field.getSchema()) == null) {
+ result.addValidationMessage(
+ new AxValidationMessage(task.getKey(), this.getClass(), ValidationResult.INVALID,
+ "task input field schema " + field.getSchema().getID() + DOES_NOT_EXIST));
+ }
+ }
+ for (final AxField field : task.getOutputFieldSet()) {
+ if (getSchemas().get(field.getSchema()) == null) {
+ result.addValidationMessage(
+ new AxValidationMessage(task.getKey(), this.getClass(), ValidationResult.INVALID,
+ "task output field schema " + field.getSchema().getID() + DOES_NOT_EXIST));
+ }
+ }
+ for (final AxArtifactKey contextAlbumKey : task.getContextAlbumReferences()) {
+ if (albums.get(contextAlbumKey) == null) {
+ result.addValidationMessage(new AxValidationMessage(task.getKey(), this.getClass(),
+ ValidationResult.INVALID, "task context album " + contextAlbumKey.getID() + DOES_NOT_EXIST));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Validate all fundamental concepts keyed in policies exist.
+ *
+ * @param result the validation result to return
+ * @return the result
+ */
+ private AxValidationResult validatePolicyKeys(final AxValidationResult result) {
+ for (final AxPolicy policy : policies.getAll(null)) {
+ for (final AxState state : policy.getStateMap().values()) {
+ validateStateReferences(state, result);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate that the references used on a state are valid
+ *
+ * @param state The state to check
+ * @param result the validation result to append to
+ */
+ private void validateStateReferences(AxState state, AxValidationResult result) {
+ for (final AxArtifactKey contextAlbumKey : state.getContextAlbumReferences()) {
+ if (albums.get(contextAlbumKey) == null) {
+ result.addValidationMessage(new AxValidationMessage(state.getKey(), this.getClass(),
+ ValidationResult.INVALID, "state context album " + contextAlbumKey.getID() + DOES_NOT_EXIST));
+ }
+ }
+
+ final AxEvent triggerEvent = events.getEventMap().get(state.getTrigger());
+ if (triggerEvent == null) {
+ result.addValidationMessage(new AxValidationMessage(state.getKey(), this.getClass(),
+ ValidationResult.INVALID, "state trigger event " + state.getTrigger().getID() + DOES_NOT_EXIST));
+ }
+
+ final AxTask defaultTask = tasks.getTaskMap().get(state.getDefaultTask());
+ if (defaultTask == null) {
+ result.addValidationMessage(new AxValidationMessage(state.getKey(), this.getClass(),
+ ValidationResult.INVALID, "state default task " + state.getDefaultTask().getID() + DOES_NOT_EXIST));
+ }
+
+ // Check task input fields and event fields are compatible for default tasks with no task
+ // selection logic
+ if (state.getTaskSelectionLogic().getKey().equals(AxReferenceKey.getNullKey()) && triggerEvent != null
+ && defaultTask != null) {
+ final Set<AxField> unhandledTaskInputFields = new TreeSet<>(defaultTask.getInputFieldSet());
+ unhandledTaskInputFields.removeAll(triggerEvent.getFields());
+ for (final AxField unhandledTaskInputField : unhandledTaskInputFields) {
+ result.addValidationMessage(new AxValidationMessage(state.getKey(), this.getClass(),
+ ValidationResult.INVALID, "task input field " + unhandledTaskInputField + " for task "
+ + defaultTask.getID() + " not in trigger event " + triggerEvent.getID()));
+ }
+ }
+
+ for (final AxStateOutput stateOutput : state.getStateOutputs().values()) {
+ if (events.getEventMap().get(stateOutput.getOutgingEvent()) == null) {
+ result.addValidationMessage(new AxValidationMessage(stateOutput.getKey(), this.getClass(),
+ ValidationResult.INVALID, "output event " + stateOutput.getOutgingEvent().getID()
+ + " for state output " + stateOutput.getID() + DOES_NOT_EXIST));
+ }
+ }
+
+ validateEventTaskFieldCompatibilityOnState(state, result);
+ }
+
+ /**
+ * Validate that the fields on tasks and events that trigger them and are output by them are
+ * compatible for all tasks used on a state
+ *
+ * @param state The state to check
+ * @param result the validation result to append to
+ */
+ private void validateEventTaskFieldCompatibilityOnState(AxState state, AxValidationResult result) {
+ // Check task output fields and event fields are compatible for tasks that directly
+ // reference state outputs
+ for (final Entry<AxArtifactKey, AxStateTaskReference> taskRefEntry : state.getTaskReferences().entrySet()) {
+ if (!taskRefEntry.getValue().getStateTaskOutputType().equals(AxStateTaskOutputType.DIRECT)) {
+ continue;
+ }
+
+ final AxTask usedTask = tasks.getTaskMap().get(taskRefEntry.getKey());
+ if (usedTask == null) {
+ result.addValidationMessage(new AxValidationMessage(state.getKey(), this.getClass(),
+ ValidationResult.INVALID, "state task " + taskRefEntry.getKey().getID() + DOES_NOT_EXIST));
+ } else {
+ AxStateOutput stateOutput =
+ state.getStateOutputs().get(taskRefEntry.getValue().getOutput().getKey().getLocalName());
+ validateEventTaskFieldCompatibilityOnStateOutput(state, usedTask, stateOutput, result);
+ }
+ }
+ }
+
+ /**
+ * Validate that the fields on a task of a state output and the events that trigger it are
+ * compatible
+ *
+ * @param state The state to check
+ * @param task The task to check
+ * @param stateOutput The state output to check
+ * @param result the validation result to append to
+ */
+ private void validateEventTaskFieldCompatibilityOnStateOutput(final AxState state, final AxTask task,
+ final AxStateOutput stateOutput, AxValidationResult result) {
+ if (stateOutput == null) {
+ result.addValidationMessage(new AxValidationMessage(state.getKey(), this.getClass(),
+ ValidationResult.INVALID, "state output on task reference for task " + task.getID() + " is null"));
+
+ } else {
+ final AxEvent usedEvent = events.getEventMap().get(stateOutput.getOutgingEvent());
+ if (usedEvent == null) {
+ result.addValidationMessage(new AxValidationMessage(stateOutput.getKey(), this.getClass(),
+ ValidationResult.INVALID, "output event " + stateOutput.getOutgingEvent().getID()
+ + " for state output " + stateOutput.getID() + DOES_NOT_EXIST));
+ }
+
+ if (task != null && usedEvent != null) {
+ final Set<AxField> unhandledTaskOutputFields = new TreeSet<>(task.getOutputFieldSet());
+ unhandledTaskOutputFields.removeAll(usedEvent.getFields());
+ for (final AxField unhandledTaskOutputField : unhandledTaskOutputFields) {
+ result.addValidationMessage(new AxValidationMessage(state.getKey(), this.getClass(),
+ ValidationResult.INVALID, "task output field " + unhandledTaskOutputField + " for task "
+ + task.getID() + " not in output event " + usedEvent.getID()));
+ }
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxModel#clean()
+ */
+ @Override
+ public void clean() {
+ super.clean();
+ policies.clean();
+ tasks.clean();
+ events.clean();
+ albums.clean();
+ schemas.clean();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxModel#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append(super.toString());
+ builder.append(",policies=");
+ builder.append(policies);
+ builder.append(",tasks=");
+ builder.append(tasks);
+ builder.append(",events=");
+ builder.append(events);
+ builder.append(",albums=");
+ builder.append(albums);
+ builder.append(",schemas=");
+ builder.append(schemas);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxPolicyModel.class);
+
+ final AxPolicyModel copy = ((AxPolicyModel) copyObject);
+ super.copyTo(targetObject);
+ copy.setPolicies(new AxPolicies(policies));
+ copy.setTasks(new AxTasks(tasks));
+ copy.setEvents(new AxEvents(events));
+ copy.setAlbums(new AxContextAlbums(albums));
+ copy.setSchemas(new AxContextSchemas(schemas));
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxModel#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + super.hashCode();
+ result = prime * result + policies.hashCode();
+ result = prime * result + tasks.hashCode();
+ result = prime * result + events.hashCode();
+ result = prime * result + albums.hashCode();
+ result = prime * result + schemas.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxModel#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ throw new IllegalArgumentException("comparison object may not be null");
+ }
+
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxPolicyModel other = (AxPolicyModel) obj;
+ if (!super.equals(other)) {
+ return false;
+ }
+ if (!policies.equals(other.policies)) {
+ return false;
+ }
+ if (!tasks.equals(other.tasks)) {
+ return false;
+ }
+ if (!events.equals(other.events)) {
+ return false;
+ }
+ if (!albums.equals(other.albums)) {
+ return false;
+ }
+ return schemas.equals(other.schemas);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxModel#compareTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ Assertions.argumentNotNull(otherObj, "comparison object may not be null");
+
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxPolicyModel other = (AxPolicyModel) otherObj;
+ if (!super.equals(other)) {
+ return super.compareTo(other);
+ }
+ if (!policies.equals(other.policies)) {
+ return policies.compareTo(other.policies);
+ }
+ if (!tasks.equals(other.tasks)) {
+ return tasks.compareTo(other.tasks);
+ }
+ if (!events.equals(other.events)) {
+ return events.compareTo(other.events);
+ }
+ if (!albums.equals(other.albums)) {
+ return albums.compareTo(other.albums);
+ }
+ return schemas.compareTo(other.schemas);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxState.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxState.java
new file mode 100644
index 000000000..895232e1c
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxState.java
@@ -0,0 +1,1020 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Embedded;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyUse;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class holds the definition of a single state in a policy. A state is a single stage in a
+ * policy. A state has a single input event, its trigger. A state can output many events, but can
+ * only output one event on a single execution. After it executes, a state can pass control to
+ * another state or can simply emit its event to an external system. In the case where a state
+ * passes control to another state, the output event of the state becomes the input event of the
+ * next state. The outputs of a state {@link AxStateOutput} are held as a map in the state. Each
+ * state output contains the outgoing event of the state and optionally the next state to pass
+ * control to.
+ * <p>
+ * A state uses tasks {@link AxTask} to execute its logic. A state holds its tasks in a map and must
+ * have at least one task. A state uses Task Selection Logic {@link AxTaskSelectionLogic} to select
+ * which task should be executed in a given execution cycle. Optional Task Selection Logic can use
+ * fields on the incoming event and information from the context albums available on the state to
+ * decide what task to execute in a given context. The default task of a state is the task that is
+ * executed when task Selection Logic is not specified. In cases where only a single task is
+ * specified on a state, the default task must be that task and the state always executes that task.
+ * <p>
+ * What happens when a state completes its execution cycle depends on the task that is selected for
+ * execution by the state. Therefore, the action to be performed a state on execution of each task
+ * must be defined in the state as a {@link AxStateTaskReference} instance for each task defined in
+ * the state. The {@link AxStateTaskReference} instance defines the action to be performed as either
+ * a {@link AxStateTaskOutputType} of {@link AxStateTaskOutputType#DIRECT} or
+ * {@link AxStateTaskOutputType#LOGIC} and contains an {@link AxReferenceKey} reference to the
+ * instance that will complete the state output.
+ * <p>
+ * In the case of direct output, the {@link AxReferenceKey} reference in the
+ * {@link AxStateTaskReference} instance is a reference to an {@link AxStateOutput} instance. The
+ * state output defines the event to be emitted by the state and the next state to pass control to
+ * if any. All fields of the executed task are marshaled onto the outgoing event automatically by
+ * Apex.
+ * <p>
+ * In the case of logic output, the {@link AxReferenceKey} reference in the
+ * {@link AxStateTaskReference} instance is a reference to State Finalizer Logic in an
+ * {@link AxStateFinalizerLogic} instance, which selects the {@link AxStateOutput} that the state
+ * will use. The state finalizer logic uses fields emitted by the executed task and information from
+ * the context albums available on the state to decide what {@link AxStateOutput} to select in a
+ * given context. The state output defines the event to be emitted by the state and the next state
+ * to pass control to if any. The State Finalizer Logic instances for the state are held in a map in
+ * the state. State Finalizer Logic must marshal the fields of the output event in whatever manner
+ * it wishes; Apex does not automatically transfer the output fields from the task directly to the
+ * output event.
+ * <p>
+ * The Task Selection Logic instance or State Finalizer Logic instances in a state may use
+ * information in context albums to arrive at their task or state output selections. The context
+ * albums that the state uses and that should be made available to the state by Apex policy
+ * distribution are held as a set of references to context albums in the state.
+ * <p>
+ * During validation of a state, the validation checks listed below are executed:
+ * <ol>
+ * <li>The policy key must not be a null key and must be valid, see validation in
+ * {@link AxReferenceKey}
+ * <li>The trigger event key must not be a null key and must be valid, see validation in
+ * {@link AxArtifactKey}
+ * <li>At least one state output must be defined
+ * <li>Each state output in a state must have that state as its parent
+ * <li>Each state output must be valid, see validation in {@link AxStateOutput}
+ * <li>The next state defined in a state output must be unique in a state
+ * <li>The default task key must not be a null key and must be valid, see validation in
+ * {@link AxArtifactKey}
+ * <li>The default task must appear in the task map of the state
+ * <li>At least one task must be defined on the state
+ * <li>Each task key on the task map for the state must not be a null key and must be valid, see
+ * validation in {@link AxArtifactKey}
+ * <li>All state task references for each task in the state must exist and must be valid, see
+ * validation in {@link AxStateTaskReference}
+ * <li>Each state task reference in a state must have that state as its parent
+ * <li>For direct state outputs from tasks, the state output must be defined on the state
+ * <li>For logic state outputs from tasks, the State Finalizer Logic must be defined on the state
+ * <li>An observation is issued for each state output defined on the state that is not used as a
+ * direct output on a task
+ * <li>An observation is issued for each state finalizer logic instance defined on the state that is
+ * not used as an output on a task
+ * <li>Each context album key on the context album set for the state must not be a null key and must
+ * be valid, see validation in {@link AxArtifactKey}
+ * <li>Task Selection logic in a state must have that state as its parent
+ * <li>Task Selection logic in a state must be valid, see validation in {@link AxTaskSelectionLogic}
+ * <li>Each State Finalizer logic instance in a state must have that state as its parent
+ * <li>Each State Finalizer logic instance in a state must be valid, see validation in
+ * {@link AxStateFinalizerLogic}
+ * </ol>
+ */
+
+@Entity
+@Table(name = "AxState")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexState", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxState", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"key", "trigger", "stateOutputs", "contextAlbumReferenceSet", "taskSelectionLogic",
+ "stateFinalizerLogicMap", "defaultTask", "taskReferenceMap"})
+
+public class AxState extends AxConcept {
+ private static final String DOES_NOT_EQUAL_STATE_KEY = " does not equal state key";
+
+ private static final long serialVersionUID = 8041771382337655535L;
+
+ @EmbeddedId
+ @XmlElement(name = "stateKey", required = true)
+ private AxReferenceKey key;
+
+ // @formatter:off
+ @Embedded
+ @AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "inTriggerName")),
+ @AttributeOverride(name = "version", column = @Column(name = "inTriggerVersion"))})
+ @Column(name = "trigger")
+ @XmlElement(required = true)
+ private AxArtifactKey trigger;
+
+ @ManyToMany(cascade = CascadeType.ALL)
+ @JoinTable(
+ joinColumns = {@JoinColumn(name = "soParentKeyName", referencedColumnName = "parentKeyName"),
+ @JoinColumn(name = "soParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+ @JoinColumn(name = "soParentLocalName", referencedColumnName = "parentLocalName"),
+ @JoinColumn(name = "soLocalName", referencedColumnName = "localName")},
+ inverseJoinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
+ @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+ @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
+ @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
+ @XmlElement(name = "stateOutputs", required = true)
+ private Map<String, AxStateOutput> stateOutputs;
+
+ @ElementCollection
+ @CollectionTable(joinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
+ @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+ @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
+ @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
+ @XmlElement(name = "contextAlbumReference")
+ private Set<AxArtifactKey> contextAlbumReferenceSet;
+
+ @OneToOne
+ @JoinTable(name = "STATE_TSL_JT",
+ joinColumns = {
+ @JoinColumn(name = "tslParentKeyName", referencedColumnName = "parentKeyName", updatable = false,
+ insertable = false),
+ @JoinColumn(name = "tslParentKeyVersion", referencedColumnName = "parentKeyVersion",
+ updatable = false, insertable = false),
+ @JoinColumn(name = "tslParentLocalName ", referencedColumnName = "parentLocalName",
+ updatable = false, insertable = false),
+ @JoinColumn(name = "tslLocalName", referencedColumnName = "localName", updatable = false,
+ insertable = false)})
+ @XmlElement(required = true)
+ private AxTaskSelectionLogic taskSelectionLogic;
+
+ @ManyToMany(cascade = CascadeType.ALL)
+ @JoinTable(
+ joinColumns = {@JoinColumn(name = "sflParentKeyName", referencedColumnName = "parentKeyName"),
+ @JoinColumn(name = "sflParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+ @JoinColumn(name = "sflParentLocalName", referencedColumnName = "parentLocalName"),
+ @JoinColumn(name = "sflLocalName", referencedColumnName = "localName")},
+ inverseJoinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
+ @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+ @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
+ @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
+ @XmlElement(name = "stateFinalizerLogicMap", required = true)
+ private Map<String, AxStateFinalizerLogic> stateFinalizerLogicMap;
+
+ @Embedded
+ @AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "defaultTaskName")),
+ @AttributeOverride(name = "version", column = @Column(name = "defaultTaskVersion"))})
+ @Column(name = "defaultTask")
+ @XmlElement(required = true)
+ private AxArtifactKey defaultTask;
+
+ @ManyToMany(cascade = CascadeType.ALL)
+ @JoinTable(
+ joinColumns = {@JoinColumn(name = "trmParentKeyName", referencedColumnName = "parentKeyName"),
+ @JoinColumn(name = "trmParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+ @JoinColumn(name = "trmParentLocalName", referencedColumnName = "parentLocalName"),
+ @JoinColumn(name = "trmLocalName", referencedColumnName = "localName")},
+ inverseJoinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
+ @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+ @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
+ @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
+ @XmlElement(name = "taskReferences", required = true)
+ private Map<AxArtifactKey, AxStateTaskReference> taskReferenceMap;
+ // @formatter:on
+
+ /**
+ * The Default Constructor creates a state with a null reference key and with default values for
+ * all other fields.
+ */
+ public AxState() {
+ this(new AxReferenceKey());
+ contextAlbumReferenceSet = new TreeSet<>();
+ taskReferenceMap = new TreeMap<>();
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxState(final AxState copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Keyed Constructor creates a state with the given reference key and with default values
+ * for all other fields.
+ *
+ * @param key the reference key of the state
+ */
+ public AxState(final AxReferenceKey key) {
+ this(key, // Key
+ AxArtifactKey.getNullKey(), // Trigger Reference
+ new TreeMap<String, AxStateOutput>(), // State Outputs
+ new TreeSet<AxArtifactKey>(), // Context Album References
+ new AxTaskSelectionLogic(), // Task Selection Logic
+ new TreeMap<String, AxStateFinalizerLogic>(), // State Finalizer Logics
+ AxArtifactKey.getNullKey(), // Default Task
+ new TreeMap<AxArtifactKey, AxStateTaskReference>() // Task References
+ );
+ }
+
+ /**
+ * This Constructor creates a state with all its fields defined.
+ *
+ * @param key the reference key of the state
+ * @param trigger the event that triggers the state
+ * @param stateOutputs the possible state outputs for the state
+ * @param contextAlbumReferenceSet the context album reference set defines the context that may
+ * be used by Task Selection Logic and State Finalizer Logic in the state
+ * @param taskSelectionLogic the task selection logic that selects the task a state executes in
+ * an execution cycle
+ * @param stateFinalizerLogicMap the state finalizer logic instances that selects the state
+ * output to use after a task executes in a state execution cycle
+ * @param defaultTask the default task that will execute in a state if Task Selection Logic is
+ * not specified
+ * @param taskReferenceMap the task reference map that defines the tasks for the state and how
+ * the task outputs are handled
+ */
+ // CHECKSTYLE:OFF: checkstyle:parameterNumber
+ public AxState(final AxReferenceKey key, final AxArtifactKey trigger, final Map<String, AxStateOutput> stateOutputs,
+ final Set<AxArtifactKey> contextAlbumReferenceSet, final AxTaskSelectionLogic taskSelectionLogic,
+ final Map<String, AxStateFinalizerLogic> stateFinalizerLogicMap, final AxArtifactKey defaultTask,
+ final Map<AxArtifactKey, AxStateTaskReference> taskReferenceMap) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(trigger, "trigger may not be null");
+ Assertions.argumentNotNull(stateOutputs, "stateOutputs may not be null");
+ Assertions.argumentNotNull(contextAlbumReferenceSet, "contextAlbumReferenceSet may not be null");
+ Assertions.argumentNotNull(taskSelectionLogic, "taskSelectionLogic may not be null");
+ Assertions.argumentNotNull(stateFinalizerLogicMap, "stateFinalizerLogicMap may not be null");
+ Assertions.argumentNotNull(defaultTask, "defaultTask may not be null");
+ Assertions.argumentNotNull(taskReferenceMap, "taskReferenceMap may not be null");
+
+ this.key = key;
+ this.trigger = trigger;
+ this.stateOutputs = stateOutputs;
+ this.contextAlbumReferenceSet = contextAlbumReferenceSet;
+ this.taskSelectionLogic = taskSelectionLogic;
+ this.stateFinalizerLogicMap = stateFinalizerLogicMap;
+ this.defaultTask = defaultTask;
+ this.taskReferenceMap = taskReferenceMap;
+ }
+ // CHECKSTYLE:ON: checkstyle:parameterNumber
+
+ /**
+ * When a state is unmarshalled from disk or from the database, the parent of contained objects
+ * is not defined. This method is called by JAXB after unmarshaling and is used to set the
+ * parent keys of all {@link AxTaskSelectionLogic}, {@link AxStateOutput}, and
+ * {@link AxStateFinalizerLogic} instance in the state.
+ *
+ * @param u the unmarshaler that is unmarshaling the model
+ * @param parent the parent object of this object in the unmarshaler
+ */
+ public void afterUnmarshal(final Unmarshaller u, final Object parent) {
+ if (!taskSelectionLogic.getKey().getLocalName().equals(AxKey.NULL_KEY_NAME)) {
+ taskSelectionLogic.getKey().setParentReferenceKey(key);
+ }
+
+ for (final Entry<String, AxStateOutput> soEntry : stateOutputs.entrySet()) {
+ soEntry.getValue().getKey().setParentReferenceKey(key);
+ }
+
+ for (final Entry<String, AxStateFinalizerLogic> sflEntry : stateFinalizerLogicMap.entrySet()) {
+ sflEntry.getValue().getKey().setParentReferenceKey(key);
+ }
+
+ for (final Entry<AxArtifactKey, AxStateTaskReference> trEntry : taskReferenceMap.entrySet()) {
+ trEntry.getValue().getKey().setParentReferenceKey(key);
+ }
+ }
+
+ /**
+ * Gets the names of all the states that this state may pass control to.
+ *
+ * @return the list of possible states that may receive control when this state completes
+ * execution
+ */
+ public Set<String> getNextStateSet() {
+ final Set<String> nextStateSet = new TreeSet<>();
+
+ for (final AxStateOutput stateOutput : stateOutputs.values()) {
+ nextStateSet.add(stateOutput.getNextState().getLocalName());
+ }
+ return nextStateSet;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxReferenceKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = key.getKeys();
+ keyList.add(new AxKeyUse(trigger.getKey()));
+ for (final AxStateOutput stateOutput : stateOutputs.values()) {
+ keyList.addAll(stateOutput.getKeys());
+ }
+ for (final AxArtifactKey contextAlbumReferenceKey : contextAlbumReferenceSet) {
+ keyList.add(new AxKeyUse(contextAlbumReferenceKey));
+ }
+ if (!taskSelectionLogic.getKey().equals(AxReferenceKey.getNullKey())) {
+ keyList.addAll(taskSelectionLogic.getKeys());
+ }
+ for (final Entry<String, AxStateFinalizerLogic> stateFinalizerLogicEntry : stateFinalizerLogicMap.entrySet()) {
+ keyList.addAll(stateFinalizerLogicEntry.getValue().getKeys());
+ }
+ keyList.add(new AxKeyUse(defaultTask.getKey()));
+ for (final Entry<AxArtifactKey, AxStateTaskReference> taskReferenceEntry : taskReferenceMap.entrySet()) {
+ keyList.add(new AxKeyUse(taskReferenceEntry.getKey()));
+
+ // A state output is allowed to be used more than once but we only return one usage as a
+ // key
+ for (AxKey referencedKey : taskReferenceEntry.getValue().getKeys()) {
+ if (keyList.contains(referencedKey)) {
+ keyList.add(referencedKey);
+ }
+ }
+ }
+ return keyList;
+ }
+
+ /**
+ * Sets the reference key of the state.
+ *
+ * @param key the state reference key
+ */
+ public void setKey(final AxReferenceKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the event that triggers the state.
+ *
+ * @return the event that triggers the state
+ */
+ public AxArtifactKey getTrigger() {
+ return trigger;
+ }
+
+ /**
+ * Sets the event that triggers the state.
+ *
+ * @param trigger the event that triggers the state
+ */
+ public void setTrigger(final AxArtifactKey trigger) {
+ Assertions.argumentNotNull(trigger, "trigger may not be null");
+ this.trigger = trigger;
+ }
+
+ /**
+ * Gets the possible state outputs for the state.
+ *
+ * @return the the possible state outputs for the state
+ */
+ public Map<String, AxStateOutput> getStateOutputs() {
+ return stateOutputs;
+ }
+
+ /**
+ * Sets the the possible state outputs for the state.
+ *
+ * @param stateOutputs the the possible state outputs for the state
+ */
+ public void setStateOutputs(final Map<String, AxStateOutput> stateOutputs) {
+ Assertions.argumentNotNull(stateOutputs, "stateOutputs may not be null");
+ this.stateOutputs = stateOutputs;
+ }
+
+ /**
+ * Gets the context album reference set defines the context that may be used by Task Selection
+ * Logic and State Finalizer Logic in the state.
+ *
+ * @return the context album reference set defines the context that may be used by Task
+ * Selection Logic and State Finalizer Logic in the state
+ */
+ public Set<AxArtifactKey> getContextAlbumReferences() {
+ return contextAlbumReferenceSet;
+ }
+
+ /**
+ * Sets the context album reference set defines the context that may be used by Task Selection
+ * Logic and State Finalizer Logic in the state.
+ *
+ * @param contextAlbumReferences the context album reference set defines the context that may be
+ * used by Task Selection Logic and State Finalizer Logic in the state
+ */
+ public void setContextAlbumReferences(final Set<AxArtifactKey> contextAlbumReferences) {
+ Assertions.argumentNotNull(contextAlbumReferences, "contextAlbumReferenceSet may not be null");
+ this.contextAlbumReferenceSet = contextAlbumReferences;
+ }
+
+ /**
+ * Gets the task selection logic that selects the task a state executes in an execution cycle.
+ *
+ * @return the task selection logic that selects the task a state executes in an execution cycle
+ */
+ public AxTaskSelectionLogic getTaskSelectionLogic() {
+ return taskSelectionLogic;
+ }
+
+ /**
+ * Sets the task selection logic that selects the task a state executes in an execution cycle.
+ *
+ * @param taskSelectionLogic the task selection logic that selects the task a state executes in
+ * an execution cycle
+ */
+ public void setTaskSelectionLogic(final AxTaskSelectionLogic taskSelectionLogic) {
+ Assertions.argumentNotNull(taskSelectionLogic, "taskSelectionLogic may not be null");
+ this.taskSelectionLogic = taskSelectionLogic;
+ }
+
+ /**
+ * Check if task selection logic has been specified the state.
+ *
+ * @return true, if task selection logic has been specified
+ */
+ public boolean checkSetTaskSelectionLogic() {
+ return !taskSelectionLogic.getKey().equals(AxReferenceKey.getNullKey());
+ }
+
+ /**
+ * Gets the state finalizer logic instances that selects the state output to use after a task
+ * executes in a state execution cycle.
+ *
+ * @return the state finalizer logic instances that selects the state output to use after a task
+ * executes in a state execution cycle
+ */
+ public Map<String, AxStateFinalizerLogic> getStateFinalizerLogicMap() {
+ return stateFinalizerLogicMap;
+ }
+
+ /**
+ * Sets the state finalizer logic instances that selects the state output to use after a task
+ * executes in a state execution cycle.
+ *
+ * @param stateFinalizerLogicMap the state finalizer logic instances that selects the state
+ * output to use after a task executes in a state execution cycle
+ */
+ public void setStateFinalizerLogicMap(final Map<String, AxStateFinalizerLogic> stateFinalizerLogicMap) {
+ Assertions.argumentNotNull(stateFinalizerLogicMap, "stateFinalizerLogic may not be null");
+ this.stateFinalizerLogicMap = stateFinalizerLogicMap;
+ }
+
+ /**
+ * Gets the default task that will execute in a state if Task Selection Logic is not specified.
+ *
+ * @return the default task that will execute in a state if Task Selection Logic is not
+ * specified
+ */
+ public AxArtifactKey getDefaultTask() {
+ return defaultTask;
+ }
+
+ /**
+ * Sets the default task that will execute in a state if Task Selection Logic is not specified.
+ *
+ * @param defaultTask the default task that will execute in a state if Task Selection Logic is
+ * not specified
+ */
+ public void setDefaultTask(final AxArtifactKey defaultTask) {
+ Assertions.argumentNotNull(defaultTask, "defaultTask may not be null");
+ this.defaultTask = defaultTask;
+ }
+
+ /**
+ * Gets the task reference map that defines the tasks for the state and how the task outputs are
+ * handled.
+ *
+ * @return the task reference map that defines the tasks for the state and how the task outputs
+ * are handled
+ */
+ public Map<AxArtifactKey, AxStateTaskReference> getTaskReferences() {
+ return taskReferenceMap;
+ }
+
+ /**
+ * Sets the task reference map that defines the tasks for the state and how the task outputs are
+ * handled.
+ *
+ * @param taskReferences the task reference map that defines the tasks for the state and how the
+ * task outputs are handled
+ */
+ public void setTaskReferences(final Map<AxArtifactKey, AxStateTaskReference> taskReferences) {
+ Assertions.argumentNotNull(taskReferences, "taskReferenceMap may not be null");
+ this.taskReferenceMap = taskReferences;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxReferenceKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (trigger.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "trigger is a null key: " + trigger));
+ }
+ result = trigger.validate(result);
+
+ if (stateOutputs.size() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "stateOutputs may not be empty"));
+ } else {
+ validateStateOutputs(result);
+ }
+
+ validateContextAlbumReferences(result);
+ result = validateTaskSelectionLogic(result);
+ validateStateFinalizerLogics(result);
+
+ if (defaultTask.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "default task has a null key: " + defaultTask));
+ }
+ result = defaultTask.validate(result);
+
+ if (taskReferenceMap.size() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "taskReferenceMap may not be empty"));
+ } else {
+ validateStateTaskReferences(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate the state outputs of the state
+ *
+ * @param result the validation result to append to
+ */
+ private void validateStateOutputs(AxValidationResult result) {
+ final Set<String> nextStateNameSet = new TreeSet<>();
+ for (final Entry<String, AxStateOutput> stateOutputEntry : stateOutputs.entrySet()) {
+ if (stateOutputEntry.getValue() == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "null state output value found on state output " + stateOutputEntry.getKey()));
+ } else {
+ if (!stateOutputEntry.getValue().getKey().getParentReferenceKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "parent key on state output " + stateOutputEntry.getKey() + DOES_NOT_EQUAL_STATE_KEY));
+ }
+
+ if (stateOutputEntry.getValue().getNextState().getLocalName().equals(key.getLocalName())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "state output next state " + stateOutputEntry.getValue().getNextState().getLocalName()
+ + " may not be this state"));
+
+ }
+
+ if (nextStateNameSet.contains(stateOutputEntry.getValue().getNextState().getLocalName())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "duplicate state output next state name "
+ + stateOutputEntry.getValue().getNextState().getLocalName() + " found"));
+ } else {
+ nextStateNameSet.add(stateOutputEntry.getValue().getNextState().getLocalName());
+ }
+ result = stateOutputEntry.getValue().validate(result);
+ }
+ }
+ }
+
+ /**
+ * Validate the context album references of the state
+ *
+ * @param result the validation result to append to
+ */
+ private void validateContextAlbumReferences(AxValidationResult result) {
+ for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
+ if (contextAlbumReference.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "key on context album reference entry " + contextAlbumReference.getKey()
+ + " may not be the null key"));
+ }
+
+ result = contextAlbumReference.validate(result);
+ }
+ }
+
+ /**
+ * Validate the task selection logic of the state
+ *
+ * @param result the validation result to append to
+ * @return the result of the validation
+ */
+ private AxValidationResult validateTaskSelectionLogic(AxValidationResult result) {
+ if (!taskSelectionLogic.getKey().equals(AxReferenceKey.getNullKey())) {
+ if (!taskSelectionLogic.getKey().getParentReferenceKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "taskSelectionLogic key " + taskSelectionLogic.getKey().getID() + DOES_NOT_EQUAL_STATE_KEY));
+ }
+ result = taskSelectionLogic.validate(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate all the state finalizer logic of the state
+ *
+ * @param result the validation result to append to
+ */
+ private void validateStateFinalizerLogics(AxValidationResult result) {
+ for (final Entry<String, AxStateFinalizerLogic> stateFinalizerLogicEntry : stateFinalizerLogicMap.entrySet()) {
+ if (stateFinalizerLogicEntry.getValue() == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "null state finalizer logic value found on state finalizer entry "
+ + stateFinalizerLogicEntry.getKey()));
+ } else {
+ if (!stateFinalizerLogicEntry.getValue().getKey().getParentReferenceKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "stateFinalizerLogic parent key " + stateFinalizerLogicEntry.getValue().getKey().getID()
+ + DOES_NOT_EQUAL_STATE_KEY));
+ }
+
+ result = stateFinalizerLogicEntry.getValue().validate(result);
+ }
+ }
+ }
+
+ /**
+ * Validate the tasks used the state
+ *
+ * @param result the validation result to append to
+ */
+ private void validateStateTaskReferences(AxValidationResult result) {
+ final Set<String> usedStateOutputNameSet = new TreeSet<>();
+ final Set<String> usedStateFinalizerLogicNameSet = new TreeSet<>();
+
+ for (final Entry<AxArtifactKey, AxStateTaskReference> taskRefEntry : taskReferenceMap.entrySet()) {
+ if (taskRefEntry.getKey().equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "task has a null key: " + taskRefEntry.getKey()));
+ }
+ result = taskRefEntry.getKey().validate(result);
+
+ if (taskRefEntry.getValue() == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "null task reference value found on task reference " + taskRefEntry.getKey()));
+ } else {
+ result = validateStateTaskReference(taskRefEntry.getKey(), taskRefEntry.getValue(),
+ usedStateOutputNameSet, usedStateFinalizerLogicNameSet, result);
+ }
+ }
+
+ final Set<String> unUsedStateOutputNameSet = new TreeSet<>(stateOutputs.keySet());
+ unUsedStateOutputNameSet.removeAll(usedStateOutputNameSet);
+ for (final String unUsedStateOutputName : unUsedStateOutputNameSet) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION,
+ "state output " + unUsedStateOutputName + " is not used directly by any task"));
+ }
+
+ final Set<String> usnUedStateFinalizerLogicNameSet = new TreeSet<>(stateFinalizerLogicMap.keySet());
+ usnUedStateFinalizerLogicNameSet.removeAll(usedStateFinalizerLogicNameSet);
+ for (final String unusedStateFinalizerLogicName : usnUedStateFinalizerLogicNameSet) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION,
+ "state finalizer logic " + unusedStateFinalizerLogicName + " is not used by any task"));
+ }
+
+ if (!taskReferenceMap.containsKey(defaultTask)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "defaultTask " + defaultTask + " not found in taskReferenceMap"));
+ }
+ }
+
+ /**
+ * Validate the references of a task used in a state
+ *
+ * @param taskKey The key of the task
+ * @param taskReference the task reference of the task
+ * @param stateOutputNameSet State outputs that have been used so far, will be appended for this
+ * task reference
+ * @param stateFinalizerLogicNameSet State finalizers that have been used so far, may be
+ * appended if this task reference uses a finalzier
+ * @param result the validation result to append to
+ * @return the result of the validation
+ */
+ private AxValidationResult validateStateTaskReference(final AxArtifactKey taskKey,
+ final AxStateTaskReference taskReference, Set<String> stateOutputNameSet,
+ Set<String> stateFinalizerLogicNameSet, AxValidationResult result) {
+ if (!taskReference.getKey().getParentReferenceKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "stateTaskReference parent key " + taskReference.getKey().getID() + DOES_NOT_EQUAL_STATE_KEY));
+ }
+
+ if (taskReference.getStateTaskOutputType().equals(AxStateTaskOutputType.DIRECT)) {
+ if (stateOutputs.containsKey(taskReference.getOutput().getLocalName())) {
+ stateOutputNameSet.add(taskReference.getOutput().getLocalName());
+ } else {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "state output for task " + taskKey + " not found in stateOutputs"));
+ }
+ } else if (taskReference.getStateTaskOutputType().equals(AxStateTaskOutputType.LOGIC)) {
+ if (stateFinalizerLogicMap.containsKey(taskReference.getOutput().getLocalName())) {
+ stateFinalizerLogicNameSet.add(taskReference.getOutput().getLocalName());
+ } else {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "state finalizer logic for task " + taskKey + " not found in stateFinalizerLogicMap"));
+ }
+ } else {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "stateTaskReference task output type " + taskReference.getStateTaskOutputType() + " is invalid"));
+ }
+
+ return taskReference.validate(result);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ trigger.clean();
+ for (final AxStateOutput stateOutput : stateOutputs.values()) {
+ stateOutput.clean();
+ }
+ for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
+ contextAlbumReference.clean();
+ }
+ taskSelectionLogic.clean();
+ for (final AxStateFinalizerLogic stateFinalizerLogic : stateFinalizerLogicMap.values()) {
+ stateFinalizerLogic.clean();
+ }
+ defaultTask.clean();
+ for (final AxStateTaskReference taskReference : taskReferenceMap.values()) {
+ taskReference.clean();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("stateKey=");
+ builder.append(key);
+ builder.append(",trigger=");
+ builder.append(trigger);
+ builder.append(",stateOutputs=");
+ builder.append(stateOutputs);
+ builder.append(",contextAlbumReferenceSet=");
+ builder.append(contextAlbumReferenceSet);
+ builder.append(",taskSelectionLogic=");
+ builder.append(taskSelectionLogic);
+ builder.append(",stateFinalizerLogicSet=");
+ builder.append(stateFinalizerLogicMap);
+ builder.append(",defaultTask=");
+ builder.append(defaultTask);
+ builder.append(",taskReferenceMap=");
+ builder.append(taskReferenceMap);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxState.class);
+
+ final AxState copy = ((AxState) copyObject);
+ copy.setKey(new AxReferenceKey(key));
+ copy.setTrigger(new AxArtifactKey(trigger));
+
+ final Map<String, AxStateOutput> newStateOutputs = new TreeMap<>();
+ for (final Entry<String, AxStateOutput> stateOutputEntry : stateOutputs.entrySet()) {
+ newStateOutputs.put(stateOutputEntry.getKey(), new AxStateOutput(stateOutputEntry.getValue()));
+ }
+ copy.setStateOutputs(newStateOutputs);
+
+ final Set<AxArtifactKey> newContextUsage = new TreeSet<>();
+ for (final AxArtifactKey contextAlbumReferenceItem : contextAlbumReferenceSet) {
+ newContextUsage.add(new AxArtifactKey(contextAlbumReferenceItem));
+ }
+ copy.setContextAlbumReferences(newContextUsage);
+
+ copy.setTaskSelectionLogic(new AxTaskSelectionLogic(taskSelectionLogic));
+
+ final Map<String, AxStateFinalizerLogic> newStateFinalizerLogicMap = new TreeMap<>();
+ for (final Entry<String, AxStateFinalizerLogic> stateFinalizerLogicEntry : stateFinalizerLogicMap.entrySet()) {
+ newStateFinalizerLogicMap.put(stateFinalizerLogicEntry.getKey(),
+ new AxStateFinalizerLogic(stateFinalizerLogicEntry.getValue()));
+ }
+ copy.setStateFinalizerLogicMap(newStateFinalizerLogicMap);
+
+ copy.setDefaultTask(new AxArtifactKey(defaultTask));
+
+ final Map<AxArtifactKey, AxStateTaskReference> newTaskReferenceMap = new TreeMap<>();
+ for (final Entry<AxArtifactKey, AxStateTaskReference> taskReferenceEntry : taskReferenceMap.entrySet()) {
+ newTaskReferenceMap.put(new AxArtifactKey(taskReferenceEntry.getKey()),
+ new AxStateTaskReference(taskReferenceEntry.getValue()));
+ }
+ copy.setTaskReferences(newTaskReferenceMap);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + trigger.hashCode();
+ result = prime * result + stateOutputs.hashCode();
+ result = prime * result + contextAlbumReferenceSet.hashCode();
+ result = prime * result + taskSelectionLogic.hashCode();
+ result = prime * result + stateFinalizerLogicMap.hashCode();
+ result = prime * result + defaultTask.hashCode();
+ result = prime * result + taskReferenceMap.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxState other = (AxState) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ if (!trigger.equals(other.trigger)) {
+ return false;
+ }
+ if (!stateOutputs.equals(other.stateOutputs)) {
+ return false;
+ }
+ if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
+ return false;
+ }
+ if (!taskSelectionLogic.equals(other.taskSelectionLogic)) {
+ return false;
+ }
+ if (!stateFinalizerLogicMap.equals(other.stateFinalizerLogicMap)) {
+ return false;
+ }
+ if (!defaultTask.equals(other.defaultTask)) {
+ return false;
+ }
+ return taskReferenceMap.equals(other.taskReferenceMap);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxState other = (AxState) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!trigger.equals(other.trigger)) {
+ return trigger.compareTo(other.trigger);
+ }
+ if (!stateOutputs.equals(other.stateOutputs)) {
+ return stateOutputs.hashCode() - other.stateOutputs.hashCode();
+ }
+ if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
+ return (contextAlbumReferenceSet.hashCode() - other.contextAlbumReferenceSet.hashCode());
+ }
+ if (!taskSelectionLogic.equals(other.taskSelectionLogic)) {
+ return taskSelectionLogic.compareTo(other.taskSelectionLogic);
+ }
+ if (!stateFinalizerLogicMap.equals(other.stateFinalizerLogicMap)) {
+ return stateFinalizerLogicMap.hashCode() - other.stateFinalizerLogicMap.hashCode();
+ }
+ if (!defaultTask.equals(other.defaultTask)) {
+ return defaultTask.compareTo(other.defaultTask);
+ }
+ if (!taskReferenceMap.equals(other.taskReferenceMap)) {
+ return (taskReferenceMap.hashCode() - other.taskReferenceMap.hashCode());
+ }
+
+ return 0;
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateFinalizerLogic.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateFinalizerLogic.java
new file mode 100644
index 000000000..76704b051
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateFinalizerLogic.java
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import javax.persistence.Entity;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+
+/**
+ * This class holds State Finalizer Logic for {@link AxState} states in Apex. It is a specialization
+ * of the {@link AxLogic} class, so that State Finalizer Logic in Apex states can be strongly typed.
+ * <p>
+ * State Finalizer Logic is used to select the output {@link AxStateOutput} that a state will use.
+ * The logic uses fields emitted by the executed {@link AxTask} task and information from the
+ * context albums available on a state to decide what state output {@link AxStateOutput} to select
+ * in a given context. State Finalizer Logic must marshal the output fields from the task onto the
+ * output event in whatever manner is appropriate for the domain being handled.
+ * <p>
+ * Validation uses standard Apex Logic validation, see validation in {@link AxLogic}.
+ */
+@Entity
+@Table(name = "AxStateFinalizerLogic")
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexStateFinalizerLogic", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxStateFinalizerLogic", namespace = "http://www.onap.org/policy/apex-pdp")
+
+public class AxStateFinalizerLogic extends AxLogic {
+ private static final long serialVersionUID = 2090324845463750391L;
+
+ /**
+ * The Default Constructor creates a logic instance with a null key, undefined logic flavour and
+ * a null logic string.
+ */
+ public AxStateFinalizerLogic() {
+ super();
+ }
+
+ /**
+ * The Key Constructor creates a logic instance with the given reference key, undefined logic
+ * flavour and a null logic string.
+ *
+ * @param key the reference key of the logic
+ */
+ public AxStateFinalizerLogic(final AxReferenceKey key) {
+ super(key, LOGIC_FLAVOUR_UNDEFINED, "");
+ }
+
+ /**
+ * This Constructor creates a logic instance with a reference key constructed from the parents
+ * key and the logic local name and all of its fields defined.
+ *
+ * @param parentKey the reference key of the parent of this logic
+ * @param logicName the logic name, held as the local name of the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxStateFinalizerLogic(final AxReferenceKey parentKey, final String logicName, final String logicFlavour,
+ final String logic) {
+ super(parentKey, logicName, logicFlavour, logic);
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and all of its fields
+ * defined.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxStateFinalizerLogic(final AxReferenceKey key, final String logicFlavour, final String logic) {
+ super(key, logicFlavour, logic);
+ }
+
+ /**
+ * This Constructor creates a logic instance by cloning the fields from another logic instance
+ * into this logic instance.
+ *
+ * @param logic the logic instance to clone from
+ */
+ public AxStateFinalizerLogic(final AxLogic logic) {
+ super(new AxReferenceKey(logic.getKey()), logic.getLogicFlavour(), logic.getLogic());
+ }
+
+ /**
+ * This Constructor creates a logic instance with a reference key constructed from the parents
+ * key and the logic local name, the given logic flavour, with the logic being provided by the
+ * given logic reader instance.
+ *
+ * @param parentKey the reference key of the parent of this logic
+ * @param logicName the logic name, held as the local name of the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logicReader the logic reader to use to read the logic for this logic instance
+ */
+ public AxStateFinalizerLogic(final AxReferenceKey parentKey, final String logicName, final String logicFlavour,
+ final AxLogicReader logicReader) {
+ super(new AxReferenceKey(parentKey, logicName), logicFlavour, logicReader);
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and logic flavour, the
+ * logic is provided by the given logic reader instance.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logicReader the logic reader to use to read the logic for this logic instance
+ */
+ public AxStateFinalizerLogic(final AxReferenceKey key, final String logicFlavour, final AxLogicReader logicReader) {
+ super(key, logicFlavour, logicReader);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateOutput.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateOutput.java
new file mode 100644
index 000000000..a0c73c260
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateOutput.java
@@ -0,0 +1,389 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyUse;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class defines a single output that a state can have. A state can have many outputs with each
+ * output defined as an instance of this class. Each state output defines the output event that will
+ * be emitted when this output is selected and optionally the next state that is executed when this
+ * state output is selected. If no next state is defined (the next state is a null
+ * {@link AxReferenceKey} key), then this state output outputs its event to an external system and
+ * is an output state for the full policy.
+ * <p>
+ * During validation of a state output, the validation checks listed below are executed:
+ * <ol>
+ * <li>The state output key must not be a null key and must be valid, see validation in
+ * {@link AxReferenceKey}
+ * <li>The outgoing event key must not be a null key and must be valid, see validation in
+ * {@link AxArtifactKey}
+ * <li>The next state key must be valid, see validation in {@link AxReferenceKey}
+ * </ol>
+ */
+
+@Entity
+@Table(name = "AxStateOutput")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexStateOutput", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxStateOutput", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"key", "outgoingEvent", "nextState"})
+
+public class AxStateOutput extends AxConcept {
+ private static final long serialVersionUID = 8041771382337655535L;
+
+ @EmbeddedId
+ @XmlElement(name = "key", required = true)
+ private AxReferenceKey key;
+
+ // @formatter:off
+ @Embedded
+ @AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "outgoingEventName")),
+ @AttributeOverride(name = "version", column = @Column(name = "outgoingEventVersion"))})
+ @Column(name = "outgoingEvent")
+ @XmlElement(required = true)
+ private AxArtifactKey outgoingEvent;
+
+ @Embedded
+ @AttributeOverrides({@AttributeOverride(name = "parentKeyName", column = @Column(name = "nextStateParentKeyName")),
+ @AttributeOverride(name = "parentKeyVersion", column = @Column(name = "nextStateParentKeyVersion")),
+ @AttributeOverride(name = "parentLocalName", column = @Column(name = "nextStateParentLocalName")),
+ @AttributeOverride(name = "localName", column = @Column(name = "nextStateLocalName"))})
+ @Column(name = "nextState")
+ @XmlElement(required = true)
+ private AxReferenceKey nextState;
+ // @formatter:on
+
+ /**
+ * The Default Constructor creates a state output instance with a null reference key, outgoing
+ * event key and next state reference key.
+ */
+ public AxStateOutput() {
+ this(new AxReferenceKey());
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxStateOutput(final AxStateOutput copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Keyed Constructor creates a state output instance with the given reference key, outgoing
+ * event key and next state reference key.
+ *
+ * @param key the reference key for the state output
+ */
+ public AxStateOutput(final AxReferenceKey key) {
+ this(key, // Key
+ AxArtifactKey.getNullKey(), // Outgoing Event
+ AxReferenceKey.getNullKey() // Next State
+ );
+ }
+
+ /**
+ * This Constructor creates a state output with a reference key composed of the given parent key
+ * and with a local name composed from the parent key local name concatenated with the next
+ * state's local name. The next state and outgoing event of the state output are set as
+ * specified.
+ *
+ * @param parentKey the parent key of the state output
+ * @param nextState the next state to which execution will pass on use of this state output
+ * @param outgoingEvent the outgoing event emitted on use of this state output
+ */
+ public AxStateOutput(final AxReferenceKey parentKey, final AxReferenceKey nextState,
+ final AxArtifactKey outgoingEvent) {
+ this(new AxReferenceKey(parentKey, parentKey.getLocalName() + '_' + nextState.getLocalName()), outgoingEvent,
+ nextState);
+ }
+
+ /**
+ * This Constructor creates a state output with the specified reference key. The next state and
+ * outgoing event of the state output are set as specified.
+ *
+ * @param key the key
+ * @param nextState the next state to which execution will pass on use of this state output
+ * @param outgoingEvent the outgoing event emitted on use of this state output
+ */
+ public AxStateOutput(final AxReferenceKey key, final AxArtifactKey outgoingEvent, final AxReferenceKey nextState) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(outgoingEvent, "outgoingEvent may not be null");
+ Assertions.argumentNotNull(nextState, "nextState may not be null");
+
+ this.key = key;
+ this.outgoingEvent = outgoingEvent;
+ this.nextState = nextState;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxReferenceKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = key.getKeys();
+ keyList.add(new AxKeyUse(outgoingEvent));
+
+ if (!nextState.equals(AxReferenceKey.getNullKey())) {
+ keyList.add(new AxKeyUse(nextState));
+ }
+
+ return keyList;
+ }
+
+ /**
+ * Sets the reference key for the state output.
+ *
+ * @param key the reference key for the state output
+ */
+ public void setKey(final AxReferenceKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the outgoing event emitted on use of this state output.
+ *
+ * @return the outgoing event emitted on use of this state output
+ */
+ public AxArtifactKey getOutgingEvent() {
+ return outgoingEvent;
+ }
+
+ /**
+ * Sets the outgoing event emitted on use of this state output.
+ *
+ * @param outgoingEvent the outgoing event emitted on use of this state output
+ */
+ public void setOutgoingEvent(final AxArtifactKey outgoingEvent) {
+ Assertions.argumentNotNull(outgoingEvent, "outgoingEvent may not be null");
+ this.outgoingEvent = outgoingEvent;
+ }
+
+ /**
+ * Gets the next state to which execution will pass on use of this state output.
+ *
+ * @return the next state to which execution will pass on use of this state output
+ */
+ public AxReferenceKey getNextState() {
+ return nextState;
+ }
+
+ /**
+ * Sets the next state to which execution will pass on use of this state output.
+ *
+ * @param nextState the next state to which execution will pass on use of this state output
+ */
+ public void setNextState(final AxReferenceKey nextState) {
+ Assertions.argumentNotNull(nextState, "nextState may not be null");
+ this.nextState = nextState;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxReferenceKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (outgoingEvent.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "outgoingEvent reference is a null key, an outgoing event must be specified"));
+ }
+ result = outgoingEvent.validate(result);
+
+ // Note: Null keys are allowed on nextState as there may not be a next state
+ result = nextState.validate(result);
+
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ outgoingEvent.clean();
+ nextState.clean();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("stateKey=");
+ builder.append(key);
+ builder.append(",outgoingEvent=");
+ builder.append(outgoingEvent);
+ builder.append(",nextState=");
+ builder.append(nextState);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxStateOutput.class);
+
+ final AxStateOutput copy = ((AxStateOutput) copyObject);
+ copy.setKey(new AxReferenceKey(key));
+ copy.setOutgoingEvent(new AxArtifactKey(outgoingEvent));
+ copy.setNextState(nextState);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + outgoingEvent.hashCode();
+ result = prime * result + nextState.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxStateOutput other = (AxStateOutput) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ if (!outgoingEvent.equals(other.outgoingEvent)) {
+ return false;
+ }
+ return nextState.equals(other.nextState);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxStateOutput other = (AxStateOutput) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!outgoingEvent.equals(other.outgoingEvent)) {
+ return outgoingEvent.compareTo(other.outgoingEvent);
+ }
+ return nextState.compareTo(other.nextState);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskOutputType.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskOutputType.java
new file mode 100644
index 000000000..741eb8833
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskOutputType.java
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * This enumeration defines the type of state output selection that is defined for a task in a
+ * state. The {@link AxStateTaskReference} instance for each task uses this enumeration to decide
+ * what type of output selection to use when a task has completed execution.
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "AxStateTaskOutputType", namespace = "http://www.onap.org/policy/apex-pdp")
+
+public enum AxStateTaskOutputType {
+ /** The state output selection for the task has not been defined. */
+ UNDEFINED,
+ /**
+ * Direct state output selection has been selected, the task will select a {@link AxStateOutput}
+ * directly.
+ */
+ DIRECT,
+ /**
+ * Logic state output selection has been selected, the task will select a {@link AxStateOutput}
+ * using logic defined in a {@link AxStateFinalizerLogic} instance.
+ */
+ LOGIC
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskReference.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskReference.java
new file mode 100644
index 000000000..011af6cbb
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTaskReference.java
@@ -0,0 +1,400 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyUse;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class defines the type of output handling that will be used when a task in a state completes
+ * execution. Each task {@link AxTask} in a state {@link AxState} must select a state output
+ * {@link AxStateOutput} in order to pass its fields to an output event. Therefore, each task has an
+ * associated instance of this class that defines how the state output of the state is selected and
+ * how the output fields of the task are marshaled onto the fields of the output event. A
+ * {@link AxStateTaskReference} instance defines the task output handling as either
+ * {@link AxStateTaskOutputType#DIRECT} or {@link AxStateTaskOutputType#LOGIC}. In the case of
+ * {@link AxStateTaskOutputType#DIRECT} output selection, the output reference key held in this
+ * {@link AxStateTaskReference} instance to an instance of an {@link AxStateOutput} class. In the
+ * case of {@link AxStateTaskOutputType#LOGIC} output selection, the output reference key held in
+ * this {@link AxStateTaskReference} instance to an instance of an {@link AxStateFinalizerLogic}
+ * class. See the explanation in the {@link AxState} class for a full description of this handling.
+ * <p>
+ *
+ * During validation of a state task reference, the validation checks listed below are executed:
+ * <ol>
+ * <li>The state task reference key must not be a null key and must be valid, see validation in
+ * {@link AxReferenceKey}
+ * <li>The output type must be defined, that is not equal to {@link AxStateTaskOutputType#UNDEFINED}
+ * <li>The output key must not be a null key and must be valid, see validation in
+ * {@link AxReferenceKey}
+ * </ol>
+ */
+
+@Entity
+@Table(name = "AxStateTaskReference")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexStateTaskReference", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxStateTaskReference", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"key", "outputType", "output"})
+
+public class AxStateTaskReference extends AxConcept {
+ private static final long serialVersionUID = 8041771382337655535L;
+
+ @EmbeddedId
+ @XmlElement(name = "key", required = true)
+ private AxReferenceKey key;
+
+ @Enumerated
+ @Column(name = "outputType")
+ @XmlElement(required = true)
+ private AxStateTaskOutputType outputType;
+
+ // @formatter:off
+ @Embedded
+ @AttributeOverrides({@AttributeOverride(name = "parentKeyName", column = @Column(name = "outputParentKeyName")),
+ @AttributeOverride(name = "parentKeyVersion", column = @Column(name = "outputParentKeyVersion")),
+ @AttributeOverride(name = "parentLocalName", column = @Column(name = "outputParentLocalName")),
+ @AttributeOverride(name = "localName", column = @Column(name = "outputLocalName"))})
+ @Column(name = "output")
+ @XmlElement(required = true)
+ private AxReferenceKey output;
+ // @formatter:on
+
+ /**
+ * The Default Constructor creates a state task reference with a null reference key, an
+ * undefined output type and a null output reference key.
+ */
+ public AxStateTaskReference() {
+ this(new AxReferenceKey());
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxStateTaskReference(final AxStateTaskReference copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Keyed Constructor creates a state task reference with the given reference key, an
+ * undefined output type and a null output reference key.
+ *
+ * @param key the key
+ */
+ public AxStateTaskReference(final AxReferenceKey key) {
+ this(key, // Key
+ AxStateTaskOutputType.UNDEFINED, // Output type
+ AxReferenceKey.getNullKey()); // Output
+ }
+
+ /**
+ * This Constructor creates a state task reference instance with a reference key composed from
+ * the given parent key with a local name composed by concatenating the name of the task key
+ * with the local name of the output. The output type and output are set to the given values.
+ *
+ * @param parentKey the parent key to use for the key of the state task reference
+ * @param taskKey the task key to use for the first part of the state task reference local name
+ * @param outputType the type of output to perform when this state task reference instance is
+ * used
+ * @param output the output to perform when this state task reference instance is used
+ */
+ public AxStateTaskReference(final AxReferenceKey parentKey, final AxArtifactKey taskKey,
+ final AxStateTaskOutputType outputType, final AxReferenceKey output) {
+ this(new AxReferenceKey(parentKey, taskKey.getName() + '_' + outputType.name() + '_' + output.getLocalName()),
+ outputType, output);
+ }
+
+ /**
+ * This Constructor creates a state task reference instance with the given reference key and all
+ * its fields defined.
+ *
+ * @param key the key of the state task reference
+ * @param outputType the type of output to perform when this state task reference instance is
+ * used
+ * @param output the output to perform when this state task reference instance is used
+ */
+ public AxStateTaskReference(final AxReferenceKey key, final AxStateTaskOutputType outputType,
+ final AxReferenceKey output) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(outputType, "outputType may not be null");
+ Assertions.argumentNotNull(output, "output may not be null");
+
+ this.key = key;
+ this.outputType = outputType;
+ this.output = output;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxReferenceKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = key.getKeys();
+
+ if (!output.equals(AxReferenceKey.getNullKey())) {
+ keyList.add(new AxKeyUse(output));
+ }
+
+ return keyList;
+ }
+
+ /**
+ * Sets the key of the state task reference.
+ *
+ * @param key the key of the state task reference
+ */
+ public void setKey(final AxReferenceKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the type of output to perform when this state task reference instance is used.
+ *
+ * @return the the type of output to perform when this state task reference instance is used
+ */
+ public AxStateTaskOutputType getStateTaskOutputType() {
+ return outputType;
+ }
+
+ /**
+ * Sets the type of output to perform when this state task reference instance is used.
+ *
+ * @param stateTaskOutputType the type of output to perform when this state task reference
+ * instance is used
+ */
+ public void setStateTaskOutputType(final AxStateTaskOutputType stateTaskOutputType) {
+ Assertions.argumentNotNull(stateTaskOutputType, "outputType may not be null");
+ this.outputType = stateTaskOutputType;
+ }
+
+ /**
+ * Gets the output to perform when this state task reference instance is used.
+ *
+ * @return the output to perform when this state task reference instance is used
+ */
+ public AxReferenceKey getOutput() {
+ return output;
+ }
+
+ /**
+ * Sets the output to perform when this state task reference instance is used.
+ *
+ * @param output the output to perform when this state task reference instance is used
+ */
+ public void setOutput(final AxReferenceKey output) {
+ Assertions.argumentNotNull(output, "output may not be null");
+ this.output = output;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxReferenceKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (outputType == AxStateTaskOutputType.UNDEFINED) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "outputType may not be UNDEFINED"));
+ }
+
+ if (output.equals(AxReferenceKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "output key " + output.getID() + " is a null key"));
+ }
+ result = output.validate(result);
+
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ output.clean();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("stateKey=");
+ builder.append(key);
+ builder.append(",outputType=");
+ builder.append(outputType);
+ builder.append(",output=");
+ builder.append(output);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxStateTaskReference.class);
+
+ final AxStateTaskReference copy = ((AxStateTaskReference) copyObject);
+ copy.setKey(new AxReferenceKey(key));
+ copy.setStateTaskOutputType(AxStateTaskOutputType.valueOf(outputType.name()));
+ copy.setOutput(output);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + outputType.hashCode();
+ result = prime * result + output.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxStateTaskReference other = (AxStateTaskReference) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ if (outputType != other.outputType) {
+ return false;
+ }
+ return output.equals(other.output);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxStateTaskReference other = (AxStateTaskReference) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!outputType.equals(other.outputType)) {
+ return outputType.compareTo(other.outputType);
+ }
+ return output.compareTo(other.output);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTree.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTree.java
new file mode 100644
index 000000000..30076ca0b
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateTree.java
@@ -0,0 +1,157 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * The Class is used to return the tree that represents the state branches or chains in a policy. It
+ * creates a tree that holds the state fan out branches in a policy that starts from the given top
+ * state of the tree. Each branch from a state is held in a set of next states for the top state and
+ * each branch in the state tree is itself a {@link AxStateTree} instance.
+ * <p>
+ * Validation checks for recursive state use, in other words validation forbids the use of a given
+ * state more than once in a state tree.
+ */
+public class AxStateTree implements Comparable<AxStateTree> {
+ private final AxState thisState;
+ private final Set<AxStateTree> nextStates;
+
+ /**
+ * This constructor recursively creates a state tree for the given policy starting at the given
+ * state.
+ *
+ * @param policy the policy from which to read states
+ * @param thisState the state to start state tree construction at
+ * @param referencedStateNameSet a set of state names already referenced in the tree, null for
+ * the first recursive call
+ */
+ public AxStateTree(final AxPolicy policy, final AxState thisState, Set<AxReferenceKey> referencedStateNameSet) {
+ Assertions.argumentNotNull(policy, "policy may not be null");
+ Assertions.argumentNotNull(thisState, "thisState may not be null");
+
+ this.thisState = thisState;
+ nextStates = new TreeSet<>();
+
+ for (final AxStateOutput stateOutput : thisState.getStateOutputs().values()) {
+ final AxState nextState = policy.getStateMap().get(stateOutput.getNextState().getLocalName());
+
+ // Check for end of state branch
+ if (stateOutput.getNextState().equals(AxReferenceKey.getNullKey())) {
+ continue;
+ }
+
+ if (referencedStateNameSet == null) {
+ referencedStateNameSet = new LinkedHashSet<>();
+ referencedStateNameSet.add(thisState.getKey());
+ }
+
+ // Check for state tree loops
+ if (referencedStateNameSet.contains(nextState.getKey())) {
+ throw new PolicyRuntimeException("loop detected in state tree for policy " + policy.getID() + " state "
+ + thisState.getKey().getLocalName() + ", next state " + nextState.getKey().getLocalName()
+ + " referenced more than once");
+ }
+ referencedStateNameSet.add(stateOutput.getNextState());
+ nextStates.add(new AxStateTree(policy, nextState, referencedStateNameSet));
+ }
+ }
+
+ /**
+ * Gets the state for this state tree node.
+ *
+ * @return the state
+ */
+ public AxState getState() {
+ return thisState;
+ }
+
+ /**
+ * Gets the next states for this state tree node.
+ *
+ * @return the next states
+ */
+ public Set<AxStateTree> getNextStates() {
+ return nextStates;
+ }
+
+ /**
+ * Gets the list of states referenced by this state tree as a list.
+ *
+ * @return the list of states referenced
+ */
+ public List<AxState> getReferencedStateList() {
+ final List<AxState> referencedStateList = new ArrayList<>();
+
+ referencedStateList.add(thisState);
+ for (final AxStateTree nextStateTree : nextStates) {
+ referencedStateList.addAll(nextStateTree.getReferencedStateList());
+ }
+
+ return referencedStateList;
+ }
+
+ /**
+ * Gets the list of states referenced by this state tree as a set.
+ *
+ * @return the set of states referenced
+ */
+ public Set<AxState> getReferencedStateSet() {
+ final Set<AxState> referencedStateSet = new TreeSet<>();
+
+ referencedStateSet.add(thisState);
+ for (final AxStateTree nextStateTree : nextStates) {
+ referencedStateSet.addAll(nextStateTree.getReferencedStateSet());
+ }
+
+ return referencedStateSet;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxStateTree otherObj) {
+ Assertions.argumentNotNull(otherObj, "comparison object may not be null");
+
+ if (this == otherObj) {
+ return 0;
+ }
+
+ final AxStateTree other = otherObj;
+ if (!thisState.equals(other.thisState)) {
+ return thisState.compareTo(other.thisState);
+ }
+ if (!nextStates.equals(other.nextStates)) {
+ return (nextStates.hashCode() - other.nextStates.hashCode());
+ }
+ return 0;
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTask.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTask.java
new file mode 100644
index 000000000..b1f26f6c0
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTask.java
@@ -0,0 +1,745 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.ElementCollection;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyUse;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
+import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
+import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class holds the definition of a task in Apex. A task is executed by a state and performs
+ * some domain specific logic to carry out work required to be done by a policy. The Task Logic that
+ * is executed by a task is held in a {@link AxTaskLogic} instance.
+ * <p>
+ * A task has a set of input fields and output fields, which are passed to and are emitted from the
+ * task during a task execution cycle. A task may have task parameters {@link AxTaskParameter},
+ * which are configuration values passed to a task at initialization time.
+ * <p>
+ * The Task Logic in a task may use information in context albums to perform their domain specific
+ * work. The context albums that the task uses and that should be made available to the task by Apex
+ * policy distribution are held as a set of references to context albums in the task.
+ * <p>
+ * During validation of a task, the validation checks listed below are executed:
+ * <ol>
+ * <li>The task key must not be a null key and must be valid, see validation in
+ * {@link AxArtifactKey}
+ * <li>The task must have at least one input field
+ * <li>The parent of each input field of a task must be that task
+ * <li>Each input field must be valid, see validation in {@link AxInputField}
+ * <li>The task must have at least one output field
+ * <li>The parent of each output field of a task must be that task
+ * <li>Each output field must be valid, see validation in {@link AxOutputField}
+ * <li>The parent of each task parameter of a task must be that task
+ * <li>Each task parameter must be valid, see validation in {@link AxTaskParameter}
+ * <li>The parent of the task logic in a task must be that task
+ * <li>The task logic must be valid, see validation in {@link AxTaskLogic}
+ * </ol>
+ */
+
+@Entity
+@Table(name = "AxTask")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexTask", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxTask", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"key", "inputFields", "outputFields", "taskParameters", "contextAlbumReferenceSet", "taskLogic"})
+
+public class AxTask extends AxConcept {
+ private static final String DOES_NOT_EQUAL_TASK_KEY = " does not equal task key";
+
+ private static final long serialVersionUID = 5374237330697362762L;
+
+ @EmbeddedId
+ @XmlElement(name = "key", required = true)
+ private AxArtifactKey key;
+
+ @OneToMany(cascade = CascadeType.ALL)
+ @XmlElement(name = "inputFields", required = true)
+ private Map<String, AxInputField> inputFields;
+
+ @OneToMany(cascade = CascadeType.ALL)
+ @XmlElement(name = "outputFields", required = true)
+ private Map<String, AxOutputField> outputFields;
+
+ @OneToMany(cascade = CascadeType.ALL)
+ @XmlElement(name = "taskParameters", required = true)
+ private Map<String, AxTaskParameter> taskParameters;
+
+ // @formatter:off
+ @ElementCollection
+ @CollectionTable(joinColumns = {@JoinColumn(name = "contextAlbumName", referencedColumnName = "name"),
+ @JoinColumn(name = "contextAlbumVersion", referencedColumnName = "version")})
+ @XmlElement(name = "contextAlbumReference")
+ private Set<AxArtifactKey> contextAlbumReferenceSet;
+ // @formatter:on
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @XmlElement(required = true)
+ private AxTaskLogic taskLogic;
+
+ /**
+ * The Default Constructor creates a task with a null key no input or output fields, no task
+ * parameters, no context album references and no logic.
+ */
+ public AxTask() {
+ this(new AxArtifactKey());
+ contextAlbumReferenceSet = new TreeSet<>();
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxTask(final AxTask copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Keyed Constructor creates a task with the given key no input or output fields, no task
+ * parameters, no context album references and no logic.
+ *
+ * @param key the key of the task
+ */
+ public AxTask(final AxArtifactKey key) {
+ this(key, // Task Key
+ new TreeMap<String, AxInputField>(), // Input fields
+ new TreeMap<String, AxOutputField>(), // Output Fields
+ new TreeMap<String, AxTaskParameter>(), // Task Parameters
+ new TreeSet<AxArtifactKey>(), // Context Album References
+ new AxTaskLogic(new AxReferenceKey(key)) // Task Logic
+ );
+ }
+
+ /**
+ * This Constructor defines all the fields of the task.
+ *
+ * @param key the key of the task
+ * @param inputFields the input fields that the task expects
+ * @param outputFields the output fields that the task emits
+ * @param taskParameters the task parameters that are used to initialize tasks of this type
+ * @param contextAlbumReferenceSet the context album reference set defines the context that may
+ * be used by Task Logic in the state
+ * @param taskLogic the task logic that performs the domain specific work of the task
+ */
+ public AxTask(final AxArtifactKey key, final Map<String, AxInputField> inputFields,
+ final Map<String, AxOutputField> outputFields, final Map<String, AxTaskParameter> taskParameters,
+ final Set<AxArtifactKey> contextAlbumReferenceSet, final AxTaskLogic taskLogic) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(inputFields, "inputFields may not be null");
+ Assertions.argumentNotNull(outputFields, "outputFields may not be null");
+ Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
+ Assertions.argumentNotNull(contextAlbumReferenceSet, "contextAlbumReferenceSet may not be null");
+ Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
+
+ this.key = key;
+ this.inputFields = inputFields;
+ this.outputFields = outputFields;
+ this.taskParameters = taskParameters;
+ this.contextAlbumReferenceSet = contextAlbumReferenceSet;
+ this.taskLogic = taskLogic;
+ }
+
+ /**
+ * When a task is unmarshalled from disk or from the database, the parent of contained objects
+ * is not defined. This method is called by JAXB after unmarshaling and is used to set the
+ * parent keys of all {@link AxInputField}, {@link AxOutputField}, and {@link AxTaskParameter}
+ * instance in the task.
+ *
+ * @param u the unmarshaler that is unmarshaling the model
+ * @param parent the parent object of this object in the unmarshaler
+ */
+ public void afterUnmarshal(final Unmarshaller u, final Object parent) {
+ taskLogic.getKey().setParentArtifactKey(key);
+
+ for (final AxInputField inputField : inputFields.values()) {
+ inputField.getKey().setParentArtifactKey(key);
+ inputField.getKey().setParentLocalName("InField");
+ }
+ for (final AxOutputField outputField : outputFields.values()) {
+ outputField.getKey().setParentArtifactKey(key);
+ outputField.getKey().setParentLocalName("OutField");
+ }
+ for (final AxTaskParameter parameter : taskParameters.values()) {
+ parameter.getKey().setParentArtifactKey(key);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxArtifactKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = key.getKeys();
+ for (final AxInputField inputField : inputFields.values()) {
+ keyList.addAll(inputField.getKeys());
+ }
+ for (final AxOutputField outputField : outputFields.values()) {
+ keyList.addAll(outputField.getKeys());
+ }
+ for (final AxTaskParameter taskParameter : taskParameters.values()) {
+ keyList.addAll(taskParameter.getKeys());
+ }
+ for (final AxArtifactKey contextAlbumKey : contextAlbumReferenceSet) {
+ keyList.add(new AxKeyUse(contextAlbumKey));
+ }
+ keyList.addAll(taskLogic.getKeys());
+ return keyList;
+ }
+
+ /**
+ * Sets the key of the task.
+ *
+ * @param key the key of the task
+ */
+ public void setKey(final AxArtifactKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the input fields that the task expects.
+ *
+ * @return the input fields that the task expects
+ */
+ public Map<String, AxInputField> getInputFields() {
+ return inputFields;
+ }
+
+ /**
+ * Gets the raw input fields that the task expects as a tree map.
+ *
+ * @return the raw input fields that the task expects
+ */
+ public Map<String, AxField> getRawInputFields() {
+ return new TreeMap<>(inputFields);
+ }
+
+ /**
+ * Convenience method to get the input fields as a set.
+ *
+ * @return the input fields as a set
+ */
+ public Set<AxField> getInputFieldSet() {
+ final Set<AxField> inputFieldSet = new TreeSet<>();
+ for (final AxInputField field : inputFields.values()) {
+ inputFieldSet.add(field);
+ }
+ return inputFieldSet;
+ }
+
+ /**
+ * Sets the input fields that the task expects.
+ *
+ * @param inputFields the input fields that the task expects
+ */
+ public void setInputFields(final Map<String, AxInputField> inputFields) {
+ Assertions.argumentNotNull(inputFields, "inputFields may not be null");
+ this.inputFields = inputFields;
+ }
+
+ /**
+ * Copy the input fields from the given map into the task. This method is used to get a copy of
+ * the input fields, which can be useful for unit testing of policies and tasks.
+ *
+ * @param fields the fields to copy into the task
+ */
+ public void duplicateInputFields(final Map<String, AxField> fields) {
+ Assertions.argumentNotNull(fields, "fields may not be null");
+
+ for (final AxField field : fields.values()) {
+ final AxReferenceKey fieldKey = new AxReferenceKey(this.getKey().getName(), this.getKey().getVersion(),
+ "inputFields", field.getKey().getLocalName());
+ final AxInputField inputField = new AxInputField(fieldKey, field.getSchema());
+ inputFields.put(inputField.getKey().getLocalName(), inputField);
+ }
+ }
+
+ /**
+ * Gets the output fields that the task emits.
+ *
+ * @return the output fields that the task emits
+ */
+ public Map<String, AxOutputField> getOutputFields() {
+ return outputFields;
+ }
+
+ /**
+ * Gets the raw output fields that the task emits as a tree map.
+ *
+ * @return the raw output fields as a tree map
+ */
+ public Map<String, AxField> getRawOutputFields() {
+ return new TreeMap<>(outputFields);
+ }
+
+ /**
+ * Gets the output fields that the task emits as a set.
+ *
+ * @return the output fields as a set
+ */
+ public Set<AxField> getOutputFieldSet() {
+ final Set<AxField> outputFieldSet = new TreeSet<>();
+ for (final AxOutputField field : outputFields.values()) {
+ outputFieldSet.add(field);
+ }
+ return outputFieldSet;
+ }
+
+ /**
+ * Sets the output fields that the task emits.
+ *
+ * @param outputFields the output fields that the task emits
+ */
+ public void setOutputFields(final Map<String, AxOutputField> outputFields) {
+ Assertions.argumentNotNull(outputFields, "outputFields may not be null");
+ this.outputFields = outputFields;
+ }
+
+ /**
+ * Copy the output fields from the given map into the task. This method is used to get a copy of
+ * the output fields, which can be useful for unit testing of policies and tasks.
+ *
+ * @param fields the fields to copy into the task
+ */
+ public void duplicateOutputFields(final Map<String, AxField> fields) {
+ Assertions.argumentNotNull(fields, "fields may not be null");
+
+ for (final AxField field : fields.values()) {
+ final AxReferenceKey fieldKey = new AxReferenceKey(this.getKey().getName(), this.getKey().getVersion(),
+ "outputFields", field.getKey().getLocalName());
+ final AxOutputField outputField = new AxOutputField(fieldKey, field.getSchema());
+ outputFields.put(outputField.getKey().getLocalName(), outputField);
+ }
+ }
+
+ /**
+ * Gets the task parameters that are used to initialize tasks of this type.
+ *
+ * @return the task parameters that are used to initialize tasks of this type
+ */
+ public Map<String, AxTaskParameter> getTaskParameters() {
+ return taskParameters;
+ }
+
+ /**
+ * Sets the task parameters that are used to initialize tasks of this type.
+ *
+ * @param taskParameters the task parameters that are used to initialize tasks of this type
+ */
+ public void setTaskParameters(final Map<String, AxTaskParameter> taskParameters) {
+ Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
+ this.taskParameters = taskParameters;
+ }
+
+ /**
+ * Gets the context album reference set defines the context that may be used by Task Logic in
+ * the state.
+ *
+ * @return the context album reference set defines the context that may be used by Task Logic in
+ * the state
+ */
+ public Set<AxArtifactKey> getContextAlbumReferences() {
+ return contextAlbumReferenceSet;
+ }
+
+ /**
+ * Sets the context album reference set defines the context that may be used by Task Logic in
+ * the state.
+ *
+ * @param contextAlbumReferences the context album reference set defines the context that may be
+ * used by Task Logic in the state
+ */
+ public void setContextAlbumReferences(final Set<AxArtifactKey> contextAlbumReferences) {
+ Assertions.argumentNotNull(contextAlbumReferences, "contextAlbumReferences may not be null");
+ this.contextAlbumReferenceSet = contextAlbumReferences;
+ }
+
+ /**
+ * Gets the task logic that performs the domain specific work of the task.
+ *
+ * @return the task logic that performs the domain specific work of the task
+ */
+ public AxTaskLogic getTaskLogic() {
+ return taskLogic;
+ }
+
+ /**
+ * Sets the task logic that performs the domain specific work of the task.
+ *
+ * @param taskLogic the task logic that performs the domain specific work of the task
+ */
+ public void setTaskLogic(final AxTaskLogic taskLogic) {
+ Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
+ this.taskLogic = taskLogic;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (inputFields.size() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "inputFields may not be empty"));
+ } else {
+ for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
+ result = validateField(inputFieldEntry.getKey(), inputFieldEntry.getValue(), "input", result);
+ }
+ }
+
+ if (outputFields.size() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "outputFields may not be empty"));
+ } else {
+ for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
+ result = validateField(outputFieldEntry.getKey(), outputFieldEntry.getValue(), "input", result);
+ }
+ }
+
+ for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
+ result = vaildateTaskParameterEntry(taskParameterEntry, result);
+ }
+
+ for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
+ result = vaildateContextAlbumReference(contextAlbumReference, result);
+ }
+
+ if (!taskLogic.getKey().getParentArtifactKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "taskLogic parent key " + taskLogic.getKey().getID() + DOES_NOT_EQUAL_TASK_KEY));
+ }
+
+ return taskLogic.validate(result);
+ }
+
+ /**
+ * Validate a field
+ *
+ * @param key the key of the field to validate
+ * @param field the field to validate
+ * @param direction The direction of the field
+ * @param result The validation result to append to
+ * @return The result of the validation
+ */
+ private AxValidationResult validateField(final String fieldKey, final AxField field, final String direction,
+ AxValidationResult result) {
+ if (field == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "null " + direction + " field value found on " + direction + " field " + fieldKey));
+ } else {
+ if (!field.getKey().getParentArtifactKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "parent key on " + direction + " field " + fieldKey + DOES_NOT_EQUAL_TASK_KEY));
+ }
+
+ result = field.validate(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate a task parameter entry
+ *
+ * @param taskParameterEntry the task parameter entry to validate
+ * @param result The validation result to append to
+ * @return The result of the validation
+ */
+ private AxValidationResult vaildateTaskParameterEntry(final Entry<String, AxTaskParameter> taskParameterEntry,
+ AxValidationResult result) {
+ if (taskParameterEntry.getValue() == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "null input task parameer value found on task parameter " + taskParameterEntry.getKey()));
+ } else {
+ if (!taskParameterEntry.getValue().getKey().getParentArtifactKey().equals(key)) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "parent key on task parameter " + taskParameterEntry.getKey() + DOES_NOT_EQUAL_TASK_KEY));
+ }
+
+ result = taskParameterEntry.getValue().validate(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate a context album reference entry
+ *
+ * @param taskParameterEntry the context album reference entry to validate
+ * @param result The validation result to append to
+ * @return The result of the validation
+ */
+ private AxValidationResult vaildateContextAlbumReference(final AxArtifactKey contextAlbumReference,
+ AxValidationResult result) {
+ if (contextAlbumReference.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "key on context item reference entry " + contextAlbumReference.getKey()
+ + " may not be the null key"));
+ }
+
+ return contextAlbumReference.validate(result);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ for (final AxInputField inputField : inputFields.values()) {
+ inputField.clean();
+ }
+ for (final AxOutputField outputField : outputFields.values()) {
+ outputField.clean();
+ }
+ for (final AxTaskParameter parameter : taskParameters.values()) {
+ parameter.clean();
+ }
+ for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
+ contextAlbumReference.clean();
+ }
+ taskLogic.clean();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("key=");
+ builder.append(key);
+ builder.append(",inputFields=");
+ builder.append(inputFields);
+ builder.append(",outputFields=");
+ builder.append(outputFields);
+ builder.append(",taskParameters=");
+ builder.append(taskParameters);
+ builder.append(",contextAlbumReferenceSet=");
+ builder.append(contextAlbumReferenceSet);
+ builder.append(",taskLogic=");
+ builder.append(taskLogic);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxTask.class);
+
+ final AxTask copy = ((AxTask) copyObject);
+ copy.setKey(key);
+
+ final Map<String, AxInputField> newInputFields = new TreeMap<>();
+ for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
+ newInputFields.put(inputFieldEntry.getKey(), new AxInputField(inputFieldEntry.getValue()));
+ }
+ copy.setInputFields(newInputFields);
+
+ final Map<String, AxOutputField> newOutputFields = new TreeMap<>();
+ for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
+ newOutputFields.put(outputFieldEntry.getKey(), new AxOutputField(outputFieldEntry.getValue()));
+ }
+ copy.setOutputFields(newOutputFields);
+
+ final Map<String, AxTaskParameter> newTaskParameter = new TreeMap<>();
+ for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
+ newTaskParameter.put(taskParameterEntry.getKey(), new AxTaskParameter(taskParameterEntry.getValue()));
+ }
+ copy.setTaskParameters(newTaskParameter);
+
+ final Set<AxArtifactKey> newContextUsage = new TreeSet<>();
+ for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
+ newContextUsage.add(new AxArtifactKey(contextAlbumReference));
+ }
+ copy.setContextAlbumReferences(newContextUsage);
+
+ copy.setTaskLogic(new AxTaskLogic((AxLogic) taskLogic));
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + inputFields.hashCode();
+ result = prime * result + outputFields.hashCode();
+ result = prime * result + taskParameters.hashCode();
+ result = prime * result + contextAlbumReferenceSet.hashCode();
+ result = prime * result + taskLogic.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxTask other = (AxTask) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ if (!inputFields.equals(other.inputFields)) {
+ return false;
+ }
+ if (!outputFields.equals(other.outputFields)) {
+ return false;
+ }
+ if (!taskParameters.equals(other.taskParameters)) {
+ return false;
+ }
+ if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
+ return false;
+ }
+ return taskLogic.equals(other.taskLogic);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxTask other = (AxTask) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!inputFields.equals(other.inputFields)) {
+ return (inputFields.hashCode() - other.inputFields.hashCode());
+ }
+ if (!outputFields.equals(other.outputFields)) {
+ return (outputFields.hashCode() - other.outputFields.hashCode());
+ }
+ if (!taskParameters.equals(other.taskParameters)) {
+ return (taskParameters.hashCode() - other.taskParameters.hashCode());
+ }
+ if (!contextAlbumReferenceSet.equals(other.contextAlbumReferenceSet)) {
+ return (contextAlbumReferenceSet.hashCode() - other.contextAlbumReferenceSet.hashCode());
+ }
+ return taskLogic.compareTo(other.taskLogic);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskLogic.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskLogic.java
new file mode 100644
index 000000000..00513e8f7
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskLogic.java
@@ -0,0 +1,136 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import javax.persistence.Entity;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+
+/**
+ * This class holds Task Logic for {@link AxTask} tasks in Apex. It is a specialization of the
+ * {@link AxLogic} class, so that Task Logic in Apex states can be strongly typed.
+ * <p>
+ * Task Logic is used to execute tasks {@link AxTask} in Apex. The logic uses fields on the incoming
+ * trigger event and information from the context albums available on a task to get context during
+ * execution. The task logic populates the output fields of the task.
+ * <p>
+ * Validation uses standard Apex Logic validation, see validation in {@link AxLogic}.
+ */
+@Entity
+@Table(name = "AxTaskLogic")
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexLogic", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxTaskLogic", namespace = "http://www.onap.org/policy/apex-pdp")
+
+public class AxTaskLogic extends AxLogic {
+ private static final long serialVersionUID = 2090324845463750391L;
+
+ /**
+ * The Default Constructor creates a logic instance with a null key, undefined logic flavour and
+ * a null logic string.
+ */
+ public AxTaskLogic() {
+ super();
+ }
+
+ /**
+ * The Key Constructor creates a logic instance with the given reference key, undefined logic
+ * flavour and a null logic string.
+ *
+ * @param key the reference key of the logic
+ */
+ public AxTaskLogic(final AxReferenceKey key) {
+ super(key, LOGIC_FLAVOUR_UNDEFINED, "");
+ }
+
+ /**
+ * This Constructor creates a logic instance with a reference key constructed from the parents
+ * key and the logic local name and all of its fields defined.
+ *
+ * @param parentKey the reference key of the parent of this logic
+ * @param logicName the logic name, held as the local name of the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxTaskLogic(final AxArtifactKey parentKey, final String logicName, final String logicFlavour,
+ final String logic) {
+ super(new AxReferenceKey(parentKey, logicName), logicFlavour, logic);
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and all of its fields
+ * defined.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxTaskLogic(final AxReferenceKey key, final String logicFlavour, final String logic) {
+ super(key, logicFlavour, logic);
+ }
+
+ /**
+ * This Constructor creates a logic instance by cloning the fields from another logic instance
+ * into this logic instance.
+ *
+ * @param logic the logic instance to clone from
+ */
+ public AxTaskLogic(final AxLogic logic) {
+ super(new AxReferenceKey(logic.getKey()), logic.getLogicFlavour(), logic.getLogic());
+ }
+
+ /**
+ * This Constructor creates a logic instance with a reference key constructed from the parents
+ * key and the logic local name, the given logic flavour, with the logic being provided by the
+ * given logic reader instance.
+ *
+ * @param parentKey the reference key of the parent of this logic
+ * @param logicName the logic name, held as the local name of the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logicReader the logic reader to use to read the logic for this logic instance
+ */
+ public AxTaskLogic(final AxArtifactKey parentKey, final String logicName, final String logicFlavour,
+ final AxLogicReader logicReader) {
+ super(new AxReferenceKey(parentKey, logicName), logicFlavour, logicReader);
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and logic flavour, the
+ * logic is provided by the given logic reader instance.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logicReader the logic reader to use to read the logic for this logic instance
+ */
+ public AxTaskLogic(final AxReferenceKey key, final String logicFlavour, final AxLogicReader logicReader) {
+ super(key, logicFlavour, logicReader);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskParameter.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskParameter.java
new file mode 100644
index 000000000..5ae3bfa42
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskParameter.java
@@ -0,0 +1,299 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class is used to specify the configuration parameters that may be passed to a task
+ * {@link AxTask}. Task parameters are read from a configuration file when Apex starts and are
+ * passed to the task by the Apex engine when a task is executed. Each task parameter has a key and
+ * a default value. If the task parameter is not set in a configuration file, the task uses its
+ * default value.
+ */
+
+@Entity
+@Table(name = "AxTaskParameter")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexTaskParameter", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxTaskParameter", namespace = "http://www.onap.org/policy/apex-pdp",
+ propOrder = {"key", "defaultValue"})
+
+public class AxTaskParameter extends AxConcept {
+ private static final long serialVersionUID = 7351688156934099977L;
+
+ @EmbeddedId
+ @XmlElement(name = "key", required = true)
+ private AxReferenceKey key;
+
+ @Column(name = "defaultValue")
+ @XmlElement
+ private String defaultValue;
+
+ /**
+ * The Default Constructor creates a task parameter with a null reference key and a null default
+ * value.
+ */
+ public AxTaskParameter() {
+ this(new AxReferenceKey());
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxTaskParameter(final AxTaskParameter copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Keyed Constructor creates a task parameter with the given reference key and a null
+ * default value.
+ *
+ * @param taskParameterKey the task parameter key
+ */
+ public AxTaskParameter(final AxReferenceKey taskParameterKey) {
+ this(taskParameterKey, "");
+ }
+
+ /**
+ * The Default Constructor creates a task parameter with the given reference key and default
+ * value.
+ *
+ * @param key the reference key of the task parameter
+ * @param defaultValue the default value of the task parameter
+ */
+ public AxTaskParameter(final AxReferenceKey key, final String defaultValue) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(defaultValue, "defaultValue may not be null");
+
+ this.key = key;
+ this.defaultValue = defaultValue.trim();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxReferenceKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ return key.getKeys();
+ }
+
+ /**
+ * Sets the reference key of the task parameter.
+ *
+ * @param key the reference key of the task parameter
+ */
+ public void setKey(final AxReferenceKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the default value of the task parameter.
+ *
+ * @return the default value of the task parameter
+ */
+ public String getTaskParameterValue() {
+ return defaultValue;
+ }
+
+ /**
+ * Sets the default value of the task parameter.
+ *
+ * @param defaultValue the default value of the task parameter
+ */
+ public void setDefaultValue(final String defaultValue) {
+ Assertions.argumentNotNull(defaultValue, "defaultValue may not be null");
+ this.defaultValue = defaultValue.trim();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxReferenceKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (defaultValue.trim().length() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.WARNING,
+ "no defaultValue specified, defaultValue is blank"));
+ }
+
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ defaultValue = defaultValue.trim();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("key=");
+ builder.append(key);
+ builder.append(",defaultValue=");
+ builder.append(defaultValue);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxTaskParameter.class);
+
+ final AxTaskParameter copy = ((AxTaskParameter) copyObject);
+ copy.setKey(new AxReferenceKey(key));
+ copy.setDefaultValue(defaultValue);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + defaultValue.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxTaskParameter other = (AxTaskParameter) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ return defaultValue.equals(other.defaultValue);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxTaskParameter other = (AxTaskParameter) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ return defaultValue.compareTo(other.defaultValue);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskSelectionLogic.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskSelectionLogic.java
new file mode 100644
index 000000000..89c9418a4
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTaskSelectionLogic.java
@@ -0,0 +1,135 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import javax.persistence.Entity;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+
+/**
+ * This class holds Task Selection Logic for {@link AxState} states in Apex. It is a specialization
+ * of the {@link AxLogic} class, so that Task Selection Logic in Apex states can be strongly typed.
+ * <p>
+ * Task Selection Logic is used to select the task {@link AxTask} that a state will execute. The
+ * logic uses fields on the incoming trigger event and information from the context albums available
+ * on a state to decide what task {@link AxTask} to select for execution in a given context.
+ * <p>
+ * Validation uses standard Apex Logic validation, see validation in {@link AxLogic}.
+ */
+@Entity
+@Table(name = "AxTaskSelectionLogic")
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexTaskSelectionLogic", namespace = "http://www.onap.org/policy/apex-pdp")
+@XmlType(name = "AxTaskSelectionLogic", namespace = "http://www.onap.org/policy/apex-pdp")
+
+public class AxTaskSelectionLogic extends AxLogic {
+ private static final long serialVersionUID = 2090324845463750391L;
+
+ /**
+ * The Default Constructor creates a logic instance with a null key, undefined logic flavour and
+ * a null logic string.
+ */
+ public AxTaskSelectionLogic() {
+ super();
+ }
+
+ /**
+ * The Key Constructor creates a logic instance with the given reference key, undefined logic
+ * flavour and a null logic string.
+ *
+ * @param key the reference key of the logic
+ */
+ public AxTaskSelectionLogic(final AxReferenceKey key) {
+ super(key, LOGIC_FLAVOUR_UNDEFINED, "");
+ }
+
+ /**
+ * This Constructor creates a logic instance with a reference key constructed from the parents
+ * key and the logic local name and all of its fields defined.
+ *
+ * @param parentKey the reference key of the parent of this logic
+ * @param logicName the logic name, held as the local name of the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxTaskSelectionLogic(final AxReferenceKey parentKey, final String logicName, final String logicFlavour,
+ final String logic) {
+ super(parentKey, logicName, logicFlavour, logic);
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and all of its fields
+ * defined.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logic the actual logic as a string
+ */
+ public AxTaskSelectionLogic(final AxReferenceKey key, final String logicFlavour, final String logic) {
+ super(key, logicFlavour, logic);
+ }
+
+ /**
+ * This Constructor creates a logic instance by cloning the fields from another logic instance
+ * into this logic instance.
+ *
+ * @param logic the logic instance to clone from
+ */
+ public AxTaskSelectionLogic(final AxLogic logic) {
+ super(new AxReferenceKey(logic.getKey()), logic.getLogicFlavour(), logic.getLogic());
+ }
+
+ /**
+ * This Constructor creates a logic instance with a reference key constructed from the parents
+ * key and the logic local name, the given logic flavour, with the logic being provided by the
+ * given logic reader instance.
+ *
+ * @param parentKey the reference key of the parent of this logic
+ * @param logicName the logic name, held as the local name of the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logicReader the logic reader to use to read the logic for this logic instance
+ */
+ public AxTaskSelectionLogic(final AxReferenceKey parentKey, final String logicName, final String logicFlavour,
+ final AxLogicReader logicReader) {
+ super(new AxReferenceKey(parentKey, logicName), logicFlavour, logicReader);
+ }
+
+ /**
+ * This Constructor creates a logic instance with the given reference key and logic flavour, the
+ * logic is provided by the given logic reader instance.
+ *
+ * @param key the reference key of this logic
+ * @param logicFlavour the flavour of this logic
+ * @param logicReader the logic reader to use to read the logic for this logic instance
+ */
+ public AxTaskSelectionLogic(final AxReferenceKey key, final String logicFlavour, final AxLogicReader logicReader) {
+ super(key, logicFlavour, logicReader);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTasks.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTasks.java
new file mode 100644
index 000000000..532d7d017
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTasks.java
@@ -0,0 +1,425 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.persistence.CascadeType;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter;
+import org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetterImpl;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class is a task container and holds a map of the tasks for an entire Apex model. All Apex
+ * models that use tasks must have an {@link AxTasks} field. The {@link AxTasks} class implements
+ * the helper methods of the {@link AxConceptGetter} interface to allow {@link AxTask} instances to
+ * be retrieved by calling methods directly on this class without referencing the contained map.
+ * <p>
+ * Validation checks that the container key is not null. An error is issued if no tasks are defined
+ * in the container. Each task entry is checked to ensure that its key and value are not null and
+ * that the key matches the key in the map value. Each task entry is then validated individually.
+ */
+@Entity
+@Table(name = "AxTasks")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "AxTasks", namespace = "http://www.onap.org/policy/apex-pdp", propOrder = {"key", "taskMap"})
+public class AxTasks extends AxConcept implements AxConceptGetter<AxTask> {
+ private static final long serialVersionUID = 4290442590545820316L;
+
+ @EmbeddedId
+ @XmlElement(name = "key", required = true)
+ private AxArtifactKey key;
+
+ // @formatter:off
+ @ManyToMany(cascade = CascadeType.ALL)
+ @JoinTable(
+ joinColumns = {@JoinColumn(name = "taskMapName", referencedColumnName = "name"),
+ @JoinColumn(name = "taskMapVersion", referencedColumnName = "version")},
+ inverseJoinColumns = {@JoinColumn(name = "taskName", referencedColumnName = "name"),
+ @JoinColumn(name = "taskVersion", referencedColumnName = "version")})
+ @XmlElement(required = true)
+ private Map<AxArtifactKey, AxTask> taskMap;
+ // @formatter:on
+
+ /**
+ * The Default Constructor creates a {@link AxTasks} object with a null artifact key and creates
+ * an empty event map.
+ */
+ public AxTasks() {
+ this(new AxArtifactKey());
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copyConcept the concept to copy from
+ */
+ public AxTasks(final AxTasks copyConcept) {
+ super(copyConcept);
+ }
+
+ /**
+ * The Keyed Constructor creates a {@link AxTasks} object with the given artifact key and
+ * creates an empty event map.
+ *
+ * @param key the key
+ */
+ public AxTasks(final AxArtifactKey key) {
+ this(key, new TreeMap<AxArtifactKey, AxTask>());
+ }
+
+ /**
+ * This Constructor creates a task container with all of its fields defined.
+ *
+ * @param key the task container key
+ * @param taskMap the tasks to be stored in the task container
+ */
+ public AxTasks(final AxArtifactKey key, final Map<AxArtifactKey, AxTask> taskMap) {
+ super();
+ Assertions.argumentNotNull(key, "key may not be null");
+ Assertions.argumentNotNull(taskMap, "taskMap may not be null");
+
+ this.key = key;
+ this.taskMap = new TreeMap<>();
+ this.taskMap.putAll(taskMap);
+ }
+
+ /**
+ * When a model is unmarshalled from disk or from the database, the task map is returned as a
+ * raw hash map. This method is called by JAXB after unmarshaling and is used to convert the
+ * hash map to a {@link NavigableMap} so that it will work with the {@link AxConceptGetter}
+ * interface.
+ *
+ * @param u the unmarshaler that is unmarshaling the model
+ * @param parent the parent object of this object in the unmarshaler
+ */
+ public void afterUnmarshal(final Unmarshaller u, final Object parent) {
+ // The map must be navigable to allow name and version searching, unmarshaling returns a
+ // hash map
+ final NavigableMap<AxArtifactKey, AxTask> navigableTaskMap = new TreeMap<>();
+ navigableTaskMap.putAll(taskMap);
+ taskMap = navigableTaskMap;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKey()
+ */
+ @Override
+ public AxArtifactKey getKey() {
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#getKeys()
+ */
+ @Override
+ public List<AxKey> getKeys() {
+ final List<AxKey> keyList = key.getKeys();
+
+ for (final AxTask task : taskMap.values()) {
+ keyList.addAll(task.getKeys());
+ }
+
+ return keyList;
+ }
+
+ /**
+ * Sets the task container key.
+ *
+ * @param key the task container key
+ */
+ public void setKey(final AxArtifactKey key) {
+ Assertions.argumentNotNull(key, "key may not be null");
+ this.key = key;
+ }
+
+ /**
+ * Gets the tasks stored in the task container.
+ *
+ * @return the tasks stored in the task container
+ */
+ public Map<AxArtifactKey, AxTask> getTaskMap() {
+ return taskMap;
+ }
+
+ /**
+ * Sets the tasks to be stored in the task container.
+ *
+ * @param taskMap the tasks to be stored in the task container
+ */
+ public void setTaskMap(final Map<AxArtifactKey, AxTask> taskMap) {
+ Assertions.argumentNotNull(taskMap, "taskMap may not be null");
+ this.taskMap = new TreeMap<>();
+ this.taskMap.putAll(taskMap);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#validate(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxValidationResult)
+ */
+ @Override
+ public AxValidationResult validate(final AxValidationResult resultIn) {
+ AxValidationResult result = resultIn;
+
+ if (key.equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(
+ new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+ }
+
+ result = key.validate(result);
+
+ if (taskMap.size() == 0) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "taskMap may not be empty"));
+ } else {
+ for (final Entry<AxArtifactKey, AxTask> taskEntry : taskMap.entrySet()) {
+ if (taskEntry.getKey().equals(AxArtifactKey.getNullKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "key on task entry " + taskEntry.getKey() + " may not be the null key"));
+ } else if (taskEntry.getValue() == null) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+ "value on task entry " + taskEntry.getKey() + " may not be null"));
+ } else {
+ if (!taskEntry.getKey().equals(taskEntry.getValue().getKey())) {
+ result.addValidationMessage(new AxValidationMessage(key, this.getClass(),
+ ValidationResult.INVALID, "key on task entry key " + taskEntry.getKey()
+ + " does not equal task value key " + taskEntry.getValue().getKey()));
+ }
+
+ result = taskEntry.getValue().validate(result);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#clean()
+ */
+ @Override
+ public void clean() {
+ key.clean();
+ for (final Entry<AxArtifactKey, AxTask> taskEntry : taskMap.entrySet()) {
+ taskEntry.getKey().clean();
+ taskEntry.getValue().clean();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(this.getClass().getSimpleName());
+ builder.append(":(");
+ builder.append("key=");
+ builder.append(key);
+ builder.append(",taskMap=");
+ builder.append(taskMap);
+ builder.append(")");
+ return builder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.basicmodel.concepts.AxConcept#copyTo(org.onap.policy.apex.model.
+ * basicmodel.concepts.AxConcept)
+ */
+ @Override
+ public AxConcept copyTo(final AxConcept targetObject) {
+ Assertions.argumentNotNull(targetObject, "target may not be null");
+
+ final Object copyObject = targetObject;
+ Assertions.instanceOf(copyObject, AxTasks.class);
+
+ final AxTasks copy = ((AxTasks) copyObject);
+ copy.setKey(new AxArtifactKey(key));
+
+ final Map<AxArtifactKey, AxTask> newTaskMap = new TreeMap<>();
+ for (final Entry<AxArtifactKey, AxTask> taskMapEntry : taskMap.entrySet()) {
+ newTaskMap.put(new AxArtifactKey(taskMapEntry.getKey()), new AxTask(taskMapEntry.getValue()));
+ }
+ copy.setTaskMap(newTaskMap);
+
+ return copy;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + key.hashCode();
+ result = prime * result + taskMap.hashCode();
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConcept#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AxTasks other = (AxTasks) obj;
+ if (!key.equals(other.key)) {
+ return false;
+ }
+ return taskMap.equals(other.taskMap);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final AxConcept otherObj) {
+ if (otherObj == null) {
+ return -1;
+ }
+ if (this == otherObj) {
+ return 0;
+ }
+ if (getClass() != otherObj.getClass()) {
+ return this.hashCode() - otherObj.hashCode();
+ }
+
+ final AxTasks other = (AxTasks) otherObj;
+ if (!key.equals(other.key)) {
+ return key.compareTo(other.key);
+ }
+ if (!taskMap.equals(other.taskMap)) {
+ return (taskMap.hashCode() - other.taskMap.hashCode());
+ }
+
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#get(org.onap.policy.apex.
+ * model. basicmodel.concepts.AxArtifactKey)
+ */
+ @Override
+ public AxTask get(final AxArtifactKey conceptKey) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxTask>) taskMap).get(conceptKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#get(java.lang.String)
+ */
+ @Override
+ public AxTask get(final String conceptKeyName) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxTask>) taskMap).get(conceptKeyName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#get(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public AxTask get(final String conceptKeyName, final String conceptKeyVersion) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxTask>) taskMap).get(conceptKeyName,
+ conceptKeyVersion);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#getAll(java.lang.String)
+ */
+ @Override
+ public Set<AxTask> getAll(final String conceptKeyName) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxTask>) taskMap).getAll(conceptKeyName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter#getAll(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public Set<AxTask> getAll(final String conceptKeyName, final String conceptKeyVersion) {
+ return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxTask>) taskMap).getAll(conceptKeyName,
+ conceptKeyVersion);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyException.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyException.java
new file mode 100644
index 000000000..3b0d53f9c
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyException.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+
+/**
+ * This exception is raised if an error occurs in an Apex policy or in Apex policy handling.
+ *
+ * @author Liam Fallon
+ */
+public class PolicyException extends ApexException {
+ private static final long serialVersionUID = -8507246953751956974L;
+
+ /**
+ * Instantiates a new apex policy exception with a message.
+ *
+ * @param message the message
+ */
+ public PolicyException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex policy exception with a message and a caused by exception.
+ *
+ * @param message the message
+ * @param e the exception that caused this exception to be thrown
+ */
+ public PolicyException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyRuntimeException.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyRuntimeException.java
new file mode 100644
index 000000000..dbd2fb64f
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/PolicyRuntimeException.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexRuntimeException;
+
+/**
+ * This exception is raised if a runtime error occurs in an Apex policy or in Apex policy handling.
+ *
+ * @author Liam Fallon
+ */
+public class PolicyRuntimeException extends ApexRuntimeException {
+ private static final long serialVersionUID = -8507246953751956974L;
+
+ /**
+ * Instantiates a new apex policy runtime exception with a message.
+ *
+ * @param message the message
+ */
+ public PolicyRuntimeException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex policy runtime exception with a message and a caused by exception.
+ *
+ * @param message the message
+ * @param e the exception that caused this exception to be thrown
+ */
+ public PolicyRuntimeException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/package-info.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/package-info.java
new file mode 100644
index 000000000..cc15a6af5
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/package-info.java
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains the concepts required to specify policies and tasks in APEX. It defines the main Apex
+ * concepts of policies and tasks.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+
+@XmlSchema(namespace = "http://www.onap.org/policy/apex-pdp", elementFormDefault = XmlNsForm.QUALIFIED,
+ xmlns = {@XmlNs(namespaceURI = "http://www.onap.org/policy/apex-pdp", prefix = "")})
+
+package org.onap.policy.apex.model.policymodel.concepts;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalyser.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalyser.java
new file mode 100644
index 000000000..99058484b
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalyser.java
@@ -0,0 +1,186 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.handling;
+
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
+import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
+import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.onap.policy.apex.model.policymodel.concepts.AxState;
+import org.onap.policy.apex.model.policymodel.concepts.AxStateOutput;
+import org.onap.policy.apex.model.policymodel.concepts.AxTask;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class analyses a policy model and shows what the usage of each context album, context item, data type, and event is.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class PolicyAnalyser {
+ /**
+ * Perform an analysis on a policy model.
+ *
+ * @param policyModel The policy model
+ * @return the analysis result of the policy model
+ */
+ public PolicyAnalysisResult analyse(final AxPolicyModel policyModel) {
+ Assertions.argumentNotNull(policyModel, "policyModel may not be null");
+
+ final PolicyAnalysisResult result = new PolicyAnalysisResult(policyModel);
+
+ for (final AxPolicy policy : policyModel.getPolicies().getPolicyMap().values()) {
+ for (final AxState state : policy.getStateMap().values()) {
+ analyseState(state, result);
+ }
+ }
+
+ for (final AxTask task : policyModel.getTasks().getTaskMap().values()) {
+ analyseTask(task, result);
+ }
+
+ for (final AxEvent event : policyModel.getEvents().getEventMap().values()) {
+ analyseEvent(event, result);
+ }
+
+ for (final AxContextAlbum contextAlbum : policyModel.getAlbums().getAll(null)) {
+ result.getContextSchemaUsage().get(contextAlbum.getItemSchema()).add(contextAlbum.getKey());
+ }
+
+ return result;
+ }
+
+ /**
+ * Perform an analysis on a single policy in a policy model.
+ *
+ * @param policyModel The policy model
+ * @param policy The policy
+ * @return the analysis result of the policy model
+ */
+ public PolicyAnalysisResult analyse(final AxPolicyModel policyModel, final AxPolicy policy) {
+ Assertions.argumentNotNull(policyModel, "policyModel may not be null");
+ Assertions.argumentNotNull(policy, "policy may not be null");
+
+ final PolicyAnalysisResult result = new PolicyAnalysisResult(policyModel);
+
+ for (final AxState state : policy.getStateMap().values()) {
+ analyseState(state, result);
+ }
+
+ // Only analyse tasks used by this policy
+ for (final Entry<AxArtifactKey, Set<AxKey>> taskUsageEntry : result.getTaskUsage().entrySet()) {
+ // If the usage set is empty, then we skip the task as its not used in the policy
+ if (!taskUsageEntry.getValue().isEmpty()) {
+ analyseTask(policyModel.getTasks().getTaskMap().get(taskUsageEntry.getKey()), result);
+ }
+ }
+
+ // Only analyse events used by this policy, same approach as for tasks
+ for (final Entry<AxArtifactKey, Set<AxKey>> eventUsageEntry : result.getEventUsage().entrySet()) {
+ if (!eventUsageEntry.getValue().isEmpty()) {
+ analyseEvent(policyModel.getEvents().getEventMap().get(eventUsageEntry.getKey()), result);
+ }
+ }
+
+ // Only analyse context albums used by this policy, same approach as for tasks
+ for (final Entry<AxArtifactKey, Set<AxKey>> contextAlbumUsageEntry : result.getContextAlbumUsage().entrySet()) {
+ if (!contextAlbumUsageEntry.getValue().isEmpty()) {
+ final AxContextAlbum contextAlbum = policyModel.getAlbums().get(contextAlbumUsageEntry.getKey());
+ result.getContextSchemaUsage().get(contextAlbum.getItemSchema()).add(contextAlbum.getKey());
+ }
+ }
+
+ for (final AxEvent event : policyModel.getEvents().getEventMap().values()) {
+ analyseEvent(event, result);
+ }
+
+ for (final AxContextAlbum contextAlbum : policyModel.getAlbums().getAll(null)) {
+ result.getContextSchemaUsage().get(contextAlbum.getItemSchema()).add(contextAlbum.getKey());
+ }
+
+ return result;
+ }
+
+ /**
+ * Analyse the usage of concepts by a state.
+ *
+ * @param state the state to analyse
+ * @param result the result
+ */
+ private void analyseState(final AxState state, final PolicyAnalysisResult result) {
+ // Event usage by state
+ result.getEventUsage().get(state.getTrigger()).add(state.getKey());
+ for (final AxStateOutput stateOutput : state.getStateOutputs().values()) {
+ result.getEventUsage().get(stateOutput.getOutgingEvent()).add(state.getKey());
+ }
+
+ // State Context Usage
+ for (final AxArtifactKey contextAlbumKey : state.getContextAlbumReferences()) {
+ result.getContextAlbumUsage().get(contextAlbumKey).add(state.getKey());
+ }
+
+ // Task usage by state
+ for (final AxArtifactKey task : state.getTaskReferences().keySet()) {
+ result.getTaskUsage().get(task).add(state.getKey());
+ }
+ }
+
+ /**
+ * Analyse the usage of concepts by a task.
+ *
+ * @param task the task to analyse
+ * @param result the result
+ */
+ private void analyseTask(final AxTask task, final PolicyAnalysisResult result) {
+ // Task Context Usage
+ for (final AxArtifactKey contextAlbumKey : task.getContextAlbumReferences()) {
+ result.getContextAlbumUsage().get(contextAlbumKey).add(task.getKey());
+ }
+
+ // Task data type usage
+ for (final AxInputField inputField : task.getInputFields().values()) {
+ result.getContextSchemaUsage().get(inputField.getSchema()).add(task.getKey());
+ }
+ for (final AxOutputField outputField : task.getOutputFields().values()) {
+ result.getContextSchemaUsage().get(outputField.getSchema()).add(task.getKey());
+ }
+ }
+
+ /**
+ * Analyse the usage of concepts by an event.
+ *
+ * @param event the event to analyse
+ * @param result the result of the analysis
+ */
+ private void analyseEvent(final AxEvent event, final PolicyAnalysisResult result) {
+ // Event data type usage
+ for (final AxField eventField : event.getFields()) {
+ result.getContextSchemaUsage().get(eventField.getSchema()).add(event.getKey());
+ }
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalysisResult.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalysisResult.java
new file mode 100644
index 000000000..d59af7cba
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalysisResult.java
@@ -0,0 +1,266 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.handling;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+
+/**
+ * This class finds and holds the usage of context schemas, context albums, events, and tasks by the policies in a policy model.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class PolicyAnalysisResult {
+ // Usage of context schemas
+ private final Map<AxArtifactKey, Set<AxKey>> contextSchemaUsage = new TreeMap<>();
+
+ // Usage of context maps
+ private final Map<AxArtifactKey, Set<AxKey>> contextAlbumUsage = new TreeMap<>();
+
+ // Usage of events
+ private final Map<AxArtifactKey, Set<AxKey>> eventUsage = new TreeMap<>();
+
+ // Usage of tasks
+ private final Map<AxArtifactKey, Set<AxKey>> taskUsage = new TreeMap<>();
+
+ /**
+ * This constructor creates a {@link PolicyAnalysisResult} instance that holds maps that contain the usage of context schemas, contxt albums, events, and
+ * tasks by all policies in a policy model.
+ *
+ * @param policyModel the policy model to analyse
+ */
+ public PolicyAnalysisResult(final AxPolicyModel policyModel) {
+ for (final AxArtifactKey contextSchemaKey : policyModel.getSchemas().getSchemasMap().keySet()) {
+ contextSchemaUsage.put(contextSchemaKey, new TreeSet<AxKey>());
+ }
+
+ for (final Entry<AxArtifactKey, AxContextAlbum> contextAlbumEntry : policyModel.getAlbums().getAlbumsMap().entrySet()) {
+ contextAlbumUsage.put(contextAlbumEntry.getKey(), new TreeSet<AxKey>());
+ }
+
+ for (final AxArtifactKey eventKey : policyModel.getEvents().getEventMap().keySet()) {
+ eventUsage.put(eventKey, new TreeSet<AxKey>());
+ }
+
+ for (final AxArtifactKey taskKey : policyModel.getTasks().getTaskMap().keySet()) {
+ taskUsage.put(taskKey, new TreeSet<AxKey>());
+ }
+ }
+
+ /**
+ * Gets the context schemas used by policies in the policy model.
+ *
+ * @return the context schemas used by policies in the policy model
+ */
+ public Map<AxArtifactKey, Set<AxKey>> getContextSchemaUsage() {
+ return contextSchemaUsage;
+ }
+
+ /**
+ * Gets the context albums used by policies in the policy model.
+ *
+ * @return the context albums used by policies in the policy model
+ */
+ public Map<AxArtifactKey, Set<AxKey>> getContextAlbumUsage() {
+ return contextAlbumUsage;
+ }
+
+ /**
+ * Gets the events used by policies in the policy model.
+ *
+ * @return the events used by policies in the policy model
+ */
+ public Map<AxArtifactKey, Set<AxKey>> getEventUsage() {
+ return eventUsage;
+ }
+
+ /**
+ * Gets the tasks used by policies in the policy model.
+ *
+ * @return the tasks used by policies in the policy model
+ */
+ public Map<AxArtifactKey, Set<AxKey>> getTaskUsage() {
+ return taskUsage;
+ }
+
+ /**
+ * Gets the context schemas used by policies in the policy model.
+ *
+ * @return the context schemas used by policies in the policy model
+ */
+ public Set<AxArtifactKey> getUsedContextSchemas() {
+ return getUsedKeySet(contextSchemaUsage);
+ }
+
+ /**
+ * Gets the context albums used by policies in the policy model.
+ *
+ * @return the context albums used by policies in the policy model
+ */
+ public Set<AxArtifactKey> getUsedContextAlbums() {
+ return getUsedKeySet(contextAlbumUsage);
+ }
+
+ /**
+ * Gets the events used by policies in the policy model.
+ *
+ * @return the events used by policies in the policy model
+ */
+ public Set<AxArtifactKey> getUsedEvents() {
+ return getUsedKeySet(eventUsage);
+ }
+
+ /**
+ * Gets the tasks used by policies in the policy model.
+ *
+ * @return the tasks used by policies in the policy model
+ */
+ public Set<AxArtifactKey> getUsedTasks() {
+ return getUsedKeySet(taskUsage);
+ }
+
+ /**
+ * Gets the context schemas in the policy model that were not used by any policies in the policy model.
+ *
+ * @return the unused context schemas
+ */
+ public Set<AxArtifactKey> getUnusedContextSchemas() {
+ return getUnusedKeySet(contextSchemaUsage);
+ }
+
+ /**
+ * Gets the context albums in the policy model that were not used by any policies in the policy model.
+ *
+ * @return the unused context albums
+ */
+ public Set<AxArtifactKey> getUnusedContextAlbums() {
+ return getUnusedKeySet(contextAlbumUsage);
+ }
+
+ /**
+ * Gets the events in the policy model that were not used by any policies in the policy model.
+ *
+ * @return the unused events
+ */
+ public Set<AxArtifactKey> getUnusedEvents() {
+ return getUnusedKeySet(eventUsage);
+ }
+
+ /**
+ * Gets the tasks in the policy model that were not used by any policies in the policy model.
+ *
+ * @return the unused tasks
+ */
+ public Set<AxArtifactKey> getUnusedTasks() {
+ return getUnusedKeySet(taskUsage);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+
+ builder.append(getUsageMapString("Context Schema usage", contextSchemaUsage));
+ builder.append(getUsageMapString("Context Album usage", contextAlbumUsage));
+ builder.append(getUsageMapString("Event usage", eventUsage));
+ builder.append(getUsageMapString("Task usage", taskUsage));
+
+ return builder.toString();
+ }
+
+ /**
+ * Gets the usage map string.
+ *
+ * @param header the header
+ * @param usageMap the usage map
+ * @return the usage map string
+ */
+ private String getUsageMapString(final String header, final Map<? extends AxKey, Set<AxKey>> usageMap) {
+ final StringBuilder builder = new StringBuilder();
+
+ builder.append(header);
+ builder.append('\n');
+ for (final Entry<? extends AxKey, Set<AxKey>> usageEntry : usageMap.entrySet()) {
+ builder.append(" ");
+ builder.append(usageEntry.getKey().getID());
+ if (usageEntry.getValue().isEmpty()) {
+ builder.append(" (unused)\n");
+ continue;
+ }
+
+ builder.append('\n');
+ for (final AxKey usageKey : usageEntry.getValue()) {
+ builder.append(" ");
+ builder.append(usageKey.getID());
+ builder.append("\n");
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Gets the used key set.
+ *
+ * @param usageMap the usage map
+ * @return the used key set
+ */
+ private Set<AxArtifactKey> getUsedKeySet(final Map<AxArtifactKey, Set<AxKey>> usageMap) {
+ final Set<AxArtifactKey> usedKeySet = new TreeSet<>();
+
+ for (final Entry<AxArtifactKey, Set<AxKey>> usageEntry : usageMap.entrySet()) {
+ if (!usageEntry.getValue().isEmpty()) {
+ usedKeySet.add(usageEntry.getKey());
+ }
+ }
+
+ return usedKeySet;
+ }
+
+ /**
+ * Gets the unused key set.
+ *
+ * @param usageMap the usage map
+ * @return the unused key set
+ */
+ private Set<AxArtifactKey> getUnusedKeySet(final Map<AxArtifactKey, Set<AxKey>> usageMap) {
+ final Set<AxArtifactKey> usedKeySet = new TreeSet<>();
+
+ for (final Entry<AxArtifactKey, Set<AxKey>> usageEntry : usageMap.entrySet()) {
+ if (usageEntry.getValue().isEmpty()) {
+ usedKeySet.add(usageEntry.getKey());
+ }
+ }
+
+ return usedKeySet;
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyComparer.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyComparer.java
new file mode 100644
index 000000000..5a947c596
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyComparer.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.handling;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicies;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
+import org.onap.policy.apex.model.utilities.comparison.KeyedMapComparer;
+import org.onap.policy.apex.model.utilities.comparison.KeyedMapDifference;
+
+/**
+ * This class compares the policies in two {@link AxPolicies} objects and returns the differences.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class PolicyComparer {
+ /**
+ * Compare two {@link AxPolicies} objects, comparing their policy maps one after another.
+ *
+ * @param left the left policies
+ * @param right the right policies
+ * @return the difference
+ */
+ public KeyedMapDifference<AxArtifactKey, AxPolicy> compare(final AxPolicies left, final AxPolicies right) {
+ // Find the difference between the AxPolicy objects
+ return new KeyedMapComparer<AxArtifactKey, AxPolicy>().compareMaps(left.getPolicyMap(), right.getPolicyMap());
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyLogicReader.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyLogicReader.java
new file mode 100644
index 000000000..3e5571242
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyLogicReader.java
@@ -0,0 +1,153 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.handling;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.policymodel.concepts.AxLogic;
+import org.onap.policy.apex.model.policymodel.concepts.AxLogicReader;
+import org.onap.policy.apex.model.policymodel.concepts.PolicyRuntimeException;
+import org.onap.policy.apex.model.utilities.ResourceUtils;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class is used to read Task Logic and Task Selection Logic from files into a string. A
+ * {@link PolicyLogicReader} can then be used to provide the logic on a {@link AxLogic} class
+ * constructor.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class PolicyLogicReader implements AxLogicReader {
+ private static final String DOT_JAVA = ".java.";
+
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(PolicyModelSplitter.class);
+
+ // The path of the logic package
+ private String logicPackage = "";
+
+ // Flag indicating if default logic should be returned
+ private String defaultLogic;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.policymodel.concepts.AxLogicReader#getLogicPackage()
+ */
+ @Override
+ public String getLogicPackage() {
+ return logicPackage;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.policymodel.concepts.AxLogicReader#setLogicPackage(java.lang.
+ * String)
+ */
+ @Override
+ public AxLogicReader setLogicPackage(final String incomingLogicPackage) {
+ this.logicPackage = incomingLogicPackage;
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.policymodel.concepts.AxLogicReader#getDefaultLogic()
+ */
+ @Override
+ public String getDefaultLogic() {
+ return defaultLogic;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.policymodel.concepts.AxLogicReader#setDefaultLogic(boolean)
+ */
+ @Override
+ public AxLogicReader setDefaultLogic(final String incomingDefaultLogic) {
+ this.defaultLogic = incomingDefaultLogic;
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.model.policymodel.concepts.AxLogicReader#readLogic(.policymodel.concepts
+ * .AxLogic)
+ */
+ @Override
+ public String readLogic(final AxLogic axLogic) {
+ // Java uses compiled logic, other executor types run scripts
+ if (axLogic.getLogicFlavour().equals("JAVA")) {
+ // Check if we're using the default logic
+ if (defaultLogic != null) {
+ // Return the java class name for the default logic
+ return logicPackage + DOT_JAVA + defaultLogic;
+ } else {
+ // Return the java class name for the logic
+ if (axLogic.getKey().getParentLocalName().equals(AxKey.NULL_KEY_NAME)) {
+ return logicPackage + DOT_JAVA + axLogic.getKey().getParentKeyName() + '_'
+ + axLogic.getKey().getLocalName();
+ } else {
+ return logicPackage + DOT_JAVA + axLogic.getKey().getParentKeyName() + '_'
+ + axLogic.getKey().getParentLocalName() + '_' + axLogic.getKey().getLocalName();
+ }
+ }
+ }
+ // Now, we read in the script
+
+ // Get the package name of the current package and convert dots to slashes for the file path
+ String fullLogicFilePath = logicPackage.replaceAll("\\.", "/");
+
+ // Now, the logic should be in a sub directory for the logic executor type
+ fullLogicFilePath += "/" + axLogic.getLogicFlavour().toLowerCase();
+
+ // Check if we're using the default logic
+ if (defaultLogic != null) {
+ // Default logic
+ fullLogicFilePath += "/" + defaultLogic;
+ } else {
+ if (axLogic.getKey().getParentLocalName().equals(AxKey.NULL_KEY_NAME)) {
+ fullLogicFilePath += "/" + axLogic.getKey().getParentKeyName() + "_" + axLogic.getKey().getLocalName();
+ } else {
+ fullLogicFilePath += "/" + axLogic.getKey().getParentKeyName() + "_"
+ + axLogic.getKey().getParentLocalName() + "_" + axLogic.getKey().getLocalName();
+ }
+ }
+
+ // Now get the type of executor to find the extension of the file
+ fullLogicFilePath += "." + axLogic.getLogicFlavour().toLowerCase();
+
+ final String logicString = ResourceUtils.getResourceAsString(fullLogicFilePath);
+
+ // Check if the logic was found
+ if (logicString == null || logicString.length() == 0) {
+ LOGGER.warn("logic not found for logic \"" + fullLogicFilePath + "\"");
+ throw new PolicyRuntimeException("logic not found for logic \"" + fullLogicFilePath + "\"");
+ }
+
+ // Return the right trimmed logic string
+ return logicString.replaceAll("\\s+$", "");
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelComparer.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelComparer.java
new file mode 100644
index 000000000..545a02e89
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelComparer.java
@@ -0,0 +1,271 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.handling;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.onap.policy.apex.model.policymodel.concepts.AxTask;
+import org.onap.policy.apex.model.utilities.comparison.KeyComparer;
+import org.onap.policy.apex.model.utilities.comparison.KeyDifference;
+import org.onap.policy.apex.model.utilities.comparison.KeyedMapComparer;
+import org.onap.policy.apex.model.utilities.comparison.KeyedMapDifference;
+
+/**
+ * This class compares two policy models {@link AxPolicyModel} and holds the result of that
+ * comparison. It compares policy models on their keys, their context schema differences, their
+ * event differences, their context album differences, their task differences, their policy
+ * differences, and their key information differences.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class PolicyModelComparer {
+ // Comparison of policy model keys
+ private final KeyDifference<AxArtifactKey> policyModelsKeyDifference;
+
+ // Comparison of context schemas
+ private final KeyDifference<AxArtifactKey> contextSchemasKeyDifference;
+ private KeyedMapDifference<AxArtifactKey, AxContextSchema> contextSchemaComparisonResult =
+ new KeyedMapDifference<>();
+
+ // Comparison of events
+ private final KeyDifference<AxArtifactKey> eventsKeyDifference;
+ private KeyedMapDifference<AxArtifactKey, AxEvent> eventComparisonResult = new KeyedMapDifference<>();
+
+ // Comparison of context albums
+ private final KeyDifference<AxArtifactKey> contextAlbumKeyDifference;
+ private KeyedMapDifference<AxArtifactKey, AxContextAlbum> contextAlbumComparisonResult = new KeyedMapDifference<>();
+
+ // Comparison of tasks
+ private final KeyDifference<AxArtifactKey> tasksKeyDifference;
+ private KeyedMapDifference<AxArtifactKey, AxTask> taskComparisonResult = new KeyedMapDifference<>();
+
+ // Comparison of policies
+ private final KeyDifference<AxArtifactKey> policiesKeyDifference;
+ private KeyedMapDifference<AxArtifactKey, AxPolicy> policyComparisonResult = new KeyedMapDifference<>();
+
+ // Comparison of key information
+ private final KeyDifference<AxArtifactKey> keyInformationKeyDifference;
+ private KeyedMapDifference<AxArtifactKey, AxKeyInfo> keyInfoComparisonResult = new KeyedMapDifference<>();
+
+ /**
+ * The Constructor.
+ *
+ * @param left the left
+ * @param right the right
+ */
+ public PolicyModelComparer(final AxPolicyModel left, final AxPolicyModel right) {
+ // @formatter:off
+ policyModelsKeyDifference = new KeyComparer<AxArtifactKey>().compareKeys(left.getKey(), right.getKey());
+ contextSchemasKeyDifference = new KeyComparer<AxArtifactKey>().compareKeys(left.getKey(), right.getKey());
+ eventsKeyDifference = new KeyComparer<AxArtifactKey>().compareKeys(left.getKey(), right.getKey());
+ contextAlbumKeyDifference = new KeyComparer<AxArtifactKey>().compareKeys(left.getKey(), right.getKey());
+ tasksKeyDifference = new KeyComparer<AxArtifactKey>().compareKeys(left.getKey(), right.getKey());
+ policiesKeyDifference = new KeyComparer<AxArtifactKey>().compareKeys(left.getKey(), right.getKey());
+ keyInformationKeyDifference = new KeyComparer<AxArtifactKey>().compareKeys(left.getKey(), right.getKey());
+
+ contextSchemaComparisonResult = new KeyedMapComparer<AxArtifactKey, AxContextSchema>().compareMaps(
+ left.getSchemas().getSchemasMap(), right.getSchemas().getSchemasMap());
+ eventComparisonResult = new KeyedMapComparer<AxArtifactKey, AxEvent>().compareMaps(
+ left.getEvents().getEventMap(), right.getEvents().getEventMap());
+ contextAlbumComparisonResult = new KeyedMapComparer<AxArtifactKey, AxContextAlbum>().compareMaps(
+ left.getAlbums().getAlbumsMap(), right.getAlbums().getAlbumsMap());
+ taskComparisonResult = new KeyedMapComparer<AxArtifactKey, AxTask>().compareMaps(left.getTasks().getTaskMap(), right.getTasks().getTaskMap());
+ policyComparisonResult = new KeyedMapComparer<AxArtifactKey, AxPolicy>().compareMaps(
+ left.getPolicies().getPolicyMap(), right.getPolicies().getPolicyMap());
+ keyInfoComparisonResult = new KeyedMapComparer<AxArtifactKey, AxKeyInfo>().compareMaps(
+ left.getKeyInformation().getKeyInfoMap(), right.getKeyInformation().getKeyInfoMap());
+ // @formatter:on
+ }
+
+ /**
+ * Gets the difference between policy model keys on the two models.
+ *
+ * @return the difference between policy model keys
+ */
+ public KeyDifference<AxArtifactKey> getPolicyModelsKeyDifference() {
+ return policyModelsKeyDifference;
+ }
+
+ /**
+ * Gets the difference between context schema keys on the two models.
+ *
+ * @return the difference between context schema keys
+ */
+ public KeyDifference<AxArtifactKey> getContextSchemaKeyDifference() {
+ return contextSchemasKeyDifference;
+ }
+
+ /**
+ * Gets the difference between context schemas on the two models.
+ *
+ * @return the difference between context schemas
+ */
+ public KeyedMapDifference<AxArtifactKey, AxContextSchema> getContextSchemaComparisonResult() {
+ return contextSchemaComparisonResult;
+ }
+
+ /**
+ * Gets the difference between event keys on the two models.
+ *
+ * @return the difference between event keys
+ */
+ public KeyDifference<AxArtifactKey> getEventKeyDifference() {
+ return eventsKeyDifference;
+ }
+
+ /**
+ * Gets the difference between the events on the two models.
+ *
+ * @return the difference between the events
+ */
+ public KeyedMapDifference<AxArtifactKey, AxEvent> getEventComparisonResult() {
+ return eventComparisonResult;
+ }
+
+ /**
+ * Gets the difference between context album keys on the two models.
+ *
+ * @return the difference between context album keys
+ */
+ public KeyDifference<AxArtifactKey> getContextAlbumKeyDifference() {
+ return contextAlbumKeyDifference;
+ }
+
+ /**
+ * Gets the difference between the context albums on the two models.
+ *
+ * @return the difference between the context albums
+ */
+ public KeyedMapDifference<AxArtifactKey, AxContextAlbum> getContextAlbumComparisonResult() {
+ return contextAlbumComparisonResult;
+ }
+
+ /**
+ * Gets the difference between task keys on the two models.
+ *
+ * @return the difference between task keys
+ */
+ public KeyDifference<AxArtifactKey> getTaskKeyDifference() {
+ return tasksKeyDifference;
+ }
+
+ /**
+ * Gets the difference between the tasks on the two models.
+ *
+ * @return the difference between the tasks
+ */
+ public KeyedMapDifference<AxArtifactKey, AxTask> getTaskComparisonResult() {
+ return taskComparisonResult;
+ }
+
+ /**
+ * Gets the difference between policy keys on the two models.
+ *
+ * @return the difference between policy keys
+ */
+ public KeyDifference<AxArtifactKey> getPolicykeyDifference() {
+ return policiesKeyDifference;
+ }
+
+ /**
+ * Gets the difference between the policies on the two models.
+ *
+ * @return the difference between the policies
+ */
+ public KeyedMapDifference<AxArtifactKey, AxPolicy> getPolicyComparisonResult() {
+ return policyComparisonResult;
+ }
+
+ /**
+ * Gets the difference between key information keys on the two models.
+ *
+ * @return the difference between key information keys
+ */
+ public KeyDifference<AxArtifactKey> getKeyInformationKeyDifference() {
+ return keyInformationKeyDifference;
+ }
+
+ /**
+ * Gets the difference between the key information on the two models.
+ *
+ * @return the difference between the key information
+ */
+ public KeyedMapDifference<AxArtifactKey, AxKeyInfo> getKeyInfoComparisonResult() {
+ return keyInfoComparisonResult;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return asString(true, true);
+ }
+
+ /**
+ * As string.
+ *
+ * @param diffsOnly the diffs only
+ * @param keysOnly the keys only
+ * @return the string
+ */
+ public String asString(final boolean diffsOnly, final boolean keysOnly) {
+ final StringBuilder builder = new StringBuilder();
+
+ builder.append("****** policy map differences ******\n");
+ builder.append(policyModelsKeyDifference.asString(diffsOnly));
+
+ builder.append("*** context schema differences ***\n");
+ builder.append(contextSchemasKeyDifference.asString(diffsOnly));
+ builder.append(contextSchemaComparisonResult.asString(diffsOnly, keysOnly));
+
+ builder.append("*** event differences ***\n");
+ builder.append(eventsKeyDifference.asString(diffsOnly));
+ builder.append(eventComparisonResult.asString(diffsOnly, keysOnly));
+
+ builder.append("*** context album differences ***\n");
+ builder.append(contextAlbumKeyDifference.asString(diffsOnly));
+ builder.append(contextAlbumComparisonResult.asString(diffsOnly, keysOnly));
+
+ builder.append("*** task differences ***\n");
+ builder.append(tasksKeyDifference.asString(diffsOnly));
+ builder.append(taskComparisonResult.asString(diffsOnly, keysOnly));
+
+ builder.append("*** policy differences ***\n");
+ builder.append(policiesKeyDifference.asString(diffsOnly));
+ builder.append(policyComparisonResult.asString(diffsOnly, keysOnly));
+
+ builder.append("*** key information differences ***\n");
+ builder.append(keyInformationKeyDifference.asString(diffsOnly));
+ builder.append(keyInfoComparisonResult.asString(diffsOnly, keysOnly));
+
+ builder.append("***********************************\n");
+
+ return builder.toString();
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelMerger.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelMerger.java
new file mode 100644
index 000000000..091f20462
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelMerger.java
@@ -0,0 +1,155 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.handling;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.handling.ApexModelException;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * Helper class used to merge information from two policy models together into a single policy
+ * model.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public final class PolicyModelMerger {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(PolicyModelMerger.class);
+
+ /**
+ * Private constructor used to prevent sub class instantiation.
+ */
+ private PolicyModelMerger() {}
+
+ /**
+ * Get a merged policy model with information from two policy models merged into a larger policy
+ * model.
+ *
+ * @param leftPolicyModel the source Apex Model
+ * @param rightPolicyModel the policies to include in sub policy model
+ * @param useLeftOnMatches if true, uses concepts from the left model if concepts with common
+ * keys are found, if false it uses the concepts from the right model
+ * @return the new Destination Model
+ * @throws ApexModelException on model transfer errors
+ */
+ public static AxPolicyModel getMergedPolicyModel(final AxPolicyModel leftPolicyModel,
+ final AxPolicyModel rightPolicyModel, final boolean useLeftOnMatches) throws ApexModelException {
+ return getMergedPolicyModel(leftPolicyModel, rightPolicyModel, useLeftOnMatches, false);
+ }
+
+ /**
+ * Get a merged policy model with information from two policy models merged into a larger policy
+ * model.
+ *
+ * @param leftPolicyModel the source Apex Model
+ * @param rightPolicyModel the policies to include in sub policy model
+ * @param useLeftOnMatches if true, uses concepts from the left model if concepts with common
+ * keys are found, if false it uses the concepts from the right model
+ * @param ignoreInvalidSource Ignore errors on the source model, do the best you can
+ * @return the new Destination Model
+ * @throws ApexModelException on model transfer errors
+ */
+ public static AxPolicyModel getMergedPolicyModel(final AxPolicyModel leftPolicyModel,
+ final AxPolicyModel rightPolicyModel, final boolean useLeftOnMatches, final boolean ignoreInvalidSource)
+ throws ApexModelException {
+ // Validate the left model
+ if (!ignoreInvalidSource) {
+ final AxValidationResult leftValidationResult = new AxValidationResult();
+ leftPolicyModel.validate(leftValidationResult);
+ if (!leftValidationResult.isValid()) {
+ LOGGER.warn("left model is invalid: " + leftValidationResult.toString());
+ throw new ApexModelException("left model is invalid: " + leftValidationResult.toString());
+ }
+ }
+
+ // Validate the right model
+ if (!ignoreInvalidSource) {
+ final AxValidationResult rightValidationResult = new AxValidationResult();
+ rightPolicyModel.validate(rightValidationResult);
+ if (!rightValidationResult.isValid()) {
+ LOGGER.warn("right model is invalid: " + rightValidationResult.toString());
+ throw new ApexModelException("right model is invalid: " + rightValidationResult.toString());
+ }
+ }
+
+ // The new policy model uses the favoured copy side as its base
+ final AxPolicyModel mergedPolicyModel = (AxPolicyModel) (useLeftOnMatches ? new AxPolicyModel(leftPolicyModel)
+ : new AxPolicyModel(rightPolicyModel));
+
+ // The Compared to policy model is the unfavoured side
+ final AxPolicyModel copyFromPolicyModel = (useLeftOnMatches ? rightPolicyModel : leftPolicyModel);
+
+ //  Get the keys to copy over
+ final Set<AxArtifactKey> copyOverKeyInfoKeys =
+ new TreeSet<>(copyFromPolicyModel.getKeyInformation().getKeyInfoMap().keySet());
+ final Set<AxArtifactKey> copyOverContextSchemaKeys =
+ new TreeSet<>(copyFromPolicyModel.getSchemas().getSchemasMap().keySet());
+ final Set<AxArtifactKey> copyOverEventKeys =
+ new TreeSet<>(copyFromPolicyModel.getEvents().getEventMap().keySet());
+ final Set<AxArtifactKey> copyOverContextAlbumKeys =
+ new TreeSet<>(copyFromPolicyModel.getAlbums().getAlbumsMap().keySet());
+ final Set<AxArtifactKey> copyOverTaskKeys = new TreeSet<>(copyFromPolicyModel.getTasks().getTaskMap().keySet());
+ final Set<AxArtifactKey> copyOverPolicyKeys =
+ new TreeSet<>(copyFromPolicyModel.getPolicies().getPolicyMap().keySet());
+
+ //  Remove keys that already exist
+ copyOverKeyInfoKeys.removeAll(mergedPolicyModel.getKeyInformation().getKeyInfoMap().keySet());
+ copyOverContextSchemaKeys.removeAll(mergedPolicyModel.getSchemas().getSchemasMap().keySet());
+ copyOverEventKeys.removeAll(mergedPolicyModel.getEvents().getEventMap().keySet());
+ copyOverContextAlbumKeys.removeAll(mergedPolicyModel.getAlbums().getAlbumsMap().keySet());
+ copyOverTaskKeys.removeAll(mergedPolicyModel.getTasks().getTaskMap().keySet());
+ copyOverPolicyKeys.removeAll(mergedPolicyModel.getPolicies().getPolicyMap().keySet());
+
+ // Now add all the concepts that must be copied over
+ for (final AxArtifactKey keyInfoKey : copyOverKeyInfoKeys) {
+ mergedPolicyModel.getKeyInformation().getKeyInfoMap().put(keyInfoKey,
+ copyFromPolicyModel.getKeyInformation().getKeyInfoMap().get(keyInfoKey));
+ }
+ for (final AxArtifactKey contextSchemaKey : copyOverContextSchemaKeys) {
+ mergedPolicyModel.getSchemas().getSchemasMap().put(contextSchemaKey,
+ copyFromPolicyModel.getSchemas().getSchemasMap().get(contextSchemaKey));
+ }
+ for (final AxArtifactKey eventKey : copyOverEventKeys) {
+ mergedPolicyModel.getEvents().getEventMap().put(eventKey,
+ copyFromPolicyModel.getEvents().getEventMap().get(eventKey));
+ }
+ for (final AxArtifactKey contextAlbumKey : copyOverContextAlbumKeys) {
+ mergedPolicyModel.getAlbums().getAlbumsMap().put(contextAlbumKey,
+ copyFromPolicyModel.getAlbums().getAlbumsMap().get(contextAlbumKey));
+ }
+ for (final AxArtifactKey taskKey : copyOverTaskKeys) {
+ mergedPolicyModel.getTasks().getTaskMap().put(taskKey,
+ copyFromPolicyModel.getTasks().getTaskMap().get(taskKey));
+ }
+ for (final AxArtifactKey policyKey : copyOverPolicyKeys) {
+ mergedPolicyModel.getPolicies().getPolicyMap().put(policyKey,
+ copyFromPolicyModel.getPolicies().getPolicyMap().get(policyKey));
+ }
+
+ // That's it, return the model
+ return mergedPolicyModel;
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelSplitter.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelSplitter.java
new file mode 100644
index 000000000..586d0706e
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyModelSplitter.java
@@ -0,0 +1,165 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.policymodel.handling;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.basicmodel.handling.ApexModelException;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * Helper class used to extract information from a policy model into a policy model that is a subset
+ * of the original policy model.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public final class PolicyModelSplitter {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(PolicyModelSplitter.class);
+
+ /**
+ * Private constructor used to prevent sub class instantiation.
+ */
+ private PolicyModelSplitter() {}
+
+ /**
+ * Get a sub policy model with only the information required for the specified policies from a
+ * larger policy model.
+ *
+ * @param sourcePolicyModel the source Apex Model
+ * @param subPolicies the policies to include in sub policy model
+ * @return the new Destination Model
+ * @throws ApexModelException on model transfer errors
+ */
+ public static AxPolicyModel getSubPolicyModel(final AxPolicyModel sourcePolicyModel,
+ final Collection<AxArtifactKey> subPolicies) throws ApexModelException {
+ return getSubPolicyModel(sourcePolicyModel, subPolicies, false);
+ }
+
+ /**
+ * Get a sub policy model with only the information required for the specified policies from a
+ * larger policy model.
+ *
+ * @param sourcePolicyModel the source Apex Model
+ * @param subPolicies the policies to include in sub policy model
+ * @param ignoreInvalidSource Ignore errors on the source model, do the best you can
+ * @return the new Destination Model
+ * @throws ApexModelException on model transfer errors
+ */
+ public static AxPolicyModel getSubPolicyModel(final AxPolicyModel sourcePolicyModel,
+ final Collection<AxArtifactKey> subPolicies, final boolean ignoreInvalidSource) throws ApexModelException {
+ // Validate the source model
+ if (!ignoreInvalidSource) {
+ final AxValidationResult sourceValidationResult = new AxValidationResult();
+ sourcePolicyModel.validate(sourceValidationResult);
+ if (!sourceValidationResult.isValid()) {
+ LOGGER.warn("source model is invalid: " + sourceValidationResult.toString());
+ throw new ApexModelException("source model is invalid: " + sourceValidationResult.toString());
+ }
+ }
+
+ // The new policy model
+ final AxPolicyModel newPolicyModel = new AxPolicyModel(sourcePolicyModel.getKey());
+ newPolicyModel.getKeyInformation().setKey(sourcePolicyModel.getKeyInformation().getKey());
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(sourcePolicyModel.getKey(),
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(sourcePolicyModel.getKey()));
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(sourcePolicyModel.getKeyInformation().getKey(),
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap()
+ .get(sourcePolicyModel.getKeyInformation().getKey()));
+
+ //  Get the events, tasks, context maps, and data types used by each policy
+ final Set<AxArtifactKey> contextSchemaSet = new TreeSet<>();
+ final Set<AxArtifactKey> eventSet = new TreeSet<>();
+ final Set<AxArtifactKey> contextAlbumSet = new TreeSet<>();
+ final Set<AxArtifactKey> taskSet = new TreeSet<>();
+
+ newPolicyModel.getPolicies().setKey(sourcePolicyModel.getPolicies().getKey());
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(sourcePolicyModel.getPolicies().getKey(),
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(sourcePolicyModel.getPolicies().getKey()));
+ for (final AxArtifactKey subPolicyKey : subPolicies) {
+ final AxPolicy subPolicy = sourcePolicyModel.getPolicies().getPolicyMap().get(subPolicyKey);
+ if (subPolicy == null) {
+ LOGGER.warn("source sub policy not found: " + subPolicyKey);
+ continue;
+ }
+
+ // Transfer the policy across
+ newPolicyModel.getPolicies().getPolicyMap().put(subPolicyKey, subPolicy);
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(subPolicyKey,
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(subPolicyKey));
+
+ // Get the references for this policy
+ final PolicyAnalysisResult analysisResult = new PolicyAnalyser().analyse(sourcePolicyModel, subPolicy);
+ contextSchemaSet.addAll(analysisResult.getUsedContextSchemas());
+ eventSet.addAll(analysisResult.getUsedEvents());
+ contextAlbumSet.addAll(analysisResult.getUsedContextAlbums());
+ taskSet.addAll(analysisResult.getUsedTasks());
+
+ }
+
+ // Now add all the referenced data types, events, context maps, and tasks to the policy
+ // model
+ newPolicyModel.getSchemas().setKey(sourcePolicyModel.getSchemas().getKey());
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(sourcePolicyModel.getSchemas().getKey(),
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(sourcePolicyModel.getSchemas().getKey()));
+ for (final AxArtifactKey contextSchemaKey : contextSchemaSet) {
+ newPolicyModel.getSchemas().getSchemasMap().put(contextSchemaKey,
+ sourcePolicyModel.getSchemas().getSchemasMap().get(contextSchemaKey));
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(contextSchemaKey,
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(contextSchemaKey));
+ }
+ newPolicyModel.getEvents().setKey(sourcePolicyModel.getEvents().getKey());
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(sourcePolicyModel.getEvents().getKey(),
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(sourcePolicyModel.getEvents().getKey()));
+ for (final AxArtifactKey eventKey : eventSet) {
+ newPolicyModel.getEvents().getEventMap().put(eventKey,
+ sourcePolicyModel.getEvents().getEventMap().get(eventKey));
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(eventKey,
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(eventKey));
+ }
+ newPolicyModel.getAlbums().setKey(sourcePolicyModel.getAlbums().getKey());
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(sourcePolicyModel.getAlbums().getKey(),
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(sourcePolicyModel.getAlbums().getKey()));
+ for (final AxArtifactKey contextAlbumKey : contextAlbumSet) {
+ newPolicyModel.getAlbums().getAlbumsMap().put(contextAlbumKey,
+ sourcePolicyModel.getAlbums().getAlbumsMap().get(contextAlbumKey));
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(contextAlbumKey,
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(contextAlbumKey));
+ }
+ newPolicyModel.getTasks().setKey(sourcePolicyModel.getTasks().getKey());
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(sourcePolicyModel.getTasks().getKey(),
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(sourcePolicyModel.getTasks().getKey()));
+ for (final AxArtifactKey taskKey : taskSet) {
+ newPolicyModel.getTasks().getTaskMap().put(taskKey, sourcePolicyModel.getTasks().getTaskMap().get(taskKey));
+ newPolicyModel.getKeyInformation().getKeyInfoMap().put(taskKey,
+ sourcePolicyModel.getKeyInformation().getKeyInfoMap().get(taskKey));
+ }
+
+ // That's it, return the model
+ return newPolicyModel;
+ }
+}
diff --git a/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/package-info.java b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/package-info.java
new file mode 100644
index 000000000..f84befd26
--- /dev/null
+++ b/model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/package-info.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains utility classes used to handle APEX polcies and policy models.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.model.policymodel.handling;