diff options
Diffstat (limited to 'model/basic-model/src/main/java/org')
44 files changed, 6743 insertions, 0 deletions
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexConceptException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexConceptException.java new file mode 100644 index 000000000..bfe296d97 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexConceptException.java @@ -0,0 +1,49 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +/** + * This class is an exception thrown on Apex Concept errors. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class ApexConceptException extends ApexException { + private static final long serialVersionUID = -8507246953751956974L; + + /** + * Instantiates a new apex concept exception. + * + * @param message the message on the exception + */ + public ApexConceptException(final String message) { + super(message); + } + + /** + * Instantiates a new apex concept exception. + * + * @param message the message on the exception + * @param e the exception that caused this Apex exception + */ + public ApexConceptException(final String message, final Exception e) { + super(message, e); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexException.java new file mode 100644 index 000000000..74a60e243 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexException.java @@ -0,0 +1,102 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +/** + * This class is a base exception from which all Apex exceptions are sub classes. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class ApexException extends Exception { + private static final long serialVersionUID = -8507246953751956974L; + + // The object on which the exception was thrown + private transient Object object = null; + + /** + * Instantiates a new apex exception. + * + * @param message the message on the exception + */ + public ApexException(final String message) { + super(message); + } + + /** + * Instantiates a new apex exception. + * + * @param message the message on the exception + * @param object the object that the exception was thrown on + */ + public ApexException(final String message, final Object object) { + super(message); + this.object = object; + } + + /** + * Instantiates a new apex exception. + * + * @param message the message on the exception + * @param e the exception that caused this Apex exception + */ + public ApexException(final String message, final Exception e) { + super(message, e); + } + + /** + * Instantiates a new apex exception. + * + * @param message the message on the exception + * @param e the exception that caused this Apex exception + * @param object the object that the exception was thrown on + */ + public ApexException(final String message, final Exception e, final Object object) { + super(message, e); + this.object = object; + } + + /** + * Get the message from this exception and its causes. + * + * @return the cascaded messages from this exception and the exceptions that caused it + */ + public String getCascadedMessage() { + final StringBuilder builder = new StringBuilder(); + builder.append(this.getMessage()); + + for (Throwable t = this; t != null; t = t.getCause()) { + builder.append("\ncaused by: "); + builder.append(t.getMessage()); + } + + return builder.toString(); + } + + /** + * + * Get the object on which the exception was thrown. + * + * @return The object on which the exception was thrown + */ + public Object getObject() { + return object; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexRuntimeException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexRuntimeException.java new file mode 100644 index 000000000..4cdfbe4b0 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexRuntimeException.java @@ -0,0 +1,101 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +/** + * This class is a base run time exception from which all Apex run time exceptions are sub classes. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class ApexRuntimeException extends RuntimeException { + private static final long serialVersionUID = -8507246953751956974L; + + // The object on which the exception was thrown + private transient Object object = null; + + /** + * Instantiates a new apex runtime exception. + * + * @param message the message on the exception + */ + public ApexRuntimeException(final String message) { + super(message); + } + + /** + * Instantiates a new apex runtime exception. + * + * @param message the message on the exception + * @param object the object that the exception was thrown on + */ + public ApexRuntimeException(final String message, final Object object) { + super(message); + this.object = object; + } + + /** + * Instantiates a new apex runtime exception. + * + * @param message the message on the exception + * @param e the exception that caused this Apex exception + */ + public ApexRuntimeException(final String message, final Exception e) { + super(message, e); + } + + /** + * Instantiates a new apex runtime exception. + * + * @param message the message on the exception + * @param e the exception that caused this Apex exception + * @param object the object that the exception was thrown on + */ + public ApexRuntimeException(final String message, final Exception e, final Object object) { + super(message, e); + this.object = object; + } + + /** + * Get the message from this exception and its causes. + * + * @return the message of this exception and all the exceptions that caused this exception + */ + public String getCascadedMessage() { + final StringBuilder builder = new StringBuilder(); + builder.append(this.getMessage()); + + for (Throwable t = this; t != null; t = t.getCause()) { + builder.append("\ncaused by: "); + builder.append(t.getMessage()); + } + + return builder.toString(); + } + + /** + * Get the object on which the exception was thrown. + * + * @return The object + */ + public Object getObject() { + return object; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxArtifactKey.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxArtifactKey.java new file mode 100644 index 000000000..1de7ae72e --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxArtifactKey.java @@ -0,0 +1,376 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +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.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * An artifact key uniquely identifies every first order entity in the system. Every first order concept in the system must have + * an {@link AxArtifactKey} to identify it. Concepts that are wholly contained in another concept are identified using + * a {@link AxReferenceKey} key. + * <p> + * Key validation checks that the name and version fields match the {@link NAME_REGEXP} and {@link VERSION_REGEXP} regular expressions respectively. + */ +@Embeddable +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "apexArtifactKey", namespace = "http://www.ericsson.com/apex") + +@XmlType(name = "AxArtifactKey", namespace = "http://www.ericsson.com/apex", propOrder = { "name", "version" }) + +public class AxArtifactKey extends AxKey { + private static final long serialVersionUID = 8932717618579392561L; + + private static final String NAME_TOKEN = "name"; + private static final String VERSION_TOKEN = "version"; + + @Column(name = NAME_TOKEN) + @XmlElement(required = true) + private String name; + + @Column(name = VERSION_TOKEN) + @XmlElement(required = true) + private String version; + + /** + * The default constructor creates a null artifact key. + */ + public AxArtifactKey() { + this(NULL_KEY_NAME, NULL_KEY_VERSION); + } + + /** + * Copy constructor + * @param copyConcept the concept to copy from + */ + public AxArtifactKey(final AxArtifactKey copyConcept) { + super(copyConcept); + } + + /** + * Constructor to create a key with the specified name and version. + * + * @param name the key name + * @param version the key version + */ + public AxArtifactKey(final String name, final String version) { + super(); + this.name = Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP); + this.version = Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP); + } + + /** + * Constructor to create a key using the key and version from the specified key ID. + * + * @param id the key ID in a format that respects the {@link KEY_ID_REGEXP} + */ + public AxArtifactKey(final String id) { + Assertions.argumentNotNull(id, "id may not be null"); + + // Check the incoming ID is valid + Assertions.validateStringParameter("id", id, KEY_ID_REGEXP); + + // Split on colon, if the id passes the regular expression test above + // it'll have just one colon separating the name and version + // No need for range checks or size checks on the array + final String[] nameVersionArray = id.split(":"); + + // Return the new key + name = Assertions.validateStringParameter(NAME_TOKEN, nameVersionArray[0], NAME_REGEXP); + version = Assertions.validateStringParameter(VERSION_TOKEN, nameVersionArray[1], VERSION_REGEXP); + } + + /** + * Get a null artifact key. + * + * @return a null artifact key + */ + public static final AxArtifactKey getNullKey() { + return new AxArtifactKey(AxKey.NULL_KEY_NAME, AxKey.NULL_KEY_VERSION); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey() + */ + @Override + public AxArtifactKey getKey() { + return this; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys() + */ + @Override + public List<AxKey> getKeys() { + final List<AxKey> keyList = new ArrayList<>(); + keyList.add(getKey()); + return keyList; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getID() + */ + @Override + public String getID() { + return name + ':' + version; + } + + /** + * Gets the key name. + * + * @return the key name + */ + public String getName() { + return name; + } + + /** + * Sets the key name. + * + * @param name the key name + */ + public void setName(final String name) { + this.name = Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP); + } + + /** + * Gets the key version. + * + * @return the key version + */ + public String getVersion() { + return version; + } + + /** + * Sets the key version. + * + * @param version the key version + */ + public void setVersion(final String version) { + this.version = Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getCompatibility(com. ericsson.apex.model.basicmodel.concepts.AxKey) + */ + @Override + public AxKey.Compatibility getCompatibility(final AxKey otherKey) { + if (!(otherKey instanceof AxArtifactKey)) { + return Compatibility.DIFFERENT; + } + final AxArtifactKey otherArtifactKey = (AxArtifactKey) otherKey; + + if (this.equals(otherArtifactKey)) { + return Compatibility.IDENTICAL; + } + if (!this.getName().equals(otherArtifactKey.getName())) { + return Compatibility.DIFFERENT; + } + + final String[] thisVersionArray = getVersion().split("\\."); + final String[] otherVersionArray = otherArtifactKey.getVersion().split("\\."); + + // There must always be at least one element in each version + if (!thisVersionArray[0].equals(otherVersionArray[0])) { + return Compatibility.MAJOR; + } + + if (thisVersionArray.length >= 2 && otherVersionArray.length >= 2 && !thisVersionArray[1].equals(otherVersionArray[1])) { + return Compatibility.MINOR; + } + + return Compatibility.PATCH; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#isCompatible(com. ericsson.apex.model.basicmodel.concepts.AxKey) + */ + @Override + public boolean isCompatible(final AxKey otherKey) { + if (!(otherKey instanceof AxArtifactKey)) { + return false; + } + final AxArtifactKey otherArtifactKey = (AxArtifactKey) otherKey; + + final Compatibility compatibility = this.getCompatibility(otherArtifactKey); + + return !(compatibility == Compatibility.DIFFERENT || compatibility == Compatibility.MAJOR); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult) + */ + @Override + public AxValidationResult validate(final AxValidationResult result) { + try { + Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP); + } + catch (final IllegalArgumentException e) { + result.addValidationMessage( + new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "name invalid-" + e.getMessage())); + } + + try { + Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP); + } + catch (final IllegalArgumentException e) { + result.addValidationMessage( + new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "version invalid-" + e.getMessage())); + } + + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean() + */ + @Override + public void clean() { + name = Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP); + version = Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString() + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + builder.append(":("); + builder.append("name="); + builder.append(name); + builder.append(",version="); + builder.append(version); + builder.append(")"); + return builder.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public AxConcept copyTo(final AxConcept target) { + Assertions.argumentNotNull(target, "target may not be null"); + + final AxConcept copyObject = target; + Assertions.instanceOf(copyObject, AxArtifactKey.class); + + final AxArtifactKey copy = ((AxArtifactKey) copyObject); + copy.setName(name); + copy.setVersion(version); + + return copyObject; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + name.hashCode(); + result = prime * result + version.hashCode(); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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 AxArtifactKey other = (AxArtifactKey) obj; + + if (!name.equals(other.name)) { + return false; + } + return version.equals(other.version); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @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 AxArtifactKey other = (AxArtifactKey) otherObj; + + if (!name.equals(other.name)) { + return name.compareTo(other.name); + } + return version.compareTo(other.version); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConcept.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConcept.java new file mode 100644 index 000000000..005d17d76 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConcept.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.apex.model.basicmodel.concepts; + +import java.io.Serializable; +import java.util.List; + +import javax.xml.bind.annotation.XmlType; + +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * This class is the base class for all Apex concept classes. It enforces implementation of abstract methods and interfaces on all concepts + * that are sub-classes of this class. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ + +@XmlType(name = "AxConcept", namespace = "http://www.ericsson.com/apex") + +public abstract class AxConcept implements Serializable, Comparable<AxConcept> { + private static final long serialVersionUID = -7434939557282697490L; + + /** + * Default constructor + */ + public AxConcept() { + } + + /** + * Copy constructor + * @param copyConcept the concept to copy from + */ + public AxConcept(final AxConcept copyConcept) { + Assertions.argumentNotNull(copyConcept, "copy concept may not be null"); + copyConcept.copyTo(this); + } + + /** + * Gets the key of this concept. + * + * @return the concept key + */ + public abstract AxKey getKey(); + + /** + * Gets a list of all keys for this concept and all concepts that are defined or referenced by this concept and its sub-concepts. + * + * @return the keys used by this concept and it's contained concepts + */ + public abstract List<AxKey> getKeys(); + + /** + * Validate that this concept is structurally correct. + * + * @param result the parameter in which the result of the validation will be returned + * @return the validation result that was passed in in the @{link result} field with the result of this validation added + */ + public abstract AxValidationResult validate(AxValidationResult result); + + /** + * Clean this concept, tidy up any superfluous information such as leading and trailing white space. + */ + public abstract void clean(); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public abstract boolean equals(Object otherObject); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public abstract String toString(); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public abstract int hashCode(); + + /** + * Copy this concept to another object. The target object must have the same class as the source object. + * + * @param target the target object to which this object is copied + * @return the copied object + */ + public abstract AxConcept copyTo(AxConcept target); + + /** + * Gets the ID string of this concept. + * + * @return the ID string of this concept + */ + public String getID() { + return getKey().getID(); + } + + /** + * Checks if this key matches the given key ID. + * + * @param id the key ID to match against + * @return true, if this key matches the ID + */ + public final boolean matchesID(final String id) { + Assertions.argumentNotNull(id, "id may not be null"); + + // Check the ID + return getID().equals(id); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetter.java new file mode 100644 index 000000000..d5d1752e6 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetter.java @@ -0,0 +1,77 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.Set; + +/** + * This interface is used to allow get methods to be placed on concepts that have embedded maps. + * <p> + * It forces those concepts with maps to implement the get methods specified on this interface as convenience methods to avoid concept users having to use a + * second level of referencing to access concepts in the the maps. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <C> the type of concept on which the interface is applied. + */ +public interface AxConceptGetter<C> { + + /** + * Get the latest version for a concept with the given key. + * + * @param conceptKey The key of the concept + * @return The concept + */ + C get(AxArtifactKey conceptKey); + + /** + * Get the latest version for a concept with the given key name. + * + * @param conceptKeyName The name of the concept + * @return The concept + */ + C get(String conceptKeyName); + + /** + * Get the latest version for a concept with the given key name and version. + * + * @param conceptKeyName The name of the concept + * @param conceptKeyVersion The version of the concept + * @return The concept + */ + C get(String conceptKeyName, String conceptKeyVersion); + + /** + * Get the all versions for a concept with the given key name. + * + * @param conceptKeyName The name of the concept + * @return The concepts + */ + Set<C> getAll(String conceptKeyName); + + /** + * Get the all versions for a concept with the given key name and starting version. + * + * @param conceptKeyName The name of the concept + * @param conceptKeyVersion The first version version of the concept to get + * @return The concepts + */ + Set<C> getAll(String conceptKeyName, String conceptKeyVersion); +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetterImpl.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetterImpl.java new file mode 100644 index 000000000..af9764113 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetterImpl.java @@ -0,0 +1,156 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.NavigableMap; +import java.util.Set; +import java.util.TreeSet; + +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * Implements concept getting from navigable maps. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <C> the type of concept on which the interface implementation is applied. + */ +public class AxConceptGetterImpl<C> implements AxConceptGetter<C> { + + // The map from which to get concepts + private final NavigableMap<AxArtifactKey, C> conceptMap; + + /** + * Constructor that sets the concept map on which the getter methods in the interface will operate.. + * + * @param conceptMap the concept map on which the method will operate + */ + public AxConceptGetterImpl(final NavigableMap<AxArtifactKey, C> conceptMap) { + this.conceptMap = conceptMap; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(com. ericsson.apex.core.basicmodel.concepts.AxArtifactKey) + */ + @Override + public C get(final AxArtifactKey conceptKey) { + return conceptMap.get(conceptKey); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String) + */ + @Override + public C get(final String conceptKeyName) { + Assertions.argumentNotNull(conceptKeyName, "conceptKeyName may not be null"); + + // The very fist key that could have this name + final AxArtifactKey lowestArtifactKey = new AxArtifactKey(conceptKeyName, "0.0.1"); + + // Check if we found a key for our name + AxArtifactKey foundKey = conceptMap.ceilingKey(lowestArtifactKey); + if (foundKey == null || !foundKey.getName().equals(conceptKeyName)) { + return null; + } + + // Look for higher versions of the key + do { + final AxArtifactKey nextkey = conceptMap.higherKey(foundKey); + if (nextkey == null || !nextkey.getName().equals(conceptKeyName)) { + break; + } + foundKey = nextkey; + } + while (true); + + return conceptMap.get(foundKey); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String, java.lang.String) + */ + @Override + public C get(final String conceptKeyName, final String conceptKeyVersion) { + Assertions.argumentNotNull(conceptKeyName, "conceptKeyName may not be null"); + + if (conceptKeyVersion != null) { + return conceptMap.get(new AxArtifactKey(conceptKeyName, conceptKeyVersion)); + } + else { + return this.get(conceptKeyName); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String) + */ + @Override + public Set<C> getAll(final String conceptKeyName) { + return getAll(conceptKeyName, null); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String, java.lang.String) + */ + @Override + public Set<C> getAll(final String conceptKeyName, final String conceptKeyVersion) { + final Set<C> returnSet = new TreeSet<>(); + + if (conceptKeyName == null) { + returnSet.addAll(conceptMap.values()); + return returnSet; + } + + // The very fist key that could have this name + final AxArtifactKey lowestArtifactKey = new AxArtifactKey(conceptKeyName, "0.0.1"); + if (conceptKeyVersion != null) { + lowestArtifactKey.setVersion(conceptKeyVersion); + } + + // Check if we found a key for our name + AxArtifactKey foundKey = conceptMap.ceilingKey(lowestArtifactKey); + if (foundKey == null || !foundKey.getName().equals(conceptKeyName)) { + return returnSet; + } + returnSet.add(conceptMap.get(foundKey)); + + // Look for higher versions of the key + do { + foundKey = conceptMap.higherKey(foundKey); + if (foundKey == null || !foundKey.getName().equals(conceptKeyName)) { + break; + } + returnSet.add(conceptMap.get(foundKey)); + } + while (true); + + return returnSet; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKey.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKey.java new file mode 100644 index 000000000..0d63dbf7d --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKey.java @@ -0,0 +1,99 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +/** + * The key uniquely identifies every entity in the system. This class is an abstract class to give a common parent for all key types in the + * system. + */ +public abstract class AxKey extends AxConcept { + private static final long serialVersionUID = 6281159885962014041L; + + /** Regular expression to specify the structure of key names. */ + public static final String NAME_REGEXP = "[A-Za-z0-9\\-_\\.]+"; + + /** Regular expression to specify the structure of key versions. */ + public static final String VERSION_REGEXP = "[A-Za-z0-9.]+"; + + /** Regular expression to specify the structure of key IDs. */ + public static final String KEY_ID_REGEXP = "[A-Za-z0-9\\-_\\.]+:[0-9].[0-9].[0-9]"; + + /** Specifies the value for names in NULL keys. */ + public static final String NULL_KEY_NAME = "NULL"; + + /** Specifies the value for versions in NULL keys. */ + public static final String NULL_KEY_VERSION = "0.0.0"; + + /** + * This enumeration is returned on key compatibility checks. + */ + public enum Compatibility { + /** The keys have different names. */ + DIFFERENT, + /** The name of the key matches but the Major version number of the keys is different (x in x.y.z do not match). */ + MAJOR, + /** The name of the key matches but the Minor version number of the keys is different (y in x.y.z do not match). */ + MINOR, + /** The name of the key matches but the Patch version number of the keys is different (z in x.y.z do not match). */ + PATCH, + /** The keys match completely. */ + IDENTICAL + } + + /** + * Default constructor + */ + public AxKey() { + super(); + } + + /** + * Copy constructor + * @param copyConcept the concept to copy from + */ + public AxKey(final AxKey copyConcept) { + super(copyConcept); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getID() + */ + @Override + public abstract String getID(); + + /** + * Return the result of a compatibility check of two keys. + * + * @param otherKey the key to check compatibility against + * @return the compatibility result of the check + */ + public abstract Compatibility getCompatibility(AxKey otherKey); + + /** + * Check if two keys are compatible, that is the keys are IDENTICAL or have only MINOR, PATCH differences. + * + * @param otherKey the key to check compatibility against + * @return true, if the keys are compatible + */ + public abstract boolean isCompatible(AxKey otherKey); +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInfo.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInfo.java new file mode 100644 index 000000000..1ffb40b27 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInfo.java @@ -0,0 +1,356 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.List; +import java.util.Random; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Convert; +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 javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.apex.model.basicmodel.dao.converters.CDATAConditioner; +import org.onap.apex.model.basicmodel.dao.converters.UUID2String; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * The key information on an {@link AxArtifactKey} key in an Apex policy model. Each {@link AxArtifactKey} must have an {@link AxKeyInfo} object. THe + * information held is the key's UUID and it's description. + * <p> + * Validation checks that all fields are defined and that the key is valid. It also observes that descriptions are blank and warns if the UUID is a zero UUID. + */ + +@Entity +@Table(name = "AxKeyInfo") + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "apexKeyInfo", namespace = "http://www.ericsson.com/apex") +@XmlType(name = "AxKeyInfo", namespace = "http://www.ericsson.com/apex", propOrder = { "key", "uuid", "description" }) + +public class AxKeyInfo extends AxConcept { + private static final long serialVersionUID = -4023935924068914308L; + + private static final int MAX_DESCRIPTION_LENGTH_8192 = 8192; + private static final int UUID_BYTE_LENGTH_16 = 16; + + @EmbeddedId + @XmlElement(name = "key", required = true) + private AxArtifactKey key; + + @Column(name = "uuid") + @Convert(converter = UUID2String.class) + @XmlJavaTypeAdapter(value = UUID2String.class) + @XmlElement(name = "UUID", required = true) + private UUID uuid; + + @Column(name = "description", length = MAX_DESCRIPTION_LENGTH_8192) + @Convert(converter = CDATAConditioner.class) + @XmlJavaTypeAdapter(value = CDATAConditioner.class) + @XmlElement(required = true) + private String description; + + /** + * The Default Constructor creates this concept with a NULL artifact key. + */ + public AxKeyInfo() { + this(new AxArtifactKey()); + } + + /** + * Copy constructor + * @param copyConcept the concept to copy from + */ + public AxKeyInfo(final AxKeyInfo copyConcept) { + super(copyConcept); + } + + /** + * Constructor to create this concept with the specified key. + * + * @param key the key of the concept + */ + public AxKeyInfo(final AxArtifactKey key) { + this(key, UUID.randomUUID(), "Generated description for concept referred to by key \"" + key.getID() + "\""); + } + + /** + * Constructor to create this concept and set all its fields. + * + * @param key the key of the concept + * @param uuid the UUID of the concept + * @param description the description of the concept + */ + public AxKeyInfo(final AxArtifactKey key, final UUID uuid, final String description) { + super(); + Assertions.argumentNotNull(key, "key may not be null"); + Assertions.argumentNotNull(uuid, "uuid may not be null"); + Assertions.argumentNotNull(description, "description may not be null"); + + this.key = key; + this.uuid = uuid; + this.description = description.trim(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey() + */ + @Override + public AxArtifactKey getKey() { + return key; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys() + */ + @Override + public List<AxKey> getKeys() { + return key.getKeys(); + } + + /** + * Sets the key of the concept. + * + * @param key the concept key + */ + public void setKey(final AxArtifactKey key) { + Assertions.argumentNotNull(key, "key may not be null"); + this.key = key; + } + + /** + * Gets the UUID of the concept. + * + * @return the uuid of the concept + */ + public UUID getUUID() { + return uuid; + } + + /** + * Sets the UUID of the concept. + * + * @param uuid the uuid of the concept + */ + public void setUuid(final UUID uuid) { + Assertions.argumentNotNull(uuid, "uuid may not be null"); + this.uuid = uuid; + } + + /** + * Gets the description of the concept. + * + * @return the description of the concept + */ + public String getDescription() { + return description; + } + + /** + * Sets the description of the concept. + * + * @param description the description of the concept + */ + public void setDescription(final String description) { + Assertions.argumentNotNull(description, "description may not be null"); + this.description = description.trim(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.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 (description.trim().length() == 0) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION, "description is blank")); + } + + if (uuid.equals(new UUID(0, 0))) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.WARNING, "UUID is a zero UUID: " + new UUID(0, 0))); + } + + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean() + */ + @Override + public void clean() { + key.clean(); + description = description.trim(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString() + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + builder.append(":("); + builder.append("artifactId="); + builder.append(key); + builder.append(",uuid="); + builder.append(uuid); + builder.append(",description="); + builder.append(description); + builder.append(")"); + return builder.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public AxConcept copyTo(final AxConcept target) { + Assertions.argumentNotNull(target, "target may not be null"); + + final Object copyObject = target; + Assertions.instanceOf(copyObject, AxKeyInfo.class); + + final AxKeyInfo copy = ((AxKeyInfo) copyObject); + copy.setKey(new AxArtifactKey(key)); + copy.setUuid(UUID.fromString(uuid.toString())); + copy.setDescription(description); + + return copy; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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 + uuid.hashCode(); + result = prime * result + description.hashCode(); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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 AxKeyInfo other = (AxKeyInfo) obj; + if (!key.equals(other.key)) { + return false; + } + if (!uuid.equals(other.uuid)) { + return false; + } + final String thisdesc = CDATAConditioner.clean(description); + final String otherdesc = CDATAConditioner.clean(other.description); + return thisdesc.equals(otherdesc); + } + + /* + * (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 AxKeyInfo other = (AxKeyInfo) otherObj; + if (!key.equals(other.key)) { + return key.compareTo(other.key); + } + if (!uuid.equals(other.uuid)) { + return uuid.compareTo(other.uuid); + } + return description.compareTo(other.description); + } + + /** + * Generate a reproducible UUID for a given string seed. + * + * @param seed the seed + * @return the uuid + */ + public static UUID generateReproducibleUUID(final String seed) { + final Random random; + if (seed != null && seed.length() > 0) { + random = new Random(seed.hashCode()); + } + else { + random = new Random(); + } + byte[] array = new byte[UUID_BYTE_LENGTH_16]; + random.nextBytes(array); + return UUID.nameUUIDFromBytes(array); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInformation.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInformation.java new file mode 100644 index 000000000..3082c4f5d --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInformation.java @@ -0,0 +1,448 @@ +/* + * ============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.apex.model.basicmodel.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 java.util.TreeSet; +import java.util.UUID; + +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.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * The Class AxKeyInformation holds a map of the key information for the entire Apex model. All Apex models {@link AxModel} must have an + * {@link AxKeyInformation} field. The {@link AxKeyInformation} class implements the helper methods of the {@link AxConceptGetter} interface to allow + * {@link AxKeyInfo} instances to be retrieved by calling methods directly on this class without referencing the contained map. + * <p> + * Validation checks that the key is not null, that the key information map is not empty, that each key and value in the map is defined, that the key in each + * map entry matches the key if each entry value, and that no duplicate UUIDs exist. Each key information entry is then validated individually. + */ +@Entity +@Table(name = "AxKeyInformation") + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "AxKeyInformation", namespace = "http://www.ericsson.com/apex", propOrder = { "key", "keyInfoMap" }) + +public class AxKeyInformation extends AxConcept implements AxConceptGetter<AxKeyInfo> { + private static final long serialVersionUID = -2746380769017043888L; + + @EmbeddedId + @XmlElement(name = "key", required = true) + private AxArtifactKey key; + + // @formatter:off + @ManyToMany(cascade = CascadeType.ALL) + @JoinTable( + joinColumns = { + @JoinColumn(name = "keyInfoMapName", referencedColumnName = "name"), + @JoinColumn(name = "keyInfoMapVersion", referencedColumnName = "version"), + }, + inverseJoinColumns = { + @JoinColumn(name = "keyInfoName", referencedColumnName = "name"), + @JoinColumn(name = "keyInfoVersion", referencedColumnName = "version") + }) + private Map<AxArtifactKey, AxKeyInfo> keyInfoMap; + // @formatter:on + + /** + * The Default Constructor creates this concept with a null key. + */ + public AxKeyInformation() { + this(new AxArtifactKey()); + } + + /** + * Copy constructor + * @param copyConcept the concept to copy from + */ + public AxKeyInformation(final AxKeyInformation copyConcept) { + super(copyConcept); + } + + /** + * Constructor to create this concept with the specified key. + * + * @param key the key of the concept + */ + public AxKeyInformation(final AxArtifactKey key) { + this(key, new TreeMap<AxArtifactKey, AxKeyInfo>()); + } + + /** + * Constructor to create this concept and set all its fields. + * + * @param key the key of the concept + * @param keyInfoMap the key info map of the concept + */ + public AxKeyInformation(final AxArtifactKey key, final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) { + super(); + Assertions.argumentNotNull(key, "key may not be null"); + Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null"); + + this.key = key; + this.keyInfoMap = new TreeMap<>(); + this.keyInfoMap.putAll(keyInfoMap); + } + + /** + * When a model is unmarshalled from disk or from the database, the key information 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, AxKeyInfo> navigablekeyInfoMap = new TreeMap<>(); + navigablekeyInfoMap.putAll(keyInfoMap); + keyInfoMap = navigablekeyInfoMap; + } + + /** + * This method generates default key information for all keys found in the concept passed in as a parameter that do not already have key information. + * + * @param concept the concept for which to generate key information + */ + public void generateKeyInfo(final AxConcept concept) { + for (final AxKey axKey : concept.getKeys()) { + if (!(axKey instanceof AxArtifactKey)) { + continue; + } + + final AxArtifactKey artifactKey = (AxArtifactKey) axKey; + if (!keyInfoMap.containsKey(artifactKey)) { + final AxKeyInfo keyInfo = new AxKeyInfo(artifactKey); + //generate a reproducible UUID + keyInfo.setUuid(AxKeyInfo.generateReproducibleUUID(keyInfo.getID() + keyInfo.getDescription())); + keyInfoMap.put(artifactKey, keyInfo); + } + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey() + */ + @Override + public AxArtifactKey getKey() { + return key; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys() + */ + @Override + public List<AxKey> getKeys() { + final List<AxKey> keyList = key.getKeys(); + keyList.addAll(keyInfoMap.keySet()); + + return keyList; + } + + /** + * Sets the key of this concept. + * + * @param key the key of this concept + */ + public void setKey(final AxArtifactKey key) { + Assertions.argumentNotNull(key, "key may not be null"); + this.key = key; + } + + /** + * Gets the key info map of this concept. + * + * @return the key info map of this concept + */ + public Map<AxArtifactKey, AxKeyInfo> getKeyInfoMap() { + return keyInfoMap; + } + + /** + * Sets the key info map of this concept. + * + * @param keyInfoMap the key info map of this concept + */ + public void setKeyInfoMap(final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) { + Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null"); + this.keyInfoMap = new TreeMap<>(); + this.keyInfoMap.putAll(keyInfoMap); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.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 (keyInfoMap.size() == 0) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "keyInfoMap may not be empty")); + } + else { + final Set<UUID> uuidSet = new TreeSet<>(); + + for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) { + result = validateKeyInfoEntry(keyInfoEntry, uuidSet, result); + } + } + + return result; + } + + /** + * Validate an key information entry + * @param keyInfoEntry the key information entry + * @param uuidSet the set of UUIDs encountered in validation so far, the UUID of this entry is added to the set + * @param result the validation result to append to + * @return The validation result + */ + private AxValidationResult validateKeyInfoEntry(final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry, Set<UUID> uuidSet, AxValidationResult result) { + if (keyInfoEntry.getKey().equals(AxArtifactKey.getNullKey())) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "key on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be the null key")); + } + else if (keyInfoEntry.getValue() == null) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "value on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be null")); + } + else { + if (!keyInfoEntry.getKey().equals(keyInfoEntry.getValue().getKey())) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "key on keyInfoMap entry " + keyInfoEntry.getKey() + " does not equal entry key " + keyInfoEntry.getValue().getKey())); + } + + result = keyInfoEntry.getValue().validate(result); + + if (uuidSet.contains(keyInfoEntry.getValue().getUUID())) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "duplicate UUID found on keyInfoMap entry " + keyInfoEntry.getKey() + ":" + keyInfoEntry.getValue().getUUID())); + } + else { + uuidSet.add(keyInfoEntry.getValue().getUUID()); + } + } + + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean() + */ + @Override + public void clean() { + key.clean(); + for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) { + keyInfoEntry.getKey().clean(); + keyInfoEntry.getValue().clean(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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(",keyInfoMap="); + builder.append(keyInfoMap); + builder.append(")"); + return builder.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public AxConcept copyTo(final AxConcept target) { + Assertions.argumentNotNull(target, "target may not be null"); + + final Object copyObject = target; + Assertions.instanceOf(copyObject, AxKeyInformation.class); + + final AxKeyInformation copy = ((AxKeyInformation) copyObject); + copy.setKey(new AxArtifactKey(key)); + final Map<AxArtifactKey, AxKeyInfo> newKeyInfoMap = new TreeMap<>(); + for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoMapEntry : keyInfoMap.entrySet()) { + newKeyInfoMap.put(new AxArtifactKey(keyInfoMapEntry.getKey()), new AxKeyInfo(keyInfoMapEntry.getValue())); + } + copy.setKeyInfoMap(newKeyInfoMap); + + return copy; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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 + keyInfoMap.hashCode(); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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 AxKeyInformation other = (AxKeyInformation) obj; + if (!key.equals(other.key)) { + return false; + } + return keyInfoMap.equals(other.keyInfoMap); + } + + /* + * (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 AxKeyInformation other = (AxKeyInformation) otherObj; + if (!key.equals(other.key)) { + return key.compareTo(other.key); + } + if (!keyInfoMap.equals(other.keyInfoMap)) { + return (keyInfoMap.hashCode() - other.keyInfoMap.hashCode()); + } + + return 0; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(com. ericsson.apex.core.basicmodel.concepts.AxArtifactKey) + */ + @Override + public AxKeyInfo get(final AxArtifactKey conceptKey) { + return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKey); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String) + */ + @Override + public AxKeyInfo get(final String conceptKeyName) { + return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String, java.lang.String) + */ + @Override + public AxKeyInfo get(final String conceptKeyName, final String conceptKeyVersion) { + return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName, conceptKeyVersion); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String) + */ + @Override + public Set<AxKeyInfo> getAll(final String conceptKeyName) { + return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String, java.lang.String) + */ + @Override + public Set<AxKeyInfo> getAll(final String conceptKeyName, final String conceptKeyVersion) { + return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName, conceptKeyVersion); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyUse.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyUse.java new file mode 100644 index 000000000..990c8f7de --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyUse.java @@ -0,0 +1,245 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.List; + +import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * This class records a usage of a key in the system. When the list of keys being used by a concept is built using the getKeys() method of + * the {@link AxConcept} class, an instance of this class is created for every key occurrence. The list of keys returned by the getKeys() + * method is a list of {@link AxKeyUse} objects. + * <p> + * Validation checks that each key is valid. + */ + +public class AxKeyUse extends AxKey { + private static final long serialVersionUID = 2007147220109881705L; + + private AxKey usedKey; + + /** + * The Default Constructor creates this concept with a null key. + */ + public AxKeyUse() { + this(new AxArtifactKey()); + } + + /** + * Copy constructor + * @param copyConcept the concept to copy from + */ + public AxKeyUse(final AxKeyUse copyConcept) { + super(copyConcept); + } + + /** + * This constructor creates an instance of this class, and holds a reference to a used key. + * + * @param usedKey a used key + */ + public AxKeyUse(final AxKey usedKey) { + Assertions.argumentNotNull(usedKey, "usedKey may not be null"); + this.usedKey = usedKey; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey() + */ + @Override + public AxKey getKey() { + return usedKey; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys() + */ + @Override + public List<AxKey> getKeys() { + return usedKey.getKeys(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getID() + */ + @Override + public String getID() { + return usedKey.getID(); + } + + /** + * Sets the key. + * + * @param key the key + */ + public void setKey(final AxKey key) { + Assertions.argumentNotNull(key, "usedKey may not be null"); + this.usedKey = key; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getCompatibility(com. ericsson.apex.model.basicmodel.concepts.AxKey) + */ + @Override + public AxKey.Compatibility getCompatibility(final AxKey otherKey) { + return usedKey.getCompatibility(otherKey); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#isCompatible(com. ericsson.apex.model.basicmodel.concepts.AxKey) + */ + @Override + public boolean isCompatible(final AxKey otherKey) { + return usedKey.isCompatible(otherKey); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult) + */ + @Override + public AxValidationResult validate(final AxValidationResult result) { + if (usedKey.equals(AxArtifactKey.getNullKey())) { + result.addValidationMessage( + new AxValidationMessage(usedKey, this.getClass(), ValidationResult.INVALID, "usedKey is a null key")); + } + return usedKey.validate(result); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean() + */ + @Override + public void clean() { + usedKey.clean(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString() + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + builder.append(":("); + builder.append("usedKey="); + builder.append(usedKey); + builder.append(")"); + return builder.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public AxConcept copyTo(final AxConcept target) { + Assertions.argumentNotNull(target, "target may not be null"); + + final Object copyObject = target; + Assertions.instanceOf(copyObject, AxKeyUse.class); + + final AxKeyUse copy = ((AxKeyUse) copyObject); + try { + copy.usedKey = usedKey.getClass().newInstance(); + } + catch (Exception e) { + throw new ApexRuntimeException("error copying concept key: " + e.getMessage(), e); + } + usedKey.copyTo(copy.usedKey); + + return copy; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + usedKey.hashCode(); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#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 AxKeyUse other = (AxKeyUse) obj; + return usedKey.equals(other.usedKey); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @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 AxKeyUse other = (AxKeyUse) otherObj; + + return usedKey.compareTo(other.usedKey); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxModel.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxModel.java new file mode 100644 index 000000000..f0489c734 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxModel.java @@ -0,0 +1,471 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import javax.persistence.CascadeType; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +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.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.apex.model.basicmodel.service.ModelService; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * This class is the base class for all models in Apex. All model classes inherit from this model so all models must have a key and have key information. + * <p> + * Validation checks that the model key is valid. It goes on to check for null keys and checks each key for uniqueness in the model. A check is carried out to + * ensure that an {@link AxKeyInfo} instance exists for every {@link AxArtifactKey} key. For each {@link AxReferenceKey} instance, a check is made that its + * parent and local name are nut null and that a {@link AxKeyInfo} entry exists for its parent. Then a check is made that each used {@link AxArtifactKey} and + * {@link AxReferenceKey} usage references a key that exists. Finally, a check is made to ensure that an {@link AxArtifactKey} instance exists for every + * {@link AxKeyInfo} instance. + */ + +@Entity +@Table(name = "AxModel") +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) + +@XmlRootElement(name = "apexModel", namespace = "http://www.ericsson.com/apex") +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "AxModel", namespace = "http://www.ericsson.com/apex", propOrder = { "key", "keyInformation" }) + +public class AxModel extends AxConcept { + private static final String IS_A_NULL_KEY = " is a null key"; + + private static final long serialVersionUID = -771659065637205430L; + + @EmbeddedId + @XmlElement(name = "key", required = true) + private AxArtifactKey key; + + // @formatter:off + @OneToOne(cascade = CascadeType.ALL) + @JoinColumns({ + @JoinColumn(name = "keyInformationName", referencedColumnName = "name"), + @JoinColumn(name = "keyInformationVersion", referencedColumnName = "version") + }) + @XmlElement(name = "keyInformation", required = true) + private AxKeyInformation keyInformation; + // @formatter:on + + /** + * The Default Constructor creates this concept with a NULL artifact key. + */ + public AxModel() { + this(new AxArtifactKey()); + } + + /** + * Copy constructor + * @param copyConcept the concept to copy from + */ + public AxModel(final AxModel copyConcept) { + super(copyConcept); + } + + /** + * Constructor to create this concept with the specified key. + * + * @param key the key of this concept + */ + public AxModel(final AxArtifactKey key) { + this(key, new AxKeyInformation(new AxArtifactKey(key.getName() + "_KeyInfo", key.getVersion()))); + } + + /** + * Constructor to create this concept and set all its fields. + * + * @param key the key of this concept + * @param keyInformation the key information of this concept + */ + public AxModel(final AxArtifactKey key, final AxKeyInformation keyInformation) { + super(); + Assertions.argumentNotNull(key, "key may not be null"); + Assertions.argumentNotNull(keyInformation, "keyInformation may not be null"); + + this.key = key; + this.keyInformation = keyInformation; + } + + /** + * Registers this model with the {@link ModelService}. All models are registered with the model service so that models can be references from anywhere in + * the Apex system without being passed as references through deep call chains. + */ + public void register() { + ModelService.registerModel(AxKeyInformation.class, getKeyInformation()); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey() + */ + @Override + public AxArtifactKey getKey() { + return key; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys() + */ + @Override + public List<AxKey> getKeys() { + final List<AxKey> keyList = key.getKeys(); + + // We just add the key for the KeyInformation itself. We don't add the + // keys from key information because + // that is a list of key information for existing keys + keyList.add(keyInformation.getKey()); + + return keyList; + } + + /** + * Sets the key of this concept. + * + * @param key the key of this concept + */ + public void setKey(final AxArtifactKey key) { + Assertions.argumentNotNull(key, "key may not be null"); + this.key = key; + } + + /** + * Gets the key information of this concept. + * + * @return the key information of this concept + */ + public AxKeyInformation getKeyInformation() { + return keyInformation; + } + + /** + * Sets the key information of this concept. + * + * @param keyInformation the key information of this concept + */ + public void setKeyInformation(final AxKeyInformation keyInformation) { + Assertions.argumentNotNull(keyInformation, "keyInformation may not be null"); + this.keyInformation = keyInformation; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.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); + result = keyInformation.validate(result); + + // Key consistency check + final Set<AxArtifactKey> artifactKeySet = new TreeSet<>(); + final Set<AxReferenceKey> referenceKeySet = new TreeSet<>(); + final Set<AxKeyUse> usedKeySet = new TreeSet<>(); + + for (final AxKey axKey : this.getKeys()) { + // Check for the two type of keys we have + if (axKey instanceof AxArtifactKey) { + result = validateArtifactKeyInModel((AxArtifactKey) axKey, artifactKeySet, result); + } + else if (axKey instanceof AxReferenceKey) { + result = validateReferenceKeyInModel((AxReferenceKey) axKey, referenceKeySet, result); + } + // It must be an AxKeyUse, nothing else is legal + else { + usedKeySet.add((AxKeyUse) axKey); + } + } + + // Check all reference keys have correct parent keys + for (final AxReferenceKey referenceKey : referenceKeySet) { + if (!artifactKeySet.contains(referenceKey.getParentArtifactKey())) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "parent artifact key not found for reference key " + referenceKey)); + } + } + + result = validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result); + + // Check key information for unused key information + for (final AxArtifactKey keyInfoKey : keyInformation.getKeyInfoMap().keySet()) { + if (!artifactKeySet.contains(keyInfoKey)) { + result.addValidationMessage( + new AxValidationMessage(keyInfoKey, this.getClass(), ValidationResult.WARNING, "key not found for key information entry")); + } + } + + return result; + } + + /** + * Check for consistent usage of an artifact key in the model + * @param artifactKey The artifact key to check + * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set + * @param result The validation result to append to + * @return the result of the validation + */ + private AxValidationResult validateArtifactKeyInModel(final AxArtifactKey artifactKey, Set<AxArtifactKey> artifactKeySet, AxValidationResult result) { + // Null key check + if (artifactKey.equals(AxArtifactKey.getNullKey())) { + result.addValidationMessage( + new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key " + artifactKey + IS_A_NULL_KEY)); + } + + // Null key name start check + if (artifactKey.getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "key " + artifactKey + " name starts with keyword " + AxKey.NULL_KEY_NAME)); + } + + // Unique key check + if (artifactKeySet.contains(artifactKey)) { + result.addValidationMessage( + new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "duplicate key " + artifactKey + " found")); + } + else { + artifactKeySet.add(artifactKey); + } + + // Key information check + if (!keyInformation.getKeyInfoMap().containsKey(artifactKey)) { + result.addValidationMessage( + new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key information not found for key " + artifactKey)); + } + + return result; + } + + /** + * Check for consistent usage of a reference key in the model + * @param artifactKey The reference key to check + * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set + * @param result The validation result to append to + * @return the result of the validation + */ + private AxValidationResult validateReferenceKeyInModel(final AxReferenceKey referenceKey, Set<AxReferenceKey> referenceKeySet, AxValidationResult result) { + // Null key check + if (referenceKey.equals(AxReferenceKey.getNullKey())) { + result.addValidationMessage( + new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key " + referenceKey + IS_A_NULL_KEY)); + } + + // Null parent key check + if (referenceKey.getParentArtifactKey().equals(AxArtifactKey.getNullKey())) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "parent artifact key of key " + referenceKey + IS_A_NULL_KEY)); + } + + // Null local name check + if (referenceKey.getLocalName().equals(AxKey.NULL_KEY_NAME)) { + result.addValidationMessage( + new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key " + referenceKey + " has a null local name")); + } + + // Null key name start check + if (referenceKey.getParentArtifactKey().getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "key " + referenceKey + " parent name starts with keyword " + AxKey.NULL_KEY_NAME)); + } + + // Unique key check + if (referenceKeySet.contains(referenceKey)) { + result.addValidationMessage( + new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "duplicate key " + referenceKey + " found")); + } + else { + referenceKeySet.add(referenceKey); + } + + // Key information check + if (!keyInformation.getKeyInfoMap().containsKey(referenceKey.getParentArtifactKey())) { + result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, + "key information not found for parent key of key " + referenceKey)); + } + + return result; + } + + /** + * Check for consistent usage of cross-key references in the model + * @param usedKeySet The set of all keys used in the model + * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set + * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set + * @param result The validation result to append to + * @return the result of the validation + */ + private AxValidationResult validateKeyUses(final Set<AxKeyUse> usedKeySet, final Set<AxArtifactKey> artifactKeySet, + final Set<AxReferenceKey> referenceKeySet, AxValidationResult result) { + // Check all key uses + for (final AxKeyUse usedKey : usedKeySet) { + if (usedKey.getKey() instanceof AxArtifactKey) { + // AxArtifact key usage, check the key exists + if (!artifactKeySet.contains(usedKey.getKey())) { + result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(), ValidationResult.INVALID, + "an artifact key used in the model is not defined")); + } + } + else { + // AxReference key usage, check the key exists + if (!referenceKeySet.contains(usedKey.getKey())) { + result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(), ValidationResult.INVALID, + "a reference key used in the model is not defined")); + } + } + } + + return result; + } + + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean() + */ + @Override + public void clean() { + key.clean(); + keyInformation.clean(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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(",keyInformation="); + builder.append(keyInformation); + builder.append(")"); + return builder.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public AxConcept copyTo(final AxConcept target) { + Assertions.argumentNotNull(target, "target may not be null"); + + final Object copyObject = target; + Assertions.instanceOf(copyObject, AxModel.class); + + final AxModel copy = ((AxModel) copyObject); + copy.setKey(new AxArtifactKey(key)); + copy.setKeyInformation(new AxKeyInformation(keyInformation)); + + return copy; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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 + keyInformation.hashCode(); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.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 AxModel other = (AxModel) obj; + if (!key.equals(other.key)) { + return false; + } + return keyInformation.equals(other.keyInformation); + } + + /* + * (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 AxModel other = (AxModel) otherObj; + if (!key.equals(other.key)) { + return key.compareTo(other.key); + } + return keyInformation.compareTo(other.keyInformation); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxReferenceKey.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxReferenceKey.java new file mode 100644 index 000000000..9401152d0 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxReferenceKey.java @@ -0,0 +1,556 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +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.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * A reference key identifies entities in the system that are contained in other entities. Every contained concept in the system must have an + * {@link AxReferenceKey} to identify it. Non-contained first order concepts are identified using an {@link AxArtifactKey} key. + * <p> + * An {@link AxReferenceKey} contains an {@link AxArtifactKey} key reference to the first order entity that contains it. The local name of the reference key + * must uniquely identify the referenced concept among those concepts contained in the reference key's parent. In other words, if a parent concept has more than + * one child, the local name in the key of all its children must be unique. + * <p> + * If a reference key's parent is itself a reference key, then the parent's local name must be set in the reference key. If the parent is a first order concept, + * then the parent's local name in the key will be set to NULL. + * <p> + * Key validation checks that the parent name and parent version fields match the {@link NAME_REGEXP} and {@link VERSION_REGEXP} regular expressions + * respectively and that the local name fields match the {@link LOCAL_NAME_REGEXP} regular expression. + */ +@Embeddable +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "apexReferenceKey", namespace = "http://www.ericsson.com/apex") +@XmlType(name = "AxReferenceKey", namespace = "http://www.ericsson.com/apex", propOrder = { "parentKeyName", "parentKeyVersion", "parentLocalName", + "localName" }) + +public class AxReferenceKey extends AxKey { + private static final String PARENT_KEY_NAME = "parentKeyName"; + private static final String PARENT_KEY_VERSION = "parentKeyVersion"; + private static final String PARENT_LOCAL_NAME = "parentLocalName"; + private static final String LOCAL_NAME = "localName"; + + private static final long serialVersionUID = 8932717618579392561L; + + /** Regular expression to specify the structure of local names in reference keys.*/ + public static final String LOCAL_NAME_REGEXP = "[A-Za-z0-9\\-_\\.]+|^$"; + + /** Regular expression to specify the structure of IDs in reference keys.*/ + public static final String REFERENCE_KEY_ID_REGEXP = "[A-Za-z0-9\\-_]+:[0-9].[0-9].[0-9]:[A-Za-z0-9\\-_]+:[A-Za-z0-9\\-_]+"; + + private static final int PARENT_NAME_FIELD = 0; + private static final int PARENT_VERSION_FIELD = 1; + private static final int PARENT_LOCAL_NAME_FIELD = 2; + private static final int LOCAL_NAME_FIELD = 3; + + @Column(name = PARENT_KEY_NAME) + @XmlElement(required = true) + private String parentKeyName; + + @Column(name = PARENT_KEY_VERSION) + @XmlElement(required = true) + private String parentKeyVersion; + + @Column(name = PARENT_LOCAL_NAME) + @XmlElement(required = true) + private String parentLocalName; + + @Column(name = LOCAL_NAME) + @XmlElement(required = true) + private String localName; + + /** + * The default constructor creates a null reference key. + */ + public AxReferenceKey() { + this(NULL_KEY_NAME, NULL_KEY_VERSION, NULL_KEY_NAME, NULL_KEY_NAME); + } + + /** + * The Copy Constructor creates a key by copying another key. + * + * @param referenceKey the reference key to copy from + */ + public AxReferenceKey(final AxReferenceKey referenceKey) { + this(referenceKey.getParentKeyName(), referenceKey.getParentKeyVersion(), referenceKey.getParentLocalName(), referenceKey.getLocalName()); + } + + /** + * Constructor to create a null reference key for the specified parent artifact key. + * + * @param axArtifactKey the parent artifact key of this reference key + */ + public AxReferenceKey(final AxArtifactKey axArtifactKey) { + this(axArtifactKey.getName(), axArtifactKey.getVersion(), NULL_KEY_NAME, NULL_KEY_NAME); + } + + /** + * Constructor to create a reference key for the given parent artifact key with the given local name. + * + * @param axArtifactKey the parent artifact key of this reference key + * @param localName the local name of this reference key + */ + public AxReferenceKey(final AxArtifactKey axArtifactKey, final String localName) { + this(axArtifactKey, NULL_KEY_NAME, localName); + } + + /** + * Constructor to create a reference key for the given parent reference key with the given local name. + * + * @param parentReferenceKey the parent reference key of this reference key + * @param localName the local name of this reference key + */ + public AxReferenceKey(final AxReferenceKey parentReferenceKey, final String localName) { + this(parentReferenceKey.getParentArtifactKey(), parentReferenceKey.getLocalName(), localName); + } + + /** + * Constructor to create a reference key for the given parent reference key (specified by the parent reference key's artifact key and local name) with the + * given local name. + * + * @param axArtifactKey the artifact key of the parent reference key of this reference key + * @param parentLocalName the local name of the parent reference key of this reference key + * @param localName the local name of this reference key + */ + public AxReferenceKey(final AxArtifactKey axArtifactKey, final String parentLocalName, final String localName) { + this(axArtifactKey.getName(), axArtifactKey.getVersion(), parentLocalName, localName); + } + + /** + * Constructor to create a reference key for the given parent artifact key (specified by the parent artifact key's name and version) with the given local + * name. + * + * @param parentKeyName the name of the parent artifact key of this reference key + * @param parentKeyVersion the version of the parent artifact key of this reference key + * @param localName the local name of this reference key + */ + public AxReferenceKey(final String parentKeyName, final String parentKeyVersion, final String localName) { + this(parentKeyName, parentKeyVersion, NULL_KEY_NAME, localName); + } + + /** + * Constructor to create a reference key for the given parent key (specified by the parent key's name, version nad local name) with the given local name. + * + * @param parentKeyName the parent key name of this reference key + * @param parentKeyVersion the parent key version of this reference key + * @param parentLocalName the parent local name of this reference key + * @param localName the local name of this reference key + */ + public AxReferenceKey(final String parentKeyName, final String parentKeyVersion, final String parentLocalName, final String localName) { + super(); + this.parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP); + this.parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP); + this.parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP); + this.localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP); + } + + /** + * Constructor to create a key from the specified key ID. + * + * @param id the key ID in a format that respects the {@link KEY_ID_REGEXP} + */ + public AxReferenceKey(final String id) { + final String conditionedId = Assertions.validateStringParameter("id", id, REFERENCE_KEY_ID_REGEXP); + + // Split on colon, if the id passes the regular expression test above + // it'll have just three colons separating the parent name, + // parent version, parent local name, and and local name + // No need for range checks or size checks on the array + final String[] nameVersionNameArray = conditionedId.split(":"); + + // Initiate the new key + parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, nameVersionNameArray[PARENT_NAME_FIELD], NAME_REGEXP); + parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, nameVersionNameArray[PARENT_VERSION_FIELD], VERSION_REGEXP); + parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, nameVersionNameArray[PARENT_LOCAL_NAME_FIELD], LOCAL_NAME_REGEXP); + localName = Assertions.validateStringParameter(LOCAL_NAME, nameVersionNameArray[LOCAL_NAME_FIELD], LOCAL_NAME_REGEXP); + } + + /** + * Get a null reference key. + * + * @return a null reference key + */ + public static AxReferenceKey getNullKey() { + return new AxReferenceKey(AxKey.NULL_KEY_NAME, AxKey.NULL_KEY_VERSION, AxKey.NULL_KEY_NAME, AxKey.NULL_KEY_NAME); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey() + */ + @Override + public AxReferenceKey getKey() { + return this; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys() + */ + @Override + public List<AxKey> getKeys() { + final List<AxKey> keyList = new ArrayList<>(); + keyList.add(getKey()); + return keyList; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getID() + */ + @Override + public String getID() { + return parentKeyName + ':' + parentKeyVersion + ':' + parentLocalName + ':' + localName; + } + + /** + * Gets the parent artifact key of this reference key. + * + * @return the parent artifact key of this reference key + */ + public AxArtifactKey getParentArtifactKey() { + return new AxArtifactKey(parentKeyName, parentKeyVersion); + } + + /** + * Gets the parent reference key of this reference key. + * + * @return the parent reference key of this reference key + */ + public AxReferenceKey getParentReferenceKey() { + return new AxReferenceKey(parentKeyName, parentKeyVersion, parentLocalName); + } + + /** + * Sets the parent artifact key of this reference key. + * + * @param parentKey the parent artifact key of this reference key + */ + public void setParentArtifactKey(final AxArtifactKey parentKey) { + Assertions.argumentNotNull(parentKey, "parentKey may not be null"); + + parentKeyName = parentKey.getName(); + parentKeyVersion = parentKey.getVersion(); + parentLocalName = NULL_KEY_NAME; + } + + /** + * Sets the parent reference key of this reference key. + * + * @param parentKey the parent reference key of this reference key + */ + public void setParentReferenceKey(final AxReferenceKey parentKey) { + Assertions.argumentNotNull(parentKey, "parentKey may not be null"); + + parentKeyName = parentKey.getParentKeyName(); + parentKeyVersion = parentKey.getParentKeyVersion(); + parentLocalName = parentKey.getLocalName(); + } + + /** + * Gets the parent key name of this reference key. + * + * @return the parent key name of this reference key + */ + public String getParentKeyName() { + return parentKeyName; + } + + /** + * Sets the parent key name of this reference key. + * + * @param parentKeyName the parent key name of this reference key + */ + public void setParentKeyName(final String parentKeyName) { + this.parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP); + } + + /** + * Gets the parent key version of this reference key. + * + * @return the parent key version of this reference key + */ + public String getParentKeyVersion() { + return parentKeyVersion; + } + + /** + * Sets the parent key version of this reference key. + * + * @param parentKeyVersion the parent key version of this reference key + */ + public void setParentKeyVersion(final String parentKeyVersion) { + this.parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP); + } + + /** + * Gets the parent local name of this reference key. + * + * @return the parent local name of this reference key + */ + public String getParentLocalName() { + return parentLocalName; + } + + /** + * Sets the parent local name of this reference key. + * + * @param parentLocalName the parent local name of this reference key + */ + public void setParentLocalName(final String parentLocalName) { + this.parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP); + } + + /** + * Gets the local name of this reference key. + * + * @return the local name of this reference key + */ + public String getLocalName() { + return localName; + } + + /** + * Sets the local name of this reference key. + * + * @param localName the local name of this reference key + */ + public void setLocalName(final String localName) { + this.localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getCompatibility(com. ericsson.apex.model.basicmodel.concepts.AxKey) + */ + @Override + public AxKey.Compatibility getCompatibility(final AxKey otherKey) { + if (!(otherKey instanceof AxReferenceKey)) { + return Compatibility.DIFFERENT; + } + final AxReferenceKey otherReferenceKey = (AxReferenceKey) otherKey; + + return this.getParentArtifactKey().getCompatibility(otherReferenceKey.getParentArtifactKey()); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#isCompatible(com. ericsson.apex.model.basicmodel.concepts.AxKey) + */ + @Override + public boolean isCompatible(final AxKey otherKey) { + if (!(otherKey instanceof AxReferenceKey)) { + return false; + } + final AxReferenceKey otherReferenceKey = (AxReferenceKey) otherKey; + + return this.getParentArtifactKey().isCompatible(otherReferenceKey.getParentArtifactKey()); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult) + */ + @Override + public AxValidationResult validate(final AxValidationResult result) { + try { + Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP); + } + catch (final IllegalArgumentException e) { + result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "parentKeyName invalid-" + e.getMessage())); + } + + try { + Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP); + } + catch (final IllegalArgumentException e) { + result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "parentKeyVersion invalid-" + e.getMessage())); + } + + try { + Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP); + } + catch (final IllegalArgumentException e) { + result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "parentLocalName invalid-" + e.getMessage())); + } + + try { + Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP); + } + catch (final IllegalArgumentException e) { + result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "localName invalid-" + e.getMessage())); + } + + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean() + */ + @Override + public void clean() { + parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP); + parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP); + parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP); + localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString() + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + builder.append(":("); + builder.append("parentKeyName="); + builder.append(parentKeyName); + builder.append(",parentKeyVersion="); + builder.append(parentKeyVersion); + builder.append(",parentLocalName="); + builder.append(parentLocalName); + builder.append(",localName="); + builder.append(localName); + builder.append(")"); + return builder.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public AxConcept copyTo(final AxConcept target) { + Assertions.argumentNotNull(target, "target may not be null"); + + final Object copyObject = target; + Assertions.instanceOf(copyObject, AxReferenceKey.class); + + final AxReferenceKey copy = ((AxReferenceKey) copyObject); + copy.setParentKeyName(parentKeyName); + copy.setParentKeyVersion(parentKeyVersion); + copy.setLocalName(localName); + copy.setParentLocalName(parentLocalName); + + return copy; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + parentKeyName.hashCode(); + result = prime * result + parentKeyVersion.hashCode(); + result = prime * result + parentLocalName.hashCode(); + result = prime * result + localName.hashCode(); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#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 AxReferenceKey other = (AxReferenceKey) obj; + + if (!parentKeyName.equals(other.parentKeyName)) { + return false; + } + if (!parentKeyVersion.equals(other.parentKeyVersion)) { + return false; + } + if (!parentLocalName.equals(other.parentLocalName)) { + return false; + } + return localName.equals(other.localName); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @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 AxReferenceKey other = (AxReferenceKey) otherObj; + if (!parentKeyName.equals(other.parentKeyName)) { + return parentKeyName.compareTo(other.parentKeyName); + } + if (!parentKeyVersion.equals(other.parentKeyVersion)) { + return parentKeyVersion.compareTo(other.parentKeyVersion); + } + if (!parentLocalName.equals(other.parentLocalName)) { + return parentLocalName.compareTo(other.parentLocalName); + } + return localName.compareTo(other.localName); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationMessage.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationMessage.java new file mode 100644 index 000000000..ef8eb317c --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationMessage.java @@ -0,0 +1,103 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * A validation message is created for each validation observation observed during validation of a concept. The message holds the key and + * the class of the concept on which the observation was made as well as the type of observation and a message describing the observation. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class AxValidationMessage { + private final AxKey observedKey; + private ValidationResult validationResult = ValidationResult.VALID; + private final String observedClass; + private final String message; + + /** + * Create an validation observation with the given fields. + * + * @param observedKey the key of the class on which the validation observation was made + * @param observedClass the class on which the validation observation was made + * @param validationResult the type of observation made + * @param message a message describing the observation + */ + public AxValidationMessage(final AxKey observedKey, final Class<?> observedClass, final ValidationResult validationResult, final String message) { + Assertions.argumentNotNull(observedKey, "observedKey may not be null"); + Assertions.argumentNotNull(observedClass, "observedClass may not be null"); + Assertions.argumentNotNull(validationResult, "validationResult may not be null"); + Assertions.argumentNotNull(message, "message may not be null"); + + this.observedKey = observedKey; + this.observedClass = observedClass.getCanonicalName(); + this.validationResult = validationResult; + this.message = message; + } + + /** + * Gets the key of the observation. + * + * @return the key of the observation + */ + public AxKey getObservedKey() { + return observedKey; + } + + /** + * Gets the observed class. + * + * @return the observed class + */ + public String getObservedClass() { + return observedClass; + } + + /** + * Gets the type of observation made. + * + * @return the type of observation made + */ + public ValidationResult getValidationResult() { + return validationResult; + } + + /** + * Get a description of the observation. + * + * @return the observation description + */ + public String getMessage() { + return message; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return observedKey.toString() + ':' + observedClass + ':' + validationResult.name() + ':' + message; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationResult.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationResult.java new file mode 100644 index 000000000..363fd1596 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationResult.java @@ -0,0 +1,145 @@ +/* + * ============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.apex.model.basicmodel.concepts; + +import java.util.LinkedList; +import java.util.List; + +/** + * This class records the result of a validation and holds all validatino observation messages. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class AxValidationResult { + /** + * The ValidationResult enumeration describes the severity of a validation result. + */ + public enum ValidationResult { + /** No problems or observations were detected during validation. */ + VALID, + /** Observations were made on a concept (such as blank descriptions) of a nature that will not affect the use of the concept. */ + OBSERVATION, + /** Warnings were made on a concept (such as defined but unused concepts) of a nature that may affect the use of the concept. */ + WARNING, + /** + * Errors were detected on a concept (such as referenced but undefined concepts) of a nature that will affect the use of the concept. + */ + INVALID + } + + // The actual verification result + private ValidationResult validationResult = ValidationResult.VALID; + + // Messages collected during the verification process + private final List<AxValidationMessage> messageList = new LinkedList<>(); + + /** + * Check if a validation reported a valid concept, returns true if the model is usable (that is, even if the model has warnings or + * observations). + * + * @return true, if the concept is reported as valid and can be used + */ + public boolean isValid() { + return validationResult != ValidationResult.INVALID; + } + + /** + * Check if a validation reported a concept with no errors or warnings, returns true if the model is OK to use. + * + * @return true, if the concept has no warnings or errors + */ + public boolean isOK() { + return validationResult == ValidationResult.VALID || validationResult == ValidationResult.OBSERVATION; + } + + /** + * Gets the validation result. + * + * @return the validation result on a concept + */ + public ValidationResult getValidationResult() { + return validationResult; + } + + /** + * Gets the list of validation results on the concept. + * + * @return the list of validaiton results + */ + public List<AxValidationMessage> getMessageList() { + return messageList; + } + + /** + * Adds a validation message to the validation result, used by validate() implementations on {@link AxConcept} subclasses to report + * validaiton observations. + * + * @param validationMessage the validation message + */ + public void addValidationMessage(final AxValidationMessage validationMessage) { + messageList.add(validationMessage); + + // Check if the incoming message has a more sever status than the + // current one on the overall validation result, + // if so, the overall result goes to that level + if (validationMessage.getValidationResult().ordinal() > validationResult.ordinal()) { + validationResult = validationMessage.getValidationResult(); + } + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + + switch (validationResult) { + case VALID: + + builder.append("***validation of model successful***"); + return builder.toString(); + case OBSERVATION: + + builder.append("\n***observations noted during validation of model***\n"); + break; + case WARNING: + + builder.append("\n***warnings issued during validation of model***\n"); + break; + case INVALID: + builder.append("\n***validation of model failed***\n"); + break; + default: + break; + } + + for (final AxValidationMessage message : messageList) { + builder.append(message); + builder.append("\n"); + } + + builder.append("********************************"); + return builder.toString(); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/package-info.java new file mode 100644 index 000000000..4d5c91c66 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/package-info.java @@ -0,0 +1,34 @@ +/* + * ============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========================================================= + */ + +/** + * This package contains the fundamental concepts for all APEX models. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ + +@XmlSchema(namespace = "http://www.ericsson.com/apex", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = { + @XmlNs(namespaceURI = "http://www.ericsson.com/apex", prefix = "") }) + +package org.onap.apex.model.basicmodel.concepts; + +import javax.xml.bind.annotation.XmlNs; +import javax.xml.bind.annotation.XmlNsForm; +import javax.xml.bind.annotation.XmlSchema; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDao.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDao.java new file mode 100644 index 000000000..5aab39c1b --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDao.java @@ -0,0 +1,207 @@ +/* + * ============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.apex.model.basicmodel.dao; + +import java.util.Collection; +import java.util.List; + +import org.onap.apex.model.basicmodel.concepts.ApexException; +import org.onap.apex.model.basicmodel.concepts.AxArtifactKey; +import org.onap.apex.model.basicmodel.concepts.AxConcept; +import org.onap.apex.model.basicmodel.concepts.AxReferenceKey; + +/** + * The Interface ApexDao describes the DAO interface for reading and writing Apex {@link AxConcept} concepts to and from databases using + * JDBC. + * + * @author Sergey Sachkov + * @author liam.fallon@ericsson.com + */ +public interface ApexDao { + + /** + * Initialize the Apex DAO with the given parameters. + * + * @param daoParameters parameters to use to access the database + * @throws ApexException on initialization errors + */ + void init(DAOParameters daoParameters) throws ApexException; + + /** + * Close the Apex DAO. + */ + void close(); + + /** + * Creates an Apex concept on the database. + * + * @param <T> the type of the object to create, a subclass of {@link AxConcept} + * @param obj the object to create + */ + <T extends AxConcept> void create(T obj); + + /** + * Delete an Apex concept on the database. + * + * @param <T> the type of the object to delete, a subclass of {@link AxConcept} + * @param obj the object to delete + */ + <T extends AxConcept> void delete(T obj); + + /** + * Delete an Apex concept on the database. + * + * @param <T> the type of the object to delete, a subclass of {@link AxConcept} + * @param aClass the class of the object to delete, a subclass of {@link AxConcept} + * @param key the key of the object to delete + */ + <T extends AxConcept> void delete(Class<T> aClass, AxArtifactKey key); + + /** + * Delete an Apex concept on the database. + * + * @param <T> the type of the object to delete, a subclass of {@link AxConcept} + * @param aClass the class of the object to delete, a subclass of {@link AxConcept} + * @param key the key of the object to delete + */ + <T extends AxConcept> void delete(Class<T> aClass, AxReferenceKey key); + + /** + * Create a collection of objects in the database. + * + * @param <T> the type of the object to create, a subclass of {@link AxConcept} + * @param objs the objects to create + */ + <T extends AxConcept> void create(Collection<T> objs); + + /** + * Delete a collection of objects in the database. + * + * @param <T> the type of the objects to delete, a subclass of {@link AxConcept} + * @param objs the objects to delete + */ + <T extends AxConcept> void delete(Collection<T> objs); + + /** + * Delete a collection of objects in the database referred to by artifact key. + * + * @param <T> the type of the objects to delete, a subclass of {@link AxConcept} + * @param aClass the class of the objects to delete, a subclass of {@link AxConcept} + * @param keys the keys of the objects to delete + * @return the number of objects deleted + */ + <T extends AxConcept> int deleteByArtifactKey(Class<T> aClass, Collection<AxArtifactKey> keys); + + /** + * Delete a collection of objects in the database referred to by reference key. + * + * @param <T> the type of the objects to delete, a subclass of {@link AxConcept} + * @param aClass the class of the objects to delete, a subclass of {@link AxConcept} + * @param keys the keys of the objects to delete + * @return the number of objects deleted + */ + <T extends AxConcept> int deleteByReferenceKey(Class<T> aClass, Collection<AxReferenceKey> keys); + + /** + * Delete all objects of a given class in the database. + * + * @param <T> the type of the objects to delete, a subclass of {@link AxConcept} + * @param aClass the class of the objects to delete, a subclass of {@link AxConcept} + */ + <T extends AxConcept> void deleteAll(Class<T> aClass); + + /** + * Get an object from the database, referred to by artifact key. + * + * @param <T> the type of the object to get, a subclass of {@link AxConcept} + * @param aClass the class of the object to get, a subclass of {@link AxConcept} + * @param key the key of the object to get + * @return the object that was retrieved from the database + */ + <T extends AxConcept> T get(Class<T> aClass, AxArtifactKey key); + + /** + * Get an object from the database, referred to by reference key. + * + * @param <T> the type of the object to get, a subclass of {@link AxConcept} + * @param aClass the class of the object to get, a subclass of {@link AxConcept} + * @param key the key of the object to get + * @return the object that was retrieved from the database or null if the object was not retrieved + */ + <T extends AxConcept> T get(Class<T> aClass, AxReferenceKey key); + + /** + * Get all the objects in the database of a given type. + * + * @param <T> the type of the objects to get, a subclass of {@link AxConcept} + * @param aClass the class of the objects to get, a subclass of {@link AxConcept} + * @return the objects or null if no objects were retrieved + */ + <T extends AxConcept> List<T> getAll(Class<T> aClass); + + /** + * Get all the objects in the database of the given type with the given parent artifact key. + * + * @param <T> the type of the objects to get, a subclass of {@link AxConcept} + * @param aClass the class of the objects to get, a subclass of {@link AxConcept} + * @param parentKey the parent key of the concepts to get + * @return the all + */ + <T extends AxConcept> List<T> getAll(Class<T> aClass, AxArtifactKey parentKey); + + /** + * Get a concept from the database with the given artifact key. + * + * @param <T> the type of the object to get, a subclass of {@link AxConcept} + * @param aClass the class of the object to get, a subclass of {@link AxConcept} + * @param artifactID the artifact key of the concept to get + * @return the concept that matches the key or null if the concept is not retrieved + */ + <T extends AxConcept> T getArtifact(Class<T> aClass, AxArtifactKey artifactID); + + /** + * Get a concept from the database with the given reference key. + * + * @param <T> the type of the object to get, a subclass of {@link AxConcept} + * @param aClass the class of the object to get, a subclass of {@link AxConcept} + * @param artifactID the artifact key of the concept to get + * @return the concept that matches the key or null if the concept is not retrieved + */ + <T extends AxConcept> T getArtifact(Class<T> aClass, AxReferenceKey artifactID); + + /** + * Get the number of instances of a concept that exist in the database. + * + * @param <T> the type of the object to get, a subclass of {@link AxConcept} + * @param aClass the class of the object to get, a subclass of {@link AxConcept} + * @return the number of instances of the concept in the database + */ + <T extends AxConcept> long size(Class<T> aClass); + + /** + * Update a concept in the database. + * + * @param <T> the type of the object to get, a subclass of {@link AxConcept} + * @param obj the object to update + * @return the updated object + */ + <T extends AxConcept> T update(T obj); +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDaoFactory.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDaoFactory.java new file mode 100644 index 000000000..ecb8a4658 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDaoFactory.java @@ -0,0 +1,66 @@ +/* + * ============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.apex.model.basicmodel.dao; + +import org.onap.apex.model.basicmodel.concepts.ApexException; +import org.onap.policy.apex.model.utilities.Assertions; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * This factory class returns an Apex DAO for the configured persistence mechanism. The factory uses the plugin class specified in {@link DAOParameters} to + * instantiate a DAO instance. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class ApexDaoFactory { + // Get a reference to the logger + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexDaoFactory.class); + + /** + * Return an Apex DAO for the required APEX DAO plugin class. + * + * @param daoParameters parameters to use to read the database configuration information + * @return the Apex DAO + * @throws ApexException on invalid JPA plugins + */ + public ApexDao createApexDao(final DAOParameters daoParameters) throws ApexException { + Assertions.argumentNotNull(daoParameters, ApexException.class, "Parameter \"daoParameters\" may not be null"); + + // Get the class for the DAO using reflection + Object apexDaoObject = null; + try { + apexDaoObject = Class.forName(daoParameters.getPluginClass()).newInstance(); + } + catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + LOGGER.error("Apex DAO class not found for DAO plugin \"" + daoParameters.getPluginClass() + "\"", e); + throw new ApexException("Apex DAO class not found for DAO plugin \"" + daoParameters.getPluginClass() + "\"", e); + } + + // Check the class is an Apex DAO + if (!(apexDaoObject instanceof ApexDao)) { + LOGGER.error("Specified Apex DAO plugin class \"" + daoParameters.getPluginClass() + "\" does not implement the ApexDao interface"); + throw new ApexException("Specified Apex DAO plugin class \"" + daoParameters.getPluginClass() + "\" does not implement the ApexDao interface"); + } + + return (ApexDao) apexDaoObject; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/DAOParameters.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/DAOParameters.java new file mode 100644 index 000000000..ccf15fea7 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/DAOParameters.java @@ -0,0 +1,124 @@ +/* + * ============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.apex.model.basicmodel.dao; + +import java.util.Properties; + +/** + * This class is a POJO that holds properties for Apex DAOs. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class DAOParameters { + /** The default Apex DAO plugin class. */ + public static final String DEFAULT_PLUGIN_CLASS = "org.onap.apex.model.basicmodel.dao.impl.DefaultApexDao"; + + private String pluginClass = DEFAULT_PLUGIN_CLASS; + private String persistenceUnit; + + private Properties jdbcProperties = new Properties(); + + /** + * Gets the DAO plugin class, this is the DAO class to use and it must implement the {@link ApexDao} interface. + * + * @return the DAO plugin class + */ + public String getPluginClass() { + return pluginClass; + } + + /** + * Sets the DAO plugin class, a class that implements the {@link ApexDao} interface. + * + * @param daoPluginClass the DAO plugin class + */ + public void setPluginClass(final String daoPluginClass) { + pluginClass = daoPluginClass; + } + + /** + * Gets the persistence unit for the DAO. The persistence unit defines the JDBC properties the DAO will use. The persistence unit must defined in the + * {@code META-INF/persistence.xml} resource file + * + * @return the persistence unit to use for JDBC access + */ + public String getPersistenceUnit() { + return persistenceUnit; + } + + /** + * Sets the persistence unit for the DAO. The persistence unit defines the JDBC properties the DAO will use. The persistence unit must defined in the + * {@code META-INF/persistence.xml} resource file + * + * @param daoPersistenceUnit the persistence unit to use for JDBC access + */ + public void setPersistenceUnit(final String daoPersistenceUnit) { + persistenceUnit = daoPersistenceUnit; + } + + /** + * Gets the JDBC properties. + * + * @return the JDBC properties + */ + public Properties getJdbcProperties() { + return jdbcProperties; + } + + /** + * Sets the JDBC properties. + * + * @param jdbcProperties the JDBC properties + */ + public void setJdbcProperties(final Properties jdbcProperties) { + this.jdbcProperties = jdbcProperties; + } + + /** + * Gets a single JDBC property. + * + * @param key the key of the property + * @return the JDBC property + */ + public String getJdbcProperty(final String key) { + return jdbcProperties.getProperty(key); + } + + /** + * Sets a single JDBC property. + * + * @param key the key of the property + * @param value the value of the JDBC property + */ + public void setJdbcProperty(final String key, final String value) { + jdbcProperties.setProperty(key, value); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "DAOParameters [pluginClass=" + pluginClass + ", persistenceUnit=" + persistenceUnit + ", jdbcProperties=" + jdbcProperties + "]"; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/CDATAConditioner.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/CDATAConditioner.java new file mode 100644 index 000000000..d949ab28a --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/CDATAConditioner.java @@ -0,0 +1,92 @@ +/* + * ============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.apex.model.basicmodel.dao.converters; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import javax.xml.bind.annotation.adapters.XmlAdapter; + +/** + * The Class CDATAConditioner converts a CDATA String to and from database format by removing spaces at the ends of lines and + * platform-specific new line endings. + * + * @author John Keeney (John.Keeney@ericsson.com) + */ +@Converter +public class CDATAConditioner extends XmlAdapter<String, String> implements AttributeConverter<String, String> { + + private static final String NL = "\n"; + + /* + * (non-Javadoc) + * + * @see javax.persistence.AttributeConverter#convertToDatabaseColumn(java.lang.Object) + */ + @Override + public String convertToDatabaseColumn(final String raw) { + return clean(raw); + } + + /* + * (non-Javadoc) + * + * @see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object) + */ + @Override + public String convertToEntityAttribute(final String db) { + return clean(db); + } + + /* + * (non-Javadoc) + * + * @see javax.xml.bind.annotation.adapters.XmlAdapter + */ + @Override + public String unmarshal(final String v) throws Exception { + return this.convertToEntityAttribute(v); + } + + /* + * (non-Javadoc) + * + * @see javax.xml.bind.annotation.adapters.XmlAdapter + */ + @Override + public String marshal(final String v) throws Exception { + return this.convertToDatabaseColumn(v); + } + + /** + * Clean. + * + * @param in the in + * @return the string + */ + public static final String clean(final String in) { + if (in == null) { + return null; + } + else { + return in.replaceAll("\\s+$", "").replaceAll("\\r?\\n", NL); + } + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/UUID2String.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/UUID2String.java new file mode 100644 index 000000000..4e6b66025 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/UUID2String.java @@ -0,0 +1,83 @@ +/* + * ============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.apex.model.basicmodel.dao.converters; + +import java.util.UUID; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import javax.xml.bind.annotation.adapters.XmlAdapter; + +/** + * The Class UUIDConverter converts a UUID to and from database format. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +@Converter +public class UUID2String extends XmlAdapter<String, UUID> implements AttributeConverter<UUID, String> { + + /* + * (non-Javadoc) + * + * @see javax.persistence.AttributeConverter#convertToDatabaseColumn(java.lang.Object) + */ + @Override + public String convertToDatabaseColumn(final UUID uuid) { + String returnString; + if (uuid == null) { + returnString = ""; + } + else { + returnString = uuid.toString(); + } + return returnString; + } + + /* + * (non-Javadoc) + * + * @see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object) + */ + @Override + public UUID convertToEntityAttribute(final String uuidString) { + return UUID.fromString(uuidString); + } + + /* + * (non-Javadoc) + * + * @see javax.xml.bind.annotation.adapters.XmlAdapter + */ + @Override + public UUID unmarshal(final String v) throws Exception { + return this.convertToEntityAttribute(v); + } + + /* + * (non-Javadoc) + * + * @see javax.xml.bind.annotation.adapters.XmlAdapter + */ + @Override + public String marshal(final UUID v) throws Exception { + return this.convertToDatabaseColumn(v); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/package-info.java new file mode 100644 index 000000000..c7bad6777 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/package-info.java @@ -0,0 +1,27 @@ +/* + * ============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 converters used by APEX EclipseLink marshaling and unmarshaling of {@link org.onap.apex.model.basicmodel.concepts.AxConcept} + * instances to and from files and databases. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +package org.onap.apex.model.basicmodel.dao.converters; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/DefaultApexDao.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/DefaultApexDao.java new file mode 100644 index 000000000..a73a15e41 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/DefaultApexDao.java @@ -0,0 +1,526 @@ +/* + * ============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.apex.model.basicmodel.dao.impl; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.onap.apex.model.basicmodel.concepts.ApexException; +import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException; +import org.onap.apex.model.basicmodel.concepts.AxArtifactKey; +import org.onap.apex.model.basicmodel.concepts.AxConcept; +import org.onap.apex.model.basicmodel.concepts.AxReferenceKey; +import org.onap.apex.model.basicmodel.dao.ApexDao; +import org.onap.apex.model.basicmodel.dao.DAOParameters; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * The Class DefaultApexDao is an JPA implementation of the {@link ApexDao} class for Apex concepts ({@link AxConcept}). It uses the default + * JPA implementation in the javax {@link Persistence} class. + * + * + * @author Sergey Sachkov (sergey.sachkov@ericsson.com) + */ +public class DefaultApexDao implements ApexDao { + private static final XLogger LOGGER = XLoggerFactory.getXLogger(DefaultApexDao.class); + + private static final String SELECT_C_FROM = "SELECT c FROM "; + private static final String AND_C_KEY_LOCAL_NAME = "' AND c.key.localName='"; + private static final String AND_C_KEY_PARENT_KEY_VERSION = "' AND c.key.parentKeyVersion='"; + private static final String C_WHERE_C_KEY_PARENT_KEY_NAME = " c WHERE c.key.parentKeyName='"; + private static final String AND_C_KEY_VERSION = "' AND c.key.version='"; + private static final String C_WHERE_C_KEY_NAME = " c WHERE c.key.name='"; + private static final String DELETE_FROM = "DELETE FROM "; + + // Entity manager for JPA + private EntityManagerFactory emf = null; + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#init(com.ericsson.apex.model.basicmodel.dao.DAOParameters) + */ + @Override + public void init(final DAOParameters daoParameters) throws ApexException { + if (daoParameters == null || daoParameters.getPersistenceUnit() == null) { + LOGGER.error("Apex persistence unit parameter not set"); + throw new ApexException("Apex persistence unit parameter not set"); + } + + LOGGER.debug("Creating Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\" . . ."); + try { + emf = Persistence.createEntityManagerFactory(daoParameters.getPersistenceUnit(), daoParameters.getJdbcProperties()); + } + catch (final Exception e) { + LOGGER.warn("Creation of Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\" failed", e); + throw new ApexException("Creation of Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\" failed", e); + } + LOGGER.debug("Created Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\""); + } + + /** + * Gets the entity manager for this DAO. + * + * @return the entity manager + */ + protected final synchronized EntityManager getEntityManager() { + if (emf == null) { + LOGGER.warn("Apex DAO has not been initialized"); + throw new ApexRuntimeException("Apex DAO has not been initialized"); + } + + return emf.createEntityManager(); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#close() + */ + @Override + public final void close() { + if (emf != null) { + emf.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#create(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public <T extends AxConcept> void create(final T obj) { + if (obj == null) { + return; + } + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + mg.merge(obj); + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public <T extends AxConcept> void delete(final T obj) { + if (obj == null) { + return; + } + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + mg.remove(mg.contains(obj) ? obj : mg.merge(obj)); + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(java.lang.Class, + * com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey) + */ + @Override + public <T extends AxConcept> void delete(final Class<T> aClass, final AxArtifactKey key) { + if (key == null) { + return; + } + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_NAME + key.getName() + AND_C_KEY_VERSION + + key.getVersion() + "'", aClass).executeUpdate(); + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(java.lang.Class, + * com.ericsson.apex.model.basicmodel.concepts.AxReferenceKey) + */ + @Override + public <T extends AxConcept> void delete(final Class<T> aClass, final AxReferenceKey key) { + if (key == null) { + return; + } + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME + key.getParentKeyName() + + AND_C_KEY_PARENT_KEY_VERSION + key.getParentKeyVersion() + AND_C_KEY_LOCAL_NAME + key.getLocalName() + "'", + aClass).executeUpdate(); + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#create(java.util.Collection) + */ + @Override + public <T extends AxConcept> void create(final Collection<T> objs) { + if (objs == null || objs.isEmpty()) { + return; + } + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + for (final T t : objs) { + mg.merge(t); + } + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(java.util.Collection) + */ + @Override + public <T extends AxConcept> void delete(final Collection<T> objs) { + if (objs == null || objs.isEmpty()) { + return; + } + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + for (final T t : objs) { + mg.remove(mg.contains(t) ? t : mg.merge(t)); + } + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#deleteByArtifactKey(java.lang.Class, java.util.Collection) + */ + @Override + public <T extends AxConcept> int deleteByArtifactKey(final Class<T> aClass, final Collection<AxArtifactKey> keys) { + if (keys == null || keys.isEmpty()) { + return 0; + } + int deletedCount = 0; + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + for (final AxArtifactKey key : keys) { + deletedCount += mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_NAME + key.getName() + + AND_C_KEY_VERSION + key.getVersion() + "'", aClass).executeUpdate(); + } + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + return deletedCount; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#deleteByReferenceKey(java.lang.Class, java.util.Collection) + */ + @Override + public <T extends AxConcept> int deleteByReferenceKey(final Class<T> aClass, final Collection<AxReferenceKey> keys) { + if (keys == null || keys.isEmpty()) { + return 0; + } + int deletedCount = 0; + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + for (final AxReferenceKey key : keys) { + deletedCount += mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME + + key.getParentKeyName() + AND_C_KEY_PARENT_KEY_VERSION + key.getParentKeyVersion() + AND_C_KEY_LOCAL_NAME + + key.getLocalName() + "'", aClass).executeUpdate(); + } + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + return deletedCount; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#deleteAll(java.lang.Class) + */ + @Override + public <T extends AxConcept> void deleteAll(final Class<T> aClass) { + final EntityManager mg = getEntityManager(); + try { + mg.getTransaction().begin(); + mg.createQuery(DELETE_FROM + aClass.getSimpleName() + " c ", aClass).executeUpdate(); + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#get(java.lang.Class, com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey) + */ + @Override + public <T extends AxConcept> T get(final Class<T> aClass, final AxArtifactKey key) { + if (aClass == null) { + return null; + } + final EntityManager mg = getEntityManager(); + try { + final T t = mg.find(aClass, key); + if (t != null) { + // This clone is created to force the JPA DAO to recurse down through the object + try { + T clonedT = aClass.newInstance(); + t.copyTo(clonedT); + return clonedT; + } + catch (Exception e) { + LOGGER.warn("Could not clone object of class \"" + aClass.getCanonicalName() + "\"", e); + return null; + } + } + else { + return null; + } + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#get(java.lang.Class, com.ericsson.apex.model.basicmodel.concepts.AxReferenceKey) + */ + @Override + public <T extends AxConcept> T get(final Class<T> aClass, final AxReferenceKey key) { + if (aClass == null) { + return null; + } + final EntityManager mg = getEntityManager(); + try { + final T t = mg.find(aClass, key); + if (t != null) { + try { + T clonedT = aClass.newInstance(); + t.copyTo(clonedT); + return clonedT; + } + catch (Exception e) { + LOGGER.warn("Could not clone object of class \"" + aClass.getCanonicalName() + "\"", e); + return null; + } + } + else { + return null; + } + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getAll(java.lang.Class) + */ + @Override + public <T extends AxConcept> List<T> getAll(final Class<T> aClass) { + if (aClass == null) { + return Collections.emptyList(); + } + final EntityManager mg = getEntityManager(); + try { + return mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + " c", aClass).getResultList(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getAll(java.lang.Class, + * com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey) + */ + @Override + public <T extends AxConcept> List<T> getAll(final Class<T> aClass, final AxArtifactKey parentKey) { + if (aClass == null) { + return Collections.emptyList(); + } + final EntityManager mg = getEntityManager(); + try { + return mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME + parentKey.getName() + + AND_C_KEY_PARENT_KEY_VERSION + parentKey.getVersion() + "'", aClass).getResultList(); + } + finally { + mg.close(); + } + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getArtifact(java.lang.Class, + * com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey) + */ + @Override + public <T extends AxConcept> T getArtifact(final Class<T> aClass, final AxArtifactKey key) { + if (aClass == null || key == null) { + return null; + } + final EntityManager mg = getEntityManager(); + List<T> ret; + try { + ret = mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_NAME + key.getName() + + AND_C_KEY_VERSION + key.getVersion() + "'", aClass).getResultList(); + } + finally { + mg.close(); + } + if (ret == null || ret.isEmpty()) { + return null; + } + if (ret.size() > 1) { + throw new IllegalArgumentException( + "More than one result was returned for search for " + aClass + " with key " + key.getID() + ": " + ret); + } + return ret.get(0); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getArtifact(java.lang.Class, + * com.ericsson.apex.model.basicmodel.concepts.AxReferenceKey) + */ + @Override + public <T extends AxConcept> T getArtifact(final Class<T> aClass, final AxReferenceKey key) { + if (aClass == null || key == null) { + return null; + } + final EntityManager mg = getEntityManager(); + List<T> ret; + try { + ret = mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME + key.getParentKeyName() + + AND_C_KEY_PARENT_KEY_VERSION + key.getParentKeyVersion() + AND_C_KEY_LOCAL_NAME + key.getLocalName() + "'", + aClass).getResultList(); + } + finally { + mg.close(); + } + if (ret == null || ret.isEmpty()) { + return null; + } + if (ret.size() > 1) { + throw new IllegalArgumentException( + "More than one result was returned for search for " + aClass + " with key " + key.getID() + ": " + ret); + } + return ret.get(0); + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#update(com.ericsson.apex.model.basicmodel.concepts.AxConcept) + */ + @Override + public <T extends AxConcept> T update(final T obj) { + final EntityManager mg = getEntityManager(); + T ret; + try { + mg.getTransaction().begin(); + ret = mg.merge(obj); + mg.flush(); + mg.getTransaction().commit(); + } + finally { + mg.close(); + } + return ret; + } + + /* + * (non-Javadoc) + * + * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#size(java.lang.Class) + */ + @Override + public <T extends AxConcept> long size(final Class<T> aClass) { + if (aClass == null) { + return 0; + } + final EntityManager mg = getEntityManager(); + long size = 0; + try { + size = mg.createQuery("SELECT COUNT(c) FROM " + aClass.getSimpleName() + " c", Long.class).getSingleResult(); + } + finally { + mg.close(); + } + return size; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/package-info.java new file mode 100644 index 000000000..16da22646 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/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 a default DAO implementation for APEX {@link org.onap.apex.model.basicmodel.concepts.AxConcept} classes that uses javax persistence. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +package org.onap.apex.model.basicmodel.dao.impl; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/package-info.java new file mode 100644 index 000000000..0ad255a9a --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/package-info.java @@ -0,0 +1,27 @@ +/* + * ============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========================================================= + */ + +/** + * Defines and implements the Data Access Object (DAO) that allows Apex {@link org.onap.apex.model.basicmodel.concepts.AxConcept} concepts to + * be read from and written to databases over JDBC. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +package org.onap.apex.model.basicmodel.dao; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelCreator.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelCreator.java new file mode 100644 index 000000000..5a9de967f --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelCreator.java @@ -0,0 +1,39 @@ +/* + * ============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.apex.model.basicmodel.handling; + +import org.onap.apex.model.basicmodel.concepts.AxModel; + +/** + * This interface is implemented by factories that create Apex models. It is mainly used by unit test classes that generate Apex models for test purposes. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <M> the type of Apex model to create, must be a sub class of {@link AxModel} + */ +public interface ApexModelCreator<M extends AxModel> { + + /** + * Gets the model created by the model creator. + * + * @return the model created by the model creator + */ + M getModel(); +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelException.java new file mode 100644 index 000000000..252bee4ed --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelException.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.apex.model.basicmodel.handling; + +import org.onap.apex.model.basicmodel.concepts.ApexException; + +/** + * This exception is invoked if an exception occurs in model handling. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class ApexModelException extends ApexException { + private static final long serialVersionUID = -4245694568321686450L; + + /** + * Instantiates a new apex model handling exception. + * + * @param message the message + */ + public ApexModelException(final String message) { + super(message); + } + + /** + * Instantiates a new apex model handling exception. + * + * @param message the message + * @param e the e + */ + public ApexModelException(final String message, final Exception e) { + super(message, e); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelFileWriter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelFileWriter.java new file mode 100644 index 000000000..8d9cf2ae0 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelFileWriter.java @@ -0,0 +1,139 @@ +/* + * ============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.apex.model.basicmodel.handling; + +import java.io.File; +import java.io.FileOutputStream; + +import org.onap.apex.model.basicmodel.concepts.ApexException; +import org.onap.apex.model.basicmodel.concepts.AxModel; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * This class writes an Apex model to a file. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <M> the type of Apex model to write to file, must be a sub class of {@link AxModel} + */ +public class ApexModelFileWriter<M extends AxModel> { + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelFileWriter.class); + + // Should models being written to files be valid + private boolean validateFlag; + + /** + * Constructor, set the validation flag. + * + * @param validateFlag indicates if validation be performed prior to output + */ + public ApexModelFileWriter(final boolean validateFlag) { + this.validateFlag = validateFlag; + } + + /** + * Write a model to an XML file. + * + * @param model The model to write + * @param rootModelClass The concept class + * @param modelFileName The name of the file to write to + * @throws ApexException thrown on errors + */ + public void apexModelWriteXMLFile(final M model, final Class<M> rootModelClass, final String modelFileName) + throws ApexException { + LOGGER.debug("running apexModelWriteXMLFile . . ."); + + final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass); + modelWriter.setValidateFlag(validateFlag); + modelWriter.getCDataFieldSet().add("description"); + modelWriter.getCDataFieldSet().add("logic"); + modelWriter.getCDataFieldSet().add("uiLogic"); + + writeModelFile(model, modelWriter, modelFileName); + + LOGGER.debug("ran apexModelWriteXMLFile"); + } + + /** + * Write a model to an JSON file. + * + * @param model The model to write + * @param rootModelClass The concept class + * @param modelFileName The name of the file to write to + * @throws ApexException thrown on errors + */ + public void apexModelWriteJSONFile(final M model, final Class<M> rootModelClass, final String modelFileName) + throws ApexException { + LOGGER.debug("running apexModelWriteJSONFile . . ."); + + final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass); + modelWriter.setJsonOutput(true); + modelWriter.setValidateFlag(validateFlag); + + writeModelFile(model, modelWriter, modelFileName); + + LOGGER.debug("ran apexModelWriteJSONFile"); + } + + /** + * Checks if the validation flag is set. + * + * @return true, the validation flag is set + */ + public boolean isValidateFlag() { + return validateFlag; + } + + /** + * Sets the validate flag. + * + * @param validateFlag the validate flag value + */ + public void setValidateFlag(final boolean validateFlag) { + this.validateFlag = validateFlag; + } + + /** + * Write a model to a file using a model writer. + * + * @param model The model to write + * @param modelWriter the model writer to use to write the model to the file + * @param modelFileName the file name of the file to write to + * @throws ApexException on exceptions writing the model + */ + private void writeModelFile(final M model, final ApexModelWriter<M> modelWriter, final String modelFileName) throws ApexException { + final File modelFile = new File(modelFileName); + if (!modelFile.getParentFile().exists() && !modelFile.getParentFile().mkdirs()) { + LOGGER.warn("could not create directory " + modelFile.getParentFile()); + throw new ApexException("could not create directory " + modelFile.getParentFile()); + } + + try { + final FileOutputStream fileOutputStream = new FileOutputStream(modelFile); + modelWriter.write(model, fileOutputStream); + fileOutputStream.close(); + } + catch (final Exception e) { + LOGGER.warn("error processing file " + modelFile.getAbsolutePath(), e); + throw new ApexException("error processing file " + modelFile.getAbsolutePath(), e); + } + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelReader.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelReader.java new file mode 100644 index 000000000..84760f5db --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelReader.java @@ -0,0 +1,279 @@ +/* + * ============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.apex.model.basicmodel.handling; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.URL; +import java.util.regex.Pattern; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.eclipse.persistence.jaxb.JAXBContextFactory; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.eclipse.persistence.oxm.MediaType; +import org.onap.apex.model.basicmodel.concepts.AxConcept; +import org.onap.apex.model.basicmodel.concepts.AxValidationResult; +import org.onap.policy.apex.model.utilities.Assertions; +import org.onap.policy.apex.model.utilities.ResourceUtils; +import org.onap.policy.apex.model.utilities.TextFileUtils; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * This class reads an Apex concept from an XML file into a Java Apex Concept {@link AxConcept}. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <C> the type of Apex concept to read, must be a sub class of {@link AxConcept} + */ +public class ApexModelReader<C extends AxConcept> { + // Get a reference to the logger + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelReader.class); + + // Regular expressions for checking input types + private static final String XML_INPUT_TYPE_REGEXP = "^\\s*<\\?xml.*>\\s*"; // (starts with <?xml...> + private static final String JSON_INPUT_TYPE_REGEXP = "^\\s*[\\(\\{\\[][\\s+\\S]*[\\)\\}\\]]"; // starts with some kind of bracket [ or ( + // or {, then has something, then has + // and has a close bracket + + // Â The root class of the concept we are reading + private final Class<C> rootConceptClass; + + // The unmarshaller for the Apex concepts + private Unmarshaller unmarshaller = null; + + // All read concepts are validated after reading if this flag is set + private boolean validateFlag = true; + + /** + * Constructor, initiates the reader with validation on. + * + * @param rootConceptClass the root concept class for concept reading + * @throws ApexModelException the apex concept reader exception + */ + public ApexModelReader(final Class<C> rootConceptClass) throws ApexModelException { + // Save the root concept class + this.rootConceptClass = rootConceptClass; + + try { + final JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {rootConceptClass}, null); + + // Set up the unmarshaller to carry out validation + unmarshaller = jaxbContext.createUnmarshaller(); + unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler()); + } + catch (final JAXBException e) { + LOGGER.error("Unable to set JAXB context", e); + throw new ApexModelException("Unable to set JAXB context", e); + } + } + + /** + * Constructor, initiates the reader. + * + * @param rootConceptClass the root concept class for concept reading + * @param validate whether to perform validation by default + * @throws ApexModelException the apex concept reader exception + */ + public ApexModelReader(final Class<C> rootConceptClass, final boolean validate) throws ApexModelException { + this(rootConceptClass); + this.validateFlag = validate; + } + + /** + * Set the schema to use for reading XML files. + * + * @param schemaFileName the schema file to use + * @throws ApexModelException if the schema cannot be set + */ + public void setSchema(final String schemaFileName) throws ApexModelException { + // Has a schema been set + if (schemaFileName != null) { + try { + // Set the concept schema + final URL schemaURL = ResourceUtils.getURLResource(schemaFileName); + final Schema apexConceptSchema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaURL); + unmarshaller.setSchema(apexConceptSchema); + } + catch (final Exception e) { + LOGGER.error("Unable to load schema ", e); + throw new ApexModelException("Unable to load schema", e); + } + } + else { + // Clear the schema + unmarshaller.setSchema(null); + } + } + + /** + * This method checks the specified Apex concept XML file and reads it into an Apex concept. + * + * @param apexConceptStream the apex concept stream + * @return the Apex concept + * @throws ApexModelException on reading exceptions + */ + public C read(final InputStream apexConceptStream) throws ApexModelException { + Assertions.argumentNotNull(apexConceptStream, "concept stream may not be null"); + + return read(new BufferedReader(new InputStreamReader(apexConceptStream))); + } + + /** + * This method reads the specified Apex reader into an Apex concept. + * + * @param apexConceptReader the apex concept reader + * @return the Apex concept + * @throws ApexModelException on reading exceptions + */ + public C read(final BufferedReader apexConceptReader) throws ApexModelException { + Assertions.argumentNotNull(apexConceptReader, "concept reader may not be null"); + + LOGGER.entry("reading Apex concept into a String . . ."); + + // Get the Apex concept as a string + String apexConceptString = null; + try { + apexConceptString = TextFileUtils.getReaderAsString(apexConceptReader).trim(); + } + catch (final IOException e) { + throw new ApexModelException("Unable to read Apex concept ", e); + } + + return read(apexConceptString); + } + + /** + * This method reads the specified Apex string into an Apex concept. + * + * @param apexConceptString the apex concept as a string + * @return the Apex concept + * @throws ApexModelException on reading exceptions + */ + public C read(final String apexConceptString) throws ApexModelException { + Assertions.argumentNotNull(apexConceptString, "concept string may not be null"); + + LOGGER.entry("reading Apex concept from string . . ."); + + final String apexString = apexConceptString.trim(); + + // Set the type of input for this stream + setInputType(apexString); + + // The Apex Concept + C apexConcept = null; + + // Use JAXB to read and verify the Apex concept XML file + try { + // Load the configuration file + final StreamSource source = new StreamSource(new StringReader(apexString)); + final JAXBElement<C> rootElement = unmarshaller.unmarshal(source, rootConceptClass); + apexConcept = rootElement.getValue(); + } + catch (final JAXBException e) { + throw new ApexModelException("Unable to unmarshal Apex concept ", e); + } + + LOGGER.debug("reading of Apex concept {} completed"); + + // Check if the concept should be validated + if (validateFlag) { + // Validate the configuration file + final AxValidationResult validationResult = apexConcept.validate(new AxValidationResult()); + LOGGER.debug(validationResult.toString()); + if (validationResult.isValid()) { + return apexConcept; + } + else { + LOGGER.error("Apex concept validation failed" + validationResult.toString()); + throw new ApexModelException("Apex concept validation failed" + validationResult.toString()); + } + } + else { + // No validation check + return apexConcept; + } + } + + /** + * Gets the value of the validation flag. + * + * @return the validation flag value + */ + public boolean getValidateFlag() { + return validateFlag; + } + + /** + * Sets the validation flag. + * + * @param validateFlag the validation flag value + */ + public void setValidateFlag(final boolean validateFlag) { + this.validateFlag = validateFlag; + } + + /** + * Set the type of input for the concept reader. + * + * @param apexConceptString The stream with + * @throws ApexModelException on errors setting input type + */ + private void setInputType(final String apexConceptString) throws ApexModelException { + // Check the input type + if (Pattern.compile(JSON_INPUT_TYPE_REGEXP).matcher(apexConceptString).find()) { + //is json + try { + unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON); + unmarshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true); + } + catch (final Exception e) { + LOGGER.warn("JAXB error setting marshaller for JSON Input", e); + throw new ApexModelException("JAXB error setting marshaller for JSON Input", e); + } + } + else if (Pattern.compile(XML_INPUT_TYPE_REGEXP).matcher(apexConceptString).find()) { + //is xml + try { + unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_XML); + } + catch (final Exception e) { + LOGGER.warn("JAXB error setting marshaller for XML Input", e); + throw new ApexModelException("JAXB error setting marshaller for XML Input", e); + } + } + else { + LOGGER.warn("format of input for Apex concept is neither JSON nor XML"); + throw new ApexModelException("format of input for Apex concept is neither JSON nor XML"); + } + } + +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelSaver.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelSaver.java new file mode 100644 index 000000000..7f4efee99 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelSaver.java @@ -0,0 +1,95 @@ +/* + * ============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.apex.model.basicmodel.handling; + +import java.io.File; + +import org.onap.apex.model.basicmodel.concepts.ApexException; +import org.onap.apex.model.basicmodel.concepts.AxModel; +import org.onap.policy.apex.model.utilities.Assertions; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * This class is used to save Apex models to file in XML or JSON format. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <M> the type of Apex model to save to file, must be a sub class of {@link AxModel} + */ +public class ApexModelSaver<M extends AxModel> { + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelSaver.class); + + // The class of the model and the model to write to disk + private final Class<M> rootModelClass; + private final M model; + + // The path into which to write the models + private final String writePath; + + /** + * Constructor, specifies the type of the Apex model (a sub class of {@link AxModel}), the model to write, and the path of a directory to which to write the + * model. + * + * @param rootModelClass the class of the model, a sub class of {@link AxModel} + * @param model the model to write, an instance of a sub class of {@link AxModel} + * @param writePath the directory to which models will be written. The name of the written model will be the Model Name for its key with the suffix + * {@code .xml} or {@code .json}. + */ + public ApexModelSaver(final Class<M> rootModelClass, final M model, final String writePath) { + Assertions.argumentNotNull(rootModelClass, "argument rootModelClass may not be null"); + Assertions.argumentNotNull(model, "argument model may not be null"); + Assertions.argumentNotNull(writePath, "writePath rootModelClass may not be null"); + + this.rootModelClass = rootModelClass; + this.model = model; + this.writePath = writePath; + } + + /** + * Write an Apex model to a file in XML format. The model will be written to {@code <writePath/modelKeyName.xml>} + * + * @throws ApexException on errors writing the Apex model + */ + public void apexModelWriteXML() throws ApexException { + LOGGER.debug("running apexModelWriteXML . . ."); + + // Write the file to disk + final File xmlFile = new File(writePath + File.separatorChar + model.getKey().getName() + ".xml"); + new ApexModelFileWriter<M>(true).apexModelWriteXMLFile(model, rootModelClass, xmlFile.getPath()); + + LOGGER.debug("ran apexModelWriteXML"); + } + + /** + * Write an Apex model to a file in JSON format. The model will be written to {@code <writePath/modelKeyName.json>} + * + * @throws ApexException on errors writing the Apex model + */ + public void apexModelWriteJSON() throws ApexException { + LOGGER.debug("running apexModelWriteJSON . . ."); + + // Write the file to disk + final File jsonFile = new File(writePath + File.separatorChar + model.getKey().getName() + ".json"); + new ApexModelFileWriter<M>(true).apexModelWriteJSONFile(model, rootModelClass, jsonFile.getPath()); + + LOGGER.debug("ran apexModelWriteJSON"); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelStringWriter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelStringWriter.java new file mode 100644 index 000000000..882092c05 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelStringWriter.java @@ -0,0 +1,149 @@ +/* + * ============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.apex.model.basicmodel.handling; + +import java.io.ByteArrayOutputStream; + +import org.onap.apex.model.basicmodel.concepts.ApexException; +import org.onap.apex.model.basicmodel.concepts.AxConcept; +import org.onap.policy.apex.model.utilities.Assertions; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * This class writes an Apex concept to a string. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <C> the type of Apex concept to write to a string, must be a sub class of {@link AxConcept} + */ +public class ApexModelStringWriter<C extends AxConcept> { + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelStringWriter.class); + + // Should concepts being written to files be valid + private boolean validateFlag; + + /** + * Constructor, set the validation flag. + * + * @param validateFlag Should validation be performed prior to output + */ + public ApexModelStringWriter(final boolean validateFlag) { + this.validateFlag = validateFlag; + } + + /** + * Write a concept to a string. + * + * @param concept The concept to write + * @param rootConceptClass The concept class + * @param jsonFlag writes JSON if true, and a generic string if false + * @return The string with the concept + * @throws ApexException thrown on errors + */ + public String writeString(final C concept, final Class<C> rootConceptClass, final boolean jsonFlag) throws ApexException { + Assertions.argumentNotNull(concept, "concept may not be null"); + + if (jsonFlag) { + return writeJSONString(concept, rootConceptClass); + } + else { + return concept.toString(); + } + } + + /** + * Write a concept to an XML string. + * + * @param concept The concept to write + * @param rootConceptClass The concept class + * @return The string with the concept + * @throws ApexException thrown on errors + */ + public String writeXMLString(final C concept, final Class<C> rootConceptClass) throws ApexException { + LOGGER.debug("running writeXMLString . . ."); + + final ApexModelWriter<C> conceptWriter = new ApexModelWriter<>(rootConceptClass); + conceptWriter.setValidateFlag(validateFlag); + conceptWriter.getCDataFieldSet().add("description"); + conceptWriter.getCDataFieldSet().add("logic"); + conceptWriter.getCDataFieldSet().add("uiLogic"); + + final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream(); + try { + conceptWriter.write(concept, baOutputStream); + baOutputStream.close(); + } + catch (final Exception e) { + LOGGER.warn("error writing XML string", e); + throw new ApexException("error writing XML string", e); + } + + LOGGER.debug("ran writeXMLString"); + return baOutputStream.toString(); + } + + /** + * Write a concept to a JSON string. + * + * @param concept The concept to write + * @param rootConceptClass The concept class + * @return The string with the concept + * @throws ApexException thrown on errors + */ + public String writeJSONString(final C concept, final Class<C> rootConceptClass) throws ApexException { + LOGGER.debug("running writeJSONString . . ."); + + final ApexModelWriter<C> conceptWriter = new ApexModelWriter<>(rootConceptClass); + conceptWriter.setJsonOutput(true); + conceptWriter.setValidateFlag(validateFlag); + + final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream(); + try { + conceptWriter.write(concept, baOutputStream); + baOutputStream.close(); + } + catch (final Exception e) { + LOGGER.warn("error writing JSON string", e); + throw new ApexException("error writing JSON string", e); + } + + LOGGER.debug("ran writeJSONString"); + return baOutputStream.toString(); + } + + /** + * Checks if is validate flag. + * + * @return true, if checks if is validate flag + */ + public boolean isValidateFlag() { + return validateFlag; + } + + /** + * Sets the validate flag. + * + * @param validateFlag the validate flag + */ + public void setValidateFlag(final boolean validateFlag) { + this.validateFlag = validateFlag; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelWriter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelWriter.java new file mode 100644 index 000000000..5b7a9568b --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelWriter.java @@ -0,0 +1,278 @@ +/* + * ============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.apex.model.basicmodel.handling; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.Set; +import java.util.TreeSet; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.eclipse.persistence.jaxb.JAXBContextFactory; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.eclipse.persistence.oxm.MediaType; +import org.onap.apex.model.basicmodel.concepts.AxConcept; +import org.onap.apex.model.basicmodel.concepts.AxValidationResult; +import org.onap.policy.apex.model.utilities.Assertions; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; +import org.w3c.dom.Document; + +/** + * This class writes an Apex concept to an XML file or JSON file from a Java Apex Concept. + * + * @author John Keeney (john.keeney@ericsson.com) + * @param <C> the type of Apex concept to write, must be a sub class of {@link AxConcept} + */ +public class ApexModelWriter<C extends AxConcept> { + private static final String CONCEPT_MAY_NOT_BE_NULL = "concept may not be null"; + private static final String CONCEPT_WRITER_MAY_NOT_BE_NULL = "concept writer may not be null"; + private static final String CONCEPT_STREAM_MAY_NOT_BE_NULL = "concept stream may not be null"; + + // Get a reference to the logger + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelWriter.class); + + // Writing as JSON or XML + private boolean jsonOutput = false; + + // The list of fields to output as CDATA + private final Set<String> cDataFieldSet = new TreeSet<>(); + + // The Marshaller for the Apex concepts + private Marshaller marshaller = null; + + // All written concepts are validated before writing if this flag is set + private boolean validateFlag = true; + + /** + * Constructor, initiates the writer. + * + * @param rootConceptClass the root concept class for concept reading + * @throws ApexModelException the apex concept writer exception + */ + public ApexModelWriter(final Class<C> rootConceptClass) throws ApexModelException { + // Set up Eclipselink for XML and JSON output + System.setProperty("javax.xml.bind.context.factory", "org.eclipse.persistence.jaxb.JAXBContextFactory"); + + try { + final JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {rootConceptClass}, null); + + // Set up the unmarshaller to carry out validation + marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler()); + } + catch (final JAXBException e) { + LOGGER.error("JAXB marshaller creation exception", e); + throw new ApexModelException("JAXB marshaller creation exception", e); + } + } + + /** + * The set of fields to be output as CDATA. + * + * @return the set of fields + */ + public Set<String> getCDataFieldSet() { + return cDataFieldSet; + } + + /** + * Return true if JSON output enabled, XML output if false. + * + * @return true for JSON output + */ + public boolean isJsonOutput() { + return jsonOutput; + } + + /** + * Set the value of JSON output, true for JSON output, false for XML output. + * + * @param jsonOutput true for JSON output + * @throws ApexModelException on errors setting output type + */ + public void setJsonOutput(final boolean jsonOutput) throws ApexModelException { + this.jsonOutput = jsonOutput; + + // Set up output specific parameters + if (this.jsonOutput) { + try { + marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON); + marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true); + } + catch (final Exception e) { + LOGGER.warn("JAXB error setting marshaller for JSON output", e); + throw new ApexModelException("JAXB error setting marshaller for JSON output", e); + } + } + else { + try { + marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_XML); + } + catch (final Exception e) { + LOGGER.warn("JAXB error setting marshaller for XML output", e); + throw new ApexModelException("JAXB error setting marshaller for XML output", e); + } + } + } + + /** + * This method validates the Apex concept then writes it into a stream. + * + * @param concept the concept to write + * @param apexConceptStream the stream to write to + * @throws ApexModelException on validation or writing exceptions + */ + public void write(final C concept, final OutputStream apexConceptStream) throws ApexModelException { + Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL); + Assertions.argumentNotNull(apexConceptStream, CONCEPT_STREAM_MAY_NOT_BE_NULL); + + this.write(concept, new OutputStreamWriter(apexConceptStream)); + } + + /** + * This method validates the Apex concept then writes it into a writer. + * + * @param concept the concept to write + * @param apexConceptWriter the writer to write to + * @throws ApexModelException on validation or writing exceptions + */ + public void write(final C concept, final Writer apexConceptWriter) throws ApexModelException { + Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL); + Assertions.argumentNotNull(apexConceptWriter, CONCEPT_WRITER_MAY_NOT_BE_NULL); + + // Check if we should validate the concept + if (validateFlag) { + // Validate the concept first + final AxValidationResult validationResult = concept.validate(new AxValidationResult()); + LOGGER.debug(validationResult.toString()); + if (!validationResult.isValid()) { + LOGGER.warn(validationResult.toString()); + throw new ApexModelException("Apex concept xml (" + concept.getKey().getID() + ") validation failed"); + } + } + + if (jsonOutput) { + writeJSON(concept, apexConceptWriter); + } + else { + writeXML(concept, apexConceptWriter); + } + } + + /** + * This method writes the Apex concept into a writer in XML format. + * + * @param concept the concept to write + * @param apexConceptWriter the writer to write to + * @throws ApexModelException on validation or writing exceptions + */ + private void writeXML(final C concept, final Writer apexConceptWriter) throws ApexModelException { + Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL); + + LOGGER.debug("writing Apex concept XML . . ."); + + try { + // Write the concept into a DOM document, then transform to add CDATA fields and pretty print, then write out the result + final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + final Document document = docBuilderFactory.newDocumentBuilder().newDocument(); + + // Marshal the concept into the empty document. + marshaller.marshal(concept, document); + + // Transform the DOM to the output stream + final TransformerFactory transformerFactory = TransformerFactory.newInstance(); + final Transformer domTransformer = transformerFactory.newTransformer(); + + // Pretty print + try { + domTransformer.setOutputProperty(OutputKeys.INDENT, "yes"); + // May fail if not using XALAN XSLT engine. But not in any way vital + domTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + } + catch (final Exception ignore) { + // We ignore exceptions here and catch errors below + } + + // Convert the cDataFieldSet into a space delimited string + domTransformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, cDataFieldSet.toString().replaceAll("[\\[\\]\\,]", " ")); + domTransformer.transform(new DOMSource(document), new StreamResult(apexConceptWriter)); + } + catch (JAXBException | TransformerException | ParserConfigurationException e) { + LOGGER.warn("Unable to marshal Apex concept XML", e); + throw new ApexModelException("Unable to marshal Apex concept XML", e); + } + LOGGER.debug("wrote Apex concept XML"); + } + + /** + * This method writes the Apex concept into a writer in JSON format. + * + * @param concept the concept to write + * @param apexConceptWriter the writer to write to + * @throws ApexModelException on validation or writing exceptions + */ + private void writeJSON(final C concept, final Writer apexConceptWriter) throws ApexModelException { + Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL); + + LOGGER.debug("writing Apex concept JSON . . ."); + + try { + marshaller.marshal(concept, apexConceptWriter); + } + catch (final JAXBException e) { + LOGGER.warn("Unable to marshal Apex concept JSON", e); + throw new ApexModelException("Unable to marshal Apex concept JSON", e); + } + LOGGER.debug("wrote Apex concept JSON"); + } + + /** + * Gets the validation flag value. + * + * @return the validation flag value + */ + public boolean getValidateFlag() { + return validateFlag; + } + + /** + * Sets the validation flag. + * + * @param validateFlag the validation flag value + */ + public void setValidateFlag(final boolean validateFlag) { + this.validateFlag = validateFlag; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexSchemaGenerator.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexSchemaGenerator.java new file mode 100644 index 000000000..5055df630 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexSchemaGenerator.java @@ -0,0 +1,166 @@ +/* + * ============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.apex.model.basicmodel.handling; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.io.StringWriter; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.SchemaOutputResolver; +import javax.xml.transform.Result; +import javax.xml.transform.stream.StreamResult; + +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * This class generates the XML model schema from the given Apex concept classes. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public class ApexSchemaGenerator { + // Get a reference to the logger + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexSchemaGenerator.class); + + /** + * A Main method to allow schema generation from the command line or from maven or scripts. + * + * @param args the command line arguments, usage is {@code ApexSchemaGenerator apex-root-class [schema-file-name]} + */ + public static void main(final String[] args) { + PrintStream printStream = null; + + if (args.length == 1) { + printStream = System.out; + } + else if (args.length == 2) { + final File schemaFile = new File(args[1]); + + try { + schemaFile.getParentFile().mkdirs(); + printStream = new PrintStream(schemaFile); + } + catch (final Exception e) { + LOGGER.error("error on Apex schema output", e); + return; + } + } + else { + LOGGER.error("usage: ApexSchemaGenerator apex-root-class [schema-file-name]"); + return; + } + + // Get the schema + final String schema = new ApexSchemaGenerator().generate(args[0]); + + // Output the schema + printStream.println(schema); + + printStream.close(); + } + + /** + * Generates the XML schema (XSD) for the Apex model described using JAXB annotations. + * + * @param rootClassName the name of the root class for schema generation + * @return The schema + */ + public String generate(final String rootClassName) { + JAXBContext jaxbContext; + try { + jaxbContext = JAXBContext.newInstance(Class.forName(rootClassName)); + } + catch (final ClassNotFoundException e) { + LOGGER.error("could not create JAXB context, root class " + rootClassName + " not found", e); + return null; + } + catch (final JAXBException e) { + LOGGER.error("could not create JAXB context", e); + return null; + } + + final ApexSchemaOutputResolver sor = new ApexSchemaOutputResolver(); + try { + jaxbContext.generateSchema(sor); + } + catch (final IOException e) { + LOGGER.error("error generating the Apex schema (XSD) file", e); + return null; + } + + String schemaString = sor.getSchema(); + schemaString = fixForUnqualifiedBug(schemaString); + + return schemaString; + } + + /** + * There is a bug in schema generation that does not specify the elements from Java Maps as being unqualified. This method "hacks" those + * elements in the schema to fix this, the elements being {@code entry}, {@code key}, and {@code value} + * + * @param schemaString The schema in which elements should be fixed + * @return the string + */ + private String fixForUnqualifiedBug(final String schemaString) { + // Fix the "entry" element + String newSchemaString = schemaString.replaceAll("<xs:element name=\"entry\" minOccurs=\"0\" maxOccurs=\"unbounded\">", + "<xs:element name=\"entry\" minOccurs=\"0\" maxOccurs=\"unbounded\" form=\"unqualified\">"); + + // Fix the "key" element + newSchemaString = newSchemaString.replaceAll("<xs:element name=\"key\"", "<xs:element name=\"key\" form=\"unqualified\""); + + // Fix the "value" element + newSchemaString = newSchemaString.replaceAll("<xs:element name=\"value\"", "<xs:element name=\"value\" form=\"unqualified\""); + + return newSchemaString; + } + + /** + * This inner class is used to receive the output of schema generation from the JAXB schema generator. + */ + private class ApexSchemaOutputResolver extends SchemaOutputResolver { + private final StringWriter stringWriter = new StringWriter(); + + /* + * (non-Javadoc) + * + * @see javax.xml.bind.SchemaOutputResolver#createOutput(java.lang.String, java.lang.String) + */ + @Override + public Result createOutput(final String namespaceURI, final String suggestedFileName) throws IOException { + final StreamResult result = new StreamResult(stringWriter); + result.setSystemId(suggestedFileName); + return result; + } + + /** + * Get the schema from the string writer created in the {@link createOutput()} method. + * + * @return the schema generated by JAXB + */ + public String getSchema() { + return stringWriter.toString(); + } + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/package-info.java new file mode 100644 index 000000000..871a0ea49 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/package-info.java @@ -0,0 +1,37 @@ +/* + * ============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 a number of utility classes for handling APEX {@link org.onap.apex.model.basicmodel.concepts.AxModel} models and + * {@link org.onap.apex.model.basicmodel.concepts.AxConcept} concepts. + * Classes to read and write models to files, strings, and databases are included, as + * well as classes to generate XML schemas for models. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ + +@XmlSchema(namespace = "http://www.ericsson.com/apex", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = { + @XmlNs(namespaceURI = "http://www.ericsson.com/apex", prefix = "") }) + +package org.onap.apex.model.basicmodel.handling; + +import javax.xml.bind.annotation.XmlNs; +import javax.xml.bind.annotation.XmlNsForm; +import javax.xml.bind.annotation.XmlSchema; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/package-info.java new file mode 100644 index 000000000..dbee9cc9d --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/package-info.java @@ -0,0 +1,29 @@ +/* + * ============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========================================================= + */ + +/** + * Provides the base definition of an APEX model. It also defines the Model Service, the mechanism that allows access to the + * model for APEX concepts anywhere in the system. + * + * It also provides handling support to models, allowing them to be read and written to file and databases in JSON and XML format. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +package org.onap.apex.model.basicmodel; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/AbstractParameters.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/AbstractParameters.java new file mode 100644 index 000000000..2cde32518 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/AbstractParameters.java @@ -0,0 +1,85 @@ +/* + * ============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.apex.model.basicmodel.service; + +import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException; +import org.onap.policy.apex.model.utilities.Assertions; + +/** + * This class defines an abstract parameter class that acts as a base class for all parameters in Apex. The abstract parameter class holds the name of a + * subclass of this abstract parameter class {@link AbstractParameters}. The class of the parameter class is checked at construction and on calls to the + * {@link #getParameterClass()} method. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public abstract class AbstractParameters { + // The name of the parameter subclass + private String parameterClassName = this.getClass().getCanonicalName(); + + /** + * Constructor, creates a parameter class that must be a subclass of {@link AbstractParameters}. + * + * @param parameterClassName the full canonical class name of the parameter class + */ + public AbstractParameters(final String parameterClassName) { + try { + Assertions.assignableFrom(Class.forName(parameterClassName), AbstractParameters.class); + } + catch (IllegalArgumentException | ClassNotFoundException e) { + throw new ApexRuntimeException( + "class \"" + parameterClassName + "\" not found or not an instance of \"" + this.getClass().getCanonicalName() + "\"", e); + } + } + + /** + * Gets the parameter class. + * + * @return the parameter class + */ + @SuppressWarnings("unchecked") + public final Class<? extends AbstractParameters> getParameterClass() { + try { + return (Class<? extends AbstractParameters>) Class.forName(parameterClassName); + } + catch (final ClassNotFoundException e) { + throw new ApexRuntimeException("class not found for parameter class name \"" + parameterClassName + "\""); + } + } + + /** + * Gets the parameter class name. + * + * @return the parameter class name + */ + public final String getParameterClassName() { + return parameterClassName; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "AbstractParameters [parameterClassName=" + parameterClassName + "]"; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ModelService.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ModelService.java new file mode 100644 index 000000000..688beaa4f --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ModelService.java @@ -0,0 +1,106 @@ +/* + * ============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.apex.model.basicmodel.service; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException; +import org.onap.apex.model.basicmodel.concepts.AxConcept; + +/** + * The model service makes Apex models available to all classes in a JVM. + * + * The reason for having a model service is to avoid having to pass concept and model definitions down long call chains in modules such as the Apex engine and + * editor. The model service makes the model and concept definitions available statically. + * + * Note that the use of the model service means that only a single Apex model of a particular type may exist in Apex (particularly the engine) at any time. Of + * course the model in a JVM can be changed at any time provided all users of the model are stopped and restrted in an orderly manner. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public abstract class ModelService { + // The map holding the models + private static Map<Class<?>, AxConcept> modelMap = new ConcurrentHashMap<>(); + + /** + * This class is an abstract static class that cannot be extended. + */ + private ModelService() { + } + + /** + * Register a model with the model service. + * + * @param <M> the generic type + * @param modelClass the class of the model, used to index the model + * @param model The model + */ + public static <M extends AxConcept> void registerModel(final Class<M> modelClass, final M model) { + modelMap.put(modelClass, model); + } + + /** + * Remove a model from the model service. + * + * @param <M> the generic type + * @param modelClass the class of the model, used to index the model + */ + public static <M extends AxConcept> void deregisterModel(final Class<M> modelClass) { + modelMap.remove(modelClass); + } + + /** + * Get a model from the model service. + * + * @param <M> the generic type + * @param modelClass the class of the model, used to index the model + * @return The model + */ + @SuppressWarnings("unchecked") + public static <M extends AxConcept> M getModel(final Class<M> modelClass) { + final M model = (M) modelMap.get(modelClass); + + if (model == null) { + throw new ApexRuntimeException("Model for " + modelClass.getCanonicalName() + " not found in model service"); + } + + return model; + } + + /** + * Check if a model is defined on the model service. + * + * @param <M> the generic type + * @param modelClass the class of the model, used to index the model + * @return true if the model is defined + */ + public static <M extends AxConcept> boolean existsModel(final Class<M> modelClass) { + return modelMap.get(modelClass) != null; + } + + /** + * Clear all models in the model service. + */ + public static void clear() { + modelMap.clear(); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ParameterService.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ParameterService.java new file mode 100644 index 000000000..9a254b0d6 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ParameterService.java @@ -0,0 +1,116 @@ +/* + * ============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.apex.model.basicmodel.service; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException; + +/** + * The parameter service makes Apex parameters available to all classes in a JVM. + * + * The reason for having a parameter service is to avoid having to pass parameters down long call chains in modules such as the Apex engine and editor. The + * parameter service makes parameters available statically. + * + * The parameter service must be used with care because changing a parameter set anywhere in a JVM will affect all users of those parameters anywhere in the + * JVM. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +public abstract class ParameterService { + // The map holding the parameters + private static Map<Class<?>, AbstractParameters> parameterMap = new ConcurrentHashMap<>(); + + /** + * This class is an abstract static class that cannot be extended. + */ + private ParameterService() { + } + + /** + * Register parameters with the parameter service. + * + * @param <P> the generic type + * @param parametersClass the class of the parameter, used to index the parameter + * @param parameters the parameters + */ + public static <P extends AbstractParameters> void registerParameters(final Class<P> parametersClass, final P parameters) { + parameterMap.put(parametersClass, parameters); + } + + /** + * Remove parameters from the parameter service. + * + * @param <P> the generic type + * @param parametersClass the class of the parameter, used to index the parameter + */ + public static <P extends AbstractParameters> void deregisterParameters(final Class<P> parametersClass) { + parameterMap.remove(parametersClass); + } + + /** + * Get parameters from the parameter service. + * + * @param <P> the generic type + * @param parametersClass the class of the parameter, used to index the parameter + * @return The parameter + */ + @SuppressWarnings("unchecked") + public static <P extends AbstractParameters> P getParameters(final Class<P> parametersClass) { + final P parameter = (P) parameterMap.get(parametersClass); + + if (parameter == null) { + throw new ApexRuntimeException("Parameters for " + parametersClass.getCanonicalName() + " not found in parameter service"); + } + + return parameter; + } + + /** + * Check if parameters is defined on the parameter service. + * + * @param <P> the generic type + * @param parametersClass the class of the parameter, used to index the parameter + * @return true if the parameter is defined + */ + public static <P extends AbstractParameters> boolean existsParameters(final Class<P> parametersClass) { + return parameterMap.get(parametersClass) != null; + } + + /** + * Get all the entries in the parameters map. + * + * @return The entries + */ + public static Set<Entry<Class<?>, AbstractParameters>> getAll() { + return parameterMap.entrySet(); + } + + /** + * Clear all parameters in the parameter service. + */ + public static void clear() { + parameterMap.clear(); + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/package-info.java new file mode 100644 index 000000000..da6c69898 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/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 the static services in Apex that make models and parameters available to all objects in the JVM. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +package org.onap.apex.model.basicmodel.service; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModel.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModel.java new file mode 100644 index 000000000..e7e50677e --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModel.java @@ -0,0 +1,332 @@ +/* + * ============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.apex.model.basicmodel.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.net.URL; + +import org.onap.apex.model.basicmodel.concepts.ApexException; +import org.onap.apex.model.basicmodel.concepts.AxModel; +import org.onap.apex.model.basicmodel.concepts.AxValidationResult; +import org.onap.apex.model.basicmodel.dao.ApexDao; +import org.onap.apex.model.basicmodel.dao.ApexDaoFactory; +import org.onap.apex.model.basicmodel.dao.DAOParameters; +import org.onap.apex.model.basicmodel.handling.ApexModelFileWriter; +import org.onap.apex.model.basicmodel.handling.ApexModelReader; +import org.onap.apex.model.basicmodel.handling.ApexModelWriter; +import org.onap.policy.apex.model.utilities.ResourceUtils; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; + +/** + * This class tests reading and writing of Apex models to file and to a database using JPA. It also tests validation of Apex models. This class is designed for + * use in unit tests in modules that define Apex models. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <M> the generic type + */ +public class TestApexModel<M extends AxModel> { + private static final String MODEL_IS_INVALID = "model is invalid "; + private static final String ERROR_PROCESSING_FILE = "error processing file "; + private static final String TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE = "test model does not equal model read from XML file "; + private static final String ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL = "error creating temporary file for Apex model"; + + private static final XLogger LOGGER = XLoggerFactory.getXLogger(TestApexModel.class); + + // The root model class that specifies the root to import and export from + private final Class<M> rootModelClass; + + // The class that provides the model + private TestApexModelCreator<M> modelCreator = null; + + /** + * Constructor, defines the subclass of {@link AxModel} that is being tested and the {@link TestApexModelCreator} object that is used to generate Apex + * models. + * + * @param rootModelClass the Apex model class, a sub class of {@link AxModel} + * @param modelCreator the @link TestApexModelCreator} that will generate Apex models of various types for testing + */ + public TestApexModel(final Class<M> rootModelClass, final TestApexModelCreator<M> modelCreator) { + this.rootModelClass = rootModelClass; + this.modelCreator = modelCreator; + } + + /** + * Get a test Apex model using the model creator. + * + * @return the test Apex model + */ + public final M getModel() { + return modelCreator.getModel(); + } + + /** + * Test write and read in XML format. + * + * @throws ApexException on write/read errors + */ + public final void testApexModelWriteReadXML() throws ApexException { + LOGGER.debug("running testApexModelWriteReadXML . . ."); + + final M model = modelCreator.getModel(); + + // Write the file to disk + File xmlFile; + + try { + xmlFile = File.createTempFile("ApexModel", ".xml"); + xmlFile.deleteOnExit(); + } + catch (final Exception e) { + LOGGER.warn(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e); + throw new ApexException(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e); + } + new ApexModelFileWriter<M>(true).apexModelWriteXMLFile(model, rootModelClass, xmlFile.getPath()); + + // Read the file from disk + final ApexModelReader<M> modelReader = new ApexModelReader<>(rootModelClass); + + try { + final URL apexModelURL = ResourceUtils.getLocalFile(xmlFile.getAbsolutePath()); + final M fileModel = modelReader.read(apexModelURL.openStream()); + if (!model.equals(fileModel)) { + LOGGER.warn(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + xmlFile.getAbsolutePath()); + throw new ApexException(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + xmlFile.getAbsolutePath()); + } + } + catch (final Exception e) { + LOGGER.warn(ERROR_PROCESSING_FILE + xmlFile.getAbsolutePath(), e); + throw new ApexException(ERROR_PROCESSING_FILE + xmlFile.getAbsolutePath(), e); + } + + final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass); + modelWriter.getCDataFieldSet().add("description"); + modelWriter.getCDataFieldSet().add("logic"); + modelWriter.getCDataFieldSet().add("uiLogic"); + + final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream(); + modelWriter.write(model, baOutputStream); + final ByteArrayInputStream baInputStream = new ByteArrayInputStream(baOutputStream.toByteArray()); + final M byteArrayModel = modelReader.read(baInputStream); + if (!model.equals(byteArrayModel)) { + LOGGER.warn("test model does not equal XML marshalled and unmarshalled model"); + throw new ApexException("test model does not equal XML marshalled and unmarshalled model"); + } + + LOGGER.debug("ran testApexModelWriteReadXML"); + } + + /** + * Test write and read in JSON format. + * + * @throws ApexException on write/read errors + */ + public final void testApexModelWriteReadJSON() throws ApexException { + LOGGER.debug("running testApexModelWriteReadJSON . . ."); + + final M model = modelCreator.getModel(); + + // Write the file to disk + File jsonFile; + try { + jsonFile = File.createTempFile("ApexModel", ".xml"); + jsonFile.deleteOnExit(); + } + catch (final Exception e) { + LOGGER.warn(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e); + throw new ApexException(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e); + } + new ApexModelFileWriter<M>(true).apexModelWriteJSONFile(model, rootModelClass, jsonFile.getPath()); + + // Read the file from disk + final ApexModelReader<M> modelReader = new ApexModelReader<>(rootModelClass); + + try { + final URL apexModelURL = ResourceUtils.getLocalFile(jsonFile.getAbsolutePath()); + final M fileModel = modelReader.read(apexModelURL.openStream()); + if (!model.equals(fileModel)) { + LOGGER.warn(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + jsonFile.getAbsolutePath()); + throw new ApexException(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + jsonFile.getAbsolutePath()); + } + } + catch (final Exception e) { + LOGGER.warn(ERROR_PROCESSING_FILE + jsonFile.getAbsolutePath(), e); + throw new ApexException(ERROR_PROCESSING_FILE + jsonFile.getAbsolutePath(), e); + } + + final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass); + modelWriter.setJsonOutput(true); + + final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream(); + modelWriter.write(model, baOutputStream); + final ByteArrayInputStream baInputStream = new ByteArrayInputStream(baOutputStream.toByteArray()); + final M byteArrayModel = modelReader.read(baInputStream); + if (!model.equals(byteArrayModel)) { + LOGGER.warn("test model does not equal JSON marshalled and unmarshalled model"); + throw new ApexException("test model does not equal JSON marshalled and unmarshalled model"); + } + + LOGGER.debug("ran testApexModelWriteReadJSON"); + } + + /** + * Test write and read of an Apex model to database using JPA. + * + * @param daoParameters the DAO parameters to use for JPA/JDBC + * @throws ApexException thrown on errors writing or reading the model to database + */ + public final void testApexModelWriteReadJPA(final DAOParameters daoParameters) throws ApexException { + LOGGER.debug("running testApexModelWriteReadJPA . . ."); + + final M model = modelCreator.getModel(); + + final ApexDao apexDao = new ApexDaoFactory().createApexDao(daoParameters); + apexDao.init(daoParameters); + + apexDao.create(model); + final M dbJPAModel = apexDao.get(rootModelClass, model.getKey()); + apexDao.close(); + + if (!model.equals(dbJPAModel)) { + LOGGER.warn("test model does not equal model written and read using generic JPA"); + throw new ApexException("test model does not equal model written and read using generic JPA"); + } + + LOGGER.debug("ran testApexModelWriteReadJPA"); + } + + /** + * Test that an Apex model is valid. + * + * @return the result of the validation + * @throws ApexException thrown on errors validating the Apex model + */ + public final AxValidationResult testApexModelValid() throws ApexException { + LOGGER.debug("running testApexModelVaid . . ."); + + final M model = modelCreator.getModel(); + final AxValidationResult result = model.validate(new AxValidationResult()); + + if (!result.isValid()) { + LOGGER.warn(MODEL_IS_INVALID + result.toString()); + throw new ApexException(MODEL_IS_INVALID + result.toString()); + } + + LOGGER.debug("ran testApexModelVaid"); + return result; + } + + /** + * Test that an Apex model is structured incorrectly. + * + * @return the result of the validation + * @throws ApexException thrown on errors validating the Apex model + */ + public final AxValidationResult testApexModelVaidateMalstructured() throws ApexException { + LOGGER.debug("running testApexModelVaidateMalstructured . . ."); + + final M model = modelCreator.getMalstructuredModel(); + final AxValidationResult result = model.validate(new AxValidationResult()); + + if (result.isValid()) { + LOGGER.warn("model should not be valid " + result.toString()); + throw new ApexException("should not be valid " + result.toString()); + } + + LOGGER.debug("ran testApexModelVaidateMalstructured"); + return result; + } + + /** + * Test that an Apex model has observations. + * + * @return the result of the validation + * @throws ApexException thrown on errors validating the Apex model + */ + public final AxValidationResult testApexModelVaidateObservation() throws ApexException { + LOGGER.debug("running testApexModelVaidateObservation . . ."); + + final M model = modelCreator.getObservationModel(); + final AxValidationResult result = model.validate(new AxValidationResult()); + + if (!result.isValid()) { + LOGGER.warn(MODEL_IS_INVALID + result.toString()); + throw new ApexException(MODEL_IS_INVALID + result.toString()); + } + + if (!result.getValidationResult().equals(AxValidationResult.ValidationResult.OBSERVATION)) { + LOGGER.warn("model should have observations"); + throw new ApexException("model should have observations"); + } + + LOGGER.debug("ran testApexModelVaidateObservation"); + return result; + } + + /** + * Test that an Apex model has warnings. + * + * @return the result of the validation + * @throws ApexException thrown on errors validating the Apex model + */ + public final AxValidationResult testApexModelVaidateWarning() throws ApexException { + LOGGER.debug("running testApexModelVaidateWarning . . ."); + + final M model = modelCreator.getWarningModel(); + final AxValidationResult result = model.validate(new AxValidationResult()); + + if (!result.isValid()) { + LOGGER.warn(MODEL_IS_INVALID + result.toString()); + throw new ApexException(MODEL_IS_INVALID + result.toString()); + } + + if (!result.getValidationResult().equals(AxValidationResult.ValidationResult.WARNING)) { + LOGGER.warn("model should have warnings"); + throw new ApexException("model should have warnings"); + } + + LOGGER.debug("ran testApexModelVaidateWarning"); + return result; + } + + /** + * Test that an Apex model is invalid. + * + * @return the result of the validation + * @throws ApexException thrown on errors validating the Apex model + */ + public final AxValidationResult testApexModelVaidateInvalidModel() throws ApexException { + LOGGER.debug("running testApexModelVaidateInvalidModel . . ."); + + final M model = modelCreator.getInvalidModel(); + final AxValidationResult result = model.validate(new AxValidationResult()); + + if (result.isValid()) { + LOGGER.warn("model should not be valid " + result.toString()); + throw new ApexException("should not be valid " + result.toString()); + } + + LOGGER.debug("ran testApexModelVaidateInvalidModel"); + return result; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModelCreator.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModelCreator.java new file mode 100644 index 000000000..7213c6694 --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModelCreator.java @@ -0,0 +1,62 @@ +/* + * ============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.apex.model.basicmodel.test; + +import org.onap.apex.model.basicmodel.concepts.AxModel; +import org.onap.apex.model.basicmodel.handling.ApexModelCreator; + +/** + * The Interface TestApexModelCreator is used to create models for Apex model tests. It is mainly used by unit tests for Apex domain models so that + * developers can write test Java programs to create models. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + * @param <M> the generic type + */ +public interface TestApexModelCreator<M extends AxModel> extends ApexModelCreator<M> { + + /** + * Gets the malstructured model. + * + * @return the malstructured model + */ + M getMalstructuredModel(); + + /** + * Gets the observation model. + * + * @return the observation model + */ + M getObservationModel(); + + /** + * Gets the warning model. + * + * @return the warning model + */ + M getWarningModel(); + + /** + * Gets the invalid model. + * + * @return the invalid model + */ + M getInvalidModel(); +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/package-info.java new file mode 100644 index 000000000..6bd6b73fb --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/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 that allow testing of validation and reads and writes on APEX models to files and databases. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ +package org.onap.apex.model.basicmodel.test; diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/AxReferenceKeyAdapter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/AxReferenceKeyAdapter.java new file mode 100644 index 000000000..a2bfbb80a --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/AxReferenceKeyAdapter.java @@ -0,0 +1,61 @@ +/* + * ============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.apex.model.basicmodel.xml; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlAdapter; + +import org.onap.apex.model.basicmodel.concepts.AxReferenceKey; + +/** + * This class manages marshaling and unmarshaling of Apex {@link AxReferenceKey} concepts using JAXB. The local name in reference keys must have specific + * handling. + */ +@XmlAccessorType(XmlAccessType.PROPERTY) +@XmlType(namespace = "http://www.ericsson.com/apex") +public class AxReferenceKeyAdapter extends XmlAdapter<String, AxReferenceKey> implements Serializable { + + private static final long serialVersionUID = -3480405083900107029L; + + /* + * (non-Javadoc) + * @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object) + */ + @Override + public final String marshal(final AxReferenceKey key) throws Exception { + return key.getLocalName(); + } + + /* + * (non-Javadoc) + * @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object) + */ + @Override + public final AxReferenceKey unmarshal(final String key) throws Exception { + final AxReferenceKey axReferenceKey = new AxReferenceKey(); + axReferenceKey.setLocalName(key); + return axReferenceKey; + } +} diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/package-info.java new file mode 100644 index 000000000..77bc0c13b --- /dev/null +++ b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/package-info.java @@ -0,0 +1,34 @@ +/* + * ============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 for managing marshaling and unmarshaling of APEX models using JAXB. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ + +@XmlSchema(namespace = "http://www.ericsson.com/apex", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = { + @XmlNs(namespaceURI = "http://www.ericsson.com/apex", prefix = "") }) + +package org.onap.apex.model.basicmodel.xml; + +import javax.xml.bind.annotation.XmlNs; +import javax.xml.bind.annotation.XmlNsForm; +import javax.xml.bind.annotation.XmlSchema; |