diff options
author | 2017-05-09 18:18:21 -0400 | |
---|---|---|
committer | 2017-05-09 18:19:11 -0400 | |
commit | 8944883589f74a9b1887469dbdba008e442edb20 (patch) | |
tree | 86a7c08217c69280cd11980bba2ee0ee6461df69 /aai-core/src/main/java/org/openecomp | |
parent | ae588b6cb80b8223e75705840ba43e70f2cb1fce (diff) |
Initial commit with all the necessary files
Change-Id: I2760ca1e2c661028be946a4335d07b1b7671a4b4
Signed-off-by: Venkata Harish K Kajur <vk250x@att.com>
Diffstat (limited to 'aai-core/src/main/java/org/openecomp')
207 files changed, 37722 insertions, 0 deletions
diff --git a/aai-core/src/main/java/org/openecomp/aai/audit/ListEndpoints.java b/aai-core/src/main/java/org/openecomp/aai/audit/ListEndpoints.java new file mode 100644 index 00000000..acf2be1a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/audit/ListEndpoints.java @@ -0,0 +1,302 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.audit; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.CaseFormat; + +/** + * The Class ListEndpoints. + */ +public class ListEndpoints { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ListEndpoints.class); + + private final String start = "inventory"; + private final String[] blacklist = { "search", "aai-internal" }; + + private List<String> endpoints = new ArrayList<>(); + private Map<String, String> endpointToLogicalName = new HashMap<String, String>(); + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + ListEndpoints endPoints = new ListEndpoints(AAIProperties.LATEST); + + System.out.println(endPoints.toString("relationship-list")); + + } + + /** + * Instantiates a new list endpoints. + * + * @param version the version + */ + public ListEndpoints(Version version) { + + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, version); + + try { + final Introspector start = loader.introspectorFromName(this.start); + Set<String> startMap = new HashSet<>(); + beginAudit(start, "/aai/" + version, startMap); + } catch (AAIUnknownObjectException e) { + throw new RuntimeException("Failed to find object " + this.start + ", cannot run ListEndpoints audit"); + } + } + + /** + * Begin audit. + * + * @param obj the obj + * @param uri the uri + */ + private void beginAudit(Introspector obj, String uri, Set<String> visited) { + + String currentUri = ""; + + if (!obj.getDbName().equals("inventory")) { + currentUri = uri + obj.getGenericURI(); + } else { + currentUri = uri; + } + if (obj.getName().equals("relationship-data") || obj.getName().equals("related-to-property")) { + return; + } + if (!obj.isContainer()) { + endpoints.add(currentUri); + } + + String dbName = obj.getDbName(); + + populateLogicalName(obj, uri, currentUri); + + Set<String> properties = obj.getProperties(); + Set<String> props = new LinkedHashSet<>(properties); + if (obj.isContainer()) { + for (String key : visited) { + if (props.remove(key)) { + try { + endpoints.add(currentUri + obj.getLoader().introspectorFromName(key).getGenericURI()); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping endpoint for " + key + " (Unknown object)", e); + } + } + } + } + + outer: for (String propName : props) { + + for (String item : blacklist) { + if (propName.equals(item)) { + continue outer; + } + } + if (obj.isListType(propName)) { + if (obj.isComplexGenericType(propName)) { + try { + final Introspector nestedObj = obj.newIntrospectorInstanceOfNestedProperty(propName); + Set<String> newVisited = new HashSet<>(); + newVisited.addAll(visited); + newVisited.add(nestedObj.getDbName()); + beginAudit( + nestedObj, + currentUri, + newVisited + ); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping nested endpoint for " + propName + " (Unknown Object)", e); + } + } + } else if (obj.isComplexType(propName)) { + try { + final Introspector nestedObj = obj.newIntrospectorInstanceOfProperty(propName); + Set<String> newVisited = new HashSet<>(); + newVisited.addAll(visited); + newVisited.add(nestedObj.getDbName()); + beginAudit(nestedObj, + currentUri, + visited + ); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping nested enpoint for " + propName + " (Unknown Object)", e); + } + } + } + + } + + /** + * Populate logical name. + * + * @param obj the obj + * @param uri the uri + * @param currentUri the current uri + */ + private void populateLogicalName(Introspector obj, String uri, String currentUri) { + + if (obj.getDbName().equals("inventory") || currentUri.split("/").length <= 4 || currentUri.endsWith("relationship-list")) { + return; + } + + if (uri.endsWith("/relationship-list")) { + uri = uri.substring(0, uri.lastIndexOf("/")); + } + + String logicalName = ""; + String keys = ""; + + + if (!obj.getAllKeys().isEmpty()) { + + Pattern p = Pattern.compile("/\\{[\\w\\d\\-]+\\}/\\{[\\w\\d\\-]+\\}+$"); + Matcher m = p.matcher(currentUri); + + if (m.find()) { + keys = StringUtils.join(obj.getAllKeys(), "-and-"); + } else { + keys = StringUtils.join(obj.getAllKeys(), "-or-"); + } + keys = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, keys); + if (!keys.isEmpty()) { + keys = "With" + keys; + } + } + + logicalName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, obj.getDbName()) + keys; + + if (endpointToLogicalName.containsKey(uri) && uri.endsWith("}")) { + logicalName = logicalName + "From" + endpointToLogicalName.get(uri); + } else if (endpointToLogicalName.containsKey(uri.substring(0, uri.lastIndexOf("/")))) { + logicalName = logicalName + "From" + endpointToLogicalName.get(uri.substring(0, uri.lastIndexOf("/"))); + } + + endpointToLogicalName.put(currentUri, logicalName); + + } + + /** + * Gets the logical names. + * + * @return the logical names + */ + public Map<String, String> getLogicalNames() { + + return endpointToLogicalName; + + } + + /** + * Gets the endpoints. + * + * @return the endpoints + */ + public List<String> getEndpoints() { + + return this.getEndpoints(""); + + } + + /** + * Gets the endpoints. + * + * @param filterOut the filter out + * @return the endpoints + */ + public List<String> getEndpoints(String filterOut) { + List<String> result = new ArrayList<>(); + Pattern p = null; + Matcher m = null; + if (!filterOut.equals("")) { + p = Pattern.compile(filterOut); + m = null; + } + for (String s : endpoints) { + if (p != null) { + m = p.matcher(s); + if (m.find()) { + continue; + } + } + + result.add(s); + } + + return result; + + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String s : endpoints) { + sb.append(s + "\n"); + } + return sb.toString(); + + } + + /** + * To string. + * + * @param filterOut the filter out + * @return the string + */ + public String toString(String filterOut) { + StringBuilder sb = new StringBuilder(); + Pattern p = Pattern.compile(filterOut); + Matcher m = null; + for (String s : endpoints) { + m = p.matcher(s); + if (!m.find()) { + sb.append(s + "\n"); + } + } + return sb.toString(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/props/AAIProperties.java b/aai-core/src/main/java/org/openecomp/aai/db/props/AAIProperties.java new file mode 100644 index 00000000..17f1fef0 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/props/AAIProperties.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.props; + +import org.openecomp.aai.introspection.Version; + +public class AAIProperties { + public static final String NODE_TYPE = "aai-node-type"; + public static final String LAST_MOD_SOURCE_OF_TRUTH = "last-mod-source-of-truth"; + public static final String SOURCE_OF_TRUTH = "source-of-truth"; + public static final String LAST_MOD_TS = "aai-last-mod-ts"; + public static final String UNIQUE_KEY = "aai-unique-key"; + public static final String CREATED_TS = "aai-created-ts"; + public static final String RESOURCE_VERSION = "resource-version"; + public static final String AAI_URI = "aai-uri"; + public static final Version LATEST = Version.v10; + public static final Integer MAXIMUM_DEPTH = 10000; + public static final String LINKED = "linked"; + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditDoc.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditDoc.java new file mode 100644 index 00000000..02606334 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditDoc.java @@ -0,0 +1,89 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.util.List; + +import org.codehaus.jackson.annotate.JsonProperty; + +public class AuditDoc { + + private List<DBProperty> properties; + private List<DBIndex> indexes; + private List<EdgeProperty> edgeLabels; + + /** + * Gets the properties. + * + * @return the properties + */ + public List<DBProperty> getProperties() { + return properties; + } + + /** + * Sets the properties. + * + * @param properties the new properties + */ + public void setProperties(List<DBProperty> properties) { + this.properties = properties; + } + + /** + * Gets the indexes. + * + * @return the indexes + */ + public List<DBIndex> getIndexes() { + return indexes; + } + + /** + * Sets the indexes. + * + * @param indexes the new indexes + */ + public void setIndexes(List<DBIndex> indexes) { + this.indexes = indexes; + } + + /** + * Gets the edge labels. + * + * @return the edge labels + */ + @JsonProperty("edge-labels") + public List<EdgeProperty> getEdgeLabels() { + return edgeLabels; + } + + /** + * Sets the edge labels. + * + * @param edgeLabels the new edge labels + */ + public void setEdgeLabels(List<EdgeProperty> edgeLabels) { + this.edgeLabels = edgeLabels; + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditOXM.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditOXM.java new file mode 100644 index 00000000..2da74d86 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditOXM.java @@ -0,0 +1,248 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.dbmodel.DbEdgeRules; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.util.AAIConstants; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.collect.Multimap; +import com.thinkaurelius.titan.core.Cardinality; +import com.thinkaurelius.titan.core.Multiplicity; +import com.thinkaurelius.titan.core.schema.SchemaStatus; + +public class AuditOXM extends Auditor { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AuditOXM.class); + + private Set<Introspector> allObjects; + + /** + * Instantiates a new audit OXM. + * + * @param version the version + */ + public AuditOXM(Version version) { + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, version); + Set<String> objectNames = getAllObjects(version); + allObjects = new HashSet<>(); + for (String key : objectNames) { + try { + final Introspector temp = loader.introspectorFromName(key); + allObjects.add(temp); + this.createDBProperties(temp); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping audit for object " + key + " (Unknown Object)", e); + } + } + for (Introspector temp : allObjects) { + this.createDBIndexes(temp); + } + createEdgeLabels(); + + } + + /** + * Gets the all objects. + * + * @param version the version + * @return the all objects + */ + private Set<String> getAllObjects(Version version) { + String fileName = AAIConstants.AAI_HOME_ETC_OXM + "aai_oxm_" + version.toString() + ".xml"; + Set<String> result = new HashSet<>(); + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + try { + docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + Document doc = docBuilder.parse(fileName); + NodeList list = doc.getElementsByTagName("java-type"); + for (int i = 0; i < list.getLength(); i++) { + result.add(list.item(i).getAttributes().getNamedItem("name").getNodeValue()); + } + } catch (ParserConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SAXException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + result.remove("EdgePropNames"); + return result; + + } + + /** + * Creates the DB properties. + * + * @param temp the temp + */ + private void createDBProperties(Introspector temp) { + Set<String> objectProperties = temp.getProperties(); + + for (String prop : objectProperties) { + if (!properties.containsKey(prop)) { + DBProperty dbProperty = new DBProperty(); + dbProperty.setName(prop); + if (temp.isListType(prop)) { + dbProperty.setCardinality(Cardinality.SET); + if (temp.isSimpleGenericType(prop)) { + Class<?> clazz = null; + try { + clazz = Class.forName(temp.getGenericType(prop)); + } catch (ClassNotFoundException e) { + clazz = Object.class; + } + dbProperty.setTypeClass(clazz); + properties.put(prop, dbProperty); + } + } else { + dbProperty.setCardinality(Cardinality.SINGLE); + if (temp.isSimpleType(prop)) { + Class<?> clazz = null; + try { + clazz = Class.forName(temp.getType(prop)); + } catch (ClassNotFoundException e) { + clazz = Object.class; + } + dbProperty.setTypeClass(clazz); + properties.put(prop, dbProperty); + } + } + } + } + + } + + /** + * Creates the DB indexes. + * + * @param temp the temp + */ + private void createDBIndexes(Introspector temp) { + String uniqueProps = temp.getMetadata(ObjectMetadata.UNIQUE_PROPS); + String namespace = temp.getMetadata(ObjectMetadata.NAMESPACE); + if (uniqueProps == null) { + uniqueProps = ""; + } + if (namespace == null) { + namespace = ""; + } + boolean isTopLevel = namespace != ""; + List<String> unique = Arrays.asList(uniqueProps.split(",")); + Set<String> indexed = temp.getIndexedProperties(); + Set<String> keys = temp.getKeys(); + + for (String prop : indexed) { + DBIndex dbIndex = new DBIndex(); + LinkedHashSet<DBProperty> properties = new LinkedHashSet<>(); + if (!this.indexes.containsKey(prop)) { + dbIndex.setName(prop); + dbIndex.setUnique(unique.contains(prop)); + properties.add(this.properties.get(prop)); + dbIndex.setProperties(properties); + dbIndex.setStatus(SchemaStatus.ENABLED); + this.indexes.put(prop, dbIndex); + } + } + if (keys.size() > 1 || isTopLevel) { + DBIndex dbIndex = new DBIndex(); + LinkedHashSet<DBProperty> properties = new LinkedHashSet<>(); + dbIndex.setName("key-for-" + temp.getDbName()); + if (!this.indexes.containsKey(dbIndex.getName())) { + boolean isUnique = false; + if (isTopLevel) { + properties.add(this.properties.get(AAIProperties.NODE_TYPE)); + } + for (String key : keys) { + properties.add(this.properties.get(key)); + + if (unique.contains(key) && !isUnique) { + isUnique = true; + } + } + dbIndex.setUnique(isUnique); + dbIndex.setProperties(properties); + dbIndex.setStatus(SchemaStatus.ENABLED); + this.indexes.put(dbIndex.getName(), dbIndex); + } + } + + } + + /** + * Creates the edge labels. + */ + private void createEdgeLabels() { + Multimap<String, String> edgeRules = DbEdgeRules.EdgeRules; + for (String key : edgeRules.keySet()) { + Collection<String> collection = edgeRules.get(key); + EdgeProperty prop = new EdgeProperty(); + //there is only ever one, they used the wrong type for EdgeRules + String label = ""; + for (String item : collection) { + label = item.split(",")[0]; + } + prop.setName(label); + prop.setMultiplicity(Multiplicity.MULTI); + this.edgeLabels.put(label, prop); + } + } + + /** + * Gets the all introspectors. + * + * @return the all introspectors + */ + public Set<Introspector> getAllIntrospectors() { + return this.allObjects; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditTitan.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditTitan.java new file mode 100644 index 00000000..743e683e --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditTitan.java @@ -0,0 +1,127 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import com.thinkaurelius.titan.core.EdgeLabel; +import com.thinkaurelius.titan.core.PropertyKey; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.schema.TitanGraphIndex; +import com.thinkaurelius.titan.core.schema.TitanManagement; + +public class AuditTitan extends Auditor { + + private final TitanGraph graph; + + /** + * Instantiates a new audit titan. + * + * @param g the g + */ + public AuditTitan (TitanGraph g) { + this.graph = g; + buildSchema(); + } + + /** + * Builds the schema. + */ + private void buildSchema() { + populateProperties(); + populateIndexes(); + populateEdgeLabels(); + } + + /** + * Populate properties. + */ + private void populateProperties() { + TitanManagement mgmt = graph.openManagement(); + Iterable<PropertyKey> iterable = mgmt.getRelationTypes(PropertyKey.class); + Iterator<PropertyKey> titanProperties = iterable.iterator(); + PropertyKey propKey = null; + while (titanProperties.hasNext()) { + propKey = titanProperties.next(); + DBProperty prop = new DBProperty(); + + prop.setName(propKey.name()); + prop.setCardinality(propKey.cardinality()); + prop.setTypeClass(propKey.dataType()); + + this.properties.put(prop.getName(), prop); + } + } + + /** + * Populate indexes. + */ + private void populateIndexes() { + TitanManagement mgmt = graph.openManagement(); + Iterable<TitanGraphIndex> iterable = mgmt.getGraphIndexes(Vertex.class); + Iterator<TitanGraphIndex> titanIndexes = iterable.iterator(); + TitanGraphIndex titanIndex = null; + while (titanIndexes.hasNext()) { + titanIndex = titanIndexes.next(); + if (titanIndex.isCompositeIndex()) { + DBIndex index = new DBIndex(); + LinkedHashSet<DBProperty> dbProperties = new LinkedHashSet<>(); + index.setName(titanIndex.name()); + index.setUnique(titanIndex.isUnique()); + PropertyKey[] keys = titanIndex.getFieldKeys(); + for (PropertyKey key : keys) { + dbProperties.add(this.properties.get(key.name())); + } + index.setProperties(dbProperties); + index.setStatus(titanIndex.getIndexStatus(keys[0])); + this.indexes.put(index.getName(), index); + } + } + } + + /** + * Populate edge labels. + */ + private void populateEdgeLabels() { + TitanManagement mgmt = graph.openManagement(); + Iterable<EdgeLabel> iterable = mgmt.getRelationTypes(EdgeLabel.class); + Iterator<EdgeLabel> titanEdgeLabels = iterable.iterator(); + EdgeLabel edgeLabel = null; + while (titanEdgeLabels.hasNext()) { + edgeLabel = titanEdgeLabels.next(); + EdgeProperty edgeProperty = new EdgeProperty(); + + edgeProperty.setName(edgeLabel.name()); + edgeProperty.setMultiplicity(edgeLabel.multiplicity()); + + this.edgeLabels.put(edgeProperty.getName(), edgeProperty); + } + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/Auditor.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/Auditor.java new file mode 100644 index 00000000..91897f43 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/Auditor.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.util.*; + +public abstract class Auditor { + + protected Map<String, DBProperty> properties = new HashMap<>(); + protected Map<String, DBIndex> indexes = new HashMap<>(); + protected Map<String, EdgeProperty> edgeLabels = new HashMap<>(); + + /** + * Gets the audit doc. + * + * @return the audit doc + */ + public AuditDoc getAuditDoc() { + AuditDoc doc = new AuditDoc(); + List<DBProperty> propertyList = new ArrayList<>(); + List<DBIndex> indexList = new ArrayList<>(); + List<EdgeProperty> edgeLabelList = new ArrayList<>(); + propertyList.addAll(this.properties.values()); + indexList.addAll(this.indexes.values()); + edgeLabelList.addAll(this.edgeLabels.values()); + Collections.sort(propertyList, new CompareByName()); + Collections.sort(indexList, new CompareByName()); + Collections.sort(edgeLabelList, new CompareByName()); + + doc.setProperties(propertyList); + doc.setIndexes(indexList); + doc.setEdgeLabels(edgeLabelList); + + return doc; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditorFactory.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditorFactory.java new file mode 100644 index 00000000..7adc587c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditorFactory.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import org.openecomp.aai.introspection.Version; +import com.thinkaurelius.titan.core.TitanGraph; + +public class AuditorFactory { + + /** + * Gets the OXM auditor. + * + * @param v the v + * @return the OXM auditor + */ + public static Auditor getOXMAuditor (Version v) { + return new AuditOXM(v); + } + + /** + * Gets the graph auditor. + * + * @param g the g + * @return the graph auditor + */ + public static Auditor getGraphAuditor (TitanGraph g) { + return new AuditTitan(g); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/CompareByName.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/CompareByName.java new file mode 100644 index 00000000..3a979b35 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/CompareByName.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.util.Comparator; + +public class CompareByName implements Comparator<Named>{ + + /** + * {@inheritDoc} + */ + @Override + public int compare(Named o1, Named o2) { + return o1.getName().compareTo(o2.getName()); + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/DBIndex.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBIndex.java new file mode 100644 index 00000000..98aab19a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBIndex.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.util.LinkedHashSet; +import java.util.Set; + +import com.thinkaurelius.titan.core.schema.SchemaStatus; + +public class DBIndex implements Named { + + private String name = null; + private boolean unique = false; + private LinkedHashSet<DBProperty> properties = new LinkedHashSet<>(); + private SchemaStatus status = null; + + /** + * Gets the name + */ + public String getName() { + return name; + } + + /** + * Sets the name. + * + * @param name the new name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Checks if is unique. + * + * @return true, if is unique + */ + public boolean isUnique() { + return unique; + } + + /** + * Sets the unique. + * + * @param unique the new unique + */ + public void setUnique(boolean unique) { + this.unique = unique; + } + + /** + * Gets the properties. + * + * @return the properties + */ + public Set<DBProperty> getProperties() { + return properties; + } + + /** + * Sets the properties. + * + * @param properties the new properties + */ + public void setProperties(LinkedHashSet<DBProperty> properties) { + this.properties = properties; + } + + /** + * Gets the status. + * + * @return the status + */ + public SchemaStatus getStatus() { + return status; + } + + /** + * Sets the status. + * + * @param status the new status + */ + public void setStatus(SchemaStatus status) { + this.status = status; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/DBProperty.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBProperty.java new file mode 100644 index 00000000..2c314d1f --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBProperty.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import org.openecomp.aai.introspection.Introspector; +import com.thinkaurelius.titan.core.Cardinality; + +public class DBProperty implements Named { + + + private String name = null; + private Cardinality cardinality = null; + private Class<?> typeClass = null; + + /** + * Gets the name + */ + public String getName() { + return name; + } + + /** + * Sets the name. + * + * @param name the new name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the cardinality. + * + * @return the cardinality + */ + public Cardinality getCardinality() { + return cardinality; + } + + /** + * Sets the cardinality. + * + * @param cardinality the new cardinality + */ + public void setCardinality(Cardinality cardinality) { + this.cardinality = cardinality; + } + + /** + * Gets the type class. + * + * @return the type class + */ + public Class<?> getTypeClass() { + return typeClass; + } + + /** + * Sets the type class. + * + * @param type the new type class + */ + public void setTypeClass(Class<?> type) { + this.typeClass = type; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/EdgeProperty.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/EdgeProperty.java new file mode 100644 index 00000000..0a63dad9 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/EdgeProperty.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import com.thinkaurelius.titan.core.Multiplicity; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.annotate.JsonPropertyOrder; + +@JsonPropertyOrder({ "label", "multiplicity" }) +public class EdgeProperty implements Named { + + private String name = null; + private Multiplicity multiplicity = null; + + /** + * Gets the name + */ + @JsonProperty("label") + public String getName() { + return name; + } + + /** + * Sets the name. + * + * @param name the new name + */ + @JsonProperty("label") + public void setName(String name) { + this.name = name; + } + + /** + * Gets the multiplicity. + * + * @return the multiplicity + */ + public Multiplicity getMultiplicity() { + return multiplicity; + } + + /** + * Sets the multiplicity. + * + * @param multiplicity the new multiplicity + */ + public void setMultiplicity(Multiplicity multiplicity) { + this.multiplicity = multiplicity; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/ManageTitanSchema.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/ManageTitanSchema.java new file mode 100644 index 00000000..940bee38 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/ManageTitanSchema.java @@ -0,0 +1,329 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.introspection.Version; +import com.thinkaurelius.titan.core.PropertyKey; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.schema.SchemaStatus; +import com.thinkaurelius.titan.core.schema.TitanGraphIndex; +import com.thinkaurelius.titan.core.schema.TitanManagement; +import com.thinkaurelius.titan.core.schema.TitanManagement.IndexBuilder; + +public class ManageTitanSchema { + + + private TitanManagement graphMgmt; + private TitanGraph graph; + private List<DBProperty> aaiProperties; + private List<DBIndex> aaiIndexes; + private List<EdgeProperty> aaiEdgeProperties; + private Auditor oxmInfo = null; + private Auditor graphInfo = null; + + /** + * Instantiates a new manage titan schema. + * + * @param graph the graph + */ + public ManageTitanSchema(final TitanGraph graph) { + this.graph = graph; + oxmInfo = AuditorFactory.getOXMAuditor(Version.v8); + graphInfo = AuditorFactory.getGraphAuditor(graph); + } + + + /** + * Builds the schema. + */ + public void buildSchema() { + + this.graphMgmt = graph.openManagement(); + aaiProperties = new ArrayList<>(); + aaiEdgeProperties = new ArrayList<>(); + aaiIndexes = new ArrayList<>(); + aaiProperties.addAll(oxmInfo.getAuditDoc().getProperties()); + aaiIndexes.addAll(oxmInfo.getAuditDoc().getIndexes()); + aaiEdgeProperties.addAll(oxmInfo.getAuditDoc().getEdgeLabels()); + try { + createPropertyKeys(); + createIndexes(); + createEdgeLabels(); + } catch (Exception e) { + e.printStackTrace(); + graphMgmt.rollback(); + } + graphMgmt.commit(); + } + + /** + * Creates the property keys. + */ + private void createPropertyKeys() { + + + for (DBProperty prop : aaiProperties) { + + if (graphMgmt.containsPropertyKey(prop.getName())) { + PropertyKey key = graphMgmt.getPropertyKey(prop.getName()); + boolean isChanged = false; + if (!prop.getCardinality().equals(key.cardinality())) { + isChanged = true; + } + if (!prop.getTypeClass().equals(key.dataType())) { + isChanged = true; + } + if (isChanged) { + //must modify! + this.replaceProperty(prop); + } + } else { + //create a new property key + System.out.println("Key: " + prop.getName() + " not found - adding"); + graphMgmt.makePropertyKey(prop.getName()).dataType(prop.getTypeClass()).cardinality(prop.getCardinality()).make(); + } + } + + } + + /** + * Creates the indexes. + */ + private void createIndexes() { + + for (DBIndex index : aaiIndexes) { + Set<DBProperty> props = index.getProperties(); + boolean isChanged = false; + boolean isNew = false; + List<PropertyKey> keyList = new ArrayList<>(); + for (DBProperty prop : props) { + keyList.add(graphMgmt.getPropertyKey(prop.getName())); + } + if (graphMgmt.containsGraphIndex(index.getName())) { + TitanGraphIndex titanIndex = graphMgmt.getGraphIndex(index.getName()); + PropertyKey[] dbKeys = titanIndex.getFieldKeys(); + if (dbKeys.length != keyList.size()) { + isChanged = true; + } else { + int i = 0; + for (PropertyKey key : keyList) { + if (!dbKeys[i].equals(key)) { + isChanged = true; + break; + } + i++; + } + } + } else { + isNew = true; + } + if (keyList.size() > 0) { + this.createIndex(graphMgmt, index.getName(), keyList, index.isUnique(), isNew, isChanged); + } + } + } + + // Use EdgeRules to make sure edgeLabels are defined in the db. NOTE: the multiplicty used here is + // always "MULTI". This is not the same as our internal "Many2Many", "One2One", "One2Many" or "Many2One" + // We use the same edge-label for edges between many different types of nodes and our internal + // multiplicty definitions depends on which two types of nodes are being connected. + /** + * Creates the edge labels. + */ + private void createEdgeLabels() { + + + for (EdgeProperty prop : aaiEdgeProperties) { + + if (graphMgmt.containsEdgeLabel(prop.getName())) { + // see what changed + } else { + graphMgmt.makeEdgeLabel(prop.getName()).multiplicity(prop.getMultiplicity()).make(); + } + + } + + + } + + /** + * Creates the property. + * + * @param mgmt the mgmt + * @param prop the prop + */ + private void createProperty(TitanManagement mgmt, DBProperty prop) { + if (mgmt.containsPropertyKey(prop.getName())) { + PropertyKey key = mgmt.getPropertyKey(prop.getName()); + boolean isChanged = false; + if (!prop.getCardinality().equals(key.cardinality())) { + isChanged = true; + } + if (!prop.getTypeClass().equals(key.dataType())) { + isChanged = true; + } + if (isChanged) { + //must modify! + this.replaceProperty(prop); + } + } else { + //create a new property key + System.out.println("Key: " + prop.getName() + " not found - adding"); + mgmt.makePropertyKey(prop.getName()).dataType(prop.getTypeClass()).cardinality(prop.getCardinality()).make(); + } + } + + /** + * Creates the index. + * + * @param mgmt the mgmt + * @param indexName the index name + * @param keys the keys + * @param isUnique the is unique + * @param isNew the is new + * @param isChanged the is changed + */ + private void createIndex(TitanManagement mgmt, String indexName, List<PropertyKey> keys, boolean isUnique, boolean isNew, boolean isChanged) { + + /*if (isChanged) { + System.out.println("Changing index: " + indexName); + TitanGraphIndex oldIndex = mgmt.getGraphIndex(indexName); + mgmt.updateIndex(oldIndex, SchemaAction.DISABLE_INDEX); + mgmt.commit(); + //cannot remove indexes + //graphMgmt.updateIndex(oldIndex, SchemaAction.REMOVE_INDEX); + }*/ + if (isNew || isChanged) { + + if (isNew) { + IndexBuilder builder = mgmt.buildIndex(indexName,Vertex.class); + for (PropertyKey k : keys) { + builder.addKey(k); + } + if (isUnique) { + builder.unique(); + } + builder.buildCompositeIndex(); + System.out.println("Built index for " + indexName + " with keys: " + keys); + + //mgmt.commit(); + } + + //mgmt = graph.asAdmin().getManagementSystem(); + //mgmt.updateIndex(mgmt.getGraphIndex(indexName), SchemaAction.REGISTER_INDEX); + //mgmt.commit(); + + try { + //waitForCompletion(indexName); + //TitanIndexRepair.hbaseRepair(AAIConstants.AAI_CONFIG_FILENAME, indexName, ""); + } catch (Exception e) { + // TODO Auto-generated catch block + graph.tx().rollback(); + graph.close(); + e.printStackTrace(); + } + + //mgmt = graph.asAdmin().getManagementSystem(); + //mgmt.updateIndex(mgmt.getGraphIndex(indexName), SchemaAction.REINDEX); + + //mgmt.updateIndex(mgmt.getGraphIndex(indexName), SchemaAction.ENABLE_INDEX); + + //mgmt.commit(); + + } + } + + /** + * Wait for completion. + * + * @param name the name + * @throws InterruptedException the interrupted exception + */ + private void waitForCompletion(String name) throws InterruptedException { + + boolean registered = false; + long before = System.currentTimeMillis(); + while (!registered) { + Thread.sleep(500L); + TitanManagement mgmt = graph.openManagement(); + TitanGraphIndex idx = mgmt.getGraphIndex(name); + registered = true; + for (PropertyKey k : idx.getFieldKeys()) { + SchemaStatus s = idx.getIndexStatus(k); + registered &= s.equals(SchemaStatus.REGISTERED); + } + mgmt.rollback(); + } + System.out.println("Index REGISTERED in " + (System.currentTimeMillis() - before) + " ms"); + } + + /** + * Replace property. + * + * @param key the key + */ + private void replaceProperty(DBProperty key) { + + + + + } + + /** + * Update index. + * + * @param index the index + */ + public void updateIndex(DBIndex index) { + + TitanManagement mgmt = graph.openManagement(); + List<PropertyKey> keys = new ArrayList<>(); + boolean isNew = false; + boolean isChanged = false; + for (DBProperty prop : index.getProperties()) { + createProperty(mgmt, prop); + keys.add(mgmt.getPropertyKey(prop.getName())); + } + if (mgmt.containsGraphIndex(index.getName())) { + System.out.println("index already exists"); + isNew = false; + isChanged = true; + } else { + isNew = true; + isChanged = false; + } + this.createIndex(mgmt, index.getName(), keys, index.isUnique(), isNew, isChanged); + + mgmt.commit(); + + } + + + + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/Named.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/Named.java new file mode 100644 index 00000000..9b0bbe37 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/Named.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +public interface Named { + + /** + * Gets the name. + * + * @return the name + */ + public String getName(); +} diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java new file mode 100644 index 00000000..fe55af68 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.io.IOException; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.util.AAIConfig; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; + +public class ScriptDriver { + + + /** + * The main method. + * + * @param args the arguments + * @throws AAIException the AAI exception + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + */ + public static void main (String[] args) throws AAIException, JsonGenerationException, JsonMappingException, IOException { + CommandLineArgs cArgs = new CommandLineArgs(); + + new JCommander(cArgs, args); + + if (cArgs.help) { + System.out.println("-c [path to graph configuration] -type [what you want to audit - oxm or graph]"); + } + String config = cArgs.config; + AAIConfig.init(); + TitanGraph graph = TitanFactory.open(config); + if (!(cArgs.type.equals("oxm") || cArgs.type.equals("graph"))) { + System.out.println("type: " + cArgs.type + " not recognized."); + System.exit(1); + } + + Auditor a = null; + if (cArgs.type.equals("oxm")) { + a = AuditorFactory.getOXMAuditor(Version.v8); + } else if (cArgs.type.equals("graph")) { + a = AuditorFactory.getGraphAuditor(graph); + } + + AuditDoc doc = a.getAuditDoc(); + + ObjectMapper mapper = new ObjectMapper(); + + String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(doc); + System.out.println(json); + + } + +} + +class CommandLineArgs { + + @Parameter(names = "--help", description = "Help") + public boolean help = false; + + @Parameter(names = "-c", description = "Configuration", required=true) + public String config; + + @Parameter(names = "-type", description = "Type", required=true) + public String type = "graph"; + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/DataGrooming.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/DataGrooming.java new file mode 100644 index 00000000..aa5084b9 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/DataGrooming.java @@ -0,0 +1,2223 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbgen; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TimeZone; +import java.util.UUID; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Property; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; + +import org.openecomp.aai.dbmap.AAIGraph; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.ingestModel.DbMaps; +import org.openecomp.aai.ingestModel.IngestModelMoxyOxm; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import com.att.eelf.configuration.Configuration; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.thinkaurelius.titan.core.TitanEdge; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanTransaction; +import com.thinkaurelius.titan.core.TitanVertex; + + +public class DataGrooming { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DataGrooming.class); + private static final String FROMAPPID = "AAI-DB"; + private static final String TRANSID = UUID.randomUUID().toString(); + private static int dupeGrpsDeleted = 0; + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + + // Set the logging file properties to be used by EELFManager + Properties props = System.getProperties(); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, AAIConstants.AAI_DATA_GROOMING_LOGBACK_PROPS); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES); + + String ver = "version"; // Placeholder + Boolean doAutoFix = false; + Boolean edgesOnlyFlag = false; + Boolean dontFixOrphansFlag = false; + Boolean singleCommits = false; + Boolean dupeCheckOff = false; + Boolean dupeFixOn = false; + Boolean ghost2CheckOff = false; + Boolean ghost2FixOn = false; + Boolean neverUseCache = false; + + int maxRecordsToFix = AAIConstants.AAI_GROOMING_DEFAULT_MAX_FIX; + int sleepMinutes = AAIConstants.AAI_GROOMING_DEFAULT_SLEEP_MINUTES; + try { + String maxFixStr = AAIConfig.get("aai.grooming.default.max.fix"); + if( maxFixStr != null && !maxFixStr.equals("") ){ + maxRecordsToFix = Integer.parseInt(maxFixStr); + } + String sleepStr = AAIConfig.get("aai.grooming.default.sleep.minutes"); + if( sleepStr != null && !sleepStr.equals("") ){ + sleepMinutes = Integer.parseInt(sleepStr); + } + } + catch ( Exception e ){ + // Don't worry, we'll just use the defaults that we got from AAIConstants + LOGGER.warn("WARNING - could not pick up aai.grooming values from aaiconfig.properties file. "); + } + + String prevFileName = ""; + dupeGrpsDeleted = 0; + SimpleDateFormat d = new SimpleDateFormat("yyyyMMddHHmm"); + d.setTimeZone(TimeZone.getTimeZone("GMT")); + String dteStr = d.format(new Date()).toString(); + String groomOutFileName = "dataGrooming." + dteStr + ".out"; + + if (args.length > 0) { + // They passed some arguments in that will affect processing + for (int i = 0; i < args.length; i++) { + String thisArg = args[i]; + if (thisArg.equals("-edgesOnly")) { + edgesOnlyFlag = true; + } else if (thisArg.equals("-autoFix")) { + doAutoFix = true; + } else if (thisArg.equals("-dontFixOrphans")) { + dontFixOrphansFlag = true; + } else if (thisArg.equals("-singleCommits")) { + singleCommits = true; + } else if (thisArg.equals("-dupeCheckOff")) { + dupeCheckOff = true; + } else if (thisArg.equals("-dupeFixOn")) { + dupeFixOn = true; + } else if (thisArg.equals("-ghost2CheckOff")) { + ghost2CheckOff = true; + } else if (thisArg.equals("-neverUseCache")) { + neverUseCache = true; + } else if (thisArg.equals("-ghost2FixOn")) { + ghost2FixOn = true; + } else if (thisArg.equals("-maxFix")) { + i++; + if (i >= args.length) { + LOGGER.error(" No value passed with -maxFix option. "); + System.exit(0); + } + String nextArg = args[i]; + try { + maxRecordsToFix = Integer.parseInt(nextArg); + } catch (Exception e) { + LOGGER.error("Bad value passed with -maxFix option: [" + + nextArg + "]"); + System.exit(0); + } + } else if (thisArg.equals("-sleepMinutes")) { + i++; + if (i >= args.length) { + LOGGER.error("No value passed with -sleepMinutes option."); + System.exit(0); + } + String nextArg = args[i]; + try { + sleepMinutes = Integer.parseInt(nextArg); + } catch (Exception e) { + LOGGER.error("Bad value passed with -sleepMinutes option: [" + + nextArg + "]"); + System.exit(0); + } + } else if (thisArg.equals("-f")) { + i++; + if (i >= args.length) { + LOGGER.error(" No value passed with -f option. "); + System.exit(0); + } + prevFileName = args[i]; + } else { + LOGGER.error(" Unrecognized argument passed to DataGrooming: [" + + thisArg + "]. "); + LOGGER.error(" Valid values are: -f -autoFix -maxFix -edgesOnly -dupeFixOn -donFixOrphans -sleepMinutes -neverUseCache"); + System.exit(0); + } + } + } + + + IngestModelMoxyOxm moxyMod = new IngestModelMoxyOxm(); + try { + ArrayList <String> defaultVerLst = new ArrayList <> (); + defaultVerLst.add( AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP) ); + moxyMod.init( defaultVerLst, false); + } + catch (Exception ex){ + LOGGER.error("ERROR - Could not do the moxyMod.init()", ex); + System.exit(1); + } + + try { + if (!prevFileName.equals("")) { + // They are trying to fix some data based on a data in a + // previous file. + LOGGER.info(" Call doTheGrooming() with a previous fileName [" + + prevFileName + "] for cleanup. "); + Boolean finalShutdownFlag = true; + Boolean cacheDbOkFlag = false; + doTheGrooming(prevFileName, edgesOnlyFlag, dontFixOrphansFlag, + maxRecordsToFix, groomOutFileName, ver, singleCommits, + dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn, + finalShutdownFlag, cacheDbOkFlag); + } else if (doAutoFix) { + // They want us to run the processing twice -- first to look for + // delete candidates, then after + // napping for a while, run it again and delete any candidates + // that were found by the first run. + // Note: we will produce a separate output file for each of the + // two runs. + LOGGER.info(" Doing an auto-fix call to Grooming. "); + LOGGER.info(" First, Call doTheGrooming() to look at what's out there. "); + Boolean finalShutdownFlag = false; + Boolean cacheDbOkFlag = true; + int fixCandCount = doTheGrooming("", edgesOnlyFlag, + dontFixOrphansFlag, maxRecordsToFix, groomOutFileName, + ver, singleCommits, dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn, + finalShutdownFlag, cacheDbOkFlag); + if (fixCandCount == 0) { + LOGGER.info(" No fix-Candidates were found by the first pass, so no second/fix-pass is needed. "); + } else { + // We'll sleep a little and then run a fix-pass based on the + // first-run's output file. + try { + LOGGER.info("About to sleep for " + sleepMinutes + + " minutes."); + int sleepMsec = sleepMinutes * 60 * 1000; + Thread.sleep(sleepMsec); + } catch (InterruptedException ie) { + LOGGER.info("\n >>> Sleep Thread has been Interrupted <<< "); + System.exit(0); + } + + d = new SimpleDateFormat("yyyyMMddHHmm"); + d.setTimeZone(TimeZone.getTimeZone("GMT")); + dteStr = d.format(new Date()).toString(); + String secondGroomOutFileName = "dataGrooming." + dteStr + + ".out"; + LOGGER.info(" Now, call doTheGrooming() a second time and pass in the name of the file " + + "generated by the first pass for fixing: [" + + groomOutFileName + "]"); + finalShutdownFlag = true; + cacheDbOkFlag = false; + doTheGrooming(groomOutFileName, edgesOnlyFlag, + dontFixOrphansFlag, maxRecordsToFix, + secondGroomOutFileName, ver, singleCommits, + dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn, + finalShutdownFlag, cacheDbOkFlag); + } + } else { + // Do the grooming - plain vanilla (no fix-it-file, no + // auto-fixing) + Boolean finalShutdownFlag = true; + LOGGER.info(" Call doTheGrooming() "); + Boolean cacheDbOkFlag = true; + if( neverUseCache ){ + // They have forbidden us from using a cached db connection. + cacheDbOkFlag = false; + } + doTheGrooming("", edgesOnlyFlag, dontFixOrphansFlag, + maxRecordsToFix, groomOutFileName, ver, singleCommits, + dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn, + finalShutdownFlag, cacheDbOkFlag); + } + } catch (Exception ex) { + LOGGER.error("Exception while grooming data", ex); + } + + LOGGER.info(" Done! "); + System.exit(0); + + }// End of main() + + /** + * Do the grooming. + * + * @param fileNameForFixing the file name for fixing + * @param edgesOnlyFlag the edges only flag + * @param dontFixOrphansFlag the dont fix orphans flag + * @param maxRecordsToFix the max records to fix + * @param groomOutFileName the groom out file name + * @param version the version + * @param singleCommits the single commits + * @param dupeCheckOff the dupe check off + * @param dupeFixOn the dupe fix on + * @param ghost2CheckOff the ghost 2 check off + * @param ghost2FixOn the ghost 2 fix on + * @param finalShutdownFlag the final shutdown flag + * @param cacheDbOkFlag the cacheDbOk flag + * @return the int + */ + private static int doTheGrooming(String fileNameForFixing, + Boolean edgesOnlyFlag, Boolean dontFixOrphansFlag, + int maxRecordsToFix, String groomOutFileName, String version, + Boolean singleCommits, + Boolean dupeCheckOff, Boolean dupeFixOn, + Boolean ghost2CheckOff, Boolean ghost2FixOn, + Boolean finalShutdownFlag, Boolean cacheDbOkFlag) { + + LOGGER.debug(" Entering doTheGrooming \n"); + + int cleanupCandidateCount = 0; + BufferedWriter bw = null; + TitanGraph graph = null; + TitanGraph graph2 = null; + int deleteCount = 0; + boolean executeFinalCommit = false; + Set<String> deleteCandidateList = new LinkedHashSet<>(); + Set<String> processedVertices = new LinkedHashSet<>(); + TitanTransaction g = null; + TitanTransaction g2 = null; + try { + AAIConfig.init(); + String targetDir = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP + + "logs" + AAIConstants.AAI_FILESEP + "data" + + AAIConstants.AAI_FILESEP + "dataGrooming"; + + // Make sure the target directory exists + new File(targetDir).mkdirs(); + + if (!fileNameForFixing.equals("")) { + deleteCandidateList = getDeleteList(targetDir, + fileNameForFixing, edgesOnlyFlag, dontFixOrphansFlag, + dupeFixOn); + } + + if (deleteCandidateList.size() > maxRecordsToFix) { + LOGGER.warn(" >> WARNING >> Delete candidate list size (" + + deleteCandidateList.size() + + ") is too big. The maxFix we are using is: " + + maxRecordsToFix + + ". No candidates will be deleted. "); + // Clear out the list so it won't be processed below. + deleteCandidateList = new LinkedHashSet<>(); + } + + SimpleDateFormat d = new SimpleDateFormat("yyyyMMddHHmm"); + d.setTimeZone(TimeZone.getTimeZone("GMT")); + + String fullOutputFileName = targetDir + AAIConstants.AAI_FILESEP + + groomOutFileName; + File groomOutFile = new File(fullOutputFileName); + try { + groomOutFile.createNewFile(); + } catch (IOException e) { + String emsg = " Problem creating output file [" + + fullOutputFileName + "], exception=" + e.getMessage(); + throw new AAIException("AAI_6124", emsg); + } + + LOGGER.info(" Will write to " + fullOutputFileName ); + FileWriter fw = new FileWriter(groomOutFile.getAbsoluteFile()); + bw = new BufferedWriter(fw); + ErrorLogHelper.loadProperties(); + + LOGGER.info(" ---- NOTE --- about to open graph (takes a little while)--------\n"); + + if( cacheDbOkFlag ){ + // Since we're just reading (not deleting/fixing anything), we can use + // a cached connection to the DB + graph = TitanFactory.open(AAIConstants.CACHED_DB_CONFIG); + } + else { + graph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG); + } + if (graph == null) { + String emsg = "null graph object in DataGrooming\n"; + throw new AAIException("AAI_6101", emsg); + } + + LOGGER.debug(" Got the graph object. "); + + g = graph.newTransaction(); + if (g == null) { + String emsg = "null graphTransaction object in DataGrooming\n"; + throw new AAIException("AAI_6101", emsg); + } + + + ArrayList<String> errArr = new ArrayList<>(); + int totalNodeCount = 0; + HashMap<String, String> misMatchedHash = new HashMap<String, String>(); + HashMap<String, TitanVertex> orphanNodeHash = new HashMap<String, TitanVertex>(); + HashMap<String, TitanVertex> missingDepNodeHash = new HashMap<String, TitanVertex>(); + HashMap<String, Edge> oneArmedEdgeHash = new HashMap<String, Edge>(); + HashMap<String, String> emptyVertexHash = new HashMap<String, String>(); + HashMap<String, TitanVertex> ghostNodeHash = new HashMap<String, TitanVertex>(); + ArrayList<String> dupeGroups = new ArrayList<>(); + + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + Iterator<String> nodeMapKPropsIterator = dbMaps.NodeKeyProps.keySet().iterator(); + String ntList = ""; + + LOGGER.info(" Starting DataGrooming Processing "); + + if (edgesOnlyFlag) { + LOGGER.info(" NOTE >> Skipping Node processing as requested. Will only process Edges. << "); + } + else { + while (nodeMapKPropsIterator.hasNext()) { + String nType = nodeMapKPropsIterator.next(); + int thisNtCount = 0; + int thisNtDeleteCount = 0; + LOGGER.debug(" > Look at : [" + nType + "] ..."); + ntList = ntList + "," + nType; + + // Get a collection of the names of the key properties for this nodeType to use later + // Determine what the key fields are for this nodeType + Collection <String> keyProps = new ArrayList <>(); + if( dbMaps.NodeKeyProps.containsKey(nType) ){ + keyProps = dbMaps.NodeKeyProps.get(nType); + } + else { + throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")"); + } + + // Get the types of nodes that this nodetype depends on for uniqueness (if any) + Collection <String> depNodeTypes = new ArrayList <>(); + if( dbMaps.NodeDependencies.containsKey(nType) ){ + depNodeTypes = dbMaps.NodeDependencies.get(nType); + } + + // Loop through all the nodes of this Node type + int lastShownForNt = 0; + ArrayList <TitanVertex> tmpList = new ArrayList <> (); + Iterable <?> verts = g.query().has("aai-node-type",nType).vertices(); + Iterator<?> iterv = verts.iterator(); + while (iterv.hasNext()) { + // We put the nodes into an ArrayList because the graph.query iterator can time out + tmpList.add((TitanVertex)iterv.next()); + } + + Iterator <?> iter = tmpList.iterator(); + while (iter.hasNext()) { + try { + thisNtCount++; + if( thisNtCount == lastShownForNt + 250 ){ + lastShownForNt = thisNtCount; + LOGGER.debug("count for " + nType + " so far = " + thisNtCount ); + } + TitanVertex thisVtx = (TitanVertex) iter.next(); + String thisVid = thisVtx.id().toString(); + if (processedVertices.contains(thisVid)) { + LOGGER.debug("skipping already processed vertex: " + thisVid); + continue; + } + totalNodeCount++; + List <TitanVertex> secondGetList = new ArrayList <> (); + // ----------------------------------------------------------------------- + // For each vertex of this nodeType, we want to: + // a) make sure that it can be retrieved using it's AAI defined key + // b) make sure that it is not a duplicate + // ----------------------------------------------------------------------- + + // For this instance of this nodeType, get the key properties + HashMap<String, Object> propHashWithKeys = new HashMap<>(); + Iterator<String> keyPropI = keyProps.iterator(); + while (keyPropI.hasNext()) { + String propName = keyPropI.next(); + String propVal = ""; + //delete an already deleted vertex + Object obj = thisVtx.<Object>property(propName).orElse(null); + if (obj != null) { + propVal = obj.toString(); + } + propHashWithKeys.put(propName, propVal); + } + try { + // If this node is dependent on another for uniqueness, then do the query from that parent node + // Note - all of our nodes that are dependent on others for uniqueness are + // "children" of that node. + boolean depNodeOk = true; + if( depNodeTypes.isEmpty() ){ + // This kind of node is not dependent on any other. + // Make sure we can get it back using it's key properties and that we only get one. + secondGetList = getNodeJustUsingKeyParams( TRANSID, FROMAPPID, g, nType, + propHashWithKeys, version ); + } + else { + // This kind of node is dependent on another for uniqueness. + // Start at it's parent (the dependent vertex) and make sure we can get it + // back using it's key properties and that we only get one. + Iterable <?> verts2 = thisVtx.query().direction(Direction.IN).has("isParent",true).vertices(); + Iterator <?> vertI2 = verts2.iterator(); + TitanVertex parentVtx = null; + int pCount = 0; + while( vertI2 != null && vertI2.hasNext() ){ + parentVtx = (TitanVertex) vertI2.next(); + pCount++; + } + if( pCount <= 0 ){ + + + //List<Vertex> vertI2 = g.traversal().V(thisVtx).union(__.outE().has("isParent-REV",true).outV(),__.inE().has("isParent",true).inV()).toList(); + //if( vertI2.isEmpty()){ + + // It's Missing it's dependent/parent node + depNodeOk = false; + boolean zeroEdges = false; + try { + Iterator<Edge> tmpEdgeIter = thisVtx.edges(Direction.BOTH); + int edgeCount = 0; + while( tmpEdgeIter.hasNext() ){ + edgeCount++; + tmpEdgeIter.next(); + } + if( edgeCount == 0 ){ + zeroEdges = true; + } + } catch (Exception ex) { + LOGGER.warn("WARNING from inside the for-each-vid-loop orphan-edges-check ", ex); + } + + if (deleteCandidateList.contains(thisVid)) { + boolean okFlag = true; + try { + processedVertices.add(thisVtx.id().toString()); + thisVtx.remove(); + deleteCount++; + thisNtDeleteCount++; + } catch (Exception e) { + okFlag = false; + LOGGER.error("ERROR trying to delete missing-dep-node VID = " + thisVid, e); + } + if (okFlag) { + LOGGER.info(" DELETED missing-dep-node VID = " + thisVid); + } + } else { + // We count nodes missing their depNodes two ways - the first if it has + // at least some edges, and the second if it has zero edges. Either + // way, they are effectively orphaned. + // NOTE - Only nodes that have dependent nodes are ever considered "orphaned". + if( zeroEdges ){ + missingDepNodeHash.put(thisVid, thisVtx); + } + else { + orphanNodeHash.put(thisVid, thisVtx); + } + } + } + else if ( pCount > 1 ){ + // Not sure how this could happen? Should we do something here? + depNodeOk = false; + } + else { + // We found the parent - so use it to do the second-look. + // NOTE --- We're just going to do the same check from the other direction - because + // there could be duplicates or the pointer going the other way could be broken + ArrayList <TitanVertex> tmpListSec = new ArrayList <> (); + tmpListSec = getConnectedChildren( g, parentVtx ) ; + Iterator<TitanVertex> vIter = tmpListSec.iterator(); + while (vIter.hasNext()) { + TitanVertex tmpV = vIter.next(); + if( vertexHasTheseKeys(tmpV, propHashWithKeys) ){ + secondGetList.add(tmpV); + } + } + } + } + + if( depNodeOk && (secondGetList == null || secondGetList.size() == 0) ){ + // We could not get the node back using it's own key info. + // So, it's a PHANTOM + if (deleteCandidateList.contains(thisVid)) { + boolean okFlag = true; + try { + thisVtx.remove(); + deleteCount++; + thisNtDeleteCount++; + } catch (Exception e) { + okFlag = false; + LOGGER.error("ERROR trying to delete phantom VID = " + thisVid, e); + } + if (okFlag) { + LOGGER.info(" DELETED VID = " + thisVid); + } + } else { + ghostNodeHash.put(thisVid, thisVtx); + } + } + else if( (secondGetList.size() > 1) && depNodeOk && !dupeCheckOff ){ + // Found some DUPLICATES - need to process them + LOGGER.info(" - now check Dupes for this guy - "); + List<String> tmpDupeGroups = checkAndProcessDupes( + TRANSID, FROMAPPID, g, version, + nType, secondGetList, dupeFixOn, + deleteCandidateList, singleCommits, dupeGroups, dbMaps); + Iterator<String> dIter = tmpDupeGroups.iterator(); + while (dIter.hasNext()) { + // Add in any newly found dupes to our running list + String tmpGrp = dIter.next(); + LOGGER.info("Found set of dupes: [" + tmpGrp + "]"); + dupeGroups.add(tmpGrp); + } + } + } + catch (AAIException e1) { + LOGGER.warn(" For nodeType = " + nType + " Caught exception", e1); + errArr.add(e1.getErrorObject().toString()); + } + catch (Exception e2) { + LOGGER.warn(" For nodeType = " + nType + + " Caught exception", e2); + errArr.add(e2.getMessage()); + } + }// try block to enclose looping of a single vertex + catch (Exception exx) { + LOGGER.warn("WARNING from inside the while-verts-loop ", exx); + } + + } // while loop for each record of a nodeType + + if ( (thisNtDeleteCount > 0) && singleCommits ) { + // NOTE - the singleCommits option is not used in normal processing + g.commit(); + g = AAIGraph.getInstance().getGraph().newTransaction(); + + } + thisNtDeleteCount = 0; + LOGGER.info( " Processed " + thisNtCount + " records for [" + nType + "], " + totalNodeCount + " total overall. " ); + + }// While-loop for each node type + }// end of check to make sure we weren't only supposed to do edges + + + // -------------------------------------------------------------------------------------- + // Now, we're going to look for one-armed-edges. Ie. an edge that + // should have + // been deleted (because a vertex on one side was deleted) but + // somehow was not deleted. + // So the one end of it points to a vertexId -- but that vertex is + // empty. + // -------------------------------------------------------------------------------------- + + // To do some strange checking - we need a second graph object + LOGGER.debug(" ---- DEBUG --- about to open a SECOND graph (takes a little while)--------\n"); + // Note - graph2 just reads - but we want it to use a fresh connection to + // the database, so we are NOT using the CACHED DB CONFIG here. + graph2 = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG); + if (graph2 == null) { + String emsg = "null graph2 object in DataGrooming\n"; + throw new AAIException("AAI_6101", emsg); + } else { + LOGGER.debug("Got the graph2 object... \n"); + } + g2 = graph2.newTransaction(); + if (g2 == null) { + String emsg = "null graphTransaction2 object in DataGrooming\n"; + throw new AAIException("AAI_6101", emsg); + } + + ArrayList<Vertex> vertList = new ArrayList<>(); + Iterable<? extends Vertex> vIt3 = g.query().vertices(); + Iterator<? extends Vertex> vItor3 = vIt3.iterator(); + // Gotta hold these in a List - or else HBase times out as you cycle + // through these + while (vItor3.hasNext()) { + Vertex v = vItor3.next(); + vertList.add(v); + } + int counter = 0; + int lastShown = 0; + Iterator<Vertex> vItor2 = vertList.iterator(); + LOGGER.info(" Checking for bad edges --- "); + + while (vItor2.hasNext()) { + Vertex v = null; + try { + try { + v = vItor2.next(); + } catch (Exception vex) { + LOGGER.warn(">>> WARNING trying to get next vertex on the vItor2 "); + continue; + } + + counter++; + String thisVertId = ""; + try { + thisVertId = v.id().toString(); + } catch (Exception ev) { + LOGGER.warn("WARNING when doing getId() on a vertex from our vertex list. "); + continue; + } + if (ghostNodeHash.containsKey(thisVertId)) { + // This is a phantom node, so don't try to use it + LOGGER.info(" >> Skipping edge check for edges from vertexId = " + + thisVertId + + ", since that guy is a Phantom Node"); + continue; + } + if (counter == lastShown + 250) { + lastShown = counter; + LOGGER.info("... Checking edges for vertex # " + + counter); + } + Iterator<Edge> eItor = v.edges(Direction.BOTH); + while (eItor.hasNext()) { + Edge e = null; + Vertex vIn = null; + Vertex vOut = null; + try { + e = eItor.next(); + } catch (Exception iex) { + LOGGER.warn(">>> WARNING trying to get next edge on the eItor ", iex); + continue; + } + + try { + vIn = e.inVertex(); + } catch (Exception err) { + LOGGER.warn(">>> WARNING trying to get edge's In-vertex ", err); + } + String vNtI = ""; + String vIdI = ""; + TitanVertex ghost2 = null; + + Boolean keysMissing = true; + Boolean cantGetUsingVid = false; + if (vIn != null) { + try { + Object ob = vIn.<Object>property("aai-node-type").orElse(null); + if (ob != null) { + vNtI = ob.toString(); + keysMissing = anyKeyFieldsMissing(vNtI, vIn, dbMaps); + } + ob = vIn.id(); + long vIdLong = 0L; + if (ob != null) { + vIdI = ob.toString(); + vIdLong = Long.parseLong(vIdI); + } + + if( ! ghost2CheckOff ){ + TitanVertex connectedVert = g2.getVertex(vIdLong); + if( connectedVert == null ) { + LOGGER.warn( "GHOST2 -- got NULL when doing getVertex for vid = " + vIdLong); + cantGetUsingVid = true; + + // If we can NOT get this ghost with the SECOND graph-object, + // it is still a ghost since even though we can get data about it using the FIRST graph + // object. + try { + ghost2 = g.getVertex(vIdLong); + } + catch( Exception ex){ + LOGGER.warn( "GHOST2 -- Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex); + } + if( ghost2 != null ){ + ghostNodeHash.put(vIdI, ghost2); + } + } + }// end of the ghost2 checking + } + catch (Exception err) { + LOGGER.warn(">>> WARNING trying to get edge's In-vertex props ", err); + } + } + if (keysMissing || vIn == null || vNtI.equals("") + || cantGetUsingVid) { + // this is a bad edge because it points to a vertex + // that isn't there anymore or is corrupted + String thisEid = e.id().toString(); + if (deleteCandidateList.contains(thisEid) || deleteCandidateList.contains(vIdI)) { + boolean okFlag = true; + if (!vIdI.equals("")) { + // try to get rid of the corrupted vertex + try { + if( (ghost2 != null) && ghost2FixOn ){ + ghost2.remove(); + } + else { + vIn.remove(); + } + if (singleCommits) { + // NOTE - the singleCommits option is not used in normal processing + g.commit(); + g = AAIGraph.getInstance().getGraph().newTransaction(); + } + deleteCount++; + } catch (Exception e1) { + okFlag = false; + LOGGER.warn("WARNING when trying to delete bad-edge-connected VERTEX VID = " + + vIdI, e1); + } + if (okFlag) { + LOGGER.info(" DELETED vertex from bad edge = " + + vIdI); + } + } else { + // remove the edge if we couldn't get the + // vertex + try { + e.remove(); + if (singleCommits) { + // NOTE - the singleCommits option is not used in normal processing + g.commit(); + g = AAIGraph.getInstance().getGraph().newTransaction(); + } + deleteCount++; + } catch (Exception ex) { + // NOTE - often, the exception is just + // that this edge has already been + // removed + okFlag = false; + LOGGER.warn("WARNING when trying to delete edge = " + + thisEid); + } + if (okFlag) { + LOGGER.info(" DELETED edge = " + thisEid); + } + } + } else { + oneArmedEdgeHash.put(thisEid, e); + if ((vIn != null) && (vIn.id() != null)) { + emptyVertexHash.put(thisEid, vIn.id() + .toString()); + } + } + } + + try { + vOut = e.outVertex(); + } catch (Exception err) { + LOGGER.warn(">>> WARNING trying to get edge's Out-vertex "); + } + String vNtO = ""; + String vIdO = ""; + ghost2 = null; + keysMissing = true; + cantGetUsingVid = false; + if (vOut != null) { + try { + Object ob = vOut.<Object>property("aai-node-type").orElse(null); + if (ob != null) { + vNtO = ob.toString(); + keysMissing = anyKeyFieldsMissing(vNtO, + vOut, dbMaps); + } + ob = vOut.id(); + long vIdLong = 0L; + if (ob != null) { + vIdO = ob.toString(); + vIdLong = Long.parseLong(vIdO); + } + + if( ! ghost2CheckOff ){ + TitanVertex connectedVert = g2.getVertex(vIdLong); + if( connectedVert == null ) { + cantGetUsingVid = true; + LOGGER.info( "GHOST2 -- got NULL when doing getVertex for vid = " + vIdLong); + // If we can get this ghost with the other graph-object, then get it -- it's still a ghost + try { + ghost2 = g.getVertex(vIdLong); + } + catch( Exception ex){ + LOGGER.warn( "GHOST2 -- Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex); + } + if( ghost2 != null ){ + ghostNodeHash.put(vIdO, ghost2); + } + } + } + } catch (Exception err) { + LOGGER.warn(">>> WARNING trying to get edge's Out-vertex props ", err); + } + } + if (keysMissing || vOut == null || vNtO.equals("") + || cantGetUsingVid) { + // this is a bad edge because it points to a vertex + // that isn't there anymore + String thisEid = e.id().toString(); + if (deleteCandidateList.contains(thisEid) || deleteCandidateList.contains(vIdO)) { + boolean okFlag = true; + if (!vIdO.equals("")) { + // try to get rid of the corrupted vertex + try { + if( (ghost2 != null) && ghost2FixOn ){ + ghost2.remove(); + } + else { + vOut.remove(); + } + if (singleCommits) { + // NOTE - the singleCommits option is not used in normal processing + g.commit(); + g = AAIGraph.getInstance().getGraph().newTransaction(); + } + deleteCount++; + } catch (Exception e1) { + okFlag = false; + LOGGER.warn("WARNING when trying to delete bad-edge-connected VID = " + + vIdO, e1); + } + if (okFlag) { + LOGGER.info(" DELETED vertex from bad edge = " + + vIdO); + } + } else { + // remove the edge if we couldn't get the + // vertex + try { + e.remove(); + if (singleCommits) { + // NOTE - the singleCommits option is not used in normal processing + g.commit(); + g = AAIGraph.getInstance().getGraph().newTransaction(); + } + deleteCount++; + } catch (Exception ex) { + // NOTE - often, the exception is just + // that this edge has already been + // removed + okFlag = false; + LOGGER.warn("WARNING when trying to delete edge = " + + thisEid, ex); + } + if (okFlag) { + LOGGER.info(" DELETED edge = " + thisEid); + } + } + } else { + oneArmedEdgeHash.put(thisEid, e); + if ((vOut != null) && (vOut.id() != null)) { + emptyVertexHash.put(thisEid, vOut.id() + .toString()); + } + } + } + }// End of while-edges-loop + } catch (Exception exx) { + LOGGER.warn("WARNING from in the while-verts-loop ", exx); + } + }// End of while-vertices-loop + + deleteCount = deleteCount + dupeGrpsDeleted; + if (!singleCommits && deleteCount > 0) { + try { + LOGGER.info("About to do the commit for " + + deleteCount + " removes. "); + executeFinalCommit = true; + LOGGER.info("Commit was successful "); + } catch (Exception excom) { + LOGGER.error(" >>>> ERROR <<<< Could not commit changes. ", excom); + deleteCount = 0; + } + } + + int ghostNodeCount = ghostNodeHash.size(); + int orphanNodeCount = orphanNodeHash.size(); + int missingDepNodeCount = missingDepNodeHash.size(); + int oneArmedEdgeCount = oneArmedEdgeHash.size(); + int dupeCount = dupeGroups.size(); + + deleteCount = deleteCount + dupeGrpsDeleted; + + bw.write("\n\n ============ Summary ==============\n"); + bw.write("Ran these nodeTypes: " + ntList + "\n\n"); + bw.write("There were this many delete candidates from previous run = " + + deleteCandidateList.size() + "\n"); + if (dontFixOrphansFlag) { + bw.write(" Note - we are not counting orphan nodes since the -dontFixOrphans parameter was used. \n"); + } + bw.write("Deleted this many delete candidates = " + deleteCount + + "\n"); + bw.write("Total number of nodes looked at = " + totalNodeCount + + "\n"); + bw.write("Ghost Nodes identified = " + ghostNodeCount + "\n"); + bw.write("Orphan Nodes identified = " + orphanNodeCount + "\n"); + bw.write("Bad Edges identified = " + oneArmedEdgeCount + "\n"); + bw.write("Missing Dependent Edge (but not orphaned) node count = " + + missingDepNodeCount + "\n"); + bw.write("Duplicate Groups count = " + dupeCount + "\n"); + bw.write("MisMatching Label/aai-node-type count = " + + misMatchedHash.size() + "\n"); + + bw.write("\n ------------- Delete Candidates ---------\n"); + for (Map.Entry<String, TitanVertex> entry : ghostNodeHash + .entrySet()) { + String vid = entry.getKey(); + bw.write("DeleteCandidate: Phantom Vid = [" + vid + "]\n"); + cleanupCandidateCount++; + } + for (Map.Entry<String, TitanVertex> entry : orphanNodeHash + .entrySet()) { + String vid = entry.getKey(); + bw.write("DeleteCandidate: OrphanDepNode Vid = [" + vid + "]\n"); + if (!dontFixOrphansFlag) { + cleanupCandidateCount++; + } + } + for (Map.Entry<String, Edge> entry : oneArmedEdgeHash.entrySet()) { + String eid = entry.getKey(); + bw.write("DeleteCandidate: Bad EDGE Edge-id = [" + eid + "]\n"); + cleanupCandidateCount++; + } + for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash + .entrySet()) { + String vid = entry.getKey(); + bw.write("DeleteCandidate: (maybe) missingDepNode Vid = [" + + vid + "]\n"); + cleanupCandidateCount++; + } + bw.write("\n-- NOTE - To see DeleteCandidates for Duplicates, you need to look in the Duplicates Detail section below.\n"); + + bw.write("\n ------------- GHOST NODES - detail "); + for (Map.Entry<String, TitanVertex> entry : ghostNodeHash + .entrySet()) { + try { + String vid = entry.getKey(); + bw.write("\n ==> Phantom Vid = " + vid + "\n"); + ArrayList<String> retArr = showPropertiesForNode( + TRANSID, FROMAPPID, entry.getValue()); + for (String info : retArr) { + bw.write(info + "\n"); + } + + retArr = showAllEdgesForNode(TRANSID, FROMAPPID, + entry.getValue()); + for (String info : retArr) { + bw.write(info + "\n"); + } + } catch (Exception dex) { + LOGGER.error("error trying to print detail info for a ghost-node: ", dex); + } + } + + bw.write("\n ------------- Missing Dependent Edge ORPHAN NODES - detail: "); + for (Map.Entry<String, TitanVertex> entry : orphanNodeHash + .entrySet()) { + try { + String vid = entry.getKey(); + bw.write("\n> Orphan Node Vid = " + vid + "\n"); + ArrayList<String> retArr = showPropertiesForNode( + TRANSID, FROMAPPID, entry.getValue()); + for (String info : retArr) { + bw.write(info + "\n"); + } + + retArr = showAllEdgesForNode(TRANSID, FROMAPPID, + entry.getValue()); + for (String info : retArr) { + bw.write(info + "\n"); + } + } catch (Exception dex) { + LOGGER.error("error trying to print detail info for a Orphan Node /missing dependent edge", dex); + } + } + + bw.write("\n ------------- Missing Dependent Edge (but not orphan) NODES: "); + for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash + .entrySet()) { + try { + String vid = entry.getKey(); + bw.write("\n> Missing edge to Dependent Node (but has edges) Vid = " + + vid + "\n"); + ArrayList<String> retArr = showPropertiesForNode( + TRANSID, FROMAPPID, entry.getValue()); + for (String info : retArr) { + bw.write(info + "\n"); + } + + retArr = showAllEdgesForNode(TRANSID, FROMAPPID, + entry.getValue()); + for (String info : retArr) { + bw.write(info + "\n"); + } + } catch (Exception dex) { + LOGGER.error("error trying to print detail info for a node missing its dependent edge but not an orphan", dex); + } + } + + bw.write("\n ------------- EDGES pointing to empty/bad vertices: "); + for (Map.Entry<String, Edge> entry : oneArmedEdgeHash.entrySet()) { + try { + String eid = entry.getKey(); + Edge thisE = entry.getValue(); + String badVid = emptyVertexHash.get(eid); + bw.write("\n> Edge pointing to bad vertex (Vid = " + + badVid + ") EdgeId = " + eid + "\n"); + bw.write("Label: [" + thisE.label() + "]\n"); + Iterator<Property<Object>> pI = thisE.properties(); + while (pI.hasNext()) { + Property<Object> propKey = pI.next(); + bw.write("Prop: [" + propKey + "], val = [" + + propKey.value() + "]\n"); + } + } catch (Exception pex) { + LOGGER.error("error trying to print empty/bad vertex data: ", pex); + } + } + + bw.write("\n ------------- Duplicates: "); + Iterator<String> dupeIter = dupeGroups.iterator(); + int dupeSetCounter = 0; + while (dupeIter.hasNext()) { + dupeSetCounter++; + String dset = (String) dupeIter.next(); + + bw.write("\n --- Duplicate Group # " + dupeSetCounter + + " Detail -----------\n"); + try { + // We expect each line to have at least two vid's, followed + // by the preferred one to KEEP + String[] dupeArr = dset.split("\\|"); + ArrayList<String> idArr = new ArrayList<>(); + int lastIndex = dupeArr.length - 1; + for (int i = 0; i <= lastIndex; i++) { + if (i < lastIndex) { + // This is not the last entry, it is one of the + // dupes, so we want to show all its info + bw.write(" >> Duplicate Group # " + + dupeSetCounter + " Node # " + i + + " ----\n"); + String vidString = dupeArr[i]; + idArr.add(vidString); + long longVertId = Long.parseLong(vidString); + Iterator<Vertex> vtxIterator = g.vertices(longVertId); + TitanVertex vtx = null; + if (vtxIterator.hasNext()) { + vtx = (TitanVertex)vtxIterator.next(); + } + ArrayList<String> retArr = showPropertiesForNode(TRANSID, FROMAPPID, vtx); + for (String info : retArr) { + bw.write(info + "\n"); + } + + retArr = showAllEdgesForNode(TRANSID, + FROMAPPID, vtx); + for (String info : retArr) { + bw.write(info + "\n"); + } + } else { + // This is the last entry which should tell us if we + // have a preferred keeper + String prefString = dupeArr[i]; + if (prefString.equals("KeepVid=UNDETERMINED")) { + bw.write("\n For this group of duplicates, could not tell which one to keep.\n"); + bw.write(" >>> This group needs to be taken care of with a manual/forced-delete.\n"); + } else { + // If we know which to keep, then the prefString + // should look like, "KeepVid=12345" + String[] prefArr = prefString.split("="); + if (prefArr.length != 2 + || (!prefArr[0].equals("KeepVid"))) { + throw new Exception("Bad format. Expecting KeepVid=999999"); + } else { + String keepVidStr = prefArr[1]; + if (idArr.contains(keepVidStr)) { + bw.write("\n The vertex we want to KEEP has vertexId = " + + keepVidStr); + bw.write("\n The others become delete candidates: \n"); + idArr.remove(keepVidStr); + for (int x = 0; x < idArr.size(); x++) { + cleanupCandidateCount++; + bw.write("DeleteCandidate: Duplicate Vid = [" + + idArr.get(x) + "]\n"); + } + } else { + throw new Exception("ERROR - Vertex Id to keep not found in list of dupes. dset = [" + + dset + "]"); + } + } + }// else we know which one to keep + }// else last entry + }// for each vertex in a group + } catch (Exception dex) { + LOGGER.error("error trying to print duplicate vertex data", dex); + } + + }// while - work on each group of dupes + + bw.write("\n ------------- Mis-matched Label/aai-node-type Nodes: \n "); + for (Map.Entry<String, String> entry : misMatchedHash.entrySet()) { + String msg = entry.getValue(); + bw.write("MixedMsg = " + msg + "\n"); + } + + bw.write("\n ------------- Got these errors while processing: \n"); + Iterator<String> errIter = errArr.iterator(); + while (errIter.hasNext()) { + String line = (String) errIter.next(); + bw.write(line + "\n"); + } + + bw.close(); + + LOGGER.info("\n ------------- Done doing all the checks ------------ "); + LOGGER.info("Output will be written to " + fullOutputFileName); + + if (cleanupCandidateCount > 0) { + // Technically, this is not an error -- but we're throwing this + // error so that hopefully a + // monitoring system will pick it up and do something with it. + throw new AAIException("AAI_6123", "See file: [" + fullOutputFileName + + "] and investigate delete candidates. "); + } + } catch (AAIException e) { + LOGGER.error("Caught AAIException while grooming data", e); + ErrorLogHelper.logException(e); + } catch (Exception ex) { + LOGGER.error("Caught exception while grooming data", ex); + ErrorLogHelper.logError("AAI_6128", ex.getMessage() + ", resolve and rerun dataGrooming"); + } finally { + + if (bw != null) { + try { + bw.close(); + } catch (IOException iox) { + LOGGER.warn("Got an IOException trying to close bufferedWriter() \n", iox); + } + } + + if (g != null && !g.isClosed()) { + // Any changes that worked correctly should have already done + // their commits. + try { + if (executeFinalCommit) { + g.commit(); + } + g.rollback(); + } catch (Exception ex) { + // Don't throw anything because Titan sometimes is just saying that the graph is already closed + LOGGER.warn("WARNING from final graphTransaction.rollback()", ex); + } + } + + if (g2 != null && !g2.isClosed()) { + // Any changes that worked correctly should have already done + // their commits. + try { + g2.rollback(); + } catch (Exception ex) { + // Don't throw anything because Titan sometimes is just saying that the graph is already closed + LOGGER.warn("WARNING from final graphTransaction2.rollback()", ex); + } + } + + if( finalShutdownFlag ){ + try { + if( graph != null && graph.isOpen() ){ + graph.tx().close(); + graph.close(); + } + } catch (Exception ex) { + // Don't throw anything because Titan sometimes is just saying that the graph is already closed{ + LOGGER.warn("WARNING from final graph.shutdown()", ex); + } + + try { + if( graph2 != null && graph2.isOpen() ){ + graph2.tx().close(); + graph2.close(); + } + } catch (Exception ex) { + // Don't throw anything because Titan sometimes is just saying that the graph is already closed{ + LOGGER.warn("WARNING from final graph2.shutdown()", ex); + } + } + + } + + return cleanupCandidateCount; + + }// end of doTheGrooming() + + + /** + * Vertex has these keys. + * + * @param tmpV the tmp V + * @param propHashWithKeys the prop hash with keys + * @return the boolean + */ + private static Boolean vertexHasTheseKeys( TitanVertex tmpV, HashMap <String, Object> propHashWithKeys) { + Iterator <?> it = propHashWithKeys.entrySet().iterator(); + while( it.hasNext() ){ + String propName = ""; + String propVal = ""; + Map.Entry <?,?>propEntry = (Map.Entry<?,?>)it.next(); + Object propNameObj = propEntry.getKey(); + if( propNameObj != null ){ + propName = propNameObj.toString(); + } + Object propValObj = propEntry.getValue(); + if( propValObj != null ){ + propVal = propValObj.toString(); + } + Object checkValObj = tmpV.<Object>property(propName).orElse(null); + if( checkValObj == null ) { + return false; + } + else if( !propVal.equals(checkValObj.toString()) ){ + return false; + } + } + return true; + } + + + /** + * Any key fields missing. + * + * @param nType the n type + * @param v the v + * @return the boolean + */ + private static Boolean anyKeyFieldsMissing(String nType, Vertex v, DbMaps dbMaps) { + + try { + // Determine what the key fields are for this nodeType + Collection <String> keyPropNamesColl = new ArrayList <>(); + if( dbMaps.NodeKeyProps.containsKey(nType) ){ + keyPropNamesColl = dbMaps.NodeKeyProps.get(nType); + } + else { + throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")"); + } + + Iterator<String> keyPropI = keyPropNamesColl.iterator(); + while (keyPropI.hasNext()) { + String propName = keyPropI.next(); + Object ob = v.<Object>property(propName).orElse(null); + if (ob == null || ob.toString().equals("")) { + // It is missing a key property + return true; + } + } + } catch (AAIException e) { + // Something was wrong + return true; + } + return false; + } + + + /** + * Gets the delete list. + * + * @param targetDir the target dir + * @param fileName the file name + * @param edgesOnlyFlag the edges only flag + * @param dontFixOrphans the dont fix orphans + * @param dupeFixOn the dupe fix on + * @return the delete list + * @throws AAIException the AAI exception + */ + private static Set<String> getDeleteList(String targetDir, + String fileName, Boolean edgesOnlyFlag, Boolean dontFixOrphans, + Boolean dupeFixOn) throws AAIException { + + // Look in the file for lines formated like we expect - pull out any + // Vertex Id's to delete on this run + Set<String> delList = new LinkedHashSet<>(); + String fullFileName = targetDir + AAIConstants.AAI_FILESEP + fileName; + BufferedReader br = null; + + try { + br = new BufferedReader(new FileReader(fullFileName)); + String line = br.readLine(); + while (line != null) { + if (!line.equals("") && line.startsWith("DeleteCandidate")) { + if (edgesOnlyFlag && (!line.contains("Bad Edge"))) { + // We're not going to process edge guys + } else if (dontFixOrphans && line.contains("Orphan")) { + // We're not going to process orphans + } else if (!dupeFixOn && line.contains("Duplicate")) { + // We're not going to process Duplicates + } else { + int begIndex = line.indexOf("id = "); + int endIndex = line.indexOf("]"); + String vidVal = line.substring(begIndex + 6, endIndex); + delList.add(vidVal); + } + } + line = br.readLine(); + } + br.close(); + } catch (IOException e) { + throw new AAIException("AAI_6124", e, "Could not open input-file [" + fullFileName + + "], exception= " + e.getMessage()); + } + + return delList; + + }// end of getDeleteList + + /** + * Gets the preferred dupe. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param g the g + * @param dupeVertexList the dupe vertex list + * @param ver the ver + * @return TitanVertex + * @throws AAIException the AAI exception + */ + public static TitanVertex getPreferredDupe(String transId, + String fromAppId, TitanTransaction g, + ArrayList<TitanVertex> dupeVertexList, String ver, DbMaps dbMaps) + throws AAIException { + + // This method assumes that it is being passed a List of vertex objects + // which + // violate our uniqueness constraints. + + TitanVertex nullVtx = null; + + if (dupeVertexList == null) { + return nullVtx; + } + int listSize = dupeVertexList.size(); + if (listSize == 0) { + return nullVtx; + } + if (listSize == 1) { + return ((TitanVertex) dupeVertexList.get(0)); + } + + TitanVertex vtxPreferred = null; + TitanVertex currentFaveVtx = (TitanVertex) dupeVertexList.get(0); + for (int i = 1; i < listSize; i++) { + TitanVertex vtxB = (TitanVertex) dupeVertexList.get(i); + vtxPreferred = pickOneOfTwoDupes(transId, fromAppId, g, + currentFaveVtx, vtxB, ver, dbMaps); + if (vtxPreferred == null) { + // We couldn't choose one + return nullVtx; + } else { + currentFaveVtx = vtxPreferred; + } + } + + return (currentFaveVtx); + + } // end of getPreferredDupe() + + /** + * Pick one of two dupes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param g the g + * @param vtxA the vtx A + * @param vtxB the vtx B + * @param ver the ver + * @return TitanVertex + * @throws AAIException the AAI exception + */ + public static TitanVertex pickOneOfTwoDupes(String transId, + String fromAppId, TitanTransaction g, TitanVertex vtxA, + TitanVertex vtxB, String ver, DbMaps dbMaps) throws AAIException { + + TitanVertex nullVtx = null; + TitanVertex preferredVtx = null; + + Long vidA = new Long(vtxA.id().toString()); + Long vidB = new Long(vtxB.id().toString()); + + String vtxANodeType = ""; + String vtxBNodeType = ""; + Object obj = vtxA.<Object>property("aai-node-type").orElse(null); + if (obj != null) { + vtxANodeType = obj.toString(); + } + obj = vtxB.<Object>property("aai-node-type").orElse(null); + if (obj != null) { + vtxBNodeType = obj.toString(); + } + + if (vtxANodeType.equals("") || (!vtxANodeType.equals(vtxBNodeType))) { + // Either they're not really dupes or there's some bad data - so + // don't pick one + return nullVtx; + } + + // Check that node A and B both have the same key values (or else they + // are not dupes) + // (We'll check dep-node later) + // Determine what the key fields are for this nodeType + Collection <String> keyProps = new ArrayList <>(); + if( dbMaps.NodeKeyProps.containsKey(vtxANodeType) ){ + keyProps = dbMaps.NodeKeyProps.get(vtxANodeType); + } + else { + throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + vtxANodeType + ")"); + } + + Iterator<String> keyPropI = keyProps.iterator(); + while (keyPropI.hasNext()) { + String propName = keyPropI.next(); + String vtxAKeyPropVal = ""; + obj = vtxA.<Object>property(propName).orElse(null); + if (obj != null) { + vtxAKeyPropVal = obj.toString(); + } + String vtxBKeyPropVal = ""; + obj = vtxB.<Object>property(propName).orElse(null); + if (obj != null) { + vtxBKeyPropVal = obj.toString(); + } + + if (vtxAKeyPropVal.equals("") + || (!vtxAKeyPropVal.equals(vtxBKeyPropVal))) { + // Either they're not really dupes or they are missing some key + // data - so don't pick one + return nullVtx; + } + } + + // Collect the vid's and aai-node-types of the vertices that each vertex + // (A and B) is connected to. + ArrayList<String> vtxIdsConn2A = new ArrayList<>(); + ArrayList<String> vtxIdsConn2B = new ArrayList<>(); + HashMap<String, String> nodeTypesConn2A = new HashMap<>(); + HashMap<String, String> nodeTypesConn2B = new HashMap<>(); + + ArrayList<TitanVertex> vertListA = getConnectedNodes( g, vtxA ); + if (vertListA != null) { + Iterator<TitanVertex> iter = vertListA.iterator(); + while (iter.hasNext()) { + TitanVertex tvCon = iter.next(); + String conVid = tvCon.id().toString(); + String nt = ""; + obj = tvCon.<Object>property("aai-node-type").orElse(null); + if (obj != null) { + nt = obj.toString(); + } + nodeTypesConn2A.put(nt, conVid); + vtxIdsConn2A.add(conVid); + } + } + + ArrayList<TitanVertex> vertListB = getConnectedNodes( g, vtxB ); + if (vertListB != null) { + Iterator<TitanVertex> iter = vertListB.iterator(); + while (iter.hasNext()) { + TitanVertex tvCon = iter.next(); + String conVid = tvCon.id().toString(); + String nt = ""; + obj = tvCon.<Object>property("aai-node-type").orElse(null); + if (obj != null) { + nt = obj.toString(); + } + nodeTypesConn2B.put(nt, conVid); + vtxIdsConn2B.add(conVid); + } + } + + // 1 - If this kind of node needs a dependent node for uniqueness, then + // verify that they both nodes + // point to the same dependent node (otherwise they're not really + // duplicates) + // Note - there are sometimes more than one dependent node type since + // one nodeType can be used in + // different ways. But for a particular node, it will only have one + // dependent node that it's + // connected to. + Collection <String> depNodeTypes = new ArrayList <>(); + if( dbMaps.NodeDependencies.containsKey(vtxANodeType) ){ + depNodeTypes = dbMaps.NodeDependencies.get(vtxANodeType); + } + + if (depNodeTypes.isEmpty()) { + // This kind of node is not dependent on any other. That is ok. + } else { + String depNodeVtxId4A = ""; + String depNodeVtxId4B = ""; + Iterator<String> iter = depNodeTypes.iterator(); + while (iter.hasNext()) { + String depNodeType = iter.next(); + if (nodeTypesConn2A.containsKey(depNodeType)) { + // This is the dependent node type that vertex A is using + depNodeVtxId4A = nodeTypesConn2A.get(depNodeType); + } + if (nodeTypesConn2B.containsKey(depNodeType)) { + // This is the dependent node type that vertex B is using + depNodeVtxId4B = nodeTypesConn2B.get(depNodeType); + } + } + if (depNodeVtxId4A.equals("") + || (!depNodeVtxId4A.equals(depNodeVtxId4B))) { + // Either they're not really dupes or there's some bad data - so + // don't pick either one + return nullVtx; + } + } + + if (vtxIdsConn2A.size() == vtxIdsConn2B.size()) { + // 2 - If they both have edges to all the same vertices, then return + // the one with the lower vertexId. + boolean allTheSame = true; + Iterator<String> iter = vtxIdsConn2A.iterator(); + while (iter.hasNext()) { + String vtxIdConn2A = iter.next(); + if (!vtxIdsConn2B.contains(vtxIdConn2A)) { + allTheSame = false; + break; + } + } + + if (allTheSame) { + if (vidA < vidB) { + preferredVtx = vtxA; + } else { + preferredVtx = vtxB; + } + } + } else if (vtxIdsConn2A.size() > vtxIdsConn2B.size()) { + // 3 - VertexA is connected to more things than vtxB. + // We'll pick VtxA if its edges are a superset of vtxB's edges. + boolean missingOne = false; + Iterator<String> iter = vtxIdsConn2B.iterator(); + while (iter.hasNext()) { + String vtxIdConn2B = iter.next(); + if (!vtxIdsConn2A.contains(vtxIdConn2B)) { + missingOne = true; + break; + } + } + if (!missingOne) { + preferredVtx = vtxA; + } + } else if (vtxIdsConn2B.size() > vtxIdsConn2A.size()) { + // 4 - VertexB is connected to more things than vtxA. + // We'll pick VtxB if its edges are a superset of vtxA's edges. + boolean missingOne = false; + Iterator<String> iter = vtxIdsConn2A.iterator(); + while (iter.hasNext()) { + String vtxIdConn2A = iter.next(); + if (!vtxIdsConn2B.contains(vtxIdConn2A)) { + missingOne = true; + break; + } + } + if (!missingOne) { + preferredVtx = vtxB; + } + } else { + preferredVtx = nullVtx; + } + + return (preferredVtx); + + } // end of pickOneOfTwoDupes() + + /** + * Check and process dupes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param g the g + * @param version the version + * @param nType the n type + * @param passedVertList the passed vert list + * @param dupeFixOn the dupe fix on + * @param deleteCandidateList the delete candidate list + * @param singleCommits the single commits + * @param alreadyFoundDupeGroups the already found dupe groups + * @param dbMaps the db maps + * @return the array list + */ + private static List<String> checkAndProcessDupes(String transId, + String fromAppId, TitanTransaction g, String version, String nType, + List<TitanVertex> passedVertList, Boolean dupeFixOn, + Set<String> deleteCandidateList, Boolean singleCommits, + ArrayList<String> alreadyFoundDupeGroups, DbMaps dbMaps ) { + + ArrayList<String> returnList = new ArrayList<>(); + ArrayList<TitanVertex> checkVertList = new ArrayList<>(); + ArrayList<String> alreadyFoundDupeVidArr = new ArrayList<>(); + Boolean noFilterList = true; + Iterator<String> afItr = alreadyFoundDupeGroups.iterator(); + while (afItr.hasNext()) { + String dupeGrpStr = afItr.next(); + String[] dupeArr = dupeGrpStr.split("\\|"); + int lastIndex = dupeArr.length - 1; + for (int i = 0; i < lastIndex; i++) { + // Note: we don't want the last one... + String vidString = dupeArr[i]; + alreadyFoundDupeVidArr.add(vidString); + noFilterList = false; + } + } + + // For a given set of Nodes that were found with a set of KEY + // Parameters, (nodeType + key data) we will + // see if we find any duplicate nodes that need to be cleaned up. Note - + // it's legit to have more than one + // node with the same key data if the nodes depend on a parent for + // uniqueness -- as long as the two nodes + // don't hang off the same Parent. + // If we find duplicates, and we can figure out which of each set of + // duplicates is the one that we + // think should be preserved, we will record that. Whether we can tell + // which one should be + // preserved or not, we will return info about any sets of duplicates + // found. + // + // Each element in the returned arrayList might look like this: + // "1234|5678|keepVid=UNDETERMINED" (if there were 2 dupes, and we + // couldn't figure out which one to keep) + // or, "100017|200027|30037|keepVid=30037" (if there were 3 dupes and we + // thought the third one was the one that should survive) + + // Because of the way the calling code loops over stuff, we can get the + // same data multiple times - so we should + // not process any vertices that we've already seen. + + try { + Iterator<TitanVertex> pItr = passedVertList.iterator(); + while (pItr.hasNext()) { + TitanVertex tvx = (TitanVertex) pItr.next(); + String passedId = tvx.id().toString(); + if (noFilterList || !alreadyFoundDupeVidArr.contains(passedId)) { + // We haven't seen this one before - so we should check it. + checkVertList.add(tvx); + } + } + + if (checkVertList.size() < 2) { + // Nothing new to check. + return returnList; + } + + if (!dbMaps.NodeDependencies.containsKey(nType)) { + // If this was a node that does NOT depend on other nodes for + // uniqueness, and we + // found more than one node using its key -- record the found + // vertices as duplicates. + String dupesStr = ""; + for (int i = 0; i < checkVertList.size(); i++) { + dupesStr = dupesStr + + ((TitanVertex) (checkVertList.get(i))).id() + .toString() + "|"; + } + if (dupesStr != "") { + TitanVertex prefV = getPreferredDupe(transId, fromAppId, + g, checkVertList, version, dbMaps); + if (prefV == null) { + // We could not determine which duplicate to keep + dupesStr = dupesStr + "KeepVid=UNDETERMINED"; + returnList.add(dupesStr); + } else { + dupesStr = dupesStr + "KeepVid=" + prefV.id(); + Boolean didRemove = false; + if (dupeFixOn) { + didRemove = deleteNonKeepersIfAppropriate(g, + dupesStr, prefV.id().toString(), + deleteCandidateList, singleCommits); + } + if (didRemove) { + dupeGrpsDeleted++; + } else { + // keep them on our list + returnList.add(dupesStr); + } + } + } + } else { + // More than one node have the same key fields since they may + // depend on a parent node for + // uniqueness. Since we're finding more than one, we want to + // check to see if any of the + // vertices that have this set of keys are also pointing at the + // same 'parent' node. + // Note: for a given set of key data, it is possible that there + // could be more than one set of + // duplicates. + HashMap<String, ArrayList<TitanVertex>> vertsGroupedByParentHash = groupVertsByDepNodes( + transId, fromAppId, g, version, nType, + checkVertList, dbMaps); + for (Map.Entry<String, ArrayList<TitanVertex>> entry : vertsGroupedByParentHash + .entrySet()) { + ArrayList<TitanVertex> thisParentsVertList = entry + .getValue(); + if (thisParentsVertList.size() > 1) { + // More than one vertex found with the same key info + // hanging off the same parent/dependent node + String dupesStr = ""; + for (int i = 0; i < thisParentsVertList.size(); i++) { + dupesStr = dupesStr + + ((TitanVertex) (thisParentsVertList + .get(i))).id() + "|"; + } + if (dupesStr != "") { + TitanVertex prefV = getPreferredDupe(transId, + fromAppId, g, thisParentsVertList, + version, dbMaps); + + if (prefV == null) { + // We could not determine which duplicate to + // keep + dupesStr = dupesStr + "KeepVid=UNDETERMINED"; + returnList.add(dupesStr); + } else { + Boolean didRemove = false; + dupesStr = dupesStr + "KeepVid=" + + prefV.id().toString(); + if (dupeFixOn) { + didRemove = deleteNonKeepersIfAppropriate( + g, dupesStr, prefV.id() + .toString(), + deleteCandidateList, singleCommits); + } + if (didRemove) { + dupeGrpsDeleted++; + } else { + // keep them on our list + returnList.add(dupesStr); + } + } + } + } + } + } + } catch (Exception e) { + LOGGER.warn(" >>> Threw an error in checkAndProcessDupes - just absorb this error and move on. ", e); + } + + return returnList; + + }// End of checkAndProcessDupes() + + /** + * Group verts by dep nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param g the g + * @param version the version + * @param nType the n type + * @param passedVertList the passed vert list + * @param dbMaps the db maps + * @return the hash map + * @throws AAIException the AAI exception + */ + private static HashMap<String, ArrayList<TitanVertex>> groupVertsByDepNodes( + String transId, String fromAppId, TitanTransaction g, String version, + String nType, ArrayList<TitanVertex> passedVertList, DbMaps dbMaps) + throws AAIException { + // Given a list of Titan Vertices, group them together by dependent + // nodes. Ie. if given a list of + // ip address nodes (assumed to all have the same key info) they might + // sit under several different parent vertices. + // Under Normal conditions, there would only be one per parent -- but + // we're trying to find duplicates - so we + // allow for the case where more than one is under the same parent node. + + HashMap<String, ArrayList<TitanVertex>> retHash = new HashMap<String, ArrayList<TitanVertex>>(); + if (!dbMaps.NodeDependencies.containsKey(nType)) { + // This method really should not have been called if this is not the + // kind of node + // that depends on a parent for uniqueness, so just return the empty + // hash. + return retHash; + } + + // Find out what types of nodes the passed in nodes can depend on + ArrayList<String> depNodeTypeL = new ArrayList<>(); + Collection<String> depNTColl = dbMaps.NodeDependencies.get(nType); + Iterator<String> ntItr = depNTColl.iterator(); + while (ntItr.hasNext()) { + depNodeTypeL.add(ntItr.next()); + } + // For each vertex, we want find its dependent vertex and add it to + // other vertexes that are dependent on that same guy. + if (passedVertList != null) { + Iterator<TitanVertex> iter = passedVertList.iterator(); + while (iter.hasNext()) { + TitanVertex thisVert = iter.next(); + ArrayList<TitanVertex> connectedVList = getConnectedNodes( g, thisVert ); + Iterator<TitanVertex> connIter = connectedVList.iterator(); + while (connIter.hasNext()) { + TitanVertex tvCon = connIter.next(); + String conNt = ""; + Object obj = tvCon.<Object>property("aai-node-type").orElse(null); + if (obj != null) { + conNt = obj.toString(); + } + if (depNTColl.contains(conNt)) { + // This must be the parent/dependent node + String parentVid = tvCon.id().toString(); + if (retHash.containsKey(parentVid)) { + // add this vert to the list for this parent key + retHash.get(parentVid).add(thisVert); + } else { + // This is the first one we found on this parent + ArrayList<TitanVertex> vList = new ArrayList<>(); + vList.add(thisVert); + retHash.put(parentVid, vList); + } + } + } + } + } + + return retHash; + + }// end of groupVertsByDepNodes() + + /** + * Delete non keepers if appropriate. + * + * @param g the g + * @param dupeInfoString the dupe info string + * @param vidToKeep the vid to keep + * @param deleteCandidateList the delete candidate list + * @param singleCommits the single commits + * @return the boolean + */ + private static Boolean deleteNonKeepersIfAppropriate(TitanTransaction g, + String dupeInfoString, String vidToKeep, + Set<String> deleteCandidateList, Boolean singleCommits) { + + Boolean deletedSomething = false; + // This assumes that the dupeInfoString is in the format of + // pipe-delimited vid's followed by + // ie. "3456|9880|keepVid=3456" + if (deleteCandidateList == null || deleteCandidateList.size() == 0) { + // No vid's on the candidate list -- so no deleting will happen on + // this run + return false; + } + + String[] dupeArr = dupeInfoString.split("\\|"); + ArrayList<String> idArr = new ArrayList<>(); + int lastIndex = dupeArr.length - 1; + for (int i = 0; i <= lastIndex; i++) { + if (i < lastIndex) { + // This is not the last entry, it is one of the dupes, + String vidString = dupeArr[i]; + idArr.add(vidString); + } else { + // This is the last entry which should tell us if we have a + // preferred keeper + String prefString = dupeArr[i]; + if (prefString.equals("KeepVid=UNDETERMINED")) { + // They sent us a bad string -- nothing should be deleted if + // no dupe could be tagged as preferred + return false; + } else { + // If we know which to keep, then the prefString should look + // like, "KeepVid=12345" + String[] prefArr = prefString.split("="); + if (prefArr.length != 2 || (!prefArr[0].equals("KeepVid"))) { + LOGGER.error("Bad format. Expecting KeepVid=999999"); + return false; + } else { + String keepVidStr = prefArr[1]; + if (idArr.contains(keepVidStr)) { + idArr.remove(keepVidStr); + + // So now, the idArr should just contain the vid's + // that we want to remove. + for (int x = 0; x < idArr.size(); x++) { + boolean okFlag = true; + String thisVid = idArr.get(x); + if (deleteCandidateList.contains(thisVid)) { + // This vid is a valid delete candidate from + // a prev. run, so we can remove it. + try { + long longVertId = Long + .parseLong(thisVid); + TitanVertex vtx = g + .getVertex(longVertId); + vtx.remove(); + if (singleCommits) { + // NOTE - the singleCommits option is not used in normal processing + g.commit(); + g = AAIGraph.getInstance().getGraph().newTransaction(); + } + } catch (Exception e) { + okFlag = false; + LOGGER.error("ERROR trying to delete VID = " + thisVid, e); + } + if (okFlag) { + LOGGER.info(" DELETED VID = " + thisVid); + deletedSomething = true; + } + } + } + } else { + LOGGER.error("ERROR - Vertex Id to keep not found in list of dupes. dupeInfoString = [" + + dupeInfoString + "]"); + return false; + } + } + }// else we know which one to keep + }// else last entry + }// for each vertex in a group + + return deletedSomething; + + }// end of deleteNonKeepersIfAppropriate() + + + /** + * Gets the node just using key params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param keyPropsHash the key props hash + * @param apiVersion the api version + * @return the node just using key params + * @throws AAIException the AAI exception + */ + public static List <TitanVertex> getNodeJustUsingKeyParams( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> keyPropsHash, String apiVersion ) throws AAIException{ + + List <TitanVertex> retVertList = new ArrayList <> (); + + // We assume that all NodeTypes have at least one key-property defined. + // Note - instead of key-properties (the primary key properties), a user could pass + // alternate-key values if they are defined for the nodeType. + List<String> kName = new ArrayList<>(); + List<Object> kVal = new ArrayList<>(); + if( keyPropsHash == null || keyPropsHash.isEmpty() ) { + throw new AAIException("AAI_6120", " NO key properties passed for this getNodeJustUsingKeyParams() request. NodeType = [" + nodeType + "]. "); + } + + int i = -1; + for( Map.Entry<String, Object> entry : keyPropsHash.entrySet() ){ + i++; + kName.add(i, entry.getKey()); + kVal.add(i, entry.getValue()); + } + int topPropIndex = i; + TitanVertex tiV = null; + String propsAndValuesForMsg = ""; + Iterable <?> verts = null; + + try { + if( topPropIndex == 0 ){ + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") "; + verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices(); + } + else if( topPropIndex == 1 ){ + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ") "; + verts = graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has("aai-node-type",nodeType).vertices(); + } + else if( topPropIndex == 2 ){ + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ", " + + kName.get(2) + " = " + kVal.get(2) + ") "; + verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has("aai-node-type",nodeType).vertices(); + } + else if( topPropIndex == 3 ){ + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ", " + + kName.get(2) + " = " + kVal.get(2) + ", " + + kName.get(3) + " = " + kVal.get(3) + ") "; + verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).has("aai-node-type",nodeType).vertices(); + } + else { + throw new AAIException("AAI_6114", " We only support 4 keys per nodeType for now \n"); + } + } + catch( Exception ex ){ + LOGGER.error( " ERROR trying to get node for: [" + propsAndValuesForMsg + "]", ex); + } + + if( verts != null ){ + Iterator <?> vertI = verts.iterator(); + while( vertI.hasNext() ){ + tiV = (TitanVertex) vertI.next(); + retVertList.add(tiV); + } + } + + if( retVertList.size() == 0 ){ + LOGGER.debug("DEBUG No node found for nodeType = [" + nodeType + + "], propsAndVal = " + propsAndValuesForMsg ); + } + + return retVertList; + + }// End of getNodeJustUsingKeyParams() + + /** + * Show all edges for node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param tVert the t vert + * @return the array list + */ + private static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){ + + ArrayList <String> retArr = new ArrayList <> (); + Iterator <Edge> eI = tVert.edges(Direction.IN); + if( ! eI.hasNext() ){ + retArr.add("No IN edges were found for this vertex. "); + } + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + String lab = ed.label(); + TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert); + if( vtx == null ){ + retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< "); + } + else { + String nType = vtx.<String>property("aai-node-type").orElse(null); + String vid = vtx.id().toString(); + retArr.add("Found an IN edge (" + lab + ") to this vertex from a [" + nType + "] node with VtxId = " + vid ); + + } + } + + eI = tVert.edges(Direction.OUT); + if( ! eI.hasNext() ){ + retArr.add("No OUT edges were found for this vertex. "); + } + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + String lab = ed.label(); + TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert); + if( vtx == null ){ + retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< "); + } + else { + String nType = vtx.<String>property("aai-node-type").orElse(null); + String vid = vtx.id().toString(); + retArr.add("Found an OUT edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid ); + } + } + return retArr; + } + + + /** + * Show properties for node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param tVert the t vert + * @return the array list + */ + private static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){ + + ArrayList <String> retArr = new ArrayList <> (); + if( tVert == null ){ + retArr.add("null Node object passed to showPropertiesForNode()\n"); + } + else { + String nodeType = ""; + Object ob = tVert.<Object>property("aai-node-type").orElse(null); + if( ob == null ){ + nodeType = "null"; + } + else{ + nodeType = ob.toString(); + } + + retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]"); + retArr.add(" Property Detail: "); + Iterator<VertexProperty<Object>> pI = tVert.properties(); + while( pI.hasNext() ){ + VertexProperty<Object> tp = pI.next(); + Object val = tp.value(); + retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] "); + } + } + return retArr; + } + + + private static ArrayList <TitanVertex> getConnectedNodes(TitanTransaction g, TitanVertex startVtx ) + throws AAIException { + + ArrayList <TitanVertex> retArr = new ArrayList <> (); + if( startVtx == null ){ + return retArr; + } + else { + GraphTraversal<Vertex, Vertex> modPipe = null; + modPipe = g.traversal().V(startVtx).both(); + if( modPipe != null && modPipe.hasNext() ){ + while( modPipe.hasNext() ){ + TitanVertex conVert = (TitanVertex) modPipe.next(); + retArr.add(conVert); + } + } + } + return retArr; + + }// End of getConnectedNodes() + + + private static ArrayList <TitanVertex> getConnectedChildren( TitanTransaction graph, + TitanVertex startVtx ) throws AAIException{ + + ArrayList <TitanVertex> childList = new ArrayList <> (); + + Iterable <?> verts = startVtx.query().direction(Direction.OUT).has("isParent",true).vertices(); + Iterator <?> vertI = verts.iterator(); + TitanVertex tmpVtx = null; + while( vertI != null && vertI.hasNext() ){ + tmpVtx = (TitanVertex) vertI.next(); + childList.add(tmpVtx); + } + + return childList; + + }// End of getConnectedChildren() + + + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/DbMeth.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/DbMeth.java new file mode 100644 index 00000000..db33e4dc --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/DbMeth.java @@ -0,0 +1,3643 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbgen; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; + +import org.openecomp.aai.dbmodel.DbEdgeRules; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.ingestModel.DbMaps; +import org.openecomp.aai.ingestModel.IngestModelMoxyOxm; +import org.openecomp.aai.serialization.db.EdgeRule; +import org.openecomp.aai.serialization.db.EdgeRules; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.net.InetAddresses; +import com.thinkaurelius.titan.core.TitanEdge; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanTransaction; +import com.thinkaurelius.titan.core.TitanVertex; + + +/** + * General Database-level Utility class. These methods deal with the database one dataNode / Edge at a time. + * Transactions are managed at a higher level by the calling classes by passing in a TitanTransaction object. + */ +public class DbMeth{ + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DbMeth.class); + + /** + * Patch aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param depNodeVal the dep node val + * @param apiVersion the api version + * @return TitanVertex + * @throws AAIException the AAI exception + */ + public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{ + // If they're calling patchAaiNode, then we only want to add/update the properties that they + // pass us in the propHash. If there are others already in the DB, we leave them alone. + + // Note: to be really official, we'd throw an error if the node wasn't already in the db. + boolean[] objectExists = new boolean[1]; + objectExists[0] = true; + Boolean patchOnly = true; + TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists); + return( tv ); + + } // end of patchAaiNode() + + /** + * Patch aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param depNodeVal the dep node val + * @return the titan vertex + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, TitanVertex depNodeVal) throws AAIException{ + return patchAaiNode( transId, fromAppId, graph, nodeType, + propHash, depNodeVal, null ); + } + + /** + * Persist aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param depNodeVal the dep node val + * @param patchOnly the patch only + * @param apiVersion the api version + * @return the titan vertex + * @throws AAIException the AAI exception + */ + public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly, String apiVersion) throws AAIException{ + boolean[] objectExists = new boolean[1]; + objectExists[0] = false; + return persistAaiNodeBASE( transId, fromAppId, graph, nodeType, + propHash, depNodeVal, patchOnly, apiVersion, objectExists); + } + + /** + * Persist aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param addIfNotFound the add if not found + * @param depNodeVal the dep node val + * @param apiVersion the api version + * @return the titan vertex + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion) throws AAIException{ + // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if + // there is already a record in the DB, but they do not pass some of the existing properties, they should + // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false + Boolean patchOnly = false; + boolean[] objectExists = new boolean[1]; + objectExists[0] = false; + TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists); + return( tv ); + } + + /** + * Persist aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param addIfNotFound the add if not found + * @param depNodeVal the dep node val + * @return the titan vertex + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal) throws AAIException{ + // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if + // there is already a record in the DB, but they do not pass some of the existing properties, they should + // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false + Boolean patchOnly = false; + boolean[] objectExists = new boolean[1]; + objectExists[0] = false; + TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, null, objectExists); + return( tv ); + } // end of persistAaiNode() + + /** + * Persist aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param addIfNotFound the add if not found + * @param depNodeVal the dep node val + * @param apiVersion the api version + * @param objectExists the object exists + * @return TitanVertex + * @throws AAIException the AAI exception + */ + public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists) throws AAIException{ + Boolean patchOnly = false; + // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if + // there is already a record in the DB, but they do not pass some of the existing properties, they should + // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false + TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null); + return( tv ); + } + + /** + * Persist aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param addIfNotFound the add if not found + * @param depNodeVal the dep node val + * @param apiVersion the api version + * @param objectExists the object exists + * @param thisNodeVertex the this node vertex + * @return the titan vertex + * @throws AAIException the AAI exception + */ + public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{ + Boolean patchOnly = false; + // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if + // there is already a record in the DB, but they do not pass some of the existing properties, they should + // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false + TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, thisNodeVertex); + return( tv ); + } + + /** + * Persist aai node BASE. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param depNodeVal the dep node val + * @param patchOnly the patch only + * @param apiVersion the api version + * @param objectExists the object exists + * @return the titan vertex + * @throws AAIException the AAI exception + */ + public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly, + String apiVersion, boolean[] objectExists) throws AAIException{ + return persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null); + } + + /** + * Persist aai node BASE. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propHash the prop hash + * @param depNodeVal the dep node val + * @param patchOnly the patch only + * @param apiVersion the api version + * @param objectExists the object exists + * @param thisNodeVertex the this node vertex + * @return the titan vertex + * @throws AAIException the AAI exception + */ + public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly, + String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{ + + if( graph == null ){ + throw new AAIException("AAI_6101", "null graph object passed to persistAaiNodeBASE()"); + } + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + boolean useDepNode = false; + String resourceVersion = null; + if( propHash.containsKey("resource-version") ){ + resourceVersion = (String)(propHash.get("resource-version")); + } + String aaiUniqueKeyVal = null; + if( propHash.containsKey("aai-unique-key") ){ + // Note -- we are assuming that nobody is monkeying with this. The 16-07 first-pass theory + // is that the REST layer is always gonna generate this or pass it through. + aaiUniqueKeyVal = (String)(propHash.get("aai-unique-key")); + propHash.remove("aai-unique-key"); + } + + if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){ + // This kind of node needs a dependent node (for uniqueness) + if( depNodeVal == null ){ + // They should have passed in the node that this one depends on + throw new AAIException("AAI_6109", "null dependentNode object passed to persistAaiNodeBASE() but " + nodeType + " requires one."); + } + else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){ + // They should have passed in the right type of node as the dependent node + throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to persistAaiNodeBASE() for nodeType" + nodeType + "."); + } + useDepNode = true; + } + else { + depNodeVal = null; + } + + // Note: as of 1607, we no longer validate property names since that's covered by the REST layer. + // Same goes for required fields (as of 1602) + + // Special ip-address validation for ipAddr nodes only... This will go away when we go to YANG and + // do validations like this up at that layer. + if( nodeType.equals("ipaddress") ){ + // Note - this will throw an exception if the ipAddress is using a bad format + ipAddressFormatOK( transId, fromAppId, (String)propHash.get("addr"), (String)propHash.get("version") ); + } + + // Use the key-fields/dependentNode to check if this is an add or an update + // We assume that all NodeTypes at least one key-property defined. A dependentNode is optional. + if( ! dbMaps.NodeKeyProps.containsKey(nodeType) ){ + // Problem if no key Properties defined for this nodeType + String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nodeType + " (ver=" + defVer + ")"); + } + + Boolean hasAltKey1 = false; + HashMap <String,Object>nodeAltKey1PropsHash = new HashMap<String,Object>(); + Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion); + if( altKey1Props != null ){ + Iterator <String> altKey1PropI = altKey1Props.iterator(); + while( altKey1PropI.hasNext() ){ + String propName = altKey1PropI.next(); + // NOTE: alt-keys are not always required fields. If it is null or blank, we won't + // do alt-key checks on it. + Object value = propHash.get(propName); + if( value != null && !value.toString().equals("") ){ + hasAltKey1 = true; + nodeAltKey1PropsHash.put(propName, value); + } + } + } + HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>(); + Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion); + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + String propName = keyPropI.next(); + + Object value = propHash.get(propName); + nodeKeyPropsHash.put(propName, value); + } + + // Check if this node is already in the database based on the Primary Key Info + TitanVertex existingVert = thisNodeVertex; + boolean foundTheNodeInDb = true; + + if (existingVert == null) { + try { + existingVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeKeyPropsHash, depNodeVal, apiVersion ); + } + catch (AAIException e) { + if (e.getErrorObject().getErrorCode().equals("6114")) { + foundTheNodeInDb = false; + } + else { + throw e; + } + } + } + + // this is so the notification knows whether or not the operation was an UPDATE or a CREATe + objectExists[0] = foundTheNodeInDb; + if( foundTheNodeInDb ){ + // A record was found in the DB using the PK. + if( needToDoResourceVerCheck(apiVersion, patchOnly) ){ + // Need to check that they knew what they were updating + String existingResVer = existingVert.<String>property("resource-version").orElse(null); + if( resourceVersion == null || resourceVersion.equals("") ){ + throw new AAIException("AAI_6130", "Resource-version not passed for update of = " + nodeType + ", " + nodeKeyPropsHash.toString()); + } + else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){ + throw new AAIException("AAI_6131", "Resource-version " + resourceVersion + " MISMATCH WITH EXISTING " + existingResVer + " for update of = " + nodeType + ", " + nodeKeyPropsHash.toString()); + } + } + + // Need to ensure that the Alternate key isn't changing to a value that points to a different existing node. + // It is ok if it points to nothing -- that would just be an update for this node. It's also ok if + // it points to this (existing) node - that just means that it wasn't being updated. + if( hasAltKey1 ){ + try { + TitanVertex chkVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion ); + if( ! chkVert.id().toString().equals(existingVert.id().toString()) ){ + throw new AAIException("AAI_6117", "In-Use AlternateKey value passed for update of nodeType = " + nodeType); + } + } + catch (AAIException e) { + if(! e.getErrorObject().getErrorCode().equals("6114") ){ + throw e; + } + } + } + } + else { + // Note not in the DB -- This will be an ADD of a new node + // a) make sure they didn't say they were just doing "patchOnly" which cannot be an ADD. + // b) if there is an alternate key, we need to make sure the AK isn't already in use by somebody else. + if( patchOnly ){ + String depMsg = ""; + if( useDepNode ){ + depMsg = " plus dependent node. "; + } + throw new AAIException("AAI_6114", "Patch Request, but no Node of type " + nodeType + " found for properties: [" + propHash + "] " + depMsg); + } + + if( needToDoResourceVerCheck(apiVersion, patchOnly) && (resourceVersion != null) && !resourceVersion.equals("") ){ + throw new AAIException("AAI_6131", "Resource-version was passed in, but this is an ADD of a " + nodeType + ", with these params: " + nodeKeyPropsHash.toString()); + } + if( hasAltKey1 ){ + try { + getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion ); + // Since the Primary Key for this nodeType wasn't found in the DB yet, the fact that + // we are able to find a record (no "6114" exception thrown) using the Alternate-Key is an error. + // We can't create a new node that uses an AK that's already in use. + throw new AAIException("AAI_6117", "Conflicting Key and Alternate-Key values passed for add of nodeType = " + nodeType); + } + catch (AAIException e) { + if(! e.getErrorObject().getErrorCode().equals("6114") ){ + throw e; + } + } + } + } + + // ------------- Done with checking. Do the add or update to the dB ----------------------- + + if( foundTheNodeInDb ){ + long unixTimeNow = System.currentTimeMillis() / 1000L; + // ----- This is an UPDATE ------ + + + String existingSourceOfTruth = fromAppId; // default value if we can't get the old one + Object tmpOb = existingVert.<Object>property("source-of-truth").orElse(null); + if( tmpOb != null ){ + existingSourceOfTruth = tmpOb.toString(); + } + long existingCreateTs = unixTimeNow; // default value if we can't get the old one + tmpOb = existingVert.<Object>property("aai-created-ts").orElse(null); + if( tmpOb != null ){ + existingCreateTs = (long) tmpOb; + } + + String msg = "UPDATE vertex of type = [" + nodeType + "] "; + if( useDepNode ){ + String depNType = depNodeVal.<String>property("aai-node-type").orElse(null); + HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal); + LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash + + "] which rides on dependent node: type = " + depNType + ", with key(s) = [" + depNodePropKeysHash + "]."); + } + else { + LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash + "] (no dep. node)."); + } + String removeList = ""; + if( ! patchOnly ){ + // They are updating an existing record, and they want us to "process all defined properties" (not just patch) + // So we will see if the node has any properties that were not passed-in. Those need to be removed. + Collection <String> propCol = dbMaps.NodeProps.get(nodeType); + Iterator <String> propIter = propCol.iterator(); + while( propIter.hasNext() ){ + String propName = propIter.next(); + if( ! propHash.containsKey(propName) && !DbEdgeRules.ReservedPropNames.containsKey(propName)){ + if( thisPropertyWasPutByNewerVersionOfCode(apiVersion, nodeType, propName) ){ + // we must be using an older version of code here - but the property that + // has not been passed in this persist call is one that this older version of + // the database did not know about. So leave it alone. + } + else { + removeList = removeList + "," + propName; + existingVert.property(propName).remove(); + } + } + } + } + if( !removeList.equals("") ){ + LOGGER.info("Removed these props on update: [" + removeList + "]"); + } + for( Map.Entry<String, Object> entry : propHash.entrySet() ){ + // update the parameters that have been passed in (except the key-properties) + // taking away the key-property check. We will now allow this since + // the keys were used to identify this node, so they should be good and + // there are times when Titan resolves conflicts by only using the + // data set in an update - and was losing our key info... + // Similar to the change noted below. + //if( ! nodeKeyPropsHash.containsKey(entry.getKey()) ){ + // existingVert.setProperty( entry.getKey(), entry.getValue() ); + //} + if( ! entry.getKey().equals("resource-version") ){ + boolean nonSingleCardinality = false; + boolean setSoNoDupes = false; + if( checkPropCardinality(entry.getKey(), "Set") ){ + nonSingleCardinality = true; + setSoNoDupes = true; + } + else if( checkPropCardinality(entry.getKey(), "List") ){ + nonSingleCardinality = true; + } + + Iterator <Object> valIter = null; + if( nonSingleCardinality ){ + String className = entry.getValue().getClass().getSimpleName(); + if( className.equals("ArrayList") ){ + valIter = ((ArrayList)(entry.getValue())).iterator(); + } + else if( className.equals("List") ){ + valIter = ((List)(entry.getValue())).iterator(); + } + else if( className.equals("Set") ){ + valIter = ((Set)(entry.getValue())).iterator(); + } + } + + if( nonSingleCardinality ){ + // This property has Cardinality of List or Set - which need to be handled carefully + // Note -- for Lists or Sets, we assume they are of dataType String - that is all + // the Rest layer supports at the moment (16-02) + ArrayList <String> currentData = new ArrayList <String> (); + if( patchOnly ){ + // When patching - gotta know what's already in the db + Iterator<VertexProperty<Object>> existingPropsIter = (existingVert.properties(entry.getKey())); + if( existingPropsIter != null ){ + while( existingPropsIter.hasNext() ){ + String existingVal = existingPropsIter.next().value().toString(); + currentData.add( existingVal ); + } + } + } + else { + // Since this is not a patch-update, we first have to clear out what is currently in the db. + existingVert.property(entry.getKey()).remove(); + } + + if( valIter != null ){ + while( valIter.hasNext() ){ + Object thisVal = valIter.next(); + if( setSoNoDupes ){ + // For Sets, we need to check that the data isn't already in the db or wasn't passed + // in to us twice in the propHash. Otherwise Titan throws an exception (instead of just ignoring it...) + if( !currentData.contains(thisVal) ){ + // We don't have this data yet, so add it to the Set + existingVert.property( entry.getKey(), thisVal ); + currentData.add( thisVal.toString() ); + } + } + else { + // For List data types, it's ok to have duplicate values in the db (why would we want this?) + existingVert.property( entry.getKey(), thisVal ); + } + } + } + } + else { + // This is a normal, "Cardinality = SINGLE" kind of property + // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below. + //Object cleanVal = convertTypeIfNeeded( entry.getKey(), entry.getValue() ); + //existingVert.setProperty( entry.getKey(), cleanVal ); + // ******************************** + existingVert.property( entry.getKey(), entry.getValue() ); + } + } + } + + // DEBUG - trying to deal with the case where simultaneous PUTs + // cause our db to wind up with a vertex that does not have these three properties filled in. + existingVert.property( "aai-node-type", nodeType ); + existingVert.property( "aai-created-ts", existingCreateTs ); + existingVert.property( "source-of-truth", existingSourceOfTruth ); + + if( aaiUniqueKeyVal != null ){ + existingVert.property( "aai-unique-key", aaiUniqueKeyVal ); + } + + existingVert.property( "aai-last-mod-ts", unixTimeNow ); + String resVers = "" + unixTimeNow; + existingVert.property( "resource-version", resVers ); + existingVert.property( "last-mod-source-of-truth", fromAppId ); + + LOGGER.info(msg + ", [aai-last-mod-ts]/[" + unixTimeNow + "]"); + + return( existingVert ); + } + else{ + // ----- Not found in the DB, This must be an ADD ------ + if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){ + throw new AAIException("AAI_6120", "nodeTypeCategory " + nodeType + " cannot be used to ADD a node. Need to pass a valid nodeType"); + } + + TitanVertex tiVnew = graph.addVertex( nodeType ); + + String msg = "ADD vertex of type = [" + nodeType + "] "; + if( depNodeVal != null ){ + String depNType = depNodeVal.<String>property("aai-node-type").orElse(null); + HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal); + msg = msg + " onto dependent node: type = " + depNType + ", which has key(s) = [" + depNodePropKeysHash + + "]. New Node Prop/values = "; + } + else { + msg = msg + " Note: no dependent node. New Node Prop/values = "; + } + boolean first = true; + for( Map.Entry<String, Object> entry : propHash.entrySet() ){ + if( ! entry.getKey().equals("resource-version") ){ + if( first ){ + msg = msg + " [" + entry.getKey() + "]/[" + entry.getValue() + "]"; + first = false; + } + else { + msg = msg + ", [" + entry.getKey() + "]/[" + entry.getValue() + "]"; + } + + boolean nonSingleCardinality = false; + boolean setSoNoDupes = false; + if( checkPropCardinality(entry.getKey(), "Set") ){ + nonSingleCardinality = true; + setSoNoDupes = true; + } + else if( checkPropCardinality(entry.getKey(), "List") ){ + nonSingleCardinality = true; + } + + Iterator <Object> valIter = null; + if( nonSingleCardinality ){ + String className = entry.getValue().getClass().getSimpleName(); + if( className.equals("ArrayList") ){ + valIter = ((ArrayList)(entry.getValue())).iterator(); + } + else if( className.equals("List") ){ + valIter = ((List)(entry.getValue())).iterator(); + } + else if( className.equals("Set") ){ + valIter = ((Set)(entry.getValue())).iterator(); + } + } + + if( nonSingleCardinality ){ + // This property has Cardinality of List or Set - which need to be handled carefully + ArrayList <String> currentData = new ArrayList <String> (); + if( valIter != null ){ + while( valIter.hasNext() ){ + Object thisVal = valIter.next(); + if( setSoNoDupes ){ + // For Sets, we need to check that they're not passing us duplicate data in propHash. + // Otherwise Titan throws an exception (instead of just ignoring it...) + if( !currentData.contains(thisVal) ){ + // We don't have this data yet, so add it to the Set + tiVnew.property( entry.getKey(), thisVal ); + currentData.add( thisVal.toString() ); + } + } + else { + // For List data types, it's ok to have duplicate values in the db (why would we want this?) + tiVnew.property( entry.getKey(), thisVal ); + } + } + } + } + else { + // This is a normal, "Cardinality = SINGLE" kind of property + // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below. + tiVnew.property( entry.getKey(), entry.getValue() ); + } + } + } + + tiVnew.property( "aai-node-type", nodeType ); + //long unixTime = System.currentTimeMillis() / 1000L; + long unixTime = System.currentTimeMillis(); + tiVnew.property( "aai-created-ts", unixTime ); + tiVnew.property( "aai-last-mod-ts", unixTime ); + String resVers = "" + unixTime; + tiVnew.property( "resource-version", resVers ); + tiVnew.property( "source-of-truth", fromAppId ); + tiVnew.property( "last-mod-source-of-truth", fromAppId ); + if( aaiUniqueKeyVal != null ){ + tiVnew.property( "aai-unique-key", aaiUniqueKeyVal ); + } + + LOGGER.info(msg + ", [aai-created-ts]/[" + unixTime + "]"); + return( tiVnew ); + } + + } // end of persistAaiNodeBASE() + + + /** + * Need to do resource ver check. + * + * @param apiVersion the api version + * @param patchOnlyFlag the patch only flag + * @return the boolean + * @throws AAIException the AAI exception + */ + public static Boolean needToDoResourceVerCheck(String apiVersion, Boolean patchOnlyFlag) + throws AAIException{ + + if( patchOnlyFlag ){ + // we do not do resource checking for patch requests. + return false; + } + + String resourceCheckOnFlag = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG); + + int apiVerInt = cleanUpApiVersion(apiVersion); + + if( (resourceCheckOnFlag != null) && resourceCheckOnFlag.equals("true") ){ + // Only do the check if the resource enable flag is set to "true" + if( apiVerInt > 4 ){ + // We're only doing the resource version checks for v5 and later + return true; + } + } + + return false; + }// End needToDoResourceVerCheck() + + + /** + * Clean up api version. + * + * @param apiVersionString the api version string + * @return the int + * @throws AAIException the AAI exception + */ + private static int cleanUpApiVersion( String apiVersionString ) throws AAIException { + // Note: we expect an apiVersion to start with the letter "v", followed by an integer. + + int versionInt = 0; + String verStr = apiVersionString; + if( (apiVersionString == null) || (apiVersionString.length() < 2) ){ + // Passed in version doesn't look right + verStr = org.openecomp.aai.util.AAIApiVersion.get(); + } + versionInt = getVerNumFromVerString( verStr ); + + return versionInt; + } + + /** + * Gets the ver num from ver string. + * + * @param versionString the version string + * @return the ver num from ver string + * @throws AAIException the AAI exception + */ + private static int getVerNumFromVerString( String versionString )throws AAIException { + int versionInt = 0; + if( versionString == null || versionString.length() < 2 ){ + throw new AAIException("AAI_6121", " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "]."); + } + + int strLen = versionString.length(); + // We assume that a version looks like "v" followed by an integer + if( ! versionString.substring(0,1).equals("v") ){ + String detail = " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "]."; + throw new AAIException("AAI_6121", detail); + } + else { + String intPart = versionString.substring(1,strLen); + try { + versionInt = Integer.parseInt( intPart ); + } + catch( Exception e ){ + String detail = " Bad Version passed to getVerNumFromVerString: [" + versionString + "]."; + throw new AAIException("AAI_6121", detail); + } + } + return versionInt; + } + + + /** + * Gets the node key prop names. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param apiVersion the api version + * @return HashMap of keyProperties + * @throws AAIException the AAI exception + */ + public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{ + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + Collection <String> keyProps = new ArrayList <String>(); + if( dbMaps.NodeKeyProps.containsKey(nodeType) ){ + keyProps = dbMaps.NodeKeyProps.get(nodeType); + } + else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){ + // The passed-in nodeType was really a nodeCategory, so we need to look up the key params + Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); + Iterator <String> catItr = nTypeCatCol.iterator(); + String catInfo = ""; + if( catItr.hasNext() ){ + // For now, we only look for one. + catInfo = catItr.next(); + } + else { + String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")"); + } + + String [] flds = catInfo.split(","); + if( flds.length != 4 ){ + throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data for nodeType = [" + nodeType + "]."); + } + + String keyPropsString = flds[0]; + String [] propNames = keyPropsString.split("\\|"); + for( int i = 0; i < propNames.length; i++ ){ + keyProps.add(propNames[i]); + } + } + else { + String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")"); + } + + return keyProps; + + }// end of getNodeKeyPropNames + + /** + * Gets the node key prop names. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @return the node key prop names + * @throws AAIException the AAI exception + */ + @Deprecated + public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType ) throws AAIException{ + return getNodeKeyPropNames( transId, fromAppId, nodeType, null); + } + + /** + * Gets the node alt key 1 prop names. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param apiVersion the api version + * @return HashMap of keyProperties + * @throws AAIException the AAI exception + */ + public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{ + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + Collection <String> altKey1Props = new ArrayList <String>(); + if( dbMaps.NodeAltKey1Props.containsKey(nodeType) ){ + altKey1Props = dbMaps.NodeAltKey1Props.get(nodeType); + } + else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){ + // The passed-in nodeType was really a nodeCategory, so we need to look up the key params + Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); + Iterator <String> catItr = nTypeCatCol.iterator(); + String catInfo = ""; + if( catItr.hasNext() ){ + catInfo = catItr.next(); + String [] flds = catInfo.split(","); + if( flds.length != 4 ){ + throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "]."); + } + + String altKeyPropsString = flds[1]; + String [] propNames = altKeyPropsString.split("\\|"); + for( int i = 0; i < propNames.length; i++ ){ + altKey1Props.add(propNames[i]); + } + } + } + + return altKey1Props; + + }// end of getNodeAltKey1PropNames + + /** + * Gets the node alt key 1 prop names. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @return the node alt key 1 prop names + * @throws AAIException the AAI exception + */ + @Deprecated + public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType ) throws AAIException{ + return getNodeAltKey1PropNames( transId, fromAppId, nodeType, null); + } + + + /** + * Gets the unique node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param keyPropsHash the key props hash + * @param depNodeVal the dep node val + * @param apiVersion the api version + * @return TitanVertex + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{ + + // NOTE - this is really for use by the PersistNode method -- it is looking to see if + // a node exists in the database given either Primary or Alternate Key data and dependent + // node data (if required for uniqueness). + + // Note - the passed in nodeType could really be a nodeTypeCategory --- + Boolean nodeTypeIsCategory = DbEdgeRules.NodeTypeCategory.containsKey(nodeType); + + Boolean useDepNode = false; + if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){ + // This kind of node depends on another node for uniqueness + if( depNodeVal == null ){ + // They should have passed in the node that this one depends on + throw new AAIException("AAI_6109", "null dependentNode object passed to getUniqueNode() but " + nodeType + " requires one."); + } + else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){ + // They should have passed in the right type of node as the dependent node + throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to getUniqueNode() for nodeType" + nodeType + ".\n"); + } + useDepNode = true; + } + else { + depNodeVal = null; + } + + // We assume that all NodeTypes have at least one key-property defined. A dependentNode is optional. + // Note - instead of key-properties (the primary key properties), a user could pass + // alternate-key values if they are defined for the nodeType. + ArrayList<String> kName = new ArrayList<String>(); + ArrayList<Object> kVal = new ArrayList<Object>(); + + Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion); + Iterator <String> keyPropI = keyProps.iterator(); + Boolean haveSomePrimKeyProps = false; + Boolean primaryKeyComplete = true; + while( keyPropI.hasNext() ){ + haveSomePrimKeyProps = true; + + String propName = keyPropI.next(); + if( ! keyPropsHash.containsKey(propName) ){ + primaryKeyComplete = false; + } + else { + Object valObj = keyPropsHash.get(propName); + if( valObj == null ){ + primaryKeyComplete = false; + } + else { + String value = valObj.toString(); + if( value == null || value.equals("") ){ + // They passed the property name, but no value + primaryKeyComplete = false; + } + } + } + } + + int i = -1; + if( haveSomePrimKeyProps && primaryKeyComplete ){ + keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + String propName = keyPropI.next(); + String value = (keyPropsHash.get(propName)).toString(); + i++; + kName.add(i, propName); + kVal.add(i, (Object)value); + } + } + else { + // See if they're using the alternate key + Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion); + Iterator <String> altKey1PropI = altKey1Props.iterator(); + Boolean haveSomeAltKey1Props = false; + Boolean altKey1Complete = true; + while( altKey1PropI.hasNext() ){ + haveSomeAltKey1Props = true; + String propName = altKey1PropI.next(); + if( ! keyPropsHash.containsKey(propName) ){ + altKey1Complete = false; + } + else { + Object valObj = keyPropsHash.get(propName); + if( valObj == null ){ + altKey1Complete = false; + } + else { + String value = valObj.toString(); + if( value == null || value.equals("") ){ + // They passed the property name, but no value + altKey1Complete = false; + } + } + } + } + if( haveSomeAltKey1Props && altKey1Complete ){ + altKey1PropI = altKey1Props.iterator(); + while( altKey1PropI.hasNext() ){ + String propName = altKey1PropI.next(); + String value = (keyPropsHash.get(propName)).toString(); + i++; + kName.add(i, propName); + kVal.add(i, (Object)value); + } + } + } + + int topPropIndex = i; + TitanVertex tiV = null; + String propsAndValuesForMsg = ""; + if( !useDepNode ){ + // There is no node that this type of node depends on, so we can look for it based + // solely on the Aai-defined key fields. + Iterable <?> verts = null; + + if( topPropIndex == -1 ){ + // Problem if no key Properties defined for this nodeType + String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + throw new AAIException("AAI_6105", "Bad or Incomplete Key Property params: (" + keyPropsHash.toString() + + ") for nodeType: " + nodeType + " (ver=" + defVer + ")"); + } + else if( topPropIndex == 0 ){ + if (nodeTypeIsCategory) // dont know real type + verts= graph.query().has(kName.get(0),kVal.get(0)).vertices(); + else // need this to find dvs switch: dvs.switch-name and port-group.switch-name issue + verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") "; + } + else if( topPropIndex == 1 ){ + verts = graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ") "; + } + else if( topPropIndex == 2 ){ + verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ", " + + kName.get(2) + " = " + kVal.get(2) + ") "; + } + else if( topPropIndex == 3 ){ + verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ", " + + kName.get(2) + " = " + kVal.get(2) + ", " + + kName.get(3) + " = " + kVal.get(3) + ") "; + } + else { + String emsg = " We only support 4 keys per nodeType for now \n"; + throw new AAIException("AAI_6114", emsg); + } + + Iterator <?> vertI = verts.iterator(); + if( vertI != null && vertI.hasNext()) { + // We found a vertex that meets the input criteria. + tiV = (TitanVertex) vertI.next(); + + if( vertI.hasNext() ){ + // Since this routine is looking for a unique node for the given input values, if + // more than one is found - it's a problem. + throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg); + } + } + else { + // No Vertex was found for this key - throw a not-found exception + throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg); + } + } + else { + // Need to use the dependent vertex to look for this one. + // filter this to the actual keys because + HashMap<String,Object> onlyKeysHash = new HashMap<String,Object>(); + + Collection <String> onlyKeyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion); + + Iterator <String> onlyKeyPropsI = onlyKeyProps.iterator(); + + while( onlyKeyPropsI.hasNext() ){ + String keyName = onlyKeyPropsI.next(); + onlyKeysHash.put(keyName, keyPropsHash.get(keyName)); + } + + propsAndValuesForMsg = onlyKeysHash.toString() + " combined with a Dependent [" + depNodeVal.<String>property("aai-node-type").orElse(null) + "] node."; + ArrayList<TitanVertex> resultList = DbMeth.getConnectedNodes(transId, fromAppId, graph, nodeType, onlyKeysHash, + depNodeVal, apiVersion, false); + if( resultList.size() > 1 ){ + // More than one vertex found when we thought there should only be one. + throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg); + } + else if( resultList.size() == 1 ){ + tiV = resultList.get(0); + } + } + + if( tiV == null ){ + // No Vertex was found for this key - throw a not-found exception + throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg); + } + else { + if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){ + // The nodeType passed in was a real one, not a nodeTypeCategory, so we will + // use it as part of the query to make sure we find the right type of node. + // This can be an issue if they're using nodeTypes covered by a nodeTypeCategory but + // pass in the wrong nodeType. We don't want them to ask for one thing and get the other. + String foundNodeType = tiV.<String>property("aai-node-type").orElse(null); + if( foundNodeType != null && !foundNodeType.equals(nodeType) ){ + throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg + " (did find a " + foundNodeType + " though.)"); + } + } + + return tiV; + } + + }// End of getUniqueNode() + + /** + * Gets the unique node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param keyPropsHash the key props hash + * @param depNodeVal the dep node val + * @return the unique node + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal) throws AAIException { + return getUniqueNode( transId, fromAppId, graph, nodeType, + keyPropsHash, depNodeVal, null ); + } + // End getUniqueNode() + + + /** + * Gets the unique node with dep params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param nodePropsHash the node props hash + * @param apiVersion the api version + * @return TitanVertex + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> nodePropsHash, String apiVersion ) + throws AAIException{ + /* + * This method uses the nodePropsHash to walk back over dependent nodes until it finds one that + * does not depend on any other for uniqueness. It uses the getUniqueNode() method as it finds + * dependent nodes. NOTE -- it is passed a hash of all the nodeProperties -- for itself and + * for any dependent nodes that it will need to find. There are some types of nodes that can + * depend on more than one node, we assume that there wouldn't be a case where BOTH types of + * dependent nodes are in the trail that we need to traverse. Ie. an ipaddress can depend on + * either a vserver or pserver. NOTE this case can now happen -- nodePropsHash + * should now be sent as a LinkedHashMap in this case so we can search in order. + */ + + // NOTE ALSO -- We're currently supporting 6 layers of dependency. We never thought there would be this + // many layers before hitting a node-type that would be uniquely identifiable on it's own. So the + // code is a little ugly with all these nested if-then-else's. Since we're supporting so many + // layers, it should be re-written so we can support "n" layers instead of having to go in hear + // and adding code... But as of 15-07, we really don't NEED more than 5. + + // NOTE: The passed in nodeType could really be a nodeTypeCategory -- + // The calls to figureDepNodeTypeForRequest() below will deal with it for the dep nodes, the + // call to getUniqueNode() takes care of it for the node itself. + + TitanVertex nullVert = null; + String depNodeType = figureDepNodeTypeForRequest( transId, fromAppId, nodeType, nodePropsHash, apiVersion ); + if( depNodeType.equals("")){ + // This kind of node does not depend on another node for uniqueness, so + // we can just use the "getUniqueNode()" method to get it. + HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion); + return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, nullVert, apiVersion) ); + } + else { + // Will need to find the second-layer dependent node + String secondLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, depNodeType, nodePropsHash, apiVersion ); + if( secondLayerDepNodeType.equals("")){ + // This second-layer kind of node does not depend on another node for uniqueness. + // So once we find the second-layer node, we can use it to get the top-layer guy. + HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion); + TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, nullVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion); + return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) ); + } + else { + // Will need to find the third-layer dependent node + /// String thirdLayerDepNodeType = dbMaps.NodeDependencies.get(secondLayerDepNodeType); + String thirdLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion ); + + if( thirdLayerDepNodeType.equals("")){ + // This third-layer kind of node does not depend on another node for uniqueness. + // So we can find it, and then use it to find the second-layer and then use that to find the top guy. + HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion); + TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion); + + return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) ); + } + else { + // Will need to find the third-layer dependent node + String forthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion ); + if( forthLayerDepNodeType == null || forthLayerDepNodeType.equals("")){ + // This forth-layer kind of node does not depend on another node for uniqueness. + // So we can find it, and then use it to find the third, then second-layer and then use that to find the top guy. + HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion); + TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion); + return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) ); + } + else { + // Will need to find the forth-layer dependent node + String fifthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion ); + if( fifthLayerDepNodeType == null || fifthLayerDepNodeType.equals("")){ + // This fifth-layer kind of node does not depend on another node for uniqueness. + // So we can find it, and then use it to find the forth, third, then second-layer and then use that to find the top guy. + HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion); + TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion); + return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) ); + } + else { + // Will need to find the fifth-layer dependent node + String sixthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion ); + if( sixthLayerDepNodeType == null || sixthLayerDepNodeType.equals("")){ + // This six-layer kind of node does not depend on another node for uniqueness. + // So we can find it, and then use it to find the fifth, forth, third, then second-layer and then use that to find the top guy. + HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex sixthLayerDepVert = getUniqueNode(transId, fromAppId, graph, fifthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, sixthLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion); + TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion); + TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion); + + thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion); + return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) ); + } + else { + // We don't currently support more layers. We can later if we need to. + // Hopefully, we'll never need to go this deep -- there should be unique keys in there somewhere! + throw new AAIException("AAI_6114", "CODE-LIMITATION - Can't resolve dependant node layers for nodeType = " + nodeType); + } + } + } + } + } + } + } // End getUniqueNodeWithDepParams() + + /** + * Gets the unique node with dep params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param nodePropsHash the node props hash + * @return the unique node with dep params + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> nodePropsHash ) throws AAIException { + return getUniqueNodeWithDepParams(transId, fromAppId, graph, nodeType, nodePropsHash, null); + } + + + /** + * Gets the this node type params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param targetNodeType the target node type + * @param passedHash the passed hash + * @param apiVersion the api version + * @return the this node type params + * @throws AAIException the AAI exception + */ + private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType, + HashMap<String,Object> passedHash, String apiVersion )throws AAIException{ + /* + * For the passed-in hash, each key is assumed to look like, "nodeType.paramName". We want to + * pick out the entries that match the targetNodeType and return those with the values they go with. The + * returned keys will have the "nodeType." stripped off. + * + * NOTE - the nodeType passed to this method could actually be a nodeTypeCategory. Just keepin it ugly. + */ + + if( passedHash == null ){ + throw new AAIException("AAI_6120", "Bad param: null passedHash "); + } + + String targetNodeTypeCat = ""; + if( DbEdgeRules.NodeTypeCatMap.containsKey(targetNodeType) ){ + targetNodeTypeCat = DbEdgeRules.NodeTypeCatMap.get(targetNodeType); + } + + HashMap <String,Object> returnHash = new HashMap <String,Object> (); + Iterator <Map.Entry<String,Object>>it = passedHash.entrySet().iterator(); + while( it.hasNext() ){ + Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next(); + String k = (pairs.getKey()).toString(); + int periodLoc = k.indexOf("."); + if( periodLoc <= 0 ){ + throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n"); + } + else { + String nty = k.substring(0,periodLoc); + String paramName = k.substring(periodLoc + 1); + if( nty.equals(targetNodeType) || (!targetNodeTypeCat.equals("") && nty.equals(targetNodeTypeCat)) ){ + String newK = paramName; + returnHash.put( newK,pairs.getValue() ); + } + } + } + + //aaiLogger.debug(logline, " - end "); + return returnHash; + + }// End of getThisNodeTypeParams() + + /** + * Gets the this node type params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param targetNodeType the target node type + * @param passedHash the passed hash + * @return the this node type params + * @throws AAIException the AAI exception + */ + @Deprecated + private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType, + HashMap<String,Object> passedHash )throws AAIException{ + return getThisNodeTypeParams( transId, fromAppId, targetNodeType, + passedHash, null); + + } + + /** + * Gets the dep node types. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param apiVersion the api version + * @return the dep node types + * @throws AAIException the AAI exception + */ + public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{ + /* + * This returns any nodeTypes that this nodeType can be dependent on. A particular instance of a node will only + * depend on one other node - we don't currently support dependence on multiple nodes. + */ + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + ArrayList <String> depNodeTypeL = new ArrayList <String> (); + if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){ + // This is a good-ole nodeType + Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType); + Iterator <String> ntItr = depNTColl.iterator(); + while( ntItr.hasNext() ){ + depNodeTypeL.add(ntItr.next()); + } + } + else { + // The passed-in nodeType must really be a nodeTypeCategory + Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); + Iterator <String> catItr = nTypeCatCol.iterator(); + String catInfo = ""; + if( catItr.hasNext() ){ + // For now, we only look for one. + catInfo = catItr.next(); + } + else { + throw new AAIException("AAI_6121", "Error getting DbEdgeRules.NodeTypeCategory info for nodeTypeCat = " + nodeType); + } + + String [] flds = catInfo.split(","); + if( flds.length != 4 ){ + throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "]."); + } + + String nodeTypesString = flds[0]; + String hasDepNodes = flds[3]; + if( hasDepNodes.equals("true") ){ + String [] ntNames = nodeTypesString.split("\\|"); + for( int i = 0; i < ntNames.length; i++ ){ + Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType); + Iterator <String> ntItr = depNTColl.iterator(); + while( ntItr.hasNext() ){ + String depNode = ntItr.next(); + if( !depNodeTypeL.contains(depNode) ){ + depNodeTypeL.add(depNode); + } + } + } + } + } + + + return depNodeTypeL; + + }// End getDepNodeTypes() + + /** + * Gets the dep node types. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @return the dep node types + * @throws AAIException the AAI exception + */ + @Deprecated + public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType)throws AAIException{ + return getDepNodeTypes( transId, fromAppId, nodeType, null); + } + + /** + * Gets the default delete scope. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param apiVersion the api version + * @return the default delete scope + * @throws AAIException the AAI exception + */ + private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{ + + // At some point we may have different delete rules for different services, so this is + // a list for now even thought there's only one scope per nodeType. + Collection <String> scopeList = DbEdgeRules.DefaultDeleteScope.get(nodeType); + if( scopeList.isEmpty() ){ + throw new AAIException("AAI_6121", "No default deleteScope found for nodeType = [" + nodeType + "] "); + } + else { + Iterator <String> ito = scopeList.iterator(); + return ito.next(); + } + + }// End getDefaultDeleteScope() + + /** + * Gets the default delete scope. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @return the default delete scope + * @throws AAIException the AAI exception + */ + @Deprecated + private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType)throws AAIException{ + return getDefaultDeleteScope( transId, fromAppId, nodeType, null); + } + + /** + * Needs A dep node 4 uniqueness. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param apiVersion the api version + * @return the boolean + * @throws AAIException the AAI exception + */ + public static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{ + // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes() + + ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion); + if( depList.isEmpty() ){ + return false; + } + else { + return true; + } + + }// End needsADepNode4Uniqueness() + + /** + * Needs A dep node 4 uniqueness. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @return the boolean + * @throws AAIException the AAI exception + */ + @Deprecated + private static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType)throws AAIException{ + return needsADepNode4Uniqueness( transId, fromAppId, nodeType, null); + } + + /** + * Node type A can depend on B. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeTypeA the node type A + * @param nodeTypeB the node type B + * @param apiVersion the api version + * @return the boolean + * @throws AAIException the AAI exception + */ + public static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB, String apiVersion) + throws AAIException{ + // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes() + + ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeTypeA, apiVersion); + if( depList.isEmpty() ){ + return false; + } + else if( depList.contains(nodeTypeB) ){ + return true; + } + else { + return false; + } + + }// End nodeTypeACanDependOnB() + + /** + * Node type A can depend on B. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeTypeA the node type A + * @param nodeTypeB the node type B + * @return the boolean + * @throws AAIException the AAI exception + */ + @Deprecated + private static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB) + throws AAIException{ + return nodeTypeACanDependOnB( transId, fromAppId, nodeTypeA, nodeTypeB, null); + } + + /** + * Figure dep node type for request. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param requestParamHash the request param hash + * @param apiVersion the api version + * @return the string + * @throws AAIException the AAI exception + */ + public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType, + HashMap<String,Object> requestParamHash, String apiVersion )throws AAIException{ + /* + * This is ugly. But if the passed-in nodeType is dependent on another nodeType for + * uniqueness, we need to return what that dependent node-type is. The ugly comes in + * because a node can be dependent on more than one type of node. So, to tell which one + * is going to apply, we root through the passed request parameters to see which of + * the possible dependent node types is being used. + * Note -- if there comes a day when there are so many dependencies that the request could + * have more than one that match -- Then we need to think up something new. But for now, + * we have to assume that if there are more than one legal dep-node-types, only one will + * be represented in the requestHash data. >>> NOTE >>> That day has come. For + * the upstreamers will send in a LinkedHashMap instead of just an unordered + * HashMap so we can look in order for the dependent node. + * + */ + + if( requestParamHash == null ){ + throw new AAIException("AAI_6120", "Bad param: null requestParamHash "); + } + + ArrayList <String> depNodeTypes = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion); + if( depNodeTypes.isEmpty() ){ + // This kind of node is not dependent on any other + //aaiLogger.debug(logline, " (not dependent) - end "); + return ""; + } + else if( depNodeTypes.size() == 1 ){ + // This kind of node can only depend on one other nodeType - so return that. + //aaiLogger.debug(logline, " (depends on " + depNodeTypes.get(0) + " - end "); + return depNodeTypes.get(0); + } + else { + // We need to look to find the first of the dep-node types that is represented in the passed-in + // request data. That will be the one we need to use. + + // first find out what node-types are represented in the requestHash + + Iterator <Map.Entry<String,Object>>it = requestParamHash.entrySet().iterator(); + while( it.hasNext() ){ + Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next(); + String k = (pairs.getKey()).toString(); + int periodLoc = k.indexOf("."); + if( periodLoc <= 0 ){ + throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n"); + } + else { + String nty = k.substring(0,periodLoc); + if( depNodeTypes.contains(nty) ){ + // This is the first possible dep. node type we've found for the passed in data set + return nty; + } + } + } + + } + + // It's not an error if none is found - the caller needs to deal with cases where there + // should be a dep. node identified but isn't. + //aaiLogger.debug(logline, " no dep NT found - end "); + return ""; + + }// End of figureDepNodeTypeForRequest() + + /** + * Figure dep node type for request. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param requestParamHash the request param hash + * @return the string + * @throws AAIException the AAI exception + */ + @Deprecated + public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType, + HashMap<String,Object> requestParamHash )throws AAIException{ + return figureDepNodeTypeForRequest( transId, fromAppId, nodeType, requestParamHash, null); + } + + /** + * Detach connected nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param startNodeVal the start node val + * @param autoDeleteOrphans the auto delete orphans + * @param apiVersion the api version + * @return deletedNodeCount + * @throws AAIException the AAI exception + */ + public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans, String apiVersion ) throws AAIException{ + + /* Find nodes that are attached to this node which meet the nodeType/filterParams criteria. + * Remove the edges that go to those nodes. + * If that turns any of the nodes into an orphan, then delete it if the autoDeleteOrphans flag is set. + * Return a count of how many nodes were actually deleted (not just detached). + */ + + int deletedCount = 0; + + if( startNodeVal == null ){ + // They should have passed in the node that this query starts from + throw new AAIException("AAI_6109", "null startNode object passed to detachConnectedNodes()."); + } + + // We want to loop through the connected Nodes that we found. + // For each connected Node, we'll get the all edges that start from that node and look for the one + // that connects back to our startNode. + // Only delete the edge that connects back to our startNode. + // then autoDeleteOrphans flag is set, then delete the connectedNode if it's now orphaned. + // + + String startNodeVId = startNodeVal.id().toString(); + ArrayList<TitanVertex> conNodeList = getConnectedNodes( transId, fromAppId, graph, nodeType, propFilterHash, startNodeVal, apiVersion, false ); + Iterator<TitanVertex> conVIter = conNodeList.iterator(); + while( conVIter.hasNext() ){ + TitanVertex connectedVert = conVIter.next(); + boolean isFirstOne = true; + Iterator<Edge> eI = connectedVert.edges(Direction.BOTH); + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + TitanVertex otherVtx = (TitanVertex) ed.otherVertex(connectedVert); + String otherSideLookingBackVId = otherVtx.id().toString(); + if( startNodeVId.equals(otherSideLookingBackVId) ){ + // This is an edge from the connected node back to our starting node + if( isFirstOne && !eI.hasNext() && autoDeleteOrphans ){ + // This was the one and only edge for this connectedNode, so + // delete the node and edge since flag was set + String resVers = connectedVert.<String>property("resource-version").orElse(null); + removeAaiNode( transId, fromAppId, graph, connectedVert, "USE_DEFAULT", apiVersion, resVers); + deletedCount = deletedCount + 1; + } + else { + removeAaiEdge( transId, fromAppId, graph, ed ); + } + } + isFirstOne = false; + } + } + return deletedCount; + + } // end of detachConnectedNodes() + + + + /** + * Detach connected nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param startNodeVal the start node val + * @param autoDeleteOrphans the auto delete orphans + * @return the int + * @throws AAIException the AAI exception + */ + @Deprecated + public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans ) throws AAIException{ + return detachConnectedNodes( transId, fromAppId, graph, nodeType, + propFilterHash, startNodeVal, autoDeleteOrphans, null); + } + + /** + * Gets the nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param noFilterOnPurpose the no filter on purpose + * @param apiVersion the api version + * @return ArrayList<TitanVertex> + * @throws AAIException the AAI exception + */ + @Deprecated + public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion ) throws AAIException{ + boolean skipGroomingFlag = true; + // we will only do real-time grooming if a system variable is set, telling us not to skip it. + String skipGroomingStr = AAIConstants.AAI_SKIPREALTIME_GROOMING; + if( skipGroomingStr.equals("false") ){ + skipGroomingFlag = false; + } + return( getNodes(transId, fromAppId, graph, nodeType, propFilterHash, noFilterOnPurpose, apiVersion, skipGroomingFlag) ); + } + + /** + * Gets the nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param noFilterOnPurpose the no filter on purpose + * @param apiVersion the api version + * @param skipGroomCheck the skip groom check + * @return ArrayList<TitanVertex> + * @throws AAIException the AAI exception + */ + @Deprecated + public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion, boolean skipGroomCheck ) + throws AAIException{ + // Note - the skipGroomCheck flag is set to true when the DataGrooming tool is using this method to collect + // node data. When the grooming tool is collecting data, we don't want any nodes skipped, because we + // want details about what nodes/edges are bad - more detail than the check in this method does + // as it checks if a node is ok to return to a caller. + + /* Use the nodeType + filterParams to find nodes. + */ + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>(); + if( nodeType == null || nodeType.equals("") ){ + // They should have passed in a nodeType + throw new AAIException("AAI_6118", "Required field: nodeType not passed to getNodes()."); + } + + if( !noFilterOnPurpose && (propFilterHash == null || propFilterHash.isEmpty()) ){ + // They should have passed at least one property to filter on + throw new AAIException("AAI_6118", "Required field: propFilterHash not passed to getNodes()."); + } + + ArrayList<String> kName = new ArrayList<String>(); + ArrayList<Object> kVal = new ArrayList<Object>(); + int i = -1; + Collection <String> indexedProps = dbMaps.NodeMapIndexedProps.get(nodeType); + // First loop through to pick up the indexed-properties if there are any being used + + if( propFilterHash != null ){ + Iterator <?> it = propFilterHash.entrySet().iterator(); + while( it.hasNext() ){ + Map.Entry<?,?> propEntry = (Map.Entry<?,?>) it.next(); + String propName = (propEntry.getKey()).toString(); + // Don't allow search on properties that do not have SINGLE cardinality + if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){ + if( indexedProps.contains(propName) ){ + i++; + kName.add(i, propName); + kVal.add(i, (Object)propEntry.getValue()); + } + } + } + + // Now go through again and pick up the non-indexed properties + it = propFilterHash.entrySet().iterator(); + while( it.hasNext() ){ + Map.Entry <?,?> propEntry = (Map.Entry<?,?>)it.next(); + String propName = (propEntry.getKey()).toString(); + // Don't allow search on properties that do not have SINGLE cardinality + if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){ + if( ! indexedProps.contains(propName) ){ + i++; + kName.add(i, propName); + kVal.add(i, (Object)propEntry.getValue()); + } + } + } + } + + Iterable <?> verts = null; + String propsAndValuesForMsg = ""; + int topPropIndex = i; + if( topPropIndex == -1 ){ + // No Filtering -- just go get them all + verts= graph.query().has("aai-node-type",nodeType).vertices(); + propsAndValuesForMsg = " ( no filter props ) "; + } + else if( topPropIndex == 0 ){ + verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") "; + } + else if( topPropIndex == 1 ){ + verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has("aai-node-type",nodeType).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ") "; + } + else if( topPropIndex == 2 ){ + verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has("aai-node-type",nodeType).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ", " + + kName.get(2) + " = " + kVal.get(2) + ") "; + } + else if( topPropIndex == 3 ){ + verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).has("aai-node-type",nodeType).vertices(); + propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", " + + kName.get(1) + " = " + kVal.get(1) + ", " + + kName.get(2) + " = " + kVal.get(2) + ", " + + kName.get(3) + " = " + kVal.get(3) + ") "; + } + else { + String emsg = " -- Sorry -- we only support 4 filter properties in getNodes() for now... \n"; + throw new AAIException("AAI_6114", emsg); + } + if( verts != null ){ + // We did find some matching vertices + Iterator <?> it = verts.iterator(); + while( it.hasNext() ){ + TitanVertex v = (TitanVertex)it.next(); + + if( skipGroomCheck ){ + // Good or bad, just return everything we find + returnVertList.add( v ); + } + else { + // Weed out any bad vertices we find + if( thisVertexNotReachable(transId, fromAppId, graph, v, apiVersion) ){ + LOGGER.info("IN-LINE GROOMING - Unreachable Node DETECTED > skipping it. "); + } + else if( thisVertexHasBadEdges(transId, fromAppId, graph, v, apiVersion) ){ + LOGGER.info("IN-LINE GROOMING - BAD EDGE DETECTED > skipping vtxId = [" + v.id() + "] "); + } + else if( thisVertexIsAPhantom(transId, fromAppId, graph, v, apiVersion) ){ + LOGGER.info("IN-LINE GROOMING - BAD NODE DETECTED > skipping vtxId = [" + v.id() + "] "); + } + else { + returnVertList.add( v ); + } + } + } + } + + return returnVertList; + } + + /** + * Gets the nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param noFilterOnPurpose the no filter on purpose + * @return the nodes + * @throws AAIException the AAI exception + */ + @Deprecated + public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose ) throws AAIException{ + return getNodes(transId, fromAppId, graph, nodeType, + propFilterHash, noFilterOnPurpose, null ); + } + // End of getNodes() + + + /** + * Gets the connected children. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param startVtx the start vtx + * @param limitToThisNodeType the limit to this node type + * @return ArrayList <TitanVertex> + * @throws AAIException the AAI exception + */ + public static ArrayList<TitanVertex> getConnectedChildren( String transId, String fromAppId, TitanTransaction graph, + TitanVertex startVtx, String limitToThisNodeType ) throws AAIException{ + + // Just get child nodes (ie. other end of an OUT edge that is tagged as a parent/Child edge) + + ArrayList <TitanVertex> childList = new ArrayList <TitanVertex> (); + Boolean doNodeTypeCheck = false; + if( limitToThisNodeType != null && ! limitToThisNodeType.equals("") ){ + doNodeTypeCheck = true; + } + + + List<Vertex> verts = graph.traversal().V(startVtx).union(__.inE().has("isParent-REV", true).outV(), __.outE().has("isParent", true).inV()).toList(); + TitanVertex tmpVtx = null; + int vertsSize = verts.size(); + for (int i = 0; i < vertsSize; i++){ + tmpVtx = (TitanVertex) verts.get(i); + if( ! doNodeTypeCheck ){ + childList.add(tmpVtx); + } + else { + String tmpNT = tmpVtx.<String>property("aai-node-type").orElse(null); + if( tmpNT != null && tmpNT.equals(limitToThisNodeType) ){ + childList.add(tmpVtx); + } + } + } + + return childList; + + }// End of getConnectedChildren() + + + + /** + * Gets the connected nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param startNodeVal the start node val + * @param apiVersion the api version + * @param excludeRecurComingIn the exclude recur coming in + * @return ArrayList <TitanVertex> + * @throws AAIException the AAI exception + */ + public static ArrayList<TitanVertex> getConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion, Boolean excludeRecurComingIn ) throws AAIException{ + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + /* Get (almost) all the nodes that are connected to this vertex. + * Narrow down what is returned using optional filter parameters nodeType and propFilterHash + * NOTE - the default behavior has changed slightly. For start-Nodes that + * can be recursivly connected, this method will only bring back the same kind of + * connected node by following an OUT edge. Ie. if the start node is an "model-element", + * then this method will only follow OUT edges to get to other "model-element" type nodes. + */ + + String startNodeNT = ""; + if( startNodeVal == null ){ + // They should have passed in the node that this query starts from + throw new AAIException("AAI_6109", "null startNode object passed to getConnectedNodes()."); + } + else { + startNodeNT = startNodeVal.<String>property("aai-node-type").orElse(null); + } + + boolean nodeTypeFilter = false; + if( nodeType != null && !nodeType.equals("") ){ + // They want to filter using nodeType + if( ! dbMaps.NodeProps.containsKey(nodeType) ){ + throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to getConnectedNodes()."); + } + nodeTypeFilter = true; + } + + ArrayList <String> excludeVidList = new <String> ArrayList (); + if( DbEdgeRules.CanBeRecursiveNT.containsKey(startNodeNT) && excludeRecurComingIn ){ + // If we're starting on a nodeType that supports recursion, then find any connected + // nodes that are coming from IN edges so we can exclude them later. + + Iterable <?> vertsR = startNodeVal.query().direction(Direction.IN).vertices(); + Iterator <?> vertIR = vertsR.iterator(); + while( vertIR != null && vertIR.hasNext() ){ + TitanVertex tmpVertIN = (TitanVertex) vertIR.next(); + String tmpNT = tmpVertIN.<String>property("aai-node-type").orElse(null); + if( tmpNT != null && tmpNT.equals(startNodeNT) ){ + // We're on a nodetype that supports recursion (like model-element) and we've + // found an connected Node of this same type on an IN edge - put this + // on our excludeList. + excludeVidList.add( tmpVertIN.id().toString() ); + } + } + } + + boolean propertyFilter = false; + if( propFilterHash != null && !propFilterHash.isEmpty() ){ + // They want to filter using some properties + Iterator <?> it = propFilterHash.entrySet().iterator(); + while( it.hasNext() ){ + Map.Entry<?,?> propEntry = (Map.Entry<?,?>)it.next(); + String propName = (propEntry.getKey()).toString(); + if( ! dbMaps.NodeProps.containsValue(propName) ){ + throw new AAIException("AAI_6116", "Unrecognized property name [" + propName + "] passed to getConnectedNodes()."); + } + // Don't allow search on properties that do not have SINGLE cardinality + if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){ + propertyFilter = true; + } + } + } + // If filter-properties were passed in, then look for nodes that have those values. + ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>(); + Iterable<TitanVertex> qResult = null; + Iterator<TitanVertex> resultI = null; + try { + qResult = startNodeVal.query().vertices(); + resultI = qResult.iterator(); + } + catch( NullPointerException npe ){ + throw new AAIException("AAI_6125", "Titan null pointer exception trying to get nodes connected to vertexId = " + + startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "]."); + } + + while( resultI != null && resultI.hasNext() ){ + boolean addThisOne = true; + TitanVertex tmpV = (TitanVertex)resultI.next(); + if( tmpV == null ){ + LOGGER.info("Titan gave a null vertex when looking for nodes connected to vertexId = " + + startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "]."); + // Note - we will skip this one, but try to return any others that we find. + addThisOne = false; + } + + else { + String tmpVid = tmpV.id().toString(); + if( nodeTypeFilter ){ + Object nto = tmpV.<Object>property("aai-node-type").orElse(null); + if( nto == null || !nto.toString().equals(nodeType) ){ + //LOGGER.info("Found a connected vertex (vertexId = " + + // tmpVid + "), but we will not collect it. It had aai-node-type [" + + // nto + "], we are looking for [" + nodeType + "]. "); + // Note - we will skip this one, but try to return any others that we find. + addThisOne = false; + } + } + + if( excludeVidList.contains(tmpVid) ){ + LOGGER.info("Found a connected vertex (vertexId = " + + tmpVid + "), but will exclude it since it is on an IN edge and this nodeType " + + startNodeNT + " can be recursively attached."); + // Note - we will skip this one, but try to return any others that we find. + addThisOne = false; + } + + if( propertyFilter ){ + Iterator <?> it = propFilterHash.entrySet().iterator(); + while( it.hasNext() ){ + Map.Entry <?,?>propEntry = (Map.Entry<?,?>)it.next(); + String propName = (propEntry.getKey()).toString(); + if( checkPropCardinality(propName, "Set") || checkPropCardinality(propName, "List") ){ + // Don't allow search on properties that do not have SINGLE cardinality + continue; + } + Object propVal = propEntry.getValue(); + Object foundVal = tmpV.<Object>property(propName).orElse(null); + if( foundVal != null && propVal != null && !foundVal.toString().equals(propVal.toString()) ){ + addThisOne = false; + break; + } + else if( (foundVal == null && propVal != null) || (foundVal != null && propVal == null) ){ + addThisOne = false; + break; + } + } + } + } + if( addThisOne ){ + // This node passed the tests -- put it on the return List + returnVertList.add( (TitanVertex)tmpV ); + } + } + //aaiLogger.debug(logline, " end "); + return returnVertList; + + }// End of getConnectedNodes() + + + /** + * Gets the connected nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param startNodeVal the start node val + * @param apiVersion the api version + * @return the connected nodes + * @throws AAIException the AAI exception + */ + @Deprecated + public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion ) throws AAIException { + return getConnectedNodes( transId, fromAppId, graph, nodeType, + propFilterHash, startNodeVal, apiVersion, true ); + } + + /** + * Gets the connected nodes. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param nodeType the node type + * @param propFilterHash the prop filter hash + * @param startNodeVal the start node val + * @return the connected nodes + * @throws AAIException the AAI exception + */ + @Deprecated + public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType, + HashMap<String,Object> propFilterHash, TitanVertex startNodeVal ) throws AAIException { + return getConnectedNodes( transId, fromAppId, graph, nodeType, + propFilterHash, startNodeVal, null, true ); + + } + + /** + * Ip address format OK. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param addrVal the addr val + * @param addrVer the addr ver + * @param apiVersion the api version + * @return Boolean + * @throws AAIException the AAI exception + */ + public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer, String apiVersion) throws AAIException{ + + /* NOTE -- the google methods we use do not allow leading zeros in ipV4 addresses. + * So it will reject, "22.33.44.001" + */ + + if( addrVal == null ){ + throw new AAIException("AAI_6120", "Bad data (addrVal = null) passed to ipAddressFormatOK()"); + } + else if( addrVer == null ){ + throw new AAIException("AAI_6120", "Bad data (addrType = null) passed to ipAddressFormatOK()"); + } + + Boolean retVal = false; + Boolean lookingForV4 = false; + Boolean lookingForV6 = false; + InetAddress inetAddr = null; + + if( addrVer.equalsIgnoreCase("v4") || addrVer.equals("ipv4") || addrVer.equals("4")){ + lookingForV4 = true; + } + else if( addrVer.equalsIgnoreCase("v6") || addrVer.equals("ipv6") || addrVer.equals("6")){ + lookingForV6 = true; + } + else { + throw new AAIException("AAI_6120", " Bad data for addressVersion [" + addrVer + "] passed to ipAddressFormatOK()"); + } + + try { + inetAddr = InetAddresses.forString(addrVal); + if( inetAddr instanceof Inet4Address ){ + if( lookingForV4 ){ + retVal = true; + } + else { + throw new AAIException("AAI_6120", "Bad data. Address is a V4, but addressType said it should be V6. [" + + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK()"); + } + } + else if( inetAddr instanceof Inet6Address ){ + if( lookingForV6 ){ + retVal = true; + } + else { + throw new AAIException("AAI_6120", "Bad data. Address is a V6, but addressType said it should be V4. [" + + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK()."); + } + } + } + catch (IllegalArgumentException e) { + throw new AAIException("AAI_6120", "Badly formed ip-address: [" + addrVal + "] passed to ipAddressFormatOK()"); + } + + return retVal; + + }//end of ipAddressFormatOk() + + /** + * Ip address format OK. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param addrVal the addr val + * @param addrVer the addr ver + * @return the boolean + * @throws AAIException the AAI exception + */ + public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer) throws AAIException{ + return ipAddressFormatOK( transId, fromAppId, addrVal, addrVer, null); + } + + /** + * Save aai edge to db. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param edgeLabel the edge label + * @param outV the out V + * @param inV the in V + * @param propHash the prop hash + * @param apiVersion the api version + * @return TitanEdge + * @throws AAIException the AAI exception + */ + private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel, + TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash, String apiVersion) throws AAIException{ + + // If this edge doesn't exist yet, then create it. + + // NOTE - the Titan javaDoc says that there might not always be an id for a node. + // This is the internal-titan-unique-id, not any of our data. + // Not sure how to know when it might be there and when it might not?! + // So far, it has worked for all my testing, but this might warrant some + // further investigation. + + TitanEdge existingEdge = null; + String inVId = inV.id().toString(); + Iterator <Edge> eI = outV.edges(Direction.BOTH, edgeLabel); + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + TitanVertex otherVtx = (TitanVertex) ed.otherVertex(outV); + if( (otherVtx.id().toString()).equals(inVId) ){ + // NOTE -?- Not sure -- at some point we might want to check the edgeLabels also since we might + // want to allow two different-type edges between the same two vertexes? (or maybe not.) + existingEdge = ed; + break; + } + } + + if( existingEdge != null ){ + // This is just an UPDATE + for( Map.Entry<String, Object> entry : propHash.entrySet() ){ + LOGGER.debug("update edge property/val = [" + entry.getKey() + "]/[" + entry.getValue() + "]"); + existingEdge.property( entry.getKey(), entry.getValue() ); + } + + return( existingEdge ); + } + else { + // This is an ADD + + // Uniqueness double-check. This is just to catch the possibility that at the transaction layer, + // if data came in for two identical nodes that point to the same dependant node (for uniqueness), + // we would only be able to catch the problem at the time the edge to the second node is added. + // For example - if they had a VM and then got a request to add two ipAddress nodes, but some + // bad data was passed and those two ipAddress nodes were identical -- we'd want to catch it. + String outV_NType = outV.<String>property("aai-node-type").orElse(null); + String inV_NType = inV.<String>property("aai-node-type").orElse(null); + if( needsADepNode4Uniqueness(transId, fromAppId, outV_NType, apiVersion) + && nodeTypeACanDependOnB(transId, fromAppId, outV_NType, inV_NType, apiVersion) ){ + // The out-Vertex has a uniqueness dependency on the in-vertex + // Make sure we haven't already added an node/edge like this in this transaction + HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, outV); + ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>(); + resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, outV_NType, nodeKeyPropsHash, inV, apiVersion, false); + if( resultList.size() > 0 ){ + String propInfo = ""; + if( nodeKeyPropsHash != null ){ + propInfo = nodeKeyPropsHash.toString(); + } + throw new AAIException("AAI_6117", "Failed to add edge. This node (" + inV_NType + ") already has an edge to a " + outV_NType + + " node with kepProps [" + propInfo + "]"); + } + } + else if( needsADepNode4Uniqueness(transId, fromAppId, inV_NType, apiVersion) + && nodeTypeACanDependOnB(transId, fromAppId, inV_NType, outV_NType, apiVersion) ){ + // The in-Vertex has a uniqueness dependency on the out-vertex + // Make sure we haven't already added an node/edge like this in this transaction + HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, inV); + ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>(); + resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, inV_NType, nodeKeyPropsHash, outV, apiVersion, false); + if( resultList.size() > 0 ){ + String propInfo = ""; + if( nodeKeyPropsHash != null ){ + propInfo = nodeKeyPropsHash.toString(); + } + throw new AAIException("AAI_6117", "Failed to add edge. This node (" + outV_NType + ") already has an edge to a " + inV_NType + + " node with kepProps [" + propInfo + "]"); + } + } + + + // We're good to go to add this edge + + TitanEdge tEdge = outV.addEdge( edgeLabel, inV ); + // Add the properties to the new Edge + for( Map.Entry<String, Object> entry : propHash.entrySet() ){ + tEdge.property( entry.getKey(), entry.getValue() ); + } + + // For (resource-id updates) we need to "touch" the vertices on each side of the edge so + // anybody working on one of those vertices will know that something (ADDing this edge) has happened. + touchVertex( transId, fromAppId, inV ); + touchVertex( transId, fromAppId, outV ); + + return tEdge; + } + + }// End saveAaiEdgeToDb() + + + + /** + * Derive edge rule key for this edge. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param tEdge the t edge + * @return String - key to look up edgeRule (fromNodeType|toNodeType) + * @throws AAIException the AAI exception + */ + public static String deriveEdgeRuleKeyForThisEdge( String transId, String fromAppId, TitanTransaction graph, + TitanEdge tEdge ) throws AAIException{ + + TitanVertex fromVtx = tEdge.outVertex(); + TitanVertex toVtx = tEdge.inVertex(); + String startNodeType = fromVtx.<String>property("aai-node-type").orElse(null); + String targetNodeType = toVtx.<String>property("aai-node-type").orElse(null); + String key = startNodeType + "|" + targetNodeType; + if( EdgeRules.getInstance().hasEdgeRule(startNodeType, targetNodeType) ){ + // We can use the node info in the order they were given + return( key ); + } + else { + key = targetNodeType + "|" + startNodeType; + if( EdgeRules.getInstance().hasEdgeRule(targetNodeType, startNodeType) ){ + return( key ); + } + else { + // Couldn't find a rule for this edge + throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", " + + targetNodeType); + } + } + }// end of deriveEdgeRuleKeyForThisEdge() + + + + /** + * Save aai edge to db. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param edgeLabel the edge label + * @param outV the out V + * @param inV the in V + * @param propHash the prop hash + * @return the titan edge + * @throws AAIException the AAI exception + */ + @Deprecated + private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel, + TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash) throws AAIException{ + return saveAaiEdgeToDb( transId, fromAppId, graph, edgeLabel, + outV, inV, propHash, null); + } + + /** + * Persist aai edge. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param startVert the start vert + * @param targetVert the target vert + * @param apiVersion the api version + * @return the titan edge + * @throws AAIException the AAI exception + */ + public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph, + TitanVertex startVert, TitanVertex targetVert, String apiVersion ) throws AAIException{ + TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, ""); + return returnEdge; + } + + /** + * Persist aai edge. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param startVert the start vert + * @param targetVert the target vert + * @param apiVersion the api version + * @param edgeType the edge type + * @return TitanEdge + * @throws AAIException the AAI exception + */ + public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph, + TitanVertex startVert, TitanVertex targetVert, String apiVersion, String edgeType ) throws AAIException{ + + TitanVertex fromVtx = null; + TitanVertex toVtx = null; + String startNodeType = startVert.<String>property("aai-node-type").orElse(null); + String targetNodeType = targetVert.<String>property("aai-node-type").orElse(null); + String fwdRuleKey = startNodeType + "|" + targetNodeType; + int fwdRuleCount = 0; + String fwdRule = ""; + String fwdLabel = ""; + String revRuleKey = targetNodeType + "|" + startNodeType; + int revRuleCount = 0; + String revRule = ""; + String revLabel = ""; + String edRule = ""; + String edLabel = ""; + + Boolean checkType = false; + if( (edgeType != null) && edgeType != "" ){ + checkType = true; + } + + // As of 16-07, it is possible to have more than one kind of edge defined between a given + // pair of nodeTypes. So we need to check to see if there is only one possibility, or if + // we need to look at the edgeType to determine which to use. + // NOTE -- we're only supporting having 2 edges between a given pair of nodeTypes and + // one and only one of them would have to be a parent-child edge. + + if( DbEdgeRules.EdgeRules.containsKey(fwdRuleKey) ){ + Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(fwdRuleKey); + Iterator <String> ruleItr = edRuleColl.iterator(); + while( ruleItr.hasNext() ){ + String tmpRule = ruleItr.next(); + String [] rules = tmpRule.split(","); + String tmpLabel = rules[0]; + String tmpParChild = rules[3]; + if( !checkType + || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild")) + || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){ + // Either they didn't want us to check the edgeType or it is a match + fwdRuleCount++; + if( fwdRuleCount > 1 ){ + // We found more than one with the given info + throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + startNodeType + "], [" + + targetNodeType + "], edgeType = [" + edgeType + "]."); + } + else { + fwdRule = tmpRule; + fwdLabel = tmpLabel; + } + } + } + } + + // Try it the other way also (unless this is the case of a nodeType recursively pointing to itself + // Ie. the edge rule: "model-element|model-element" + if( !revRuleKey.equals(fwdRuleKey) && DbEdgeRules.EdgeRules.containsKey(revRuleKey) ){ + Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(revRuleKey); + Iterator <String> ruleItr = edRuleColl.iterator(); + while( ruleItr.hasNext() ){ + String tmpRule = ruleItr.next(); + String [] rules = tmpRule.split(","); + String tmpLabel = rules[0]; + String tmpParChild = rules[3]; + if( !checkType + || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild")) + || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){ + // Either they didn't want us to check the edgeType or it is a match + revRuleCount++; + if( revRuleCount > 1 ){ + // We found more than one with the given info + throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + targetNodeType + "], [" + + startNodeType + "], edgeType = [" + edgeType + "]."); + } + else { + revRule = tmpRule; + revLabel = tmpLabel; + } + } + } + } + + if( (fwdRuleCount == 1) && (revRuleCount == 0) ){ + // We can use the node info in the order they were given + fromVtx = startVert; + toVtx = targetVert; + edRule = fwdRule; + edLabel = fwdLabel; + } + else if( (fwdRuleCount == 0) && (revRuleCount == 1) ){ + // We need to switch the vertex order so the edge-direction is correct + toVtx = startVert; + fromVtx = targetVert; + edRule = revRule; + edLabel = revLabel; + } + else if( (fwdRuleCount == 0) && (revRuleCount == 0) ){ + // No edge rule found for this + throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", " + targetNodeType + + "], checkLabelType = [" + edgeType + "]."); + } + else if( (fwdRuleCount > 0) && (revRuleCount > 0) ){ + // We found more than one with the given info + throw new AAIException("AAI_6120", "Multiple EdgeRules (fwd and rev) found for nodeTypes: [" + startNodeType + "], [" + + targetNodeType + "], checkLabelType = [" + edgeType + "]."); + } + + // If we got to this point, we now have a single edge label and we know to and from Vtx. + + HashMap <String,Object> edgeParamHash = getEdgeTagPropPutHash4Rule(transId, fromAppId, edRule); + // We do "source-of-truth" for all edges + edgeParamHash.put("source-of-truth", fromAppId ); + + TitanEdge returnEdge = saveAaiEdgeToDb(transId, fromAppId, graph, edLabel, fromVtx, toVtx, edgeParamHash, apiVersion); + + return returnEdge; + + } + + /** + * Persist aai edge. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param startVert the start vert + * @param targetVert the target vert + * @return the titan edge + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph, + TitanVertex startVert, TitanVertex targetVert ) throws AAIException{ + return persistAaiEdge( transId, fromAppId, graph, + startVert, targetVert, null); + } + // End persistAaiEdge() + + + /** + * Persist aai edge. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param edgeLabel the edge label + * @param startVert the start vert + * @param targetVert the target vert + * @param propHash the prop hash + * @param addIfNotFound the add if not found + * @return the titan edge + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph, + String edgeLabel, TitanVertex startVert, TitanVertex targetVert, + HashMap <String,Object> propHash, Boolean addIfNotFound ) throws AAIException{ + + /*----- This method is depricated ------ + * We will ignore the parameters: edgeLabel, propHash and addIfNotFound + * We will use the remaining params to call the newer version of this method + */ + TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, null); + + return returnEdge; + + }// End depricated version of persistAaiEdge() + + + /** + * Persist aai edge with dep params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param startVert the start vert + * @param targetNodeType the target node type + * @param targetNodeParamHash the target node param hash + * @param apiVersion the api version + * @return TitanEdge + * @throws AAIException the AAI exception + */ + public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph, + TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash, String apiVersion) throws AAIException{ + + TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion ); + TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion); + + return returnEdge; + + }// End persistAaiEdgeWithDepParams() + + // Version that lets you pass in an edgeType ("parentChild" or "cousin" since it sometimes cannot be determined + /** + * Persist aai edge with dep params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param startVert the start vert + * @param targetNodeType the target node type + * @param targetNodeParamHash the target node param hash + * @param apiVersion the api version + * @param edgeType the edge type + * @return the titan edge + * @throws AAIException the AAI exception + */ + // from the two nodeTypes anymore (16-07) + public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph, + TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash, + String apiVersion, String edgeType) throws AAIException{ + TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion ); + TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, edgeType); + + return returnEdge; + + }// End persistAaiEdgeWithDepParams() + + /** + * Persist aai edge with dep params. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param startVert the start vert + * @param targetNodeType the target node type + * @param targetNodeParamHash the target node param hash + * @return the titan edge + * @throws AAIException the AAI exception + */ + @Deprecated + public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph, + TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash) throws AAIException{ + return persistAaiEdgeWithDepParams( transId, fromAppId, graph, + startVert, targetNodeType, targetNodeParamHash, null); + } + + /** + * Gets the node key prop hash. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param vtx the vtx + * @return nodeKeyPropHash + * @throws AAIException the AAI exception + */ + public static HashMap <String, Object> getNodeKeyPropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx) throws AAIException{ + + if( vtx == null ){ + throw new AAIException("AAI_6109", "null node object passed to getNodeKeyPropHash()."); + } + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + String nType = vtx.<String>property("aai-node-type").orElse(null); + if( ! dbMaps.NodeKeyProps.containsKey(nType) ){ + // Problem if no key Properties defined for this nodeType + String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nType + " (ver=" + defVer + ")"); + } + + HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>(); + Collection <String> keyProps = dbMaps.NodeKeyProps.get(nType); + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + String propName = keyPropI.next(); + Object value = (Object) vtx.<Object>property(propName).orElse(null); + nodeKeyPropsHash.put(propName, value); + } + + return nodeKeyPropsHash; + + }// End of getNodeKeyPropHash() + + /** + * Gets the node name prop hash. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param vtx the vtx + * @param apiVersion the api version + * @return nodeKeyPropHash + * @throws AAIException the AAI exception + */ + public static HashMap <String, Object> getNodeNamePropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx, String apiVersion) throws AAIException{ + + if( vtx == null ){ + throw new AAIException("AAI_6109", "null node object passed to getNodeNamePropHash()." ); + } + + String nType = vtx.<String>property("aai-node-type").orElse(null); + HashMap <String,Object>nodeNamePropsHash = new HashMap<String,Object>(); + Collection <String> keyProps = DbMeth.getNodeNameProps(transId, fromAppId, nType, apiVersion); + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + String propName = keyPropI.next(); + Object value = (Object) vtx.<Object>property(propName).orElse(null); + nodeNamePropsHash.put(propName, value); + } + + return nodeNamePropsHash; + + }// End of getNodeNamePropHash() + + + /** + * Removes the aai edge. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param tEdge the t edge + * @return void + */ + public static void removeAaiEdge( String transId, String fromAppId, TitanTransaction graph, TitanEdge tEdge){ + // Before removing the edge, touch the vertices on each side so their resource-versions will get updated + TitanVertex tmpVIn = tEdge.inVertex(); + touchVertex( transId, fromAppId, tmpVIn ); + + TitanVertex tmpVOut = tEdge.outVertex(); + touchVertex( transId, fromAppId, tmpVOut ); + + // Remove the passed in edge. + tEdge.remove(); + + }// end of removeAaiEdge() + + + /** + * Removes the aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param thisVtx the this vtx + * @param scopeParam the scope param + * @param apiVersion the api version + * @param resourceVersion the resource version + * @throws AAIException the AAI exception + */ + public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam, + String apiVersion, String resourceVersion ) throws AAIException{ + // Note: the resource Version Override flag is only set to true when called by the Model Delete code which + // has no way to know the resource-versions of nodes at lower-levels of it's model topology. + Boolean resVersionOverrideFlag = false; + removeAaiNode( transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, resourceVersion, resVersionOverrideFlag ); + } + + + /** + * <pre> + * Possible values for deleteScope can be: + * USE_DEFAULT - Get the scope from ref data for this node + * THIS_NODE_ONLY (but should fail if it there are nodes that depend on it for uniqueness) + * CASCADE_TO_CHILDREN - will look for OUT-Edges that have parentOf/hasDelTarget = true and follow those down + * ERROR_4_IN_EDGES_OR_CASCADE - combo of error-if-any-IN-edges + CascadeToChildren + * ERROR_IF_ANY_IN_EDGES - Fail if this node has any existing IN edges + * ERROR_IF_ANY_EDGES - Fail if this node has any existing edges at all! + * </pre>. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param thisVtx the this vtx + * @param scopeParam the scope param + * @param apiVersion the api version + * @param resourceVersion the resource version + * @param resVerOverride the res ver override + * @return void + * @throws AAIException the AAI exception + */ + public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam, + String apiVersion, String resourceVersion, Boolean resVerOverride ) throws AAIException{ + String nodeType2Del = thisVtx.<String>property("aai-node-type").orElse(null); + String deleteScope = scopeParam; + if( scopeParam.equals("USE_DEFAULT") ){ + deleteScope = getDefaultDeleteScope(transId, fromAppId, nodeType2Del, apiVersion); + } + + if( !resVerOverride && needToDoResourceVerCheck(apiVersion, false) ){ + // Need to check that they knew what they were deleting + String existingResVer = thisVtx.<String>property("resource-version").orElse(null); + if( resourceVersion == null || resourceVersion.equals("") ){ + throw new AAIException("AAI_6130", "Resource-version not passed for delete of = " + nodeType2Del); + } + else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){ + throw new AAIException("AAI_6131", "Resource-version MISMATCH for delete of = " + nodeType2Del); + } + } + + if( !deleteScope.equals("THIS_NODE_ONLY") + && !deleteScope.equals("CASCADE_TO_CHILDREN") + && !deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE") + && !deleteScope.equals("ERROR_IF_ANY_EDGES") + && !deleteScope.equals("ERROR_IF_ANY_IN_EDGES") ){ + throw new AAIException("AAI_6120", "Unrecognized value in deleteScope: [" + deleteScope + "]."); + } + + if( deleteScope.equals("ERROR_IF_ANY_EDGES") ){ + if ( thisVtx.edges(Direction.BOTH).hasNext() ) { + throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the ERROR_IF_ANY_EDGES scope was used."); + } + } + else if( deleteScope.equals("ERROR_IF_ANY_IN_EDGES") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE") ){ + Iterator <Edge> eI = thisVtx.edges(Direction.IN); + boolean onlyHasParent = false; + Edge temp = null; + if( eI != null && eI.hasNext() ){ + temp = eI.next(); + Boolean isParent = temp.<Boolean>property("isParent").orElse(null); + if (isParent != null && isParent && !eI.hasNext()) { + onlyHasParent = true; + } + + if (!onlyHasParent) { + throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the " + deleteScope + " scope was used."); + } + } + } + else if( deleteScope.equals("THIS_NODE_ONLY")){ + // Make sure nobody depends on this node. + Iterator<Edge> eI = thisVtx.edges(Direction.BOTH); + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx); + String nodeTypeA = otherVtx.<String>property("aai-node-type").orElse(null); + if( nodeTypeACanDependOnB(transId, fromAppId, nodeTypeA, nodeType2Del, apiVersion)){ + // We're only supposed to delete this node - but another node is dependant on it, + // so we shouldn't delete this one. + throw new AAIException("AAI_6110", "Node cannot be deleted using scope = " + deleteScope + + " another node (type = " + nodeTypeA + ") depends on it for uniqueness."); + } + } + } + + // We've passed our checks - so do some deleting of edges and maybe pass + // the delete request down to children or delete-targets. + + // First we deal with the "IN"-Edges which can't have children/delete-targets which + // by definition (of "IN") on the other end + Iterator <Edge> eI_In = thisVtx.edges(Direction.IN); + while( eI_In.hasNext() ){ + TitanEdge ed = (TitanEdge) eI_In.next(); + + //- "touch" vertex on other side of this edge so it gets a fresh resource-version + TitanVertex tmpVOther = ed.otherVertex(thisVtx); + touchVertex( transId, fromAppId, tmpVOther ); + + ed.remove(); + } + + // Now look at the "OUT"-edges which might include children or delete-targets + String cascadeMsg = "This nt = " + nodeType2Del + ", Cascading del to: "; + Iterator <Edge> eI_Out = thisVtx.edges(Direction.OUT); + if( !eI_Out.hasNext() ){ + cascadeMsg = cascadeMsg + "[no children for this node]"; + } + while( eI_Out.hasNext() ){ + TitanEdge ed = (TitanEdge) eI_Out.next(); + + // "touch" vertex on other side of this edge so it gets a fresh resource-version + TitanVertex tmpVOther = ed.otherVertex(thisVtx); + touchVertex( transId, fromAppId, tmpVOther ); + + Boolean otherVtxAChild = ed.<Boolean>property("isParent").orElse(null); + if( otherVtxAChild == null ){ + otherVtxAChild = false; + } + + Boolean otherVtxADeleteTarget = ed.<Boolean>property("hasDelTarget").orElse(null); + if( otherVtxADeleteTarget == null ){ + otherVtxADeleteTarget = false; + } + + if( (otherVtxAChild || otherVtxADeleteTarget) && + (deleteScope.equals("CASCADE_TO_CHILDREN") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE")) ){ + // Delete the edge to the child and Pass the delete down to it. + ed.remove(); + TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx); + String vid = otherVtx.id().toString(); + String nty = otherVtx.<String>property("aai-node-type").orElse(null); + String resVers = otherVtx.<String>property("resource-version").orElse(null); + cascadeMsg = cascadeMsg + "[" + nty + ":" + vid + "]"; + removeAaiNode(transId, fromAppId, graph, otherVtx, "CASCADE_TO_CHILDREN", apiVersion, resVers); + } + else { + // The other node is not a child or deleteTarget. Delete the edge to it if it is not + // dependent (Should never be dependent since it's not a child/delTarget... but + // someone could create a node that was dependent for Uniqueness without + // being a child/target. + + // DEBUG -- eventually add the check for dependancy that isn't on a parent-type or delTarget-type edge + ed.remove(); + } + } + + LOGGER.info(cascadeMsg); + + Iterator<Edge> eI = thisVtx.edges(Direction.BOTH); + if( ! eI.hasNext() ){ + // By this point, either there were no edges to deal with, or we have dealt with them. + thisVtx.remove(); + } + else { + // Something went wrong and we couldn't delete all the edges for this guy. + throw new AAIException("AAI_6110", "Node could be deleted because it unexpectedly still has Edges.\n"); + } + } + + + /** + * Removes the aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param thisVtx the this vtx + * @param scopeParam the scope param + * @return void + * @throws AAIException the AAI exception + */ + @Deprecated + public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam) throws AAIException{ + removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, null, null); + } + + /** + * Removes the aai node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param thisVtx the this vtx + * @param scopeParam the scope param + * @param apiVersion the api version + * @throws AAIException the AAI exception + */ + @Deprecated + public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam, + String apiVersion ) throws AAIException{ + removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, null); + } + // end of removeAaiNode() + + + /** + * Delete all graph data. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @return void + */ + public static void deleteAllGraphData( String transId, String fromAppId, TitanGraph graph ){ + /** ====================================================================== + * WARNING -- this removes ALL the data that is currently in the graph. + * ====================================================================== + **/ + LOGGER.warn("deleteAllGraphData called! Run for the hills!"); + Iterator<Edge> edges = graph.edges(Direction.BOTH); + graph.tx().commit(); + Edge edge = null; + while (edges.hasNext()) { + edge = edges.next(); + edges.remove(); + } + graph.tx().commit(); + Iterator<Vertex> vertices = graph.vertices(); + graph.tx().commit(); + Vertex vertex = null; + while (vertices.hasNext()) { + vertex = vertices.next(); + vertex.remove(); + } + graph.tx().commit(); + } + + + /** + * Show all edges for node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param tVert the t vert + * @return the array list + */ + public static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){ + + ArrayList <String> retArr = new ArrayList <String> (); + Iterator <Edge> eI = tVert.edges(Direction.IN); + if( ! eI.hasNext() ){ + retArr.add("No IN edges were found for this vertex. "); + } + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + String lab = ed.label(); + TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert); + if( vtx == null ){ + retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< "); + } + else { + String nType = vtx.<String>property("aai-node-type").orElse(null); + String vid = vtx.id().toString(); + retArr.add("Found an IN edge (" + lab + ") to this vertex from a [" + nType + "] node with VtxId = " + vid ); + //DEBUG --- + //showPropertiesForEdge( transId, fromAppId, ed ); + } + } + + eI = tVert.edges(Direction.OUT); + if( ! eI.hasNext() ){ + retArr.add("No OUT edges were found for this vertex. "); + } + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + String lab = ed.label(); + TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert); + if( vtx == null ){ + retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< "); + } + else { + String nType = vtx.<String>property("aai-node-type").orElse(null); + String vid = vtx.id().toString(); + retArr.add("Found an OUT edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid ); + //DEBUG --- + //showPropertiesForEdge( transId, fromAppId, ed ); + } + } + return retArr; + } + + + /** + * Show properties for node. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param tVert the t vert + * @return the array list + */ + public static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){ + + ArrayList <String> retArr = new ArrayList <String> (); + if( tVert == null ){ + retArr.add("null Node object passed to showPropertiesForNode()\n"); + } + else { + String nodeType = ""; + //String datType = ""; + Object ob = tVert.<Object>property("aai-node-type").orElse(null); + if( ob == null ){ + nodeType = "null"; + } + else{ + nodeType = ob.toString(); + //datType = ob.getClass().getSimpleName(); + } + + retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]"); + retArr.add(" Property Detail: "); + Iterator<VertexProperty<Object>> pI = tVert.properties(); + while( pI.hasNext() ){ + VertexProperty<Object> tp = pI.next(); + Object val = tp.value(); + //retArr.add("Prop: [" + tp.getPropertyKey() + "], val = [" + val + "], dataType = " + val.getClass() ); + retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] "); + } + } + return retArr; + } + + + /** + * Gets the node name props. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param nodeType the node type + * @param apiVersion the api version + * @return HashMap of keyProperties + * @throws AAIException the AAI exception + */ + public static Collection <String> getNodeNameProps( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{ + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + Collection <String> nameProps = new ArrayList <String>(); + if( dbMaps.NodeNameProps.containsKey(nodeType) ){ + nameProps = dbMaps.NodeNameProps.get(nodeType); + } + else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){ + // The passed-in nodeType was really a nodeCategory, theoretically, all the guys in the same + // category should have the same name property -- so if they just give us the category, we will + // just give the name info from the first nodeType we encounter of that category. + Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); + Iterator <String> catItr = nTypeCatCol.iterator(); + String catInfo = ""; + if( catItr.hasNext() ){ + // For now, we only look for one. + catInfo = catItr.next(); + } + else { + throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType); + } + + String [] flds = catInfo.split(","); + if( flds.length != 4 ){ + throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "]."); + } + + String nodeTypesString = flds[0]; + String [] nodeTypeNames = nodeTypesString.split("\\|"); + if( nodeTypeNames != null && nodeTypeNames.length > 0 ){ + // We'll just use the first one + String nt = nodeTypeNames[0]; + nameProps = dbMaps.NodeNameProps.get(nt); + } + } + + + // Note - it's ok if there was no defined name property for this nodeType. + + return nameProps; + + }// end of getNodeKeyPropNames + + + /** + * Gets the edge tag prop put hash 4 rule. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param edRule the ed rule + * @return the edge tag prop put hash 4 rule + * @throws AAIException the AAI exception + */ + public static HashMap <String,Object> getEdgeTagPropPutHash4Rule( String transId, String fromAppId, String edRule ) + throws AAIException{ + // For a given edgeRule - already pulled out of DbEdgeRules.EdgeRules -- parse out the "tags" that + // need to be set for this kind of edge. + // These are the Boolean properties like, "isParent", "usesResource" etc. + HashMap <String,Object> retEdgePropPutMap = new HashMap <String,Object>(); + + if( (edRule == null) || edRule.equals("") ){ + // No edge rule found for this + throw new AAIException("AAI_6120", "blank edRule passed to getEdgeTagPropPutHash4Rule()"); + } + + int tagCount = DbEdgeRules.EdgeInfoMap.size(); + String [] rules = edRule.split(","); + if( rules.length != tagCount ){ + throw new AAIException("AAI_6121", "Bad EdgeRule data (itemCount =" + rules.length + ") for rule = [" + edRule + "]."); + } + + // In DbEdgeRules.EdgeRules -- What we have as "edRule" is a comma-delimited set of strings. + // The first item is the edgeLabel. + // The second in the list is always "direction" which is always OUT for the way we've implemented it. + // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to + // tags as defined in EdgeInfoMap. + // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it + for( int i = DbEdgeRules.firstTagIndex; i < tagCount; i++ ){ + String booleanStr = rules[i]; + Integer mapKey = new Integer(i); + String propName = DbEdgeRules.EdgeInfoMap.get(mapKey); + String revPropName = propName + "-REV"; + + if( booleanStr.equals("true") ){ + retEdgePropPutMap.put(propName, true); + retEdgePropPutMap.put(revPropName,false); + } + else if( booleanStr.equals("false") ){ + retEdgePropPutMap.put(propName, false); + retEdgePropPutMap.put(revPropName,false); + } + else if( booleanStr.equals("reverse") ){ + retEdgePropPutMap.put(propName, false); + retEdgePropPutMap.put(revPropName,true); + } + else { + throw new AAIException("AAI_6121", "Bad EdgeRule data for rule = [" + edRule + "], val = [" + booleanStr + "]."); + } + + } + + return retEdgePropPutMap; + + } // End of getEdgeTagPropPutHash() + + + + /** + * Gets the edge tag prop put hash. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param edgeRuleKey the edge rule key + * @return the edge tag prop put hash + * @throws AAIException the AAI exception + */ + public static Map<String, EdgeRule> getEdgeTagPropPutHash( String transId, String fromAppId, String edgeRuleKey ) + throws AAIException{ + // For a given edgeRuleKey (nodeTypeA|nodeTypeB), look up the rule that goes with it in + // DbEdgeRules.EdgeRules and parse out the "tags" that need to be set on each edge. + // These are the Boolean properties like, "isParent", "usesResource" etc. + // Note - this code is also used by the updateEdgeTags.java code + + String[] edgeRuleKeys = edgeRuleKey.split("\\|"); + + if (edgeRuleKeys.length < 2 || ! EdgeRules.getInstance().hasEdgeRule(edgeRuleKeys[0], edgeRuleKeys[1])) { + throw new AAIException("AAI_6120", "Could not find an DbEdgeRule entry for passed edgeRuleKey (nodeTypeA|nodeTypeB): " + edgeRuleKey + "."); + } + + Map<String, EdgeRule> edgeRules = EdgeRules.getInstance().getEdgeRules(edgeRuleKeys[0], edgeRuleKeys[1]); + + return edgeRules; + + } // End of getEdgeTagPropPutHash() + + + /** + * This property was put by newer version of code. + * + * @param apiVersionStr the api version str + * @param nodeType the node type + * @param propName the prop name + * @return true, if successful + * @throws AAIException the AAI exception + */ + private static boolean thisPropertyWasPutByNewerVersionOfCode( String apiVersionStr, + String nodeType, String propName) throws AAIException{ + // We want to return True if the nodeType + property-name combo was introduced AFTER the apiVersion passed. + + int apiVerInt = 0; + int propIntroVerInt = 0; + + if( apiVersionStr == null || apiVersionStr.equals("") ){ + apiVersionStr = org.openecomp.aai.util.AAIApiVersion.get(); + } + apiVerInt = getVerNumFromVerString(apiVersionStr); + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + String propIntroKey = nodeType + "|" + propName; + if( propName.equals("prov-status") ){ + // This is a special case -- The dbMaps from v2 has it in there, but it was introduced half way through. So + // it needs to be catogorized as v3. + propIntroVerInt = 3; + } + else if( ! dbMaps.PropertyVersionInfoMap.containsKey(propIntroKey) ){ + String detail = propIntroKey + " [" + propIntroKey + "] not found in dbMaps.PropertyVersionInfoMap."; + throw new AAIException("AAI_6121", detail); + } + else { + String propIntroVerString = dbMaps.PropertyVersionInfoMap.get(propIntroKey); + propIntroVerInt = getVerNumFromVerString( propIntroVerString ); + } + + if( propIntroVerInt > apiVerInt ){ + return true; + } + else { + return false; + } + + } // End of thisPropertyWasPutByNewerVersionOfCode() + + + /** + * Touch vertex. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param v the v + * @return void + */ + public static void touchVertex( String transId, String fromAppId, TitanVertex v ){ + // We want to "touch" the vertex -- Ie. update it's last-mod-date, last-mod- resource-version to the current date/time + if( v != null ){ + long unixTimeNow = System.currentTimeMillis() / 1000L; + String timeNowInSec = "" + unixTimeNow; + v.property( "aai-last-mod-ts", timeNowInSec ); + v.property( "resource-version", timeNowInSec ); + v.property( "last-mod-source-of-truth", fromAppId ); + } + } // End of touchVertex() + + + /** + * Check prop cardinality. + * + * @param propName the prop name + * @param cardinalityType the cardinality type + * @return boolean + * @throws AAIException the AAI exception + */ + public static boolean checkPropCardinality( String propName, String cardinalityType ) throws AAIException { + + // Return true if the named property is tagged in our dbMaps PropetyDataTypeMap as + // having the passed in cardinality type. + // NOTE: supported cardinality types in dbMaps = "Set" or "List" + // In Titan (and ex5.json), those go in as "SET" and "LIST" + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){ + String propDataType = dbMaps.PropertyDataTypeMap.get(propName); + if( propDataType != null && propDataType.startsWith(cardinalityType) ){ + return true; + } + } + return false; + + } // End of checkPropCardinality() + + /** + * Convert type if needed. + * + * @param propName the prop name + * @param val the val + * @return convertedValue (if it was a String but needed to be a Boolean) + * @throws AAIException the AAI exception + */ + public static Object convertTypeIfNeeded( String propName, Object val ) + throws AAIException { + // Make sure the dataType of the passed-in Object matches what the DB expects + + // NOTE: since this is a fix very late in our dev cycle, we'll just fix the scenarios that + // we're having trouble with which is Strings getting into the db which should be going in as + // Booleans or Integers. + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){ + String dbExpectedDataType = dbMaps.PropertyDataTypeMap.get(propName); + if( dbExpectedDataType != null + && dbExpectedDataType.equals("Boolean") + && val != null + && !(val instanceof Boolean) ){ + String valStr = val.toString().trim(); + if( valStr.equals("true") || valStr.equals("True") || valStr.equals("TRUE") ){ + return Boolean.valueOf("true"); + } + else if( valStr.equals("false") || valStr.equals("False") || valStr.equals("FALSE") ){ + return Boolean.valueOf("false"); + } + else { + String emsg = "Error trying to convert value: [" + valStr + "] to a Boolean for property + " + propName + "\n"; + throw new AAIException("AAI_6120", emsg); + } + } + else if( dbExpectedDataType != null + && dbExpectedDataType.equals("Integer") + && val != null + && !(val.toString().trim().equals("")) + && !(val instanceof Integer) ){ + String valStr = val.toString().trim(); + Integer newInt; + try { + newInt = Integer.valueOf(valStr); + return newInt; + } + catch( Exception e ){ + String emsg = "Error trying to convert value: [" + valStr + "] to an Integer for property + " + propName + "\n"; + throw new AAIException("AAI_6120", emsg); + } + } + } + + // If it didn't need to be converted, just return it. + return val; + + } // End of convertTypeIfNeeded() + + + + /** + * This vertex not reachable. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param v the v + * @param version the version + * @return boolean + */ + public static boolean thisVertexNotReachable( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){ + if( v == null ){ + return true; + } + else { + try { + v.id().toString(); + } + catch( Exception ex ){ + // Could not get this -- sometimes we're holding a vertex object that has gotten deleted, so + // when we try to get stuff from it, we get an "Element Has Been Removed" error from Titan + return true; + } + } + + return false; + + } // End of thisVertexNotReachable() + + /** + * This vertex has bad edges. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param v the v + * @param version the version + * @return boolean + */ + public static boolean thisVertexHasBadEdges( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){ + + Iterator <Edge> eItor = v.edges(Direction.BOTH); + while( eItor.hasNext() ){ + Edge e = null; + e = eItor.next(); + if( e == null ){ + return true; + } + Vertex vIn = e.inVertex(); + if( (vIn == null) || (vIn.<String>property("aai-node-type").orElse(null) == null) ){ + // this is a bad edge because it points to a vertex that isn't there anymore + return true; + } + + Vertex vOut = e.outVertex(); + if( (vOut == null) || (vOut.<String>property("aai-node-type").orElse(null) == null) ){ + // this is a bad edge because it points to a vertex that isn't there anymore + return true; + } + } + + // If we made it to here, the vertex's edges must be ok. + return false; + + } // End of thisVertexHasBadEdges() + + + /** + * This vertex is A phantom. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param v the v + * @param version the version + * @return boolean + * @throws AAIException the AAI exception + */ + public static boolean thisVertexIsAPhantom( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version ) + throws AAIException { + + + // The kind of Phantom we're looking for is the kind that we sometimes get when we do a select without + // using key properties. They can be in the database as a vertex, but the indexes that should point to + // them are not working -- so they cannot be used by normal interfaces (like the REST API) which means + // that if we return it, it can mess up a caller who tries to use it. + if( v == null ){ + return true; + } + String thisVid = v.id().toString(); + + DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)); + + Object propOb = v.<Object>property("aai-node-type").orElse(null); + if( propOb == null ){ + // This vertex does not have an aai-node-type ---> it is messed up + return true; + } + String nType = propOb.toString(); + if( ! dbMaps.NodeKeyProps.containsKey(nType) ){ + // This node Type does not have keys defined + // This could just be bad reference data, so we will not flag this guy, but we + // can't really do our test... + return false; + } + + HashMap <String,Object> propHashWithKeys = new HashMap<String, Object>(); + Collection <String> keyProps = null; + try { + keyProps = getNodeKeyPropNames(transId, fromAppId, nType, version); + } + catch (AAIException ex) { + // something wrong with getting this guy's key property names - we'll abandon this test... + return false; + } + + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + String propName = keyPropI.next(); + String propVal = ""; + Object ob = v.<Object>property(propName).orElse(null); + if( ob != null ){ + propVal = ob.toString(); + } + propHashWithKeys.put(propName, propVal); + } + try { + // Note - We can get more than one back since some nodes need a dep. node for uniqueness. + // We don't care about that -- we just want to make sure we can get this vertex back when + // we're searching with it's indexed fields. + // NOTE - we're passing the skipGroomCheck to getNodes so we don't wind up in an infinite loop + ArrayList <TitanVertex> vertList2 = getNodes( transId, fromAppId, graph, nType, propHashWithKeys, false, version, true ); + Iterator<TitanVertex> iter2 = vertList2.iterator(); + while( iter2.hasNext() ){ + TitanVertex tvx2 = iter2.next(); + String foundId = tvx2.id().toString(); + if( foundId.equals( thisVid ) ){ + // We could get back the vertex by looking it up using key properties... That's good. + return false; + } + } + } + catch (Exception e2) { + //String msg = " Error encountered for this vertex id: [" + thisVid + + // "]. Caught this exception: " + e2.toString(); + // Something messed up - but that doesn't prove that this is a phantom. + return false; + } + + // If we dropped down to here, we have looked but could not pull the vertex out of the + // db using it's key fields, so it gets flagged as a Phantom. + return true; + + } // End of thisVertexIsAPhantom() + + + /** + * Gets the node by unique key. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param aaiUniquekey the aai uniquekey + * @return the node by unique key + */ + public TitanVertex getNodeByUniqueKey(String transId, String fromAppId, TitanTransaction graph, String aaiUniquekey) { + + TitanVertex vert = null; + + Iterator<?> vertI = graph.query().has("aai-unique-key", aaiUniquekey).vertices().iterator(); + + if( vertI != null && vertI.hasNext()) { + // We found a vertex that meets the input criteria. + vert = (TitanVertex) vertI.next(); + } + + return vert; + } + + + +} + diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/GenTester.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/GenTester.java new file mode 100644 index 00000000..43f8f76b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/GenTester.java @@ -0,0 +1,123 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbgen; + +import com.att.eelf.configuration.Configuration; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.schema.TitanManagement; +import org.openecomp.aai.dbmap.AAIGraph; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; + +import java.util.Properties; + + +public class GenTester { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(GenTester.class); + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + + TitanGraph graph = null; + + // Set the logging file properties to be used by EELFManager + Properties props = System.getProperties(); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, AAIConstants.AAI_CREATE_DB_SCHEMA_LOGBACK_PROPS); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES); + boolean addDefaultCR = true; + + try { + AAIConfig.init(); + if (args != null && args.length > 0 ){ + if( "genDbRulesOnly".equals(args[0]) ){ + ErrorLogHelper.logError("AAI_3100", + " This option is no longer supported. What was in DbRules is now derived from the OXM files. "); + return; + } + else if ( "GEN_DB_WITH_NO_SCHEMA".equals(args[0]) ){ + // Note this is done to create an empty DB with no Schema so that + // an HBase copyTable can be used to set up a copy of the db. + LOGGER.info(" ---- NOTE --- about to load a graph without doing any schema processing (takes a little while) -------- "); + graph = AAIGraph.getInstance().getGraph(); + + if( graph == null ){ + ErrorLogHelper.logError("AAI_5102", "Error creating Titan graph."); + return; + } + else { + LOGGER.auditEvent("Successfully loaded a Titan graph without doing any schema work. "); + return; + } + } else if ("GEN_DB_WITH_NO_DEFAULT_CR".equals(args[0])) { + addDefaultCR = false; + } + else { + ErrorLogHelper.logError("AAI_3000", "Unrecognized argument passed to GenTester.java: [" + args[0] + "]. "); + LOGGER.error("Unrecognized argument passed to GenTester.java: [" + args[0] + "]. "); + LOGGER.error("Either pass no argument for normal processing, or use 'GEN_DB_WITH_NO_SCHEMA'."); + return; + } + } + + //AAIConfig.init(); + ErrorLogHelper.loadProperties(); + LOGGER.info(" ---- NOTE --- about to open graph (takes a little while)--------;"); + graph = AAIGraph.getInstance().getGraph(); + + if( graph == null ){ + ErrorLogHelper.logError("AAI_5102", "Error creating Titan graph. "); + return; + } + + // Load the propertyKeys, indexes and edge-Labels into the DB + TitanManagement graphMgt = graph.openManagement(); + + LOGGER.info("-- Loading new schema elements into Titan --"); + SchemaGenerator.loadSchemaIntoTitan( graph, graphMgt, addDefaultCR ); + + } catch(Exception ex) { + ErrorLogHelper.logError("AAI_4000", ex.getMessage()); + } + + + if( graph != null ){ + LOGGER.info("-- graph commit"); + graph.tx().commit(); + + LOGGER.info("-- graph shutdown "); + graph.close(); + } + + LOGGER.auditEvent("-- all done, if program does not exit, please kill."); + System.exit(0); + } + +} + + diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/PropertyLimitDesc.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/PropertyLimitDesc.java new file mode 100644 index 00000000..aad519e4 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/PropertyLimitDesc.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbgen; + +public enum PropertyLimitDesc { + SHOW_NONE, + SHOW_ALL, + SHOW_NAME_AND_KEYS_ONLY +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java new file mode 100644 index 00000000..fb8e8977 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java @@ -0,0 +1,168 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbgen; + + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.collect.Multimap; +import com.thinkaurelius.titan.core.*; +import com.thinkaurelius.titan.core.schema.TitanManagement; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.EdgeRule; +import org.openecomp.aai.serialization.db.EdgeRules; +import org.openecomp.aai.util.AAIConfig; + +import java.util.*; + + +public class SchemaGenerator { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SchemaGenerator.class); + private static boolean addDefaultCR = true; + + + /** + * Load schema into titan. + * + * @param graph the graph + * @param graphMgmt the graph mgmt + * @param addDefaultCloudRegion the add default cloud region + */ + public static void loadSchemaIntoTitan(final TitanGraph graph, final TitanManagement graphMgmt, boolean addDefaultCloudRegion) { + addDefaultCR = addDefaultCloudRegion; + loadSchemaIntoTitan(graph, graphMgmt); + } + + /** + * Load schema into titan. + * + * @param graph the graph + * @param graphMgmt the graph mgmt + */ + public static void loadSchemaIntoTitan(final TitanGraph graph, final TitanManagement graphMgmt) { + + try { + AAIConfig.init(); + } + catch (Exception ex){ + LOGGER.error(" ERROR - Could not run AAIConfig.init(). ", ex); + System.exit(1); + } + + // NOTE - Titan 0.5.3 doesn't keep a list of legal node Labels. + // They are only used when a vertex is actually being created. Titan 1.1 will keep track (we think). + + + // Use EdgeRules to make sure edgeLabels are defined in the db. NOTE: the multiplicty used here is + // always "MULTI". This is not the same as our internal "Many2Many", "One2One", "One2Many" or "Many2One" + // We use the same edge-label for edges between many different types of nodes and our internal + // multiplicty definitions depends on which two types of nodes are being connected. + + Multimap<String, EdgeRule> edges = null; + Set<String> labels = new HashSet<>(); + try { + edges = EdgeRules.getInstance().getAllRules(); + for (EdgeRule rule : edges.values()) { + labels.add(rule.getLabel()); + } + } catch (AAIException e) { + LOGGER.error("could not get edge rules", e); + System.exit(1); + } + for( String label: labels){ + if( graphMgmt.containsRelationType(label) ) { + LOGGER.debug(" EdgeLabel [" + label + "] already existed. "); + } else { + LOGGER.debug("Making EdgeLabel: [" + label + "]"); + graphMgmt.makeEdgeLabel(label).multiplicity(Multiplicity.valueOf("MULTI")).make(); + } + } + + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, AAIProperties.LATEST); + Map<String, Introspector> objs = loader.getAllObjects(); + Map<String, PropertyKey> seenProps = new HashMap<>(); + + for (Introspector obj : objs.values()) { + for (String propName : obj.getProperties()) { + String dbPropName = propName; + Optional<String> alias = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS); + if (alias.isPresent()) { + dbPropName = alias.get(); + } + if( graphMgmt.containsRelationType(propName) ){ + LOGGER.debug(" PropertyKey [" + propName + "] already existed in the DB. "); + } else { + Class<?> type = obj.getClass(propName); + Cardinality cardinality = Cardinality.SINGLE; + boolean process = false; + if (obj.isListType(propName) && obj.isSimpleGenericType(propName)) { + cardinality = Cardinality.SET; + type = obj.getGenericTypeClass(propName); + process = true; + } else if (obj.isSimpleType(propName)) { + process = true; + } + + if (process) { + + LOGGER.info("Creating PropertyKey: [" + dbPropName + "], ["+ type.getSimpleName() + "], [" + cardinality + "]"); + PropertyKey propK; + if (!seenProps.containsKey(dbPropName)) { + propK = graphMgmt.makePropertyKey(dbPropName).dataType(type).cardinality(cardinality).make(); + seenProps.put(dbPropName, propK); + } else { + propK = seenProps.get(dbPropName); + } + if (graphMgmt.containsGraphIndex(dbPropName)) { + LOGGER.debug(" Index [" + dbPropName + "] already existed in the DB. "); + } else { + if( obj.getIndexedProperties().contains(propName) ){ + if( obj.getUniqueProperties().contains(propName) ){ + LOGGER.info("Add Unique index for PropertyKey: [" + dbPropName + "]"); + graphMgmt.buildIndex(dbPropName,Vertex.class).addKey(propK).unique().buildCompositeIndex(); + } else { + LOGGER.info("Add index for PropertyKey: [" + dbPropName + "]"); + graphMgmt.buildIndex(dbPropName,Vertex.class).addKey(propK).buildCompositeIndex(); + } + } else { + LOGGER.info("No index added for PropertyKey: [" + dbPropName + "]"); + } + } + } + } + } + } + + LOGGER.info("-- About to call graphMgmt commit"); + graphMgmt.commit(); + }// End of loadSchemaIntoTitan() + +} + + diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgraphgen/DbSearchWithTags.java b/aai-core/src/main/java/org/openecomp/aai/dbgraphgen/DbSearchWithTags.java new file mode 100644 index 00000000..cceb950b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbgraphgen/DbSearchWithTags.java @@ -0,0 +1,366 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbgraphgen; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; +import org.openecomp.aai.util.AAIConfig; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + + + +/** + * Database-level Search-Utility class that uses edge-tags to help it navigate the graph. + */ +public class DbSearchWithTags{ + + private EELFLogger LOGGER = EELFManager.getInstance().getLogger(DbSearchWithTags.class); + + private TransactionalGraphEngine engine; + + protected DbSearchWithTags() { + + } + public DbSearchWithTags(Loader loader, TransactionalGraphEngine engine, DBSerializer serializer) { + this.engine = engine; + } + + /** + * Run edge tag query. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param edgeTag the edge tag + * @param searchRootType - root collection point when doing the search + * @param displayRootType - if they want more data than would be included using the searchRootType, this + * lets them specify it. + * @param searchDirectionStr the search direction str + * @param initialFilterHash the initial filter hash + * @param secondaryFilterHash the secondary filter hash + * @param pruneLevel either "none", "searchLevel" or "displayLevel". + * @param retNodeType could be either "all" for the full map, or a single nodeType + * @param trimList list of nodes to "stop" at when collecting data + * @return List<resultSet> + * @throws AAIException the AAI exception + */ + public Tree<Vertex> runEdgeTagQuery( String transId, String fromAppId, + String edgeTag, + String searchRootType, + Map<String,Object> initialFilterHash, + Map<String,Object> secondaryFilterHash) + throws AAIException{ + + final String tag = edgeTag; + final String reverseTag = edgeTag + "-REV"; + //max levels is not used at this time, but may be used again + int maxLevels = 50; // default value + String maxString = AAIConfig.get("aai.edgeTag.proc.max.levels"); + if( maxString != null && !maxString.equals("") ){ + try { + int maxVal = Integer.parseInt(maxString); + maxLevels = maxVal; + } + catch ( Exception nfe ){ + // Don't worry, we will leave "maxLevels" set to the default value it was initialized with + } + } + + // First, we need to use the intialFilter plus the edgeTag to identify a set of search-root-nodes + HashMap <String, Vertex> searchRootHash = identifyTopNodeSet( transId, fromAppId, + edgeTag, searchRootType, initialFilterHash, maxLevels ); + + + Set<String> keySet = searchRootHash.keySet(); + Iterator<String> itr = keySet.iterator(); + String[] arrayOfVertices = new String[keySet.size()]; + int i = 0; + while (itr.hasNext()) { + arrayOfVertices[i] = itr.next(); + i++; + } + //start from all vertices provided + //repeat checking the out edge for the tag and the in edge for reverse tag + //emit all vertices not already seen and start again + //return a tree structure of the vertices and edges touched by this traversal + Tree<Element> resultTree = this.engine.asAdmin().getReadOnlyTraversalSource().V(arrayOfVertices) + .emit().repeat(__.union(__.outE().has(tag, true), __.inE().has(reverseTag, true)).otherV()).tree().next(); + + //the resulting tree includes the edges because of our query, we'll need to remove them + Tree<Vertex> sanitizedTree = removeUnwantedItems(resultTree); + + //if we have secondary filters then check each tree returned for matches + if (!secondaryFilterHash.isEmpty()) { + filterOutResultTrees(sanitizedTree, secondaryFilterHash); + } + return sanitizedTree; + + }// End of runEdgeTagQuery() + + /** + * Identify top node set. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param edgeTag the edge tag + * @param topNodeType the top node type + * @param initialFilterHash the initial filter hash + * @param maxLevels the max levels + * @return List<titanVertex> + * @throws AAIException the AAI exception + */ + public HashMap<String, Vertex> identifyTopNodeSet( String transId, String fromAppId, + String edgeTag, String topNodeType, Map<String,Object> initialFilterHash, int maxLevels ) + throws AAIException { + + final String tag = edgeTag; + final String reverseTag = edgeTag + "-REV"; + HashMap <String, Vertex> topVertHash = new HashMap <>(); + + // Given the filter, we want to select all the nodes of the type the filter tells us that have the + // property they gave us. + // Then looping through those start points, we will look "up" and then "down" to find the set of target/top nodes. + + if( initialFilterHash == null || initialFilterHash.isEmpty() ){ + throw new AAIException("AAI_6118", " initialFilterHash is required for identifyInitialNodeSet() call. \n"); + } + + // NOTE: we're expecting the filter to have a format like this: "nodeType.parameterName:parameterValue" + Iterator <?> it = initialFilterHash.entrySet().iterator(); + // -- DEBUG -- for now we only deal with ONE initial filter parameter + // it would be easy enough to deal with multiple parameters if they all + // applied to the same nodeType. + String propNodeTypeDotName = ""; + String initNodeType = ""; + String initPropName = ""; + + String extraChecks = ""; + + String propVal = ""; + if( it.hasNext() ){ + Map.Entry<?,?> propEntry = (Map.Entry<?,?>) it.next(); + propNodeTypeDotName = (propEntry.getKey()).toString(); + propVal = (propEntry.getValue()).toString(); + } + + GraphTraversalSource source = this.engine.asAdmin().getReadOnlyTraversalSource(); + GraphTraversal<Vertex, Vertex> g; + + int periodLoc = propNodeTypeDotName.indexOf("."); + if( periodLoc <= 0 ){ + throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + propNodeTypeDotName + "]. Expected format = [nodeName.paramName]\n"); + } + else { + initNodeType = propNodeTypeDotName.substring(0,periodLoc); + initPropName = propNodeTypeDotName.substring(periodLoc + 1); + + //there used to be logic here that would do something special for generic-vnf.vnf-name and vserver.vserver-name + //it would attempt a search as they sent it, if nothing came back, try as all upper, try as all lower, then fail + //here it checks whether something comes back or not, if not change the case and try again + if( (initNodeType.equals("generic-vnf") && initPropName.equals("vnf-name")) + || (initNodeType.equals("vserver") && initPropName.equals("vserver-name")) ){ + if (!this.checkKludgeCase(initNodeType, initPropName, propVal)) { + if (this.checkKludgeCase(initNodeType, initPropName, propVal.toUpperCase())) { + propVal = propVal.toUpperCase(); + } else { + if (this.checkKludgeCase(initNodeType, initPropName, propVal)) { + propVal = propVal.toLowerCase(); + } + } + } + } + g = source.V().has(AAIProperties.NODE_TYPE, initNodeType).has(initPropName, propVal); + + //search all around bounded by our edge tag for start nodes that match our topNodeType + if (!topNodeType.equals(initNodeType)) { + + g.union(__.<Vertex>start().until(__.has(AAIProperties.NODE_TYPE, topNodeType)) + .repeat(__.union(__.inE().has(reverseTag, true), __.outE().has(tag, true)).otherV()), + __.<Vertex>start().until(__.has(AAIProperties.NODE_TYPE, topNodeType)) + .repeat(__.union(__.inE().has(tag, true), __.outE().has(reverseTag, true)).otherV())).dedup(); + } + + List<Vertex> results = g.toList(); + + results.forEach(v -> { + topVertHash.put(v.id().toString(), v); + }); + } + if( topVertHash.isEmpty() ){ + // No Vertex was found - throw a not-found exception + throw new AAIException("AAI_6114", "No Node of type " + topNodeType + " found for properties: " + initialFilterHash.toString() + extraChecks); + } + else { + return topVertHash; + } + + }// End identifyInitialNodeSet() + + /** + * This is a carryover from the previous version. + * We may be able to remove this. + * + * @param nodeType + * @param propName + * @param propValue + * @return + */ + private boolean checkKludgeCase(String nodeType, String propName, String propValue) { + return this.engine.getQueryBuilder().getVerticesByIndexedProperty(AAIProperties.NODE_TYPE, nodeType).getVerticesByProperty(propName, propValue).hasNext(); + } + + /** + * This method starts from the top of the tree object and checks each nested tree. + * If that tree does not contain a node (or nodes) that match the filterHash, remove it + * + * @param tree + * @param filterHash + * @throws AAIException + */ + private void filterOutResultTrees(Tree<Vertex> tree, Map<String,Object> filterHash) throws AAIException { + Set<Vertex> topLevelKeys = new LinkedHashSet<>(tree.keySet()); + for (Vertex topLevel : topLevelKeys) { + if (!this.checkVertexWithFilters(topLevel, filterHash)) { + if (!filterOutResultTreesHelper(tree.get(topLevel), filterHash)) { + //if we never found anything to satisfy our filter, remove the entire result tree + tree.remove(topLevel); + } + } + } + } + + /** + * Checks all vertices of a tree with the provided filterHash + * + * @param tree + * @param filterHash + * @return + * @throws AAIException + */ + private boolean filterOutResultTreesHelper(Tree<Vertex> tree, Map<String,Object> filterHash) throws AAIException { + + Set<Vertex> keys = tree.keySet(); + + for (Vertex v : keys) { + if (checkVertexWithFilters(v, filterHash)) { + return true; + } else { + if (filterOutResultTreesHelper(tree.get(v), filterHash)) { + return true; + } + } + } + + return false; + } + /** + * Checks whether a vertex matches the filterHash provided + * + * @param v + * @param filterHash + * @return + * @throws AAIException + */ + private boolean checkVertexWithFilters(Vertex v, Map<String,Object> filterHash) throws AAIException { + Iterator <?> it = filterHash.entrySet().iterator(); + + while( it.hasNext() ){ + Map.Entry<?,?> filtEntry = (Map.Entry<?,?>) it.next(); + String propNodeTypeDotName = (filtEntry.getKey()).toString(); + String value = (filtEntry.getValue()).toString(); + + int periodLoc = propNodeTypeDotName.indexOf("."); + if( periodLoc <= 0 ){ + throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + propNodeTypeDotName + "]. Expected format = [nodeName.paramName]\n"); + } + else { + String nodeType = propNodeTypeDotName.substring(0,periodLoc); + String propertyName = propNodeTypeDotName.substring(periodLoc + 1); + String nt = v.<String>property("aai-node-type").orElse(null); + if( nt.equals( nodeType ) ){ + if( propertyName.equals("vertex-id") ){ + // vertex-id can't be gotten the same way as other properties + String thisVtxId = v.id().toString(); + if( thisVtxId.equals(value) ){ + return true; + } + } + else { + Object thisValObj = v.property(propertyName).orElse(null); + if( thisValObj != null ){ + String thisVal = thisValObj.toString(); + if( thisVal.equals(value) ){ + return true; + } + } + } + } + } + } + + return false; + } + + /** + * Removes every other tree from the originalTree provided. + * It is designed to specifically handle removing unwanted edges from the originalTree + * @param originalTree + * @return + */ + private Tree<Vertex> removeUnwantedItems(Tree<Element> originalTree) { + + Tree<Vertex> newTree = new Tree<>(); + Set<Element> keys = originalTree.keySet(); + for (Element element : keys) { + newTree.put((Vertex)element, removeUnwantedItemsHelper(originalTree.get(element).getTreesAtDepth(2))); + } + + return newTree; + + + } + + private Tree<Vertex> removeUnwantedItemsHelper(List<Tree<Element>> originalTrees) { + Tree<Vertex> newTree = new Tree<>(); + for (Tree<Element> tree : originalTrees) { + newTree.addTree(removeUnwantedItems(tree)); + } + + return newTree; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmap/AAIGraph.java b/aai-core/src/main/java/org/openecomp/aai/dbmap/AAIGraph.java new file mode 100644 index 00000000..b4be1a37 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbmap/AAIGraph.java @@ -0,0 +1,187 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbmap; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.tinkerpop.gremlin.structure.io.IoCore; + +import org.openecomp.aai.dbgen.SchemaGenerator; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.util.AAIConstants; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanTransaction; +import com.thinkaurelius.titan.core.schema.TitanManagement; + +/** + * Database Mapping class which acts as the middle man between the REST + * interface objects and Titan DB objects. This class provides methods to commit + * the objects received on the REST interface into the Titan graph database as + * vertices and edges. Transactions are also managed here by using a TitanGraph + * object to load, commit/rollback and shutdown for each request. The data model + * rules such as keys/required properties are handled by calling DBMeth methods + * which are driven by a specification file in json. + * + + */ +public class AAIGraph { + + protected Map<String, TitanGraph> graphs = new HashMap<>(); + protected static final String COMPONENT = "aaidbmap"; + private final String REALTIME_DB = "realtime"; + private final String CACHED_DB = "cached"; + private final EELFLogger logger = EELFManager.getInstance().getLogger(this.getClass().getSimpleName()); + + + /** + * Instantiates a new AAI graph. + */ + private AAIGraph() { + try { + String rtConfig = System.getProperty("realtime.db.config"); + String cachedConfig = System.getProperty("cached.db.config"); + if (rtConfig == null) { + rtConfig = AAIConstants.REALTIME_DB_CONFIG; + } + if (cachedConfig == null) { + cachedConfig = AAIConstants.CACHED_DB_CONFIG; + } + this.loadGraph(REALTIME_DB, rtConfig); + this.loadGraph(CACHED_DB, cachedConfig); + } catch (Exception e) { + throw new RuntimeException("Failed to instantiate graphs", e); + } + } + + private static class Helper { + private static final AAIGraph INSTANCE = new AAIGraph(); + } + + /** + * Gets the single instance of AAIGraph. + * + * @return single instance of AAIGraph + */ + public static AAIGraph getInstance() { + return Helper.INSTANCE; + } + + private void loadGraph(String name, String configPath) throws AAIException { + try { + final TitanGraph graph = TitanFactory.open(configPath); + InputStream is = new FileInputStream(configPath); + Properties graphProps = new Properties(); + graphProps.load(is); + + if (graphProps.get("storage.backend").equals("inmemory")) { + // Load the propertyKeys, indexes and edge-Labels into the DB + loadSchema(graph); + if (graphProps.containsKey("load.snapshot.file")) { + String value = graphProps.getProperty("load.snapshot.file"); + if ("true".equals(value)) { + try { + String location = System.getProperty("snapshot.location"); + logAndPrint(logger, "Loading snapshot to inmemory graph."); + TitanTransaction transaction = graph.newTransaction(); + transaction.io(IoCore.graphson()).readGraph(location); + transaction.commit(); + logAndPrint(logger, "Snapshot loaded to inmemory graph."); + } catch (IOException e) { + graph.close(); + logAndPrint(logger, "ERROR: Could not load datasnapshot to in memory graph. \n" + ExceptionUtils.getFullStackTrace(e)); + System.exit(0); + } + } + } + } + + if (graph == null) { + throw new AAIException("AAI_5102"); + } + + graphs.put(name, graph); + } catch (FileNotFoundException fnfe) { + throw new AAIException("AAI_4001"); + } catch (IOException e) { + throw new AAIException("AAI_4002"); + + } + } + + private void loadSchema(TitanGraph graph) { + // Load the propertyKeys, indexes and edge-Labels into the DB + TitanManagement graphMgt = graph.openManagement(); + + System.out.println("-- loading schema into Titan"); + SchemaGenerator.loadSchemaIntoTitan( graph, graphMgt ); + } + + /** + * Graph shutdown. + */ + public void graphShutdown() { + graphs.get(REALTIME_DB).close(); + } + + /** + * Gets the graph. + * + * @return the graph + */ + public TitanGraph getGraph() { + return graphs.get(REALTIME_DB); + } + + public void graphShutdown(DBConnectionType connectionType) { + + graphs.get(this.getGraphName(connectionType)).close(); + } + + public TitanGraph getGraph(DBConnectionType connectionType) { + return graphs.get(this.getGraphName(connectionType)); + } + + private String getGraphName(DBConnectionType connectionType) { + String graphName = ""; + if (DBConnectionType.CACHED.equals(connectionType)) { + graphName = this.CACHED_DB; + } else if (DBConnectionType.REALTIME.equals(connectionType)) { + graphName = this.REALTIME_DB; + } + + return graphName; + } + + private void logAndPrint(EELFLogger logger, String msg) { + System.out.println(msg); + logger.info(msg); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmap/DBConnectionType.java b/aai-core/src/main/java/org/openecomp/aai/dbmap/DBConnectionType.java new file mode 100644 index 00000000..a2c01e21 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbmap/DBConnectionType.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbmap; + +public enum DBConnectionType { + REALTIME, + CACHED +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java new file mode 100644 index 00000000..9a56fc69 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java @@ -0,0 +1,472 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbmodel; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Multimap; + +public class DbEdgeRules { + + /* + * The EdgeRules data is set up as a key (fromNodeTypeA|toNodeTypeB) mapped + * to a string which holds the info we need to build an edge from nodeTypeA + * to nodeTypeB. Note -- the MultiMap will let us define more than one type + * of edge between a given pair of nodeTypes, but for now we never define + * more than one. + * + * The edgeInfo part is comma separated and looks like this: + * "edgeLabel,direction,multiplicityRule,isParent,usesResource,hasDelTarget,SVC-INFRA" This + * format is encoded into the EdgeInfoMap below. + * MultiplicityRule can be either "Many2Many", "Many2One", "One2Many" or "One2One" + * The values for the things after multiplicityRule can be either "true", "false" or "reverse". "reverse" is + * really saying that this tag does apply, but the edge will be traversed + * the opposite way from the same tag that just has "true". + */ + public static final Map<Integer, String> EdgeInfoMap; + static { + EdgeInfoMap = new HashMap<Integer, String>(); + EdgeInfoMap.put(0, "edgeLabel"); + EdgeInfoMap.put(1, "direction"); + EdgeInfoMap.put(2, "multiplicityRule"); + EdgeInfoMap.put(3, "isParent"); + EdgeInfoMap.put(4, "usesResource"); + EdgeInfoMap.put(5, "hasDelTarget"); + EdgeInfoMap.put(6, "SVC-INFRA"); + } + + public static Integer firstTagIndex = 3; + + public static final Multimap<String, String> EdgeRules = new ImmutableSetMultimap.Builder<String, String>() + .putAll("availability-zone|complex", + "groupsResourcesIn,OUT,Many2Many,false,false,false,false") + .putAll("availability-zone|service-capability", + "supportsServiceCapability,OUT,Many2Many,false,false,false,false") + .putAll("cloud-region|complex", + "locatedIn,OUT,Many2One,false,false,false,false") + .putAll("cloud-region|l3-network", + "uses,OUT,Many2Many,false,false,false,false") + .putAll("cloud-region|tenant", + "has,OUT,One2Many,true,false,false,reverse") + .putAll("cloud-region|image", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|flavor", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|availability-zone", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|oam-network", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|dvs-switch", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|volume-group", + "has,OUT,One2Many,true,true,false,false") + .putAll("cloud-region|group-assignment", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|snapshot", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|zone", + "isMemberOf,OUT,Many2One,false,false,false,false") + .putAll("complex|ctag-pool", + "hasCtagPool,OUT,Many2Many,true,false,false,false") + .putAll("complex|l3-network", + "usesL3Network,OUT,Many2Many,false,false,false,true") + .putAll("ctag-pool|availability-zone", + "supportsAvailabilityZone,OUT,Many2Many,false,false,false,false") + .putAll("customer|service-subscription", + "subscribesTo,OUT,Many2Many,true,false,false,reverse") + .putAll("dvs-switch|availability-zone", + "existsIn,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("generic-vnf|availability-zone", + "hasAvailabilityZone,OUT,Many2Many,false,false,false,true") + .putAll("generic-vnf|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,true") + .putAll("generic-vnf|l3-network", + "usesL3Network,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|pserver", + "runsOnPserver,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|vnf-image", + "usesVnfImage,OUT,Many2One,false,false,false,true") + .putAll("generic-vnf|vserver", + "runsOnVserver,OUT,One2Many,false,true,false,true") + .putAll("generic-vnf|service-instance", + "hasInstance,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|site-pair-set", + "hasSitePairSet,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|network-profile", + "hasNetworkProfile,OUT,Many2Many,false,false,false,false") + .putAll("group-assignment|tenant", + "has,OUT,Many2Many,false,false,false,false") + .putAll("group-assignment|pserver", + "has,OUT,One2Many,false,false,false,false") + .putAll("image|metadata", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("image|metadatum", + "hasMetaDatum,OUT,Many2Many,true,false,false,false") + .putAll("l-interface|instance-group", + "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("l-interface|l3-interface-ipv4-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("l-interface|l3-interface-ipv6-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("l-interface|l-interface", + "has,OUT,One2Many,true,false,false,true") + .putAll("l-interface|logical-link", + "usesLogicalLink,OUT,Many2Many,false,false,true,true") + .putAll("lag-interface|logical-link", + "uses,OUT,Many2Many,false,false,true,true") + .putAll("l-interface|vlan","hasVlan,OUT,Many2Many,true,false,false,false") + .putAll("l-interface|sriov-vf","has,OUT,One2One,true,false,false,false") + .putAll("l3-interface-ipv4-address-list|instance-group", + "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("l3-interface-ipv6-address-list|instance-group", + "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("l3-interface-ipv4-address-list|l3-network", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv6-address-list|l3-network", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv4-address-list|subnet", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv6-address-list|subnet", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-network|vpn-binding", + "usesVpnBinding,OUT,Many2Many,false,false,false,false") + .putAll("l3-network|subnet", + "hasSubnet,OUT,Many2Many,true,false,false,reverse") + .putAll("l3-network|service-instance", + "hasInstance,OUT,Many2Many,false,false,false,reverse") + .putAll("l3-network|ctag-assignment", + "hasCtagAssignment,OUT,Many2Many,true,false,false,true") + .putAll("l3-network|network-policy", + "uses,OUT,Many2Many,false,false,false,true") + .putAll("l3-network|segmentation-assignment", + "has,OUT,One2Many,true,false,false,false") + .putAll("l3-network|route-table-reference", + "uses,OUT,Many2Many,false,false,false,false") + .putAll("lag-interface|lag-link", + "usesLAGLink,OUT,Many2Many,false,true,true,true") + .putAll("lag-interface|p-interface", + "usesPInterface,OUT,Many2Many,false,true,false,true") + .putAll("lag-interface|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("logical-link|lag-link", + "usesLAGLink,OUT,Many2Many,false,true,false,true") + .putAll("logical-link|pnf", + "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|logical-link", + "uses,OUT,One2Many,false,false,false,true") + .putAll("model|model-ver", + "has,OUT,One2Many,true,false,false,false") + .putAll("model-ver|model-element", + "startsWith,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-ver", + "isA,OUT,Many2One,false,false,false,false") + .putAll("model-ver|metadatum", + "hasMetaData,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-element", + "connectsTo,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-constraint", + "uses,OUT,One2Many,true,false,false,false") + .putAll("model-element|constrained-element-set", + "connectsTo,OUT,One2Many,true,false,false,false") + .putAll("model-constraint|constrained-element-set", + "uses,OUT,One2Many,true,false,false,false") + .putAll("constrained-element-set|element-choice-set", + "uses,OUT,One2Many,true,false,false,false") + .putAll("element-choice-set|model-element", + "has,OUT,One2Many,true,false,false,false") + .putAll("named-query|model", + "relatedTo,OUT,One2Many,false,false,false,false") + .putAll("named-query|named-query-element", + "startsWith,OUT,One2One,true,false,false,false") + .putAll("named-query-element|named-query-element", + "connectsTo,OUT,Many2Many,true,false,false,false") + .putAll("named-query-element|model", + "isA,OUT,Many2One,false,false,false,false") + .putAll("named-query-element|property-constraint", + "uses,OUT,One2Many,true,false,false,false") + .putAll("named-query-element|related-lookup", + "uses,OUT,One2Many,true,false,false,false") + .putAll("instance-group|model", + "targets,OUT,Many2Many,false,false,false,false") + .putAll("newvce|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,false") + .putAll("oam-network|complex", + "definedFor,OUT,Many2Many,false,false,false,false") + .putAll("oam-network|service-capability", + "supportsServiceCapability,OUT,Many2Many,false,false,false,false") + .putAll("p-interface|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("p-interface|physical-link", + "usesPhysicalLink,OUT,Many2Many,false,false,true,false") + .putAll("p-interface|logical-link", + "usesLogicalLink,OUT,Many2One,false,false,false,true") + .putAll("port-group|cvlan-tag", "hasCTag,OUT,Many2Many,true,true,false,true") + .putAll("pserver|complex", "locatedIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|cloud-region","locatedIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|availability-zone","existsIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,true") + .putAll("pserver|p-interface", + "hasPinterface,OUT,Many2Many,true,true,false,true") + .putAll("pserver|zone", + "isMemberOf,OUT,Many2One,false,false,false,false") + .putAll("pnf|p-interface", + "hasPinterface,OUT,Many2Many,true,true,false,true") + .putAll("pnf|lag-interface", + "has,OUT,One2Many,true,false,false,true") + .putAll("pnf|complex", + "locatedIn,OUT,Many2One,false,false,false,false") + .putAll("pnf|instance-group", + "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("pnf|zone", + "isMemberOf,OUT,Many2One,false,false,false,false") + .putAll("service-instance|cvlan-tag", + "hasIPAGFacingVLAN,OUT,Many2Many,false,true,false,false") + .putAll("service-instance|pnf", + "uses,OUT,One2Many,false,true,false,false") + .putAll("service-subscription|service-instance", + "hasInstance,OUT,Many2Many,true,false,false,reverse") + .putAll("site-pair-set|routing-instance", + "hasRoutingInstance,OUT,Many2Many,true,false,false,false") + .putAll("routing-instance|site-pair", + "hasSitePair,OUT,Many2Many,true,false,false,false") + .putAll("site-pair|class-of-service", + "hasClassOfService,OUT,Many2Many,true,false,false,false") + .putAll("tenant|l3-network", + "usesL3Network,OUT,Many2Many,false,false,false,false") + .putAll("tenant|service-subscription", + "relatedTo,OUT,Many2Many,false,false,false,false") + .putAll("tenant|vserver", "owns,OUT,One2Many,true,false,false,reverse") + .putAll("vce|availability-zone", + "hasAvailabilityZone,OUT,Many2Many,false,false,false,false") + .putAll("vce|complex", "locatedIn,OUT,Many2Many,false,false,false,true") + .putAll("vce|port-group", "hasPortGroup,OUT,Many2Many,true,true,false,true") + .putAll("vce|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,true") + .putAll("vce|service-instance", + "hasServiceInstance,OUT,Many2Many,false,false,false,reverse") + .putAll("virtual-data-center|generic-vnf", + "hasVNF,OUT,Many2Many,false,false,false,reverse") + .putAll("vlan|l3-interface-ipv4-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("vlan|l3-interface-ipv6-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("vpe|complex", "locatedIn,OUT,Many2Many,false,false,false,false") + .putAll("vpe|ctag-pool", "usesCtagPool,OUT,Many2Many,false,false,false,false") + .putAll("vpe|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,false") + .putAll("vpe|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,false") + .putAll("vpe|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,false") + .putAll("vpls-pe|complex", "locatedIn,OUT,Many2Many,false,false,false,false") + .putAll("vpls-pe|ctag-pool", + "usesCtagPool,OUT,Many2Many,false,false,false,false") + .putAll("vpls-pe|p-interface", + "hasPinterface,OUT,Many2Many,true,false,false,false") + .putAll("vpls-pe|lag-interface", + "hasLAGinterface,OUT,Many2Many,true,false,false,false") + .putAll("vserver|flavor", "hasFlavor,OUT,Many2One,false,false,false,true") + .putAll("vserver|image", "hasImage,OUT,Many2One,false,false,false,true") + .putAll("vserver|ipaddress", + "hasIpAddress,OUT,Many2Many,true,true,false,false") + .putAll("vserver|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("vserver|pserver", + "runsOnPserver,OUT,Many2One,false,true,false,true") + .putAll("vserver|volume", "hasVolume,OUT,Many2Many,true,true,false,true") + .putAll("vserver|vnfc", "hosts,OUT,Many2Many,false,true,false,true") + .putAll("vserver|snapshot", "uses,OUT,One2One,false,false,false,true") + .putAll("service-instance|connector", "uses,OUT,Many2Many,false,true,false,false") + .putAll("service-instance|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("service-instance|logical-link", "uses,OUT,Many2Many,false,false,true,false") + .putAll("service-instance|vlan", "dependsOn,OUT,One2Many,false,true,false,false") + .putAll("service-instance|service-instance", "dependsOn,OUT,One2Many,false,true,false,false") + .putAll("connector|virtual-data-center", "contains,OUT,Many2Many,false,false,false,false") + .putAll("connector|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("virtual-data-center|logical-link", "contains,OUT,Many2Many,false,true,false,false") + .putAll("logical-link|generic-vnf", "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|pserver", "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("vlan|multicast-configuration", "uses,OUT,Many2Many,false,true,false,false") + .putAll("volume-group|complex", "existsIn,OUT,Many2Many,false,false,false,true") + .putAll("volume-group|tenant", "belongsTo,OUT,Many2Many,false,false,false,true") + .putAll("ipsec-configuration|vig-server", "hasVigServer,OUT,One2Many,true,true,false,false") + .putAll("generic-vnf|ipsec-configuration", "uses,OUT,Many2One,false,true,false,false") + .putAll("vf-module|volume-group", "uses,OUT,One2One,false,false,false,true") + .putAll("vserver|vf-module", "isPartOf,OUT,Many2One,false,false,false,true") + .putAll("vf-module|l3-network", "uses,OUT,Many2Many,false,false,false,true") + .putAll("vf-module|vnfc", "uses,OUT,One2Many,false,false,true,true") + .putAll("generic-vnf|vf-module", "has,OUT,One2Many,true,false,false,true") + .putAll("generic-vnf|volume-group", "uses,OUT,One2Many,false,false,false,true") + .putAll("generic-vnf|vnfc", "uses,OUT,One2Many,false,false,true,true") + .putAll("vlan|logical-link", "usesLogicalLink,OUT,Many2Many,false,false,true,true") + .putAll("vpn-binding|route-target", "has,OUT,One2Many,true,false,false,false") + .putAll("service-instance|ctag-assignment","uses,OUT,One2Many,false,false,false,false") + // The next edge is needed in 1702 but will be worked in user story AAI-6848 + //.putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|generic-vnf", "isPartOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|l3-network", "isPartOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|network-policy", "uses,OUT,One2One,false,false,false,false") + .putAll("allotted-resource|vlan", "isPartOf,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("service-instance|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|tunnel-xconnect", "has,OUT,One2One,true,false,false,false") + .putAll("logical-link|cloud-region", "existsIn,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|vpn-binding", "uses,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|entitlement", "has,OUT,One2Many,true,false,false,false") + .putAll("generic-vnf|license", "has,OUT,One2Many,true,false,false,false") + .putAll("vce|entitlement", "has,OUT,One2Many,true,false,false,false") + .putAll("vce|license", "has,OUT,One2Many,true,false,false,false") + .putAll("vpe|entitlement", "has,OUT,One2Many,true,false,false,false") + .putAll("vpe|license", "has,OUT,One2Many,true,false,false,false") + .putAll("zone|complex", "existsIn,OUT,Many2One,false,false,false,false") + .putAll("service-instance|allotted-resource", "has,OUT,Many2Many,true,false,false,false") + .putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false") + .build(); + + public static final Multimap<String, String> DefaultDeleteScope = new ImmutableSetMultimap.Builder<String, String>() + .putAll("customer", "CASCADE_TO_CHILDREN") + .putAll("cloud-region", "THIS_NODE_ONLY") + .putAll("service-subscription", "CASCADE_TO_CHILDREN") + .putAll("service-instance", "CASCADE_TO_CHILDREN") + .putAll("vce", "CASCADE_TO_CHILDREN") + .putAll("port-group", "CASCADE_TO_CHILDREN") + .putAll("cvlan-tag", "THIS_NODE_ONLY") + .putAll("tenant", "THIS_NODE_ONLY") + .putAll("vserver", "CASCADE_TO_CHILDREN") + .putAll("volume", "THIS_NODE_ONLY") + .putAll("ipaddress", "THIS_NODE_ONLY") + .putAll("image", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("pserver", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("availability-zone", "ERROR_IF_ANY_IN_EDGES") + .putAll("oam-network", "ERROR_IF_ANY_IN_EDGES") + .putAll("dvs-switch", "THIS_NODE_ONLY") + .putAll("service-capability", "ERROR_IF_ANY_IN_EDGES") + .putAll("complex", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("flavor", "ERROR_IF_ANY_IN_EDGES") + .putAll("metadata", "THIS_NODE_ONLY") + .putAll("metadatum", "THIS_NODE_ONLY") + .putAll("model", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("model-ver", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("model-element", "CASCADE_TO_CHILDREN") + .putAll("model-constraint", "CASCADE_TO_CHILDREN") + .putAll("property-constraint", "CASCADE_TO_CHILDREN") + .putAll("related-lookup", "CASCADE_TO_CHILDREN") + .putAll("constrained-element-set", "CASCADE_TO_CHILDREN") + .putAll("element-choice-set", "CASCADE_TO_CHILDREN") + .putAll("named-query", "CASCADE_TO_CHILDREN") + .putAll("named-query-element", "CASCADE_TO_CHILDREN") + .putAll("network-policy", "THIS_NODE_ONLY") + .putAll("collect-lookup", "THIS_NODE_ONLY") + .putAll("service", "ERROR_IF_ANY_IN_EDGES") + .putAll("newvce", "CASCADE_TO_CHILDREN") + .putAll("vpe", "CASCADE_TO_CHILDREN") + .putAll("vpls-pe", "CASCADE_TO_CHILDREN") + .putAll("l-interface", "CASCADE_TO_CHILDREN") + .putAll("vlan", "CASCADE_TO_CHILDREN") + .putAll("p-interface", "CASCADE_TO_CHILDREN") + .putAll("l3-interface-ipv6-address-list", "THIS_NODE_ONLY") + .putAll("l3-interface-ipv4-address-list", "THIS_NODE_ONLY") + .putAll("logical-link", "THIS_NODE_ONLY") + .putAll("physical-link", "THIS_NODE_ONLY") + .putAll("lag-link", "THIS_NODE_ONLY") + .putAll("lag-interface", "CASCADE_TO_CHILDREN") + .putAll("virtual-data-center", "CASCADE_TO_CHILDREN") + .putAll("generic-vnf", "CASCADE_TO_CHILDREN") + .putAll("l3-network", "CASCADE_TO_CHILDREN") + .putAll("ctag-pool", "THIS_NODE_ONLY") + .putAll("subnet", "THIS_NODE_ONLY") + .putAll("sriov-vf", "THIS_NODE_ONLY") + .putAll("vpn-binding", "ERROR_IF_ANY_IN_EDGES") + .putAll("vnf-image", "ERROR_IF_ANY_IN_EDGES") + .putAll("site-pair-set", "CASCADE_TO_CHILDREN") + .putAll("routing-instance", "CASCADE_TO_CHILDREN") + .putAll("site-pair", "CASCADE_TO_CHILDREN") + .putAll("class-of-service", "THIS_NODE_ONLY") + .putAll("connector", "CASCADE_TO_CHILDREN") + .putAll("vnfc", "THIS_NODE_ONLY") + .putAll("multicast-configuration", "THIS_NODE_ONLY") + .putAll("volume-group", "THIS_NODE_ONLY") + .putAll("ctag-assignment", "THIS_NODE_ONLY") + .putAll("pnf", "CASCADE_TO_CHILDREN") + .putAll("ipsec-configuration", "CASCADE_TO_CHILDREN") + .putAll("vig-server", "THIS_NODE_ONLY") + .putAll("vf-module", "THIS_NODE_ONLY") + .putAll("snapshot", "THIS_NODE_ONLY") + .putAll("group-assignment", "THIS_NODE_ONLY") + .putAll("segmentation-assignment", "THIS_NODE_ONLY") + .putAll("route-table-reference", "THIS_NODE_ONLY") + .putAll("network-profile", "THIS_NODE_ONLY") + .putAll("allotted-resource", "CASCADE_TO_CHILDREN") + .putAll("tunnel-xconnect", "THIS_NODE_ONLY") + .putAll("instance-group","THIS_NODE_ONLY") + .putAll("entitlement","THIS_NODE_ONLY") + .putAll("license","THIS_NODE_ONLY") + .putAll("zone", "THIS_NODE_ONLY") + .putAll("route-target", "CASCADE_TO_CHILDREN").build(); + + // NOTE -- Sorry, this is ugly, but we are mapping the nodeTypeCategory two + // ways just to + // make the code a little less bulky. But that means that we need to ensure + // that + // nodeTypeCategory and nodeTypeCatMap are kept in synch. + + // NodeTypeCategory: key is: nodeTypeCategory, value is: + // "nodeTypes,keyProperties,AltKeyProps,depNode4UniquenessFlag" + public static final Multimap<String, String> NodeTypeCategory = new ImmutableSetMultimap.Builder<String, String>() + .putAll("vnf", "vce|vpe|generic-vnf,vnf-id,,true").build(); + + // NodeTypeCatMap: key is nodeType; value is: "nodeTypeCategory" + // So -- we're assuming that a nodeType can only be in one nodeTypeCategory. + public static final Map<String, String> NodeTypeCatMap; + static { + NodeTypeCatMap = new HashMap<String, String>(); + NodeTypeCatMap.put("vpe", "vnf"); + NodeTypeCatMap.put("vce", "vnf"); + NodeTypeCatMap.put("generic-vnf", "vnf"); + } + + // ReservedPropNames: keys are property names of (node) properties that are + // common to all nodes and + // should not be removed if not passed in on an UPDATE request. + public static final Map<String, String> ReservedPropNames; + static { + ReservedPropNames = new HashMap<String, String>(); + ReservedPropNames.put("source-of-truth", ""); + ReservedPropNames.put("last-mod-source-of-truth", ""); + ReservedPropNames.put("aai-created-ts", ""); + ReservedPropNames.put("aai-last-mod-ts", ""); + } + + // This just lists which node types can be connected to themselves recursively. + // It's temporary - since DbEdgeRules is going to be overhauled in 16-10, this will + // get generated automatically. But for 1607, it can work like this. + public static final Map<String, String> CanBeRecursiveNT; + static { + CanBeRecursiveNT = new HashMap<String, String>(); + CanBeRecursiveNT.put("model-element", ""); + CanBeRecursiveNT.put("service-instance", ""); + CanBeRecursiveNT.put("named-query-element", ""); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/v8/gen/DbEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v8/gen/DbEdgeRules.java new file mode 100644 index 00000000..fac0ae48 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v8/gen/DbEdgeRules.java @@ -0,0 +1,300 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbmodel.v8.gen; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Multimap; + +public class DbEdgeRules { + + /* + * The EdgeRules data is set up as a key (fromNodeTypeA|toNodeTypeB) mapped + * to a string which holds the info we need to build an edge from nodeTypeA + * to nodeTypeB. Note -- the MultiMap will let us define more than one type + * of edge between a given pair of nodeTypes, but for now we never define + * more than one. + * + * The edgeInfo part is comma separated and looks like this: + * "edgeLabel,direction,multiplicityRule,isParent,usesResource,hasDelTarget,SVC-INFRA" This + * format is encoded into the EdgeInfoMap below. + * MultiplicityRule can be either "Many2Many", "Many2One", "One2Many" or "One2One" + * The values for the things after multiplicityRule can be either "true", "false" or "reverse". "reverse" is + * really saying that this tag does apply, but the edge will be traversed + * the opposite way from the same tag that just has "true". + */ + public static final Map<Integer, String> EdgeInfoMap; + static { + EdgeInfoMap = new HashMap<Integer, String>(); + EdgeInfoMap.put(0, "edgeLabel"); + EdgeInfoMap.put(1, "direction"); + EdgeInfoMap.put(2, "multiplicityRule"); + EdgeInfoMap.put(3, "isParent"); + EdgeInfoMap.put(4, "usesResource"); + EdgeInfoMap.put(5, "hasDelTarget"); + EdgeInfoMap.put(6, "SVC-INFRA"); + } + + public static Integer firstTagIndex = 3; + + public static final Multimap<String, String> EdgeRules = new ImmutableSetMultimap.Builder<String, String>() + .putAll("cloud-region|l3-network", + "uses,OUT,Many2Many,false,false,false,false") + .putAll("cloud-region|tenant", + "has,OUT,One2Many,true,false,false,reverse") + .putAll("cloud-region|image", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|flavor", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|availability-zone", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|volume-group", + "has,OUT,One2Many,true,true,false,false") + .putAll("cloud-region|group-assignment", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|snapshot", + "has,OUT,One2Many,true,false,false,false") + .putAll("customer|service-subscription", + "subscribesTo,OUT,Many2Many,true,false,false,reverse") + .putAll("generic-vnf|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("generic-vnf|availability-zone", + "hasAvailabilityZone,OUT,Many2Many,false,false,false,true") + .putAll("generic-vnf|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,true") + .putAll("generic-vnf|l3-network", + "usesL3Network,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|pserver", + "runsOnPserver,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|vserver", + "runsOnVserver,OUT,One2Many,false,true,false,true") + .putAll("generic-vnf|service-instance", + "hasInstance,OUT,Many2Many,false,true,false,true") + .putAll("group-assignment|tenant", + "has,OUT,Many2Many,false,false,false,false") + .putAll("group-assignment|pserver", + "has,OUT,One2Many,false,false,false,false") + .putAll("image|metadata", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("image|metadatum", + "hasMetaDatum,OUT,Many2Many,true,false,false,false") + .putAll("l-interface|l3-interface-ipv4-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("l-interface|l3-interface-ipv6-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("l-interface|logical-link", + "usesLogicalLink,OUT,Many2Many,false,false,true,true") + .putAll("l-interface|vlan","hasVlan,OUT,Many2Many,true,false,false,false") + .putAll("l3-interface-ipv4-address-list|l3-network", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv6-address-list|l3-network", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv4-address-list|subnet", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv6-address-list|subnet", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-network|subnet", + "hasSubnet,OUT,Many2Many,true,false,false,reverse") + .putAll("l3-network|service-instance", + "hasInstance,OUT,Many2Many,false,false,false,reverse") + .putAll("l3-network|ctag-assignment", + "hasCtagAssignment,OUT,Many2Many,true,false,false,true") + .putAll("l3-network|segmentation-assignment", + "has,OUT,One2Many,true,false,false,false") + .putAll("lag-interface|p-interface", + "usesPInterface,OUT,Many2Many,false,true,false,true") + .putAll("lag-interface|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("logical-link|pnf", + "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|logical-link", + "uses,OUT,One2Many,false,false,false,true") + .putAll("model|model-element", + "startsWith,OUT,One2Many,true,false,false,false") + .putAll("model-element|model", + "isA,OUT,Many2One,false,false,false,false") + .putAll("model|metadatum", + "hasMetaData,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-element", + "connectsTo,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-constraint", + "uses,OUT,One2Many,true,false,false,false") + .putAll("model-element|constrained-element-set", + "connectsTo,OUT,One2Many,true,false,false,false") + .putAll("model-constraint|constrained-element-set", + "uses,OUT,One2Many,true,false,false,false") + .putAll("constrained-element-set|element-choice-set", + "uses,OUT,One2Many,true,false,false,false") + .putAll("element-choice-set|model-element", + "has,OUT,One2Many,true,false,false,false") + .putAll("named-query|model", + "relatedTo,OUT,One2Many,false,false,false,false") + .putAll("named-query|named-query-element", + "startsWith,OUT,One2One,true,false,false,false") + .putAll("named-query-element|named-query-element", + "connectsTo,OUT,Many2Many,true,false,false,false") + .putAll("named-query-element|model", + "isA,OUT,Many2One,false,false,false,false") + .putAll("named-query-element|property-constraint", + "uses,OUT,One2Many,true,false,false,false") + .putAll("named-query-element|related-lookup", + "uses,OUT,One2Many,true,false,false,false") + .putAll("p-interface|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("p-interface|physical-link", + "usesPhysicalLink,OUT,Many2Many,false,false,true,false") + .putAll("p-interface|logical-link", + "usesLogicalLink,OUT,Many2One,false,false,false,true") + .putAll("pserver|cloud-region","locatedIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|availability-zone","existsIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,true") + .putAll("pserver|p-interface", + "hasPinterface,OUT,Many2Many,true,true,false,true") + .putAll("pnf|p-interface", + "hasPinterface,OUT,Many2Many,true,true,false,true") + .putAll("pnf|lag-interface", + "has,OUT,One2Many,true,false,false,true") + .putAll("service-instance|pnf", + "uses,OUT,One2Many,false,true,false,false") + .putAll("service-subscription|service-instance", + "hasInstance,OUT,Many2Many,true,false,false,reverse") + .putAll("tenant|l3-network", + "usesL3Network,OUT,Many2Many,false,false,false,false") + .putAll("tenant|service-subscription", + "relatedTo,OUT,Many2Many,false,false,false,false") + .putAll("tenant|vserver", "owns,OUT,One2Many,true,false,false,reverse") + .putAll("vlan|l3-interface-ipv4-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("vlan|l3-interface-ipv6-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("vserver|flavor", "hasFlavor,OUT,Many2One,false,false,false,true") + .putAll("vserver|image", "hasImage,OUT,Many2One,false,false,false,true") + .putAll("vserver|ipaddress", + "hasIpAddress,OUT,Many2Many,true,true,false,false") + .putAll("vserver|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("vserver|pserver", + "runsOnPserver,OUT,Many2One,false,true,false,true") + .putAll("vserver|volume", "hasVolume,OUT,Many2Many,true,true,false,true") + .putAll("vserver|vnfc", "hosts,OUT,Many2Many,false,true,false,true") + .putAll("vserver|snapshot", "uses,OUT,One2One,false,false,false,true") + .putAll("service-instance|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("service-instance|logical-link", "uses,OUT,Many2Many,false,false,true,false") + .putAll("service-instance|vlan", "dependsOn,OUT,One2Many,false,true,false,false") + .putAll("service-instance|service-instance", "dependsOn,OUT,One2Many,false,true,false,false") + .putAll("logical-link|generic-vnf", "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|pserver", "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("volume-group|tenant", "belongsTo,OUT,Many2Many,false,false,false,true") + .putAll("vf-module|volume-group", "uses,OUT,One2One,false,false,false,true") + .putAll("vserver|vf-module", "isPartOf,OUT,Many2One,false,false,false,true") + .putAll("vf-module|l3-network", "uses,OUT,Many2Many,false,false,false,true") + .putAll("vf-module|vnfc", "uses,OUT,One2Many,false,false,true,true") + .putAll("generic-vnf|vf-module", "has,OUT,One2Many,true,false,false,true") + .putAll("generic-vnf|volume-group", "uses,OUT,One2Many,false,false,false,true") + .putAll("generic-vnf|vnfc", "uses,OUT,One2Many,false,false,true,true") + .putAll("vlan|logical-link", "usesLogicalLink,OUT,One2One,false,false,true,true") + .build(); + + public static final Multimap<String, String> DefaultDeleteScope = new ImmutableSetMultimap.Builder<String, String>() + .putAll("customer", "CASCADE_TO_CHILDREN") + .putAll("cloud-region", "THIS_NODE_ONLY") + .putAll("service-subscription", "CASCADE_TO_CHILDREN") + .putAll("service-instance", "CASCADE_TO_CHILDREN") + .putAll("tenant", "CASCADE_TO_CHILDREN") + .putAll("vserver", "CASCADE_TO_CHILDREN") + .putAll("volume", "THIS_NODE_ONLY") + .putAll("ipaddress", "THIS_NODE_ONLY") + .putAll("image", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("pserver", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("availability-zone", "ERROR_IF_ANY_IN_EDGES") + .putAll("flavor", "ERROR_IF_ANY_IN_EDGES") + .putAll("metadata", "THIS_NODE_ONLY") + .putAll("metadatum", "THIS_NODE_ONLY") + .putAll("model", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("model-element", "CASCADE_TO_CHILDREN") + .putAll("named-query", "CASCADE_TO_CHILDREN") + .putAll("named-query-element", "CASCADE_TO_CHILDREN") + .putAll("collect-lookup", "THIS_NODE_ONLY") + .putAll("service", "ERROR_IF_ANY_IN_EDGES") + .putAll("l-interface", "CASCADE_TO_CHILDREN") + .putAll("vlan", "CASCADE_TO_CHILDREN") + .putAll("p-interface", "CASCADE_TO_CHILDREN") + .putAll("l3-interface-ipv6-address-list", "THIS_NODE_ONLY") + .putAll("l3-interface-ipv4-address-list", "THIS_NODE_ONLY") + .putAll("logical-link", "THIS_NODE_ONLY") + .putAll("physical-link", "THIS_NODE_ONLY") + .putAll("lag-interface", "CASCADE_TO_CHILDREN") + .putAll("l3-network", "CASCADE_TO_CHILDREN") + .putAll("subnet", "THIS_NODE_ONLY") + .putAll("vnfc", "THIS_NODE_ONLY") + .putAll("volume-group", "THIS_NODE_ONLY") + .putAll("ctag-assignment", "THIS_NODE_ONLY") + .putAll("pnf", "CASCADE_TO_CHILDREN") + .putAll("vf-module", "THIS_NODE_ONLY") + .putAll("snapshot", "THIS_NODE_ONLY") + .putAll("group-assignment", "THIS_NODE_ONLY") + .putAll("segmentation-assignment", "THIS_NODE_ONLY") + .putAll("generic-vnf", "CASCADE_TO_CHILDREN").build(); + + // NOTE -- Sorry, this is ugly, but we are mapping the nodeTypeCategory two + // ways just to + // make the code a little less bulky. But that means that we need to ensure + // that + // nodeTypeCategory and nodeTypeCatMap are kept in synch. + + // NodeTypeCategory: key is: nodeTypeCategory, value is: + // "nodeTypes,keyProperties,AltKeyProps,depNode4UniquenessFlag" + public static final Multimap<String, String> NodeTypeCategory = new ImmutableSetMultimap.Builder<String, String>() + .putAll("vnf", "generic-vnf,vnf-id,,true").build(); + + // NodeTypeCatMap: key is nodeType; value is: "nodeTypeCategory" + // So -- we're assuming that a nodeType can only be in one nodeTypeCategory. + public static final Map<String, String> NodeTypeCatMap; + static { + NodeTypeCatMap = new HashMap<String, String>(); + NodeTypeCatMap.put("generic-vnf", "vnf"); + } + + // ReservedPropNames: keys are property names of (node) properties that are + // common to all nodes and + // should not be removed if not passed in on an UPDATE request. + public static final Map<String, String> ReservedPropNames; + static { + ReservedPropNames = new HashMap<String, String>(); + ReservedPropNames.put("source-of-truth", ""); + ReservedPropNames.put("last-mod-source-of-truth", ""); + ReservedPropNames.put("aai-created-ts", ""); + ReservedPropNames.put("aai-last-mod-ts", ""); + } + + // This just lists which node types can be connected to themselves recursively. + // It's temporary - since DbEdgeRules is going to be overhauled in 16-10, this will + // get generated automatically. But for 1607, it can work like this. + public static final Map<String, String> CanBeRecursiveNT; + static { + CanBeRecursiveNT = new HashMap<String, String>(); + CanBeRecursiveNT.put("model-element", ""); + CanBeRecursiveNT.put("named-query-element", ""); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/v9/gen/DbEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v9/gen/DbEdgeRules.java new file mode 100644 index 00000000..3787bc80 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v9/gen/DbEdgeRules.java @@ -0,0 +1,459 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dbmodel.v9.gen; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Multimap; + +public class DbEdgeRules { + + /* + * The EdgeRules data is set up as a key (fromNodeTypeA|toNodeTypeB) mapped + * to a string which holds the info we need to build an edge from nodeTypeA + * to nodeTypeB. Note -- the MultiMap will let us define more than one type + * of edge between a given pair of nodeTypes, but for now we never define + * more than one. + * + * The edgeInfo part is comma separated and looks like this: + * "edgeLabel,direction,multiplicityRule,isParent,usesResource,hasDelTarget,SVC-INFRA" This + * format is encoded into the EdgeInfoMap below. + * MultiplicityRule can be either "Many2Many", "Many2One", "One2Many" or "One2One" + * The values for the things after multiplicityRule can be either "true", "false" or "reverse". "reverse" is + * really saying that this tag does apply, but the edge will be traversed + * the opposite way from the same tag that just has "true". + */ + public static final Map<Integer, String> EdgeInfoMap; + static { + EdgeInfoMap = new HashMap<Integer, String>(); + EdgeInfoMap.put(0, "edgeLabel"); + EdgeInfoMap.put(1, "direction"); + EdgeInfoMap.put(2, "multiplicityRule"); + EdgeInfoMap.put(3, "isParent"); + EdgeInfoMap.put(4, "usesResource"); + EdgeInfoMap.put(5, "hasDelTarget"); + EdgeInfoMap.put(6, "SVC-INFRA"); + } + + public static Integer firstTagIndex = 3; + + public static final Multimap<String, String> EdgeRules = new ImmutableSetMultimap.Builder<String, String>() + .putAll("availability-zone|complex", + "groupsResourcesIn,OUT,Many2Many,false,false,false,false") + .putAll("availability-zone|service-capability", + "supportsServiceCapability,OUT,Many2Many,false,false,false,false") + .putAll("cloud-region|complex", + "locatedIn,OUT,Many2One,false,false,false,false") + .putAll("cloud-region|l3-network", + "uses,OUT,Many2Many,false,false,false,false") + .putAll("cloud-region|tenant", + "has,OUT,One2Many,true,false,false,reverse") + .putAll("cloud-region|image", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|flavor", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|availability-zone", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|oam-network", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|dvs-switch", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|volume-group", + "has,OUT,One2Many,true,true,false,false") + .putAll("cloud-region|group-assignment", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|snapshot", + "has,OUT,One2Many,true,false,false,false") + .putAll("cloud-region|zone", + "isMemberOf,OUT,Many2One,false,false,false,false") + .putAll("complex|ctag-pool", + "hasCtagPool,OUT,Many2Many,true,false,false,false") + .putAll("complex|l3-network", + "usesL3Network,OUT,Many2Many,false,false,false,true") + .putAll("ctag-pool|availability-zone", + "supportsAvailabilityZone,OUT,Many2Many,false,false,false,false") + .putAll("customer|service-subscription", + "subscribesTo,OUT,Many2Many,true,false,false,reverse") + .putAll("dvs-switch|availability-zone", + "existsIn,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("generic-vnf|availability-zone", + "hasAvailabilityZone,OUT,Many2Many,false,false,false,true") + .putAll("generic-vnf|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,true") + .putAll("generic-vnf|l3-network", + "usesL3Network,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|pserver", + "runsOnPserver,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|vnf-image", + "usesVnfImage,OUT,Many2One,false,false,false,true") + .putAll("generic-vnf|vserver", + "runsOnVserver,OUT,One2Many,false,true,false,true") + .putAll("generic-vnf|service-instance", + "hasInstance,OUT,Many2Many,false,true,false,true") + .putAll("generic-vnf|site-pair-set", + "hasSitePairSet,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|network-profile", + "hasNetworkProfile,OUT,Many2Many,false,false,false,false") + .putAll("group-assignment|tenant", + "has,OUT,Many2Many,false,false,false,false") + .putAll("group-assignment|pserver", + "has,OUT,One2Many,false,false,false,false") + .putAll("image|metadata", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("image|metadatum", + "hasMetaDatum,OUT,Many2Many,true,false,false,false") + .putAll("l-interface|l3-interface-ipv4-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("l-interface|l3-interface-ipv6-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("l-interface|logical-link", + "usesLogicalLink,OUT,Many2Many,false,false,true,true") + .putAll("l-interface|vlan","hasVlan,OUT,Many2Many,true,false,false,false") + .putAll("l-interface|sriov-vf","has,OUT,One2One,true,false,false,false") + .putAll("l3-interface-ipv4-address-list|l3-network", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv6-address-list|l3-network", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv4-address-list|subnet", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-interface-ipv6-address-list|subnet", + "isMemberOf,OUT,Many2Many,false,false,false,true") + .putAll("l3-network|vpn-binding", + "usesVpnBinding,OUT,Many2Many,false,false,false,false") + .putAll("l3-network|subnet", + "hasSubnet,OUT,Many2Many,true,false,false,reverse") + .putAll("l3-network|service-instance", + "hasInstance,OUT,Many2Many,false,false,false,reverse") + .putAll("l3-network|ctag-assignment", + "hasCtagAssignment,OUT,Many2Many,true,false,false,true") + .putAll("l3-network|network-policy", + "uses,OUT,Many2Many,false,false,false,true") + .putAll("l3-network|segmentation-assignment", + "has,OUT,One2Many,true,false,false,false") + .putAll("l3-network|route-table-reference", + "uses,OUT,Many2Many,false,false,false,false") + .putAll("lag-interface|lag-link", + "usesLAGLink,OUT,Many2Many,false,true,true,true") + .putAll("lag-interface|p-interface", + "usesPInterface,OUT,Many2Many,false,true,false,true") + .putAll("lag-interface|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("logical-link|lag-link", + "usesLAGLink,OUT,Many2Many,false,true,false,true") + .putAll("logical-link|pnf", + "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|logical-link", + "uses,OUT,One2Many,false,false,false,true") + .putAll("model|model-ver", + "has,OUT,One2Many,true,false,false,false") + .putAll("model-ver|model-element", + "startsWith,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-ver", + "isA,OUT,Many2One,false,false,false,false") + .putAll("model-ver|metadatum", + "hasMetaData,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-element", + "connectsTo,OUT,One2Many,true,false,false,false") + .putAll("model-element|model-constraint", + "uses,OUT,One2Many,true,false,false,false") + .putAll("model-element|constrained-element-set", + "connectsTo,OUT,One2Many,true,false,false,false") + .putAll("model-constraint|constrained-element-set", + "uses,OUT,One2Many,true,false,false,false") + .putAll("constrained-element-set|element-choice-set", + "uses,OUT,One2Many,true,false,false,false") + .putAll("element-choice-set|model-element", + "has,OUT,One2Many,true,false,false,false") + .putAll("named-query|model", + "relatedTo,OUT,One2Many,false,false,false,false") + .putAll("named-query|named-query-element", + "startsWith,OUT,One2One,true,false,false,false") + .putAll("named-query-element|named-query-element", + "connectsTo,OUT,Many2Many,true,false,false,false") + .putAll("named-query-element|model", + "isA,OUT,Many2One,false,false,false,false") + .putAll("named-query-element|property-constraint", + "uses,OUT,One2Many,true,false,false,false") + .putAll("named-query-element|related-lookup", + "uses,OUT,One2Many,true,false,false,false") + .putAll("instance-group|model", + "targets,OUT,Many2Many,false,false,false,false") + .putAll("newvce|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,false") + .putAll("oam-network|complex", + "definedFor,OUT,Many2Many,false,false,false,false") + .putAll("oam-network|service-capability", + "supportsServiceCapability,OUT,Many2Many,false,false,false,false") + .putAll("p-interface|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("p-interface|physical-link", + "usesPhysicalLink,OUT,Many2Many,false,false,true,false") + .putAll("p-interface|logical-link", + "usesLogicalLink,OUT,Many2One,false,false,false,true") + .putAll("port-group|cvlan-tag", "hasCTag,OUT,Many2Many,true,true,false,true") + .putAll("pserver|complex", "locatedIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|cloud-region","locatedIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|availability-zone","existsIn,OUT,Many2One,false,false,false,true") + .putAll("pserver|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,true") + .putAll("pserver|p-interface", + "hasPinterface,OUT,Many2Many,true,true,false,true") + .putAll("pserver|zone", + "isMemberOf,OUT,Many2One,false,false,false,false") + .putAll("pnf|p-interface", + "hasPinterface,OUT,Many2Many,true,true,false,true") + .putAll("pnf|lag-interface", + "has,OUT,One2Many,true,false,false,true") + .putAll("pnf|complex", + "locatedIn,OUT,Many2One,false,false,false,false") + .putAll("pnf|instance-group", + "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("pnf|zone", + "isMemberOf,OUT,Many2One,false,false,false,false") + .putAll("service-instance|cvlan-tag", + "hasIPAGFacingVLAN,OUT,Many2Many,false,true,false,false") + .putAll("service-instance|pnf", + "uses,OUT,One2Many,false,true,false,false") + .putAll("service-subscription|service-instance", + "hasInstance,OUT,Many2Many,true,false,false,reverse") + .putAll("site-pair-set|routing-instance", + "hasRoutingInstance,OUT,Many2Many,true,false,false,false") + .putAll("routing-instance|site-pair", + "hasSitePair,OUT,Many2Many,true,false,false,false") + .putAll("site-pair|class-of-service", + "hasClassOfService,OUT,Many2Many,true,false,false,false") + .putAll("tenant|l3-network", + "usesL3Network,OUT,Many2Many,false,false,false,false") + .putAll("tenant|service-subscription", + "relatedTo,OUT,Many2Many,false,false,false,false") + .putAll("tenant|vserver", "owns,OUT,One2Many,true,false,false,reverse") + .putAll("vce|availability-zone", + "hasAvailabilityZone,OUT,Many2Many,false,false,false,false") + .putAll("vce|complex", "locatedIn,OUT,Many2Many,false,false,false,true") + .putAll("vce|port-group", "hasPortGroup,OUT,Many2Many,true,true,false,true") + .putAll("vce|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,true") + .putAll("vce|service-instance", + "hasServiceInstance,OUT,Many2Many,false,false,false,reverse") + .putAll("virtual-data-center|generic-vnf", + "hasVNF,OUT,Many2Many,false,false,false,reverse") + .putAll("vlan|l3-interface-ipv4-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("vlan|l3-interface-ipv6-address-list", + "hasIpAddress,OUT,Many2Many,true,false,false,true") + .putAll("vpe|complex", "locatedIn,OUT,Many2Many,false,false,false,false") + .putAll("vpe|ctag-pool", "usesCtagPool,OUT,Many2Many,false,false,false,false") + .putAll("vpe|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,false") + .putAll("vpe|lag-interface", + "hasLAGInterface,OUT,Many2Many,true,false,false,false") + .putAll("vpe|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,false") + .putAll("vpls-pe|complex", "locatedIn,OUT,Many2Many,false,false,false,false") + .putAll("vpls-pe|ctag-pool", + "usesCtagPool,OUT,Many2Many,false,false,false,false") + .putAll("vpls-pe|p-interface", + "hasPinterface,OUT,Many2Many,true,false,false,false") + .putAll("vpls-pe|lag-interface", + "hasLAGinterface,OUT,Many2Many,true,false,false,false") + .putAll("vserver|flavor", "hasFlavor,OUT,Many2One,false,false,false,true") + .putAll("vserver|image", "hasImage,OUT,Many2One,false,false,false,true") + .putAll("vserver|ipaddress", + "hasIpAddress,OUT,Many2Many,true,true,false,false") + .putAll("vserver|l-interface", + "hasLInterface,OUT,Many2Many,true,false,false,true") + .putAll("vserver|pserver", + "runsOnPserver,OUT,Many2One,false,true,false,true") + .putAll("vserver|volume", "hasVolume,OUT,Many2Many,true,true,false,true") + .putAll("vserver|vnfc", "hosts,OUT,Many2Many,false,true,false,true") + .putAll("vserver|snapshot", "uses,OUT,One2One,false,false,false,true") + .putAll("service-instance|connector", "uses,OUT,Many2Many,false,true,false,false") + .putAll("service-instance|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("service-instance|logical-link", "uses,OUT,Many2Many,false,false,true,false") + .putAll("service-instance|vlan", "dependsOn,OUT,One2Many,false,true,false,false") + .putAll("service-instance|service-instance", "dependsOn,OUT,One2Many,false,true,false,false") + .putAll("connector|virtual-data-center", "contains,OUT,Many2Many,false,false,false,false") + .putAll("connector|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false") + .putAll("virtual-data-center|logical-link", "contains,OUT,Many2Many,false,true,false,false") + .putAll("logical-link|generic-vnf", "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|pserver", "bridgedTo,OUT,Many2Many,false,false,false,false") + .putAll("vlan|multicast-configuration", "uses,OUT,Many2Many,false,true,false,false") + .putAll("volume-group|complex", "existsIn,OUT,Many2Many,false,false,false,true") + .putAll("volume-group|tenant", "belongsTo,OUT,Many2Many,false,false,false,true") + .putAll("ipsec-configuration|vig-server", "hasVigServer,OUT,One2Many,true,true,false,false") + .putAll("generic-vnf|ipsec-configuration", "uses,OUT,Many2One,false,true,false,false") + .putAll("vf-module|volume-group", "uses,OUT,One2One,false,false,false,true") + .putAll("vserver|vf-module", "isPartOf,OUT,Many2One,false,false,false,true") + .putAll("vf-module|l3-network", "uses,OUT,Many2Many,false,false,false,true") + .putAll("vf-module|vnfc", "uses,OUT,One2Many,false,false,true,true") + .putAll("generic-vnf|vf-module", "has,OUT,One2Many,true,false,false,true") + .putAll("generic-vnf|volume-group", "uses,OUT,One2Many,false,false,false,true") + .putAll("generic-vnf|vnfc", "uses,OUT,One2Many,false,false,true,true") + .putAll("vlan|logical-link", "usesLogicalLink,OUT,Many2Many,false,false,true,true") + .putAll("service-instance|ctag-assignment","uses,OUT,One2Many,false,false,false,false") + // The next edge is needed in 1702 but will be worked in user story AAI-6848 + //.putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|generic-vnf", "isPartOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|l3-network", "isPartOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|vlan", "isPartOf,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("service-instance|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false") + .putAll("allotted-resource|tunnel-xconnect", "has,OUT,One2One,true,false,false,false") + .putAll("logical-link|cloud-region", "existsIn,OUT,Many2Many,false,false,false,false") + .putAll("logical-link|vpn-binding", "uses,OUT,Many2Many,false,false,false,false") + .putAll("generic-vnf|entitlement", "has,OUT,One2Many,true,false,false,false") + .putAll("generic-vnf|license", "has,OUT,One2Many,true,false,false,false") + .putAll("vce|entitlement", "has,OUT,One2Many,true,false,false,false") + .putAll("vce|license", "has,OUT,One2Many,true,false,false,false") + .putAll("vpe|entitlement", "has,OUT,One2Many,true,false,false,false") + .putAll("vpe|license", "has,OUT,One2Many,true,false,false,false") + .putAll("zone|complex", "existsIn,OUT,Many2One,false,false,false,false") + .putAll("service-instance|allotted-resource", "has,OUT,Many2Many,true,false,false,false") + .putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false") + .build(); + + public static final Multimap<String, String> DefaultDeleteScope = new ImmutableSetMultimap.Builder<String, String>() + .putAll("customer", "CASCADE_TO_CHILDREN") + .putAll("cloud-region", "THIS_NODE_ONLY") + .putAll("service-subscription", "CASCADE_TO_CHILDREN") + .putAll("service-instance", "CASCADE_TO_CHILDREN") + .putAll("vce", "CASCADE_TO_CHILDREN") + .putAll("port-group", "CASCADE_TO_CHILDREN") + .putAll("cvlan-tag", "THIS_NODE_ONLY") + .putAll("tenant", "THIS_NODE_ONLY") + .putAll("vserver", "CASCADE_TO_CHILDREN") + .putAll("volume", "THIS_NODE_ONLY") + .putAll("ipaddress", "THIS_NODE_ONLY") + .putAll("image", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("pserver", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("availability-zone", "ERROR_IF_ANY_IN_EDGES") + .putAll("oam-network", "ERROR_IF_ANY_IN_EDGES") + .putAll("dvs-switch", "THIS_NODE_ONLY") + .putAll("service-capability", "ERROR_IF_ANY_IN_EDGES") + .putAll("complex", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("flavor", "ERROR_IF_ANY_IN_EDGES") + .putAll("metadata", "THIS_NODE_ONLY") + .putAll("metadatum", "THIS_NODE_ONLY") + .putAll("model", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("model-ver", "ERROR_4_IN_EDGES_OR_CASCADE") + .putAll("model-element", "CASCADE_TO_CHILDREN") + .putAll("model-constraint", "CASCADE_TO_CHILDREN") + .putAll("property-constraint", "CASCADE_TO_CHILDREN") + .putAll("related-lookup", "CASCADE_TO_CHILDREN") + .putAll("constrained-element-set", "CASCADE_TO_CHILDREN") + .putAll("element-choice-set", "CASCADE_TO_CHILDREN") + .putAll("named-query", "CASCADE_TO_CHILDREN") + .putAll("named-query-element", "CASCADE_TO_CHILDREN") + .putAll("network-policy", "THIS_NODE_ONLY") + .putAll("collect-lookup", "THIS_NODE_ONLY") + .putAll("service", "ERROR_IF_ANY_IN_EDGES") + .putAll("newvce", "CASCADE_TO_CHILDREN") + .putAll("vpe", "CASCADE_TO_CHILDREN") + .putAll("vpls-pe", "CASCADE_TO_CHILDREN") + .putAll("l-interface", "CASCADE_TO_CHILDREN") + .putAll("vlan", "CASCADE_TO_CHILDREN") + .putAll("p-interface", "CASCADE_TO_CHILDREN") + .putAll("l3-interface-ipv6-address-list", "THIS_NODE_ONLY") + .putAll("l3-interface-ipv4-address-list", "THIS_NODE_ONLY") + .putAll("logical-link", "THIS_NODE_ONLY") + .putAll("physical-link", "THIS_NODE_ONLY") + .putAll("lag-link", "THIS_NODE_ONLY") + .putAll("lag-interface", "CASCADE_TO_CHILDREN") + .putAll("virtual-data-center", "CASCADE_TO_CHILDREN") + .putAll("generic-vnf", "CASCADE_TO_CHILDREN") + .putAll("l3-network", "CASCADE_TO_CHILDREN") + .putAll("ctag-pool", "THIS_NODE_ONLY") + .putAll("subnet", "THIS_NODE_ONLY") + .putAll("sriov-vf", "THIS_NODE_ONLY") + .putAll("vpn-binding", "ERROR_IF_ANY_IN_EDGES") + .putAll("vnf-image", "ERROR_IF_ANY_IN_EDGES") + .putAll("site-pair-set", "CASCADE_TO_CHILDREN") + .putAll("routing-instance", "CASCADE_TO_CHILDREN") + .putAll("site-pair", "CASCADE_TO_CHILDREN") + .putAll("class-of-service", "THIS_NODE_ONLY") + .putAll("connector", "CASCADE_TO_CHILDREN") + .putAll("vnfc", "THIS_NODE_ONLY") + .putAll("multicast-configuration", "THIS_NODE_ONLY") + .putAll("volume-group", "THIS_NODE_ONLY") + .putAll("ctag-assignment", "THIS_NODE_ONLY") + .putAll("pnf", "CASCADE_TO_CHILDREN") + .putAll("ipsec-configuration", "CASCADE_TO_CHILDREN") + .putAll("vig-server", "THIS_NODE_ONLY") + .putAll("vf-module", "THIS_NODE_ONLY") + .putAll("snapshot", "THIS_NODE_ONLY") + .putAll("group-assignment", "THIS_NODE_ONLY") + .putAll("segmentation-assignment", "THIS_NODE_ONLY") + .putAll("route-table-reference", "THIS_NODE_ONLY") + .putAll("network-profile", "THIS_NODE_ONLY") + .putAll("allotted-resource", "CASCADE_TO_CHILDREN") + .putAll("tunnel-xconnect", "THIS_NODE_ONLY") + .putAll("instance-group","THIS_NODE_ONLY") + .putAll("entitlement","THIS_NODE_ONLY") + .putAll("license","THIS_NODE_ONLY") + .putAll("zone", "THIS_NODE_ONLY").build(); + + // NOTE -- Sorry, this is ugly, but we are mapping the nodeTypeCategory two + // ways just to + // make the code a little less bulky. But that means that we need to ensure + // that + // nodeTypeCategory and nodeTypeCatMap are kept in synch. + + // NodeTypeCategory: key is: nodeTypeCategory, value is: + // "nodeTypes,keyProperties,AltKeyProps,depNode4UniquenessFlag" + public static final Multimap<String, String> NodeTypeCategory = new ImmutableSetMultimap.Builder<String, String>() + .putAll("vnf", "vce|vpe|generic-vnf,vnf-id,,true").build(); + + // NodeTypeCatMap: key is nodeType; value is: "nodeTypeCategory" + // So -- we're assuming that a nodeType can only be in one nodeTypeCategory. + public static final Map<String, String> NodeTypeCatMap; + static { + NodeTypeCatMap = new HashMap<String, String>(); + NodeTypeCatMap.put("vpe", "vnf"); + NodeTypeCatMap.put("vce", "vnf"); + NodeTypeCatMap.put("generic-vnf", "vnf"); + } + + // ReservedPropNames: keys are property names of (node) properties that are + // common to all nodes and + // should not be removed if not passed in on an UPDATE request. + public static final Map<String, String> ReservedPropNames; + static { + ReservedPropNames = new HashMap<String, String>(); + ReservedPropNames.put("source-of-truth", ""); + ReservedPropNames.put("last-mod-source-of-truth", ""); + ReservedPropNames.put("aai-created-ts", ""); + ReservedPropNames.put("aai-last-mod-ts", ""); + } + + // This just lists which node types can be connected to themselves recursively. + // It's temporary - since DbEdgeRules is going to be overhauled in 16-10, this will + // get generated automatically. But for 1607, it can work like this. + public static final Map<String, String> CanBeRecursiveNT; + static { + CanBeRecursiveNT = new HashMap<String, String>(); + CanBeRecursiveNT.put("model-element", ""); + CanBeRecursiveNT.put("service-instance", ""); + CanBeRecursiveNT.put("named-query-element", ""); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResource.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResource.java new file mode 100644 index 00000000..7fc1f7a3 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResource.java @@ -0,0 +1,675 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.model; + +import java.util.ArrayList; +import java.util.Map; + +import com.google.common.collect.Multimap; + + +public class AAIResource { + private AAIResource parent; + private AAIResources children; + + private AAIResourceKeys aaiResourceKeys; + + private String namespace; // /Network/Vces/Vce/PortGroups/PortGroup/CvlanTags/CvlanTag -> "Network" + + private String resourceType; // node or container + private String resourceClassName; + private String simpleName; // Vce + private String fullName; // /Network/Vces/Vce/PortGroups/PortGroup/CvlanTags/CvlanTag + private String uri; // /network/vces/vce/{vnf-id}/port-groups/port-group/{interface-name}/cvlan-tags/cvlan-tag/{cvlan-tag} + private String apiVersion; + private String relationshipListClass; + private String relationshipUtils; + + private Map<String, String> PropertyDataTypeMap; + private Multimap<String, String> NodeMapIndexedProps; + private Multimap<String, String> NodeAltKey1Props; + private Multimap<String, String> NodeDependencies; + private Multimap<String, String> NodeKeyProps; + private Multimap<String, String> NodeReqProps; + private Multimap<String, String> NodeNameProps; + private Multimap<String, String> NodeUniqueProps; + + // if new dataTypes are added - make sure to update getAllFields() method below + private ArrayList<String> stringFields; + private ArrayList<String> stringListFields; + private ArrayList<String> longFields; + private ArrayList<String> intFields; + private ArrayList<String> shortFields; + private ArrayList<String> booleanFields; + + private ArrayList<String> requiredFields; + private ArrayList<String> orderedFields; + private AAIResource recurseToResource; + private boolean allowDirectWrite; + private boolean allowDirectRead; + private ArrayList<String> autoGenUuidFields; + + /** + * Gets the parent. + * + * @return the parent + */ + public AAIResource getParent() { + return parent; + } + + /** + * Sets the parent. + * + * @param parent the new parent + */ + public void setParent(AAIResource parent) { + this.parent = parent; + } + + /** + * Gets the children. + * + * @return the children + */ + public AAIResources getChildren() { + if (this.children == null) { + this.children = new AAIResources(); + } + return this.children; + } + + /** + * Gets the aai resource keys. + * + * @return the aai resource keys + */ + public AAIResourceKeys getAaiResourceKeys() { + if (aaiResourceKeys == null) { + aaiResourceKeys = new AAIResourceKeys(); + } + return aaiResourceKeys; + } + + /** + * Gets the namespace. + * + * @return the namespace + */ + public String getNamespace() { + return namespace; + } + + /** + * Sets the namespace. + * + * @param namespace the new namespace + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + /** + * Gets the resource type. + * + * @return the resource type + */ + public String getResourceType() { + return resourceType; + } + + /** + * Sets the resource type. + * + * @param resourceType the new resource type + */ + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + /** + * Gets the simple name. + * + * @return the simple name + */ + public String getSimpleName() { + return simpleName; + } + + /** + * Sets the simple name. + * + * @param simpleName the new simple name + */ + public void setSimpleName(String simpleName) { + this.simpleName = simpleName; + } + + /** + * Gets the full name. + * + * @return the full name + */ + public String getFullName() { + return fullName; + } + + /** + * Sets the full name. + * + * @param fullName the new full name + */ + public void setFullName(String fullName) { + this.fullName = fullName; + } + + /** + * Gets the uri. + * + * @return the uri + */ + public String getUri() { + return uri; + } + + /** + * Sets the uri. + * + * @param uri the new uri + */ + public void setUri(String uri) { + this.uri = uri; + } + + /** + * Gets the resource class name. + * + * @return the resource class name + */ + public String getResourceClassName() { + return resourceClassName; + } + + /** + * Sets the resource class name. + * + * @param resourceClassName the new resource class name + */ + public void setResourceClassName(String resourceClassName) { + this.resourceClassName = resourceClassName; + } + + /** + * Gets the property data type map. + * + * @return the property data type map + */ + public Map<String, String> getPropertyDataTypeMap() { + return PropertyDataTypeMap; + } + + /** + * Sets the property data type map. + * + * @param propertyDataTypeMap the property data type map + */ + public void setPropertyDataTypeMap(Map<String, String> propertyDataTypeMap) { + PropertyDataTypeMap = propertyDataTypeMap; + } + + /** + * Gets the node map indexed props. + * + * @return the node map indexed props + */ + public Multimap<String, String> getNodeMapIndexedProps() { + return NodeMapIndexedProps; + } + + /** + * Sets the node map indexed props. + * + * @param nodeMapIndexedProps the node map indexed props + */ + public void setNodeMapIndexedProps(Multimap<String, String> nodeMapIndexedProps) { + NodeMapIndexedProps = nodeMapIndexedProps; + } + + /** + * Gets the node key props. + * + * @return the node key props + */ + public Multimap<String, String> getNodeKeyProps() { + return NodeKeyProps; + } + + /** + * Sets the node key props. + * + * @param nodeKeyProps the node key props + */ + public void setNodeKeyProps(Multimap<String, String> nodeKeyProps) { + this.NodeKeyProps = nodeKeyProps; + } + + /** + * Gets the node name props. + * + * @return the node name props + */ + public Multimap<String, String> getNodeNameProps() { + return NodeNameProps; + } + + /** + * Sets the node name props. + * + * @param nodeNameProps the node name props + */ + public void setNodeNameProps(Multimap<String, String> nodeNameProps) { + + NodeNameProps = nodeNameProps; + } + + /** + * Gets the node unique props. + * + * @return the node unique props + */ + public Multimap<String, String> getNodeUniqueProps() { + return NodeUniqueProps; + } + + /** + * Sets the node unique props. + * + * @param nodeUniqueProps the node unique props + */ + public void setNodeUniqueProps(Multimap<String, String> nodeUniqueProps) { + NodeUniqueProps = nodeUniqueProps; + } + + /** + * Gets the node req props. + * + * @return the node req props + */ + public Multimap<String, String> getNodeReqProps() { + return NodeReqProps; + } + + /** + * Sets the node req props. + * + * @param nodeReqProps the node req props + */ + public void setNodeReqProps(Multimap<String, String> nodeReqProps) { + NodeReqProps = nodeReqProps; + } + + /** + * Gets the api version. + * + * @return the api version + */ + public String getApiVersion() { + return apiVersion; + } + + /** + * Sets the api version. + * + * @param apiVersion the new api version + */ + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + /** + * Gets the relationship list class. + * + * @return the relationship list class + */ + public String getRelationshipListClass() { + return relationshipListClass; + } + + /** + * Sets the relationship list class. + * + * @param relationshipListClass the new relationship list class + */ + public void setRelationshipListClass(String relationshipListClass) { + this.relationshipListClass = relationshipListClass; + } + + /** + * Gets the relationship utils. + * + * @return the relationship utils + */ + public String getRelationshipUtils() { + return relationshipUtils; + } + + /** + * Sets the relationship utils. + * + * @param relationshipUtils the new relationship utils + */ + public void setRelationshipUtils(String relationshipUtils) { + this.relationshipUtils = relationshipUtils; + } + + /** + * Gets the string fields. + * + * @return the string fields + */ + public ArrayList<String> getStringFields() { + if (this.stringFields == null) { + this.stringFields = new ArrayList<String>(); + } + return this.stringFields; + } + + /** + * Sets the string fields. + * + * @param stringFields the new string fields + */ + public void setStringFields(ArrayList<String> stringFields) { + this.stringFields = stringFields; + } + + /** + * Gets the string list fields. + * + * @return the string list fields + */ + public ArrayList<String> getStringListFields() { + if (this.stringListFields == null) { + this.stringListFields = new ArrayList<String>(); + } + return this.stringListFields; + } + + /** + * Sets the string list fields. + * + * @param stringListFields the new string list fields + */ + public void setStringListFields(ArrayList<String> stringListFields) { + this.stringListFields = stringListFields; + } + + /** + * Gets the long fields. + * + * @return the long fields + */ + public ArrayList<String> getLongFields() { + if (this.longFields == null) { + this.longFields = new ArrayList<String>(); + } + return longFields; + } + + /** + * Sets the long fields. + * + * @param longFields the new long fields + */ + public void setLongFields(ArrayList<String> longFields) { + this.longFields = longFields; + } + + /** + * Gets the int fields. + * + * @return the int fields + */ + public ArrayList<String> getIntFields() { + if (this.intFields == null) { + this.intFields = new ArrayList<String>(); + } + return intFields; + } + + /** + * Sets the int fields. + * + * @param intFields the new int fields + */ + public void setIntFields(ArrayList<String> intFields) { + this.intFields = intFields; + } + + /** + * Gets the short fields. + * + * @return the short fields + */ + public ArrayList<String> getShortFields() { + if (this.shortFields == null) { + this.shortFields = new ArrayList<String>(); + } + return shortFields; + } + + /** + * Sets the short fields. + * + * @param shortFields the new short fields + */ + public void setShortFields(ArrayList<String> shortFields) { + this.shortFields = shortFields; + } + + /** + * Gets the boolean fields. + * + * @return the boolean fields + */ + public ArrayList<String> getBooleanFields() { + if (this.booleanFields == null) { + this.booleanFields = new ArrayList<String>(); + } + return booleanFields; + } + + /** + * Sets the boolean fields. + * + * @param booleanFields the new boolean fields + */ + public void setBooleanFields(ArrayList<String> booleanFields) { + this.booleanFields = booleanFields; + } + + /** + * Gets the required fields. + * + * @return the required fields + */ + public ArrayList<String> getRequiredFields() { + if (this.requiredFields == null) { + this.requiredFields = new ArrayList<String>(); + } + return requiredFields; + } + + /** + * Sets the required fields. + * + * @param requiredFields the new required fields + */ + public void setRequiredFields(ArrayList<String> requiredFields) { + this.requiredFields = requiredFields; + } + + /** + * Gets the ordered fields. + * + * @return the ordered fields + */ + public ArrayList<String> getOrderedFields() { + if (this.orderedFields == null) { + this.orderedFields = new ArrayList<String>(); + } + return this.orderedFields; + } + + /** + * Gets the all fields. + * + * @return the all fields + */ + public ArrayList<String> getAllFields() { + + ArrayList<String> allFields = new ArrayList<String>(); + allFields.addAll(getBooleanFields()); + allFields.addAll(getStringListFields()); + allFields.addAll(getStringFields()); + allFields.addAll(getIntFields()); + allFields.addAll(getLongFields()); + allFields.addAll(getShortFields()); + + return allFields; + } + + /** + * Gets the plural name. + * + * @return the plural name + */ + public String getPluralName() { + + if (simpleName.contains("List") || simpleName.contains("-list") ) + return ""; + String[] fullNameList = getFullName().split("/"); + return fullNameList[fullNameList.length - 2]; + } + + /** + * Sets the node alt key 1 props. + * + * @param _dbRulesNodeAltKey1Props the db rules node alt key 1 props + */ + public void setNodeAltKey1Props(Multimap<String, String> _dbRulesNodeAltKey1Props) { + this.NodeAltKey1Props = _dbRulesNodeAltKey1Props; + } + + /** + * Gets the node alt key 1 props. + * + * @return the node alt key 1 props + */ + public Multimap<String,String> getNodeAltKey1Props() { + return this.NodeAltKey1Props; + } + + /** + * Sets the node dependencies. + * + * @param _dbRulesNodeDependencies the db rules node dependencies + */ + public void setNodeDependencies(Multimap<String, String> _dbRulesNodeDependencies) { + this.NodeDependencies = _dbRulesNodeDependencies; + } + + /** + * Gets the node dependencies. + * + * @return the node dependencies + */ + public Multimap<String,String> getNodeDependencies() { + return this.NodeDependencies; + } + + /** + * Gets the recurse to resource. + * + * @return the recurse to resource + */ + public AAIResource getRecurseToResource() { + return this.recurseToResource; + } + + /** + * Sets the recurse to resource. + * + * @param ancestor the new recurse to resource + */ + public void setRecurseToResource(AAIResource ancestor) { + this.recurseToResource = ancestor; + + } + + /** + * Sets the allow direct write. + * + * @param allowDirectWrite the new allow direct write + */ + public void setAllowDirectWrite(boolean allowDirectWrite) { + this.allowDirectWrite = allowDirectWrite; + } + + /** + * Checks if is allow direct write. + * + * @return true, if is allow direct write + */ + public boolean isAllowDirectWrite() { + return this.allowDirectWrite; + } + + /** + * Sets the allow direct read. + * + * @param allowDirectRead the new allow direct read + */ + public void setAllowDirectRead(boolean allowDirectRead) { + this.allowDirectRead = allowDirectRead; + } + + /** + * Checks if is allow direct read. + * + * @return true, if is allow direct read + */ + public boolean isAllowDirectRead() { + return this.allowDirectRead; + } + + /** + * Gets the auto gen uuid fields. + * + * @return the auto gen uuid fields + */ + public ArrayList<String> getAutoGenUuidFields() { + if (this.autoGenUuidFields == null) { + this.autoGenUuidFields = new ArrayList<String>(); + } + return this.autoGenUuidFields; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKey.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKey.java new file mode 100644 index 00000000..5129992b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKey.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.model; + +import com.google.common.base.CaseFormat; + +public class AAIResourceKey { + private String keyName; + private String keyType; + private String pathParamName; + private String dnCamKeyName; + + /** + * Gets the key name. + * + * @return the key name + */ + public String getKeyName() { + return keyName; + } + + /** + * Sets the key name. + * + * @param keyName the new key name + */ + public void setKeyName(String keyName) { + this.keyName = keyName; + } + + /** + * Gets the key type. + * + * @return the key type + */ + public String getKeyType() { + return keyType; + } + + /** + * Sets the key type. + * + * @param t the new key type + */ + public void setKeyType(String t) { + this.keyType = t; + } + + /** + * Gets the path param name. + * + * @return the path param name + */ + public String getPathParamName() { + return pathParamName; + } + + /** + * Sets the path param name. + * + * @param pathParamName the new path param name + */ + public void setPathParamName(String pathParamName) { + this.pathParamName = pathParamName; + } + + /** + * Gets the dn cam key name. + * + * @return the dn cam key name + */ + public String getDnCamKeyName() { + return dnCamKeyName; + } + + /** + * Sets the dn cam key name. + * + * @param dnCamKeyName the new dn cam key name + */ + public void setDnCamKeyName(String dnCamKeyName) { + this.dnCamKeyName = dnCamKeyName; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKeys.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKeys.java new file mode 100644 index 00000000..2aa752c8 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKeys.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.model; + +import java.util.ArrayList; +import java.util.List; + +public class AAIResourceKeys { + private List<AAIResourceKey> aaiResourceKey; + + /** + * Gets the aai resource key. + * + * @return the aai resource key + */ + public List<AAIResourceKey> getAaiResourceKey() { + if (aaiResourceKey == null) { + aaiResourceKey = new ArrayList<AAIResourceKey>(); + } + return aaiResourceKey; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResources.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResources.java new file mode 100644 index 00000000..6aff26e8 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResources.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.model; + +import java.util.HashMap; + +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; + +public class AAIResources { + + private DynamicJAXBContext jaxbContext; + + private HashMap<String, AAIResource> aaiResources; + private HashMap<String, AAIResource> resourceLookup; + + + /** + * Gets the aai resources. + * + * @return the aai resources + */ + public HashMap<String, AAIResource> getAaiResources() { + if (aaiResources == null) { + aaiResources = new HashMap<String, AAIResource>(); + } + return aaiResources; + } + + /** + * Gets the jaxb context. + * + * @return the jaxb context + */ + public DynamicJAXBContext getJaxbContext() { + return jaxbContext; + } + + /** + * Sets the jaxb context. + * + * @param jaxbContext the new jaxb context + */ + public void setJaxbContext(DynamicJAXBContext jaxbContext) { + this.jaxbContext = jaxbContext; + } + + /** + * Gets the resource lookup. + * + * @return the resource lookup + */ + public HashMap<String, AAIResource> getResourceLookup() { + if (resourceLookup == null) { + resourceLookup = new HashMap<String, AAIResource>(); + } + return resourceLookup; + } + + /** + * Sets the resource lookup. + * + * @param resourceLookup the resource lookup + */ + public void setResourceLookup(HashMap<String, AAIResource> resourceLookup) { + this.resourceLookup = resourceLookup; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/NotificationEvent.java b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/NotificationEvent.java new file mode 100644 index 00000000..18585518 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/NotificationEvent.java @@ -0,0 +1,564 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2016.01.06 at 05:38:00 PM EST +// + + +package org.openecomp.aai.domain.notificationEvent; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; +import org.w3c.dom.Element; + + +/** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="cambria.partition" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="event-header" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="timestamp" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="source-name" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="domain" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="sequence-number" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="severity" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="event-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="action" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="top-entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="entity-link" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="status" type="{http://www.w3.org/2001/XMLSchema}string"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <any processContents='lax' namespace='##other' minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "cambriaPartition", + "eventHeader", + "entity" +}) +@XmlRootElement(name = "NotificationEvent") +public class NotificationEvent { + + @XmlElement(name = "cambria.partition") + protected String cambriaPartition; + @XmlElement(name = "event-header") + protected NotificationEvent.EventHeader eventHeader; + @XmlAnyElement(lax = true) + protected Object entity; + + /** + * Gets the value of the eventHeader property. + * + * @return + * possible object is + * {@link NotificationEvent.EventHeader } + * + */ + public NotificationEvent.EventHeader getEventHeader() { + return eventHeader; + } + + /** + * Sets the value of the eventHeader property. + * + * @param value + * allowed object is + * {@link NotificationEvent.EventHeader } + * + */ + public void setEventHeader(NotificationEvent.EventHeader value) { + this.eventHeader = value; + } + + /** + * Gets the value of the any property. + * + * @return + * possible object is + * {@link Object } + * {@link Element } + * + */ + public Object getEntity() { + return entity; + } + + /** + * Sets the value of the any property. + * + * @param value + * allowed object is + * {@link Object } + * {@link Element } + * + */ + public void setEntity(Object value) { + this.entity = value; + } + + /** + * Gets the value of the cambriaPartition property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCambriaPartition() { + return cambriaPartition; + } + + /** + * Sets the value of the cambriaPartition property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCambriaPartition(String value) { + this.cambriaPartition = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="timestamp" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="source-name" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="domain" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="sequence-number" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="severity" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="event-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="action" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="top-entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="entity-link" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="status" type="{http://www.w3.org/2001/XMLSchema}string"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "id", + "timestamp", + "sourceName", + "domain", + "sequenceNumber", + "severity", + "eventType", + "version", + "action", + "entityType", + "topEntityType", + "entityLink", + "status" + }) + public static class EventHeader { + + @XmlElement(required = true) + protected String id; + @XmlElement(required = true) + protected String timestamp; + @XmlElement(name = "source-name", required = true) + protected String sourceName; + @XmlElement(required = true) + protected String domain; + @XmlElement(name = "sequence-number", required = true) + protected String sequenceNumber; + @XmlElement(required = true) + protected String severity; + @XmlElement(name = "event-type", required = true) + protected String eventType; + @XmlElement(required = true) + protected String version; + @XmlElement(required = true) + protected String action; + @XmlElement(name = "entity-type", required = true) + protected String entityType; + @XmlElement(name = "top-entity-type", required = true) + protected String topEntityType; + @XmlElement(name = "entity-link", required = true) + protected String entityLink; + @XmlElement(required = true) + protected String status; + + /** + * Gets the value of the id property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getId() { + return id; + } + + /** + * Sets the value of the id property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setId(String value) { + this.id = value; + } + + /** + * Gets the value of the timestamp property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTimestamp() { + return timestamp; + } + + /** + * Sets the value of the timestamp property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTimestamp(String value) { + this.timestamp = value; + } + + /** + * Gets the value of the sourceName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getSourceName() { + return sourceName; + } + + /** + * Sets the value of the sourceName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setSourceName(String value) { + this.sourceName = value; + } + + /** + * Gets the value of the domain property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getDomain() { + return domain; + } + + /** + * Sets the value of the domain property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setDomain(String value) { + this.domain = value; + } + + /** + * Gets the value of the sequenceNumber property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getSequenceNumber() { + return sequenceNumber; + } + + /** + * Sets the value of the sequenceNumber property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setSequenceNumber(String value) { + this.sequenceNumber = value; + } + + /** + * Gets the value of the severity property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getSeverity() { + return severity; + } + + /** + * Sets the value of the severity property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setSeverity(String value) { + this.severity = value; + } + + /** + * Gets the value of the eventType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getEventType() { + return eventType; + } + + /** + * Sets the value of the eventType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setEventType(String value) { + this.eventType = value; + } + + /** + * Gets the value of the version property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVersion() { + return version; + } + + /** + * Sets the value of the version property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVersion(String value) { + this.version = value; + } + + /** + * Gets the value of the action property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getAction() { + return action; + } + + /** + * Sets the value of the action property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setAction(String value) { + this.action = value; + } + + /** + * Gets the value of the entityType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getEntityType() { + return entityType; + } + + /** + * Sets the value of the entityType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setEntityType(String value) { + this.entityType = value; + } + + /** + * Gets the value of the topEntityType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTopEntityType() { + return topEntityType; + } + + /** + * Sets the value of the topEntityType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTopEntityType(String value) { + this.topEntityType = value; + } + + /** + * Gets the value of the entityLink property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getEntityLink() { + return entityLink; + } + + /** + * Sets the value of the entityLink property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setEntityLink(String value) { + this.entityLink = value; + } + + /** + * Gets the value of the status property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getStatus() { + return status; + } + + /** + * Sets the value of the status property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setStatus(String value) { + this.status = value; + } + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/ObjectFactory.java new file mode 100644 index 00000000..c8bfab89 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/ObjectFactory.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2016.01.06 at 05:38:00 PM EST +// + + +package org.openecomp.aai.domain.notificationEvent; + +import javax.xml.bind.annotation.XmlRegistry; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.openecomp.aai.domain.notificationEvent package. + * <p>An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.notificationEvent + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link NotificationEvent }. + * + * @return the notification event + */ + public NotificationEvent createNotificationEvent() { + return new NotificationEvent(); + } + + /** + * Create an instance of {@link NotificationEvent.EventHeader } + * + * @return the event header + */ + public NotificationEvent.EventHeader createNotificationEventEventHeader() { + return new NotificationEvent.EventHeader(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessage.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessage.java new file mode 100644 index 00000000..5cbe3167 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessage.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.responseMessage; + +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; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "aaiResponseMessageCode", + "aaiResponseMessageResourceType", + "aaiResponseMessageDescription", + "aaiResponseMessageData", +}) +@XmlRootElement(name = "aai-response-message", namespace = "http://org.openecomp.aai.inventory") +public class AAIResponseMessage { + + @XmlElement(name = "aai-response-message-code", required = true) + protected String aaiResponseMessageCode; + @XmlElement(name = "aai-response-message-resource-type") + protected String aaiResponseMessageResourceType; + @XmlElement(name = "aai-response-message-description") + protected String aaiResponseMessageDescription; + @XmlElement(name = "aai-response-message-data") + protected AAIResponseMessageData aaiResponseMessageData; + + /** + * Gets the aai response message code. + * + * @return the aai response message code + */ + public String getAaiResponseMessageCode() { + return aaiResponseMessageCode; + } + + /** + * Sets the aai response message code. + * + * @param aaiResponseMessageCode the new aai response message code + */ + public void setAaiResponseMessageCode(String aaiResponseMessageCode) { + this.aaiResponseMessageCode = aaiResponseMessageCode; + } + + /** + * Gets the aai response message resource type. + * + * @return the aai response message resource type + */ + public String getAaiResponseMessageResourceType() { + return aaiResponseMessageResourceType; + } + + /** + * Sets the aai response message resource type. + * + * @param aaiResponseMessageResourceType the new aai response message resource type + */ + public void setAaiResponseMessageResourceType( + String aaiResponseMessageResourceType) { + this.aaiResponseMessageResourceType = aaiResponseMessageResourceType; + } + + /** + * Gets the aai response message description. + * + * @return the aai response message description + */ + public String getAaiResponseMessageDescription() { + return aaiResponseMessageDescription; + } + + /** + * Sets the aai response message description. + * + * @param aaiResponseMessageDescription the new aai response message description + */ + public void setAaiResponseMessageDescription( + String aaiResponseMessageDescription) { + this.aaiResponseMessageDescription = aaiResponseMessageDescription; + } + + /** + * Gets the aai response message data. + * + * @return the aai response message data + */ + public AAIResponseMessageData getAaiResponseMessageData() { + if (aaiResponseMessageData == null) { + aaiResponseMessageData = new AAIResponseMessageData(); + } + return aaiResponseMessageData; + } + + /** + * Sets the AAI response message data. + * + * @param aaiResponseMessageData the new AAI response message data + */ + public void setAAIResponseMessageData( + AAIResponseMessageData aaiResponseMessageData) { + this.aaiResponseMessageData = aaiResponseMessageData; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageData.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageData.java new file mode 100644 index 00000000..2f16b98a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageData.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.responseMessage; + + +// +//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +//Any modifications to this file will be lost upon recompilation of the source schema. +//Generated on: 2015.09.11 at 11:53:27 AM EDT +// + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "aaiResponseMessageDatum", + "any" +}) +@XmlRootElement(name = "aai-response-message-data", namespace = "http://org.openecomp.aai.inventory") +public class AAIResponseMessageData { + + @XmlElement(name = "aai-response-message-datum") + protected List<AAIResponseMessageDatum> aaiResponseMessageDatum; + @XmlAnyElement(lax = true) + protected List<Object> any; + + /** + * Gets the AAI response message datum. + * + * @return the AAI response message datum + */ + public List<AAIResponseMessageDatum> getAAIResponseMessageDatum() { + if (aaiResponseMessageDatum == null) { + aaiResponseMessageDatum = new ArrayList<AAIResponseMessageDatum>(); + } + return this.aaiResponseMessageDatum; + } + + /** + * Gets the any. + * + * @return the any + */ + public List<Object> getAny() { + if (any == null) { + any = new ArrayList<Object>(); + } + return this.any; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageDatum.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageDatum.java new file mode 100644 index 00000000..9e56333d --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageDatum.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.responseMessage; + +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; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "aaiResponseMessageDatumKey", + "aaiResponseMessageDatumValue", + +}) + +@XmlRootElement(name = "aai-response-message-datum", namespace = "http://org.openecomp.aai.inventory") +public class AAIResponseMessageDatum { + + @XmlElement(name = "aai-response-message-datum-key", required = true) + protected String aaiResponseMessageDatumKey; + @XmlElement(name = "aai-response-message-datum-value", required = true) + protected String aaiResponseMessageDatumValue; + + /** + * Gets the aai response message datum key. + * + * @return the aai response message datum key + */ + public String getAaiResponseMessageDatumKey() { + return aaiResponseMessageDatumKey; + } + + /** + * Sets the aai response message datum key. + * + * @param aaiResponseMessageDatumKey the new aai response message datum key + */ + public void setAaiResponseMessageDatumKey(String aaiResponseMessageDatumKey) { + this.aaiResponseMessageDatumKey = aaiResponseMessageDatumKey; + } + + /** + * Gets the aai response message datum value. + * + * @return the aai response message datum value + */ + public String getAaiResponseMessageDatumValue() { + return aaiResponseMessageDatumValue; + } + + /** + * Sets the aai response message datum value. + * + * @param aaiResponseMessageDatumValue the new aai response message datum value + */ + public void setAaiResponseMessageDatumValue(String aaiResponseMessageDatumValue) { + this.aaiResponseMessageDatumValue = aaiResponseMessageDatumValue; + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessages.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessages.java new file mode 100644 index 00000000..ec6d645d --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessages.java @@ -0,0 +1,118 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.responseMessage; + + +// +//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +//Any modifications to this file will be lost upon recompilation of the source schema. +//Generated on: 2015.09.11 at 11:53:27 AM EDT +// + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +/** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="flavor" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="flavor-id" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="flavor-name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="flavor-vcpus" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/> + * <element name="flavor-ram" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/> + * <element name="flavor-disk" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/> + * <element name="flavor-ephemeral" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/> + * <element name="flavor-swap" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="flavor-is-public" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/> + * <element name="flavor-selflink" type="{urn:ietf:params:xml:ns:yang:ietf-inet-types}uri" minOccurs="0"/> + * <element name="flavor-disabled" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/> + * <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/> + * <element ref="{http://org.openecomp.aai.inventory/v3}relationship-list" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "aaiResponseMessage", + "any" +}) +@XmlRootElement(name = "aai-response-messages", namespace = "http://org.openecomp.aai.inventory") +public class AAIResponseMessages { + @XmlElement(name = "aai-response-message") + protected List<AAIResponseMessage> aaiResponseMessage; + @XmlAnyElement(lax = true) + protected List<Object> any; + + /** + * Gets the AAI response message. + * + * @return the AAI response message + */ + public List<AAIResponseMessage> getAAIResponseMessage() { + if (aaiResponseMessage == null) { + aaiResponseMessage = new ArrayList<AAIResponseMessage>(); + } + return this.aaiResponseMessage; + } + + /** + * Gets the any. + * + * @return the any + */ + public List<Object> getAny() { + if (any == null) { + any = new ArrayList<Object>(); + } + return this.any; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/package-info.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/package-info.java new file mode 100644 index 00000000..0c024ff2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/package-info.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.06.15 at 03:03:58 PM EDT +// + +@javax.xml.bind.annotation.XmlSchema( + namespace = "http://org.openecomp.aai.inventory", + elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) +package org.openecomp.aai.domain.responseMessage; + diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/Fault.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/Fault.java new file mode 100644 index 00000000..68281cf6 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/Fault.java @@ -0,0 +1,382 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.02.11 at 04:54:39 PM EST +// + + +package org.openecomp.aai.domain.restPolicyException; + +import java.util.ArrayList; +import java.util.List; +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; + + +/** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="requestError"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="policyException"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "requestError" +}) +@XmlRootElement(name = "Fault") +public class Fault { + + @XmlElement(required = true) + protected Fault.RequestError requestError; + + /** + * Gets the value of the requestError property. + * + * @return + * possible object is + * {@link Fault.RequestError } + * + */ + public Fault.RequestError getRequestError() { + return requestError; + } + + /** + * Sets the value of the requestError property. + * + * @param value + * allowed object is + * {@link Fault.RequestError } + * + */ + public void setRequestError(Fault.RequestError value) { + this.requestError = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="policyException"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "policyException" + }) + public static class RequestError { + + @XmlElement(required = true) + protected Fault.RequestError.PolicyException policyException; + + /** + * Gets the value of the policyException property. + * + * @return + * possible object is + * {@link Fault.RequestError.PolicyException } + * + */ + public Fault.RequestError.PolicyException getPolicyException() { + return policyException; + } + + /** + * Sets the value of the policyException property. + * + * @param value + * allowed object is + * {@link Fault.RequestError.PolicyException } + * + */ + public void setPolicyException(Fault.RequestError.PolicyException value) { + this.policyException = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "messageId", + "text", + "variables" + }) + public static class PolicyException { + + @XmlElement(required = true) + protected String messageId; + @XmlElement(required = true) + protected String text; + @XmlElement(required = true) + protected Fault.RequestError.PolicyException.Variables variables; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the text property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getText() { + return text; + } + + /** + * Sets the value of the text property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setText(String value) { + this.text = value; + } + + /** + * Gets the value of the variables property. + * + * @return + * possible object is + * {@link Fault.RequestError.PolicyException.Variables } + * + */ + public Fault.RequestError.PolicyException.Variables getVariables() { + return variables; + } + + /** + * Sets the value of the variables property. + * + * @param value + * allowed object is + * {@link Fault.RequestError.PolicyException.Variables } + * + */ + public void setVariables(Fault.RequestError.PolicyException.Variables value) { + this.variables = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "variable" + }) + public static class Variables { + + protected List<String> variable; + + /** + * Gets the value of the variable property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the variable property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getVariable().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link String } + * + * @return the variable + */ + public List<String> getVariable() { + if (variable == null) { + variable = new ArrayList<String>(); + } + return this.variable; + } + + } + + } + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/ObjectFactory.java new file mode 100644 index 00000000..3d3cffe2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/ObjectFactory.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.02.11 at 04:54:39 PM EST +// + + +package org.openecomp.aai.domain.restPolicyException; + +import javax.xml.bind.annotation.XmlRegistry; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.openecomp.aai.domain.restPolicyException package. + * <p>An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.restPolicyException + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Fault }. + * + * @return the fault + */ + public Fault createFault() { + return new Fault(); + } + + /** + * Create an instance of {@link Fault.RequestError } + * + * @return the request error + */ + public Fault.RequestError createFaultRequestError() { + return new Fault.RequestError(); + } + + /** + * Create an instance of {@link Fault.RequestError.PolicyException } + * + * @return the policy exception + */ + public Fault.RequestError.PolicyException createFaultRequestErrorPolicyException() { + return new Fault.RequestError.PolicyException(); + } + + /** + * Create an instance of {@link Fault.RequestError.PolicyException.Variables } + * + * @return the variables + */ + public Fault.RequestError.PolicyException.Variables createFaultRequestErrorPolicyExceptionVariables() { + return new Fault.RequestError.PolicyException.Variables(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/PolicyException.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/PolicyException.java new file mode 100644 index 00000000..b0e427bb --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/PolicyException.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.restPolicyException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "messageId", + "text", + "variables" +}) +public class PolicyException { + + @JsonProperty("messageId") + private String messageId; + @JsonProperty("text") + private String text; + @JsonProperty("variables") + private List<String> variables = new ArrayList<String>(); + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * Gets the message id. + * + * @return The messageId + */ + @JsonProperty("messageId") + public String getMessageId() { + return messageId; + } + + /** + * Sets the message id. + * + * @param messageId The messageId + */ + @JsonProperty("messageId") + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + /** + * Gets the text. + * + * @return The text + */ + @JsonProperty("text") + public String getText() { + return text; + } + + /** + * Sets the text. + * + * @param text The text + */ + @JsonProperty("text") + public void setText(String text) { + this.text = text; + } + + /** + * Gets the variables. + * + * @return The variables + */ + @JsonProperty("variables") + public List<String> getVariables() { + return variables; + } + + /** + * Sets the variables. + * + * @param variables The variables + */ + @JsonProperty("variables") + public void setVariables(List<String> variables) { + this.variables = variables; + } + + /** + * Gets the additional properties. + * + * @return the additional properties + */ + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + /** + * Sets the additional property. + * + * @param name the name + * @param value the value + */ + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RESTResponse.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RESTResponse.java new file mode 100644 index 00000000..bf929e8c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RESTResponse.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.restPolicyException; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "requestError" +}) +public class RESTResponse { + + @JsonProperty("requestError") + private RequestError requestError; + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * Gets the request error. + * + * @return The requestError + */ + @JsonProperty("requestError") + public RequestError getRequestError() { + return requestError; + } + + /** + * Sets the request error. + * + * @param requestError The requestError + */ + @JsonProperty("requestError") + public void setRequestError(RequestError requestError) { + this.requestError = requestError; + } + + /** + * Gets the additional properties. + * + * @return the additional properties + */ + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + /** + * Sets the additional property. + * + * @param name the name + * @param value the value + */ + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RequestError.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RequestError.java new file mode 100644 index 00000000..ebbb8984 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RequestError.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.restPolicyException; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "policyException" +}) +public class RequestError { + + @JsonProperty("policyException") + private PolicyException policyException; + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * Gets the policy exception. + * + * @return The policyException + */ + @JsonProperty("policyException") + public PolicyException getPolicyException() { + return policyException; + } + + /** + * Sets the policy exception. + * + * @param policyException The policyException + */ + @JsonProperty("policyException") + public void setPolicyException(PolicyException policyException) { + this.policyException = policyException; + } + + /** + * Gets the additional properties. + * + * @return the additional properties + */ + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + /** + * Sets the additional property. + * + * @param name the name + * @param value the value + */ + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} + diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/Info.java b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/Info.java new file mode 100644 index 00000000..a91fdb5b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/Info.java @@ -0,0 +1,385 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.10.28 at 05:53:17 PM EDT +// + + +package org.openecomp.aai.domain.restResponseInfo; + +import java.util.ArrayList; +import java.util.List; +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; + + +/** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="responseMessages" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="responseMessage" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "responseMessages" +}) +@XmlRootElement(name = "Info") +public class Info { + + protected Info.ResponseMessages responseMessages; + + /** + * Gets the value of the responseMessages property. + * + * @return + * possible object is + * {@link Info.ResponseMessages } + * + */ + public Info.ResponseMessages getResponseMessages() { + return responseMessages; + } + + /** + * Sets the value of the responseMessages property. + * + * @param value + * allowed object is + * {@link Info.ResponseMessages } + * + */ + public void setResponseMessages(Info.ResponseMessages value) { + this.responseMessages = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="responseMessage" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "responseMessage" + }) + public static class ResponseMessages { + + protected List<Info.ResponseMessages.ResponseMessage> responseMessage; + + /** + * Gets the value of the responseMessage property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the responseMessage property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getResponseMessage().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link Info.ResponseMessages.ResponseMessage } + * + * @return the response message + */ + public List<Info.ResponseMessages.ResponseMessage> getResponseMessage() { + if (responseMessage == null) { + responseMessage = new ArrayList<Info.ResponseMessages.ResponseMessage>(); + } + return this.responseMessage; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "messageId", + "text", + "variables" + }) + public static class ResponseMessage { + + @XmlElement(required = true) + protected String messageId; + @XmlElement(required = true) + protected String text; + @XmlElement(required = true) + protected Info.ResponseMessages.ResponseMessage.Variables variables; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the text property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getText() { + return text; + } + + /** + * Sets the value of the text property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setText(String value) { + this.text = value; + } + + /** + * Gets the value of the variables property. + * + * @return + * possible object is + * {@link Info.ResponseMessages.ResponseMessage.Variables } + * + */ + public Info.ResponseMessages.ResponseMessage.Variables getVariables() { + return variables; + } + + /** + * Sets the value of the variables property. + * + * @param value + * allowed object is + * {@link Info.ResponseMessages.ResponseMessage.Variables } + * + */ + public void setVariables(Info.ResponseMessages.ResponseMessage.Variables value) { + this.variables = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "variable" + }) + public static class Variables { + + protected List<String> variable; + + /** + * Gets the value of the variable property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the variable property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getVariable().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link String } + * + * @return the variable + */ + public List<String> getVariable() { + if (variable == null) { + variable = new ArrayList<String>(); + } + return this.variable; + } + + } + + } + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/ObjectFactory.java new file mode 100644 index 00000000..c964cd59 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/ObjectFactory.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.10.28 at 05:53:17 PM EDT +// + + +package org.openecomp.aai.domain.restResponseInfo; + +import javax.xml.bind.annotation.XmlRegistry; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.openecomp.aai.domain.restResponseInfo package. + * <p>An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.restResponseInfo + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Info }. + * + * @return the info + */ + public Info createInfo() { + return new Info(); + } + + /** + * Create an instance of {@link Info.ResponseMessages } + * + * @return the response messages + */ + public Info.ResponseMessages createInfoResponseMessages() { + return new Info.ResponseMessages(); + } + + /** + * Create an instance of {@link Info.ResponseMessages.ResponseMessage } + * + * @return the response message + */ + public Info.ResponseMessages.ResponseMessage createInfoResponseMessagesResponseMessage() { + return new Info.ResponseMessages.ResponseMessage(); + } + + /** + * Create an instance of {@link Info.ResponseMessages.ResponseMessage.Variables } + * + * @return the variables + */ + public Info.ResponseMessages.ResponseMessage.Variables createInfoResponseMessagesResponseMessageVariables() { + return new Info.ResponseMessages.ResponseMessage.Variables(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/Fault.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/Fault.java new file mode 100644 index 00000000..639a5cff --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/Fault.java @@ -0,0 +1,382 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.02.11 at 04:54:29 PM EST +// + + +package org.openecomp.aai.domain.restServiceException; + +import java.util.ArrayList; +import java.util.List; +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; + + +/** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="requestError"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="serviceException"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "requestError" +}) +@XmlRootElement(name = "Fault") +public class Fault { + + @XmlElement(required = true) + protected Fault.RequestError requestError; + + /** + * Gets the value of the requestError property. + * + * @return + * possible object is + * {@link Fault.RequestError } + * + */ + public Fault.RequestError getRequestError() { + return requestError; + } + + /** + * Sets the value of the requestError property. + * + * @param value + * allowed object is + * {@link Fault.RequestError } + * + */ + public void setRequestError(Fault.RequestError value) { + this.requestError = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="serviceException"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "serviceException" + }) + public static class RequestError { + + @XmlElement(required = true) + protected Fault.RequestError.ServiceException serviceException; + + /** + * Gets the value of the serviceException property. + * + * @return + * possible object is + * {@link Fault.RequestError.ServiceException } + * + */ + public Fault.RequestError.ServiceException getServiceException() { + return serviceException; + } + + /** + * Sets the value of the serviceException property. + * + * @param value + * allowed object is + * {@link Fault.RequestError.ServiceException } + * + */ + public void setServiceException(Fault.RequestError.ServiceException value) { + this.serviceException = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="variables"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "messageId", + "text", + "variables" + }) + public static class ServiceException { + + @XmlElement(required = true) + protected String messageId; + @XmlElement(required = true) + protected String text; + @XmlElement(required = true) + protected Fault.RequestError.ServiceException.Variables variables; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the text property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getText() { + return text; + } + + /** + * Sets the value of the text property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setText(String value) { + this.text = value; + } + + /** + * Gets the value of the variables property. + * + * @return + * possible object is + * {@link Fault.RequestError.ServiceException.Variables } + * + */ + public Fault.RequestError.ServiceException.Variables getVariables() { + return variables; + } + + /** + * Sets the value of the variables property. + * + * @param value + * allowed object is + * {@link Fault.RequestError.ServiceException.Variables } + * + */ + public void setVariables(Fault.RequestError.ServiceException.Variables value) { + this.variables = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "variable" + }) + public static class Variables { + + protected List<String> variable; + + /** + * Gets the value of the variable property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the variable property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getVariable().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link String } + * + * @return the variable + */ + public List<String> getVariable() { + if (variable == null) { + variable = new ArrayList<String>(); + } + return this.variable; + } + + } + + } + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ObjectFactory.java new file mode 100644 index 00000000..c6c06766 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ObjectFactory.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.02.11 at 04:54:29 PM EST +// + + +package org.openecomp.aai.domain.restServiceException; + +import javax.xml.bind.annotation.XmlRegistry; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.openecomp.aai.domain.restServiceException package. + * <p>An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.restServiceException + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Fault }. + * + * @return the fault + */ + public Fault createFault() { + return new Fault(); + } + + /** + * Create an instance of {@link Fault.RequestError } + * + * @return the request error + */ + public Fault.RequestError createFaultRequestError() { + return new Fault.RequestError(); + } + + /** + * Create an instance of {@link Fault.RequestError.ServiceException } + * + * @return the service exception + */ + public Fault.RequestError.ServiceException createFaultRequestErrorServiceException() { + return new Fault.RequestError.ServiceException(); + } + + /** + * Create an instance of {@link Fault.RequestError.ServiceException.Variables } + * + * @return the variables + */ + public Fault.RequestError.ServiceException.Variables createFaultRequestErrorServiceExceptionVariables() { + return new Fault.RequestError.ServiceException.Variables(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RESTResponse.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RESTResponse.java new file mode 100644 index 00000000..bef20f79 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RESTResponse.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.restServiceException; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "requestError" +}) +public class RESTResponse { + + @JsonProperty("requestError") + private RequestError requestError; + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * Gets the request error. + * + * @return The requestError + */ + @JsonProperty("requestError") + public RequestError getRequestError() { + return requestError; + } + + /** + * Sets the request error. + * + * @param requestError The requestError + */ + @JsonProperty("requestError") + public void setRequestError(RequestError requestError) { + this.requestError = requestError; + } + + /** + * Gets the additional properties. + * + * @return the additional properties + */ + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + /** + * Sets the additional property. + * + * @param name the name + * @param value the value + */ + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RequestError.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RequestError.java new file mode 100644 index 00000000..9a076908 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RequestError.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.restServiceException; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "serviceException" +}) +public class RequestError { + + @JsonProperty("serviceException") + private ServiceException serviceException; + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * Gets the service exception. + * + * @return The serviceException + */ + @JsonProperty("serviceException") + public ServiceException getServiceException() { + return serviceException; + } + + /** + * Sets the service exception. + * + * @param serviceException The serviceException + */ + @JsonProperty("serviceException") + public void setServiceException(ServiceException serviceException) { + this.serviceException = serviceException; + } + + /** + * Gets the additional properties. + * + * @return the additional properties + */ + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + /** + * Sets the additional property. + * + * @param name the name + * @param value the value + */ + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ServiceException.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ServiceException.java new file mode 100644 index 00000000..86b21de3 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ServiceException.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.restServiceException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "messageId", + "text", + "variables" +}) +public class ServiceException { + + @JsonProperty("messageId") + private String messageId; + @JsonProperty("text") + private String text; + @JsonProperty("variables") + private List<String> variables = new ArrayList<String>(); + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * Gets the message id. + * + * @return The messageId + */ + @JsonProperty("messageId") + public String getMessageId() { + return messageId; + } + + /** + * Sets the message id. + * + * @param messageId The messageId + */ + @JsonProperty("messageId") + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + /** + * Gets the text. + * + * @return The text + */ + @JsonProperty("text") + public String getText() { + return text; + } + + /** + * Sets the text. + * + * @param text The text + */ + @JsonProperty("text") + public void setText(String text) { + this.text = text; + } + + /** + * Gets the variables. + * + * @return The variables + */ + @JsonProperty("variables") + public List<String> getVariables() { + return variables; + } + + /** + * Sets the variables. + * + * @param variables The variables + */ + @JsonProperty("variables") + public void setVariables(List<String> variables) { + this.variables = variables; + } + + /** + * Gets the additional properties. + * + * @return the additional properties + */ + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + /** + * Sets the additional property. + * + * @param name the name + * @param value the value + */ + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntries.java b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntries.java new file mode 100644 index 00000000..0497da42 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntries.java @@ -0,0 +1,131 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.03.20 at 09:46:47 AM CDT +// + + +package org.openecomp.aai.domain.translog; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="update" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="update-node-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="update-node-key" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key-name" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="key-value" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <element name="action" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="action-type" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="action-data" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="property-name" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="property-value" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "transactionLogEntries" +}) +@XmlRootElement(name = "transaction-log-entries", namespace = "http://org.openecomp.aai.inventory") +public class TransactionLogEntries { + + protected List<TransactionLogEntry> transactionLogEntries; + + /** + * Gets the transaction log entries. + * + * @return the transaction log entries + */ + public List<TransactionLogEntry> getTransactionLogEntries() { + if (transactionLogEntries == null) { + transactionLogEntries = new ArrayList<TransactionLogEntry>(); + } + return this.transactionLogEntries; + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntry.java b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntry.java new file mode 100644 index 00000000..6c2f815b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntry.java @@ -0,0 +1,438 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.domain.translog; + +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 com.sun.xml.txw2.annotation.XmlCDATA; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "transactionLogEntryId", + "status", + "rqstDate", + "respDate", + "sourceId", + "resourceId", + "resourceType", + "rqstBuf", + "respBuf", + "notificationPayload", + "notificationId", + "notificationStatus", + "notificationTopic", + "notificationEntityLink", + "notificationAction" +}) +@XmlRootElement(name = "transaction-log-entry", namespace = "http://org.openecomp.aai.inventory") +public class TransactionLogEntry { + + @XmlElement(name = "transaction-log-entry-id", required = true) + protected String transactionLogEntryId; + @XmlElement(name = "status") + protected String status; + @XmlElement(name = "rqst-date") + protected String rqstDate; + @XmlElement(name = "resp-date") + protected String respDate; + @XmlElement(name = "source-id") + protected String sourceId; + @XmlElement(name = "resource-id") + protected String resourceId; + @XmlElement(name = "resource-type") + protected String resourceType; + @XmlElement(name = "rqst-buf") + protected String rqstBuf; + @XmlElement(name = "resp-buf") + protected String respBuf; + @XmlElement(name = "notification-payload") + protected String notificationPayload; + @XmlElement(name = "notification-id") + protected String notificationId; + @XmlElement(name = "notification-status") + protected String notificationStatus; + @XmlElement(name = "notification-topic") + private String notificationTopic; + @XmlElement(name = "notification-entity-link") + private String notificationEntityLink; + @XmlElement(name = "notification-action") + private String notificationAction; + + /** + * Gets the value of the transcationLogEntryId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTransactionLogEntryId() { + return transactionLogEntryId; + } + + /** + * Sets the value of the transactionLogEntryId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTransactionLogEntryId(String value) { + this.transactionLogEntryId = value; + } + + /** + * Gets the value of the status property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getStatus() { + return status; + } + + /** + * Sets the value of the status property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setStatus(String value) { + this.status = value; + } + + /** + * Gets the value of the rqstDate property. + * + * @return + * possible object is + * {@link String } + * + */ + + public String getRqstDate() { + return rqstDate; + } + + /** + * Sets the value of the rqstDate property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRqstDate(String value) { + this.rqstDate = value; + } + + + /** + * Gets the value of the respDate property. + * + * @return + * possible object is + * {@link String } + * + */ + + public String getRespDate() { + return respDate; + } + + /** + * Sets the value of the respDate property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRespDate(String value) { + this.respDate = value; + } + /** + * Gets the value of the sourceId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getSourceId() { + return sourceId; + } + + /** + * Sets the value of the sourceId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setSourceId(String value) { + this.sourceId = value; + } + + /** + * Gets the value of the resourceId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getResourceId() { + return resourceId; + } + + /** + * Sets the value of the resourceId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setResourceId(String value) { + this.resourceId = value; + } + + /** + * Gets the value of the resourceType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getResourceType() { + return resourceType; + } + + /** + * Sets the value of the resourceType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setResourceType(String value) { + this.resourceType = value; + } + + /** + * Gets the value of the rqstBuf property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRqstBuf() { + return rqstBuf; + } + + /** + * Sets the value of the rqstBuf property. + * + * @param value + * allowed object is + * {@link String } + * + */ + @XmlCDATA + public void setRqstBuf(String value) { + this.rqstBuf = value; + } + + /** + * Gets the value of the respBuf property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getrespBuf() { + return respBuf; + } + + /** + * Sets the value of the respBuf property. + * + * @param value + * allowed object is + * {@link String } + * + */ + @XmlCDATA + public void setrespBuf(String value) { + this.respBuf = value; + } + + /** + * Gets the value of the notificationPayload property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNotificationPayload() { + return notificationPayload; + } + + /** + * Sets the value of the notificationPayload property. + * + * @param value + * allowed object is + * {@link String } + * + */ + @XmlCDATA + public void setNotificationPayload(String value) { + this.notificationPayload = value; + } + + + /** + * Gets the value of the notificationId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNotificationId() { + return notificationId; + } + + /** + * Sets the value of the notificationId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNotificationId(String value) { + this.notificationId = value; + } + + /** + * Gets the value of the notificationId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNotificationStatus() { + return notificationStatus; + } + + /** + * Sets the value of the notificationId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNotificationStatus(String value) { + this.notificationStatus = value; + } + + /** + * Gets the value of the notificationTopic property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNotificationTopic() { + return notificationTopic; + } + + /** + * Sets the value of the notificationTopic property. + * + * @param topic the new notification topic + */ + public void setNotificationTopic(String topic) { + this.notificationTopic = topic; + } + + /** + * Gets the value of the notificationEntityLink property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNotificationEntityLink() { + return notificationEntityLink; + } + + /** + * Sets the value of the notificationEntityLink property. + * + * @param entityLink the new notification entity link + */ + public void setNotificationEntityLink(String entityLink) { + this.notificationEntityLink = entityLink; + } + + /** + * Sets the value of the notificationAction property. + * + * @return the notification action + */ + public String getNotificationAction() { + return notificationAction; + } + + /** + * Sets the value of the notificationAction property. + * + * @param action the new notification action + */ + public void setNotificationAction(String action) { + this.notificationAction = action; + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIException.java b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIException.java new file mode 100644 index 00000000..75ee12f2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIException.java @@ -0,0 +1,146 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.exceptions; + +import java.util.Collection; +import java.util.LinkedList; + +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.logging.ErrorObject; +import org.openecomp.aai.logging.ErrorObjectNotFoundException; + +public class AAIException extends Exception { + + public static final String DEFAULT_EXCEPTION_CODE = "AAI_4000"; + private static final long serialVersionUID = 1L; + + private final String code; + private final ErrorObject errorObject; + private final Collection<String> templateVars; + + /** + * Instantiates a new AAI exception. + */ + public AAIException() { + super(); + this.code = DEFAULT_EXCEPTION_CODE; + this.templateVars = new LinkedList<String> (); + + try { + this.errorObject = ErrorLogHelper.getErrorObject(getCode()); + } catch (ErrorObjectNotFoundException e) { + throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode() + + " - update error.properties before using this exception code"); + } + } + + /** + * Instantiates a new AAI exception. + * + * @param code the code + */ + public AAIException(String code) { + super(); + + this.code = code; + this.templateVars = new LinkedList<String> (); + + try { + this.errorObject = ErrorLogHelper.getErrorObject(getCode()); + } catch (ErrorObjectNotFoundException e) { + throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode() + + " - update error.properties before using this exception code"); + } + } + + /** + * Instantiates a new AAI exception. + * + * @param code the code + * @param details the details + */ + public AAIException(String code, String details) { + super(details); + + this.code = code; + this.templateVars = new LinkedList<String> (); + + try { + this.errorObject = ErrorLogHelper.getErrorObject(getCode()); + } catch (ErrorObjectNotFoundException e) { + throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode() + + " - update error.properties before using this exception code"); + } + } + + /** + * Instantiates a new AAI exception. + * + * @param code the code + * @param cause the cause + */ + public AAIException(String code, Throwable cause) { + super(cause); + + this.code = code; + this.templateVars = new LinkedList<String> (); + + try { + this.errorObject = ErrorLogHelper.getErrorObject(getCode()); + } catch (ErrorObjectNotFoundException e) { + throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode() + + " - update error.properties before using this exception code"); + } + } + + /** + * Instantiates a new AAI exception. + * + * @param code the code + * @param cause the cause + * @param details the details + */ + public AAIException(String code, Throwable cause, String details) { + super(details, cause); + + this.code = code; + this.templateVars = new LinkedList<String> (); + + try { + this.errorObject = ErrorLogHelper.getErrorObject(getCode()); + } catch (ErrorObjectNotFoundException e) { + throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode() + + " - update error.properties before using this exception code"); + } + } + + public String getCode() { + return code; + } + + public ErrorObject getErrorObject() { + return errorObject; + } + + public Collection<String> getTemplateVars() { + return templateVars; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIExceptionWithInfo.java b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIExceptionWithInfo.java new file mode 100644 index 00000000..5065612e --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIExceptionWithInfo.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.exceptions; + +import java.util.HashMap; + +public class AAIExceptionWithInfo extends AAIException { + + HashMap<String, Object> infoHash; + String info; + + /** + * Instantiates a new AAI exception with info. + * + * @param infoHash the info hash + * @param info the info + */ + public AAIExceptionWithInfo(HashMap<String, Object> infoHash, String info) { + super(); + setInfoHash(infoHash); + setInfo(info); + } + + /** + * Instantiates a new AAI exception with info. + * + * @param code the code + * @param infoHash the info hash + * @param info the info + */ + public AAIExceptionWithInfo(String code, HashMap<String, Object> infoHash, String info) { + super(code); + setInfoHash(infoHash); + setInfo(info); + } + + /** + * Instantiates a new AAI exception with info. + * + * @param code the code + * @param details the details + * @param infoHash the info hash + * @param info the info + */ + public AAIExceptionWithInfo(String code, String details, HashMap<String, Object> infoHash, String info) { + super(code, details); + setInfoHash(infoHash); + setInfo(info); + } + + /** + * Instantiates a new AAI exception with info. + * + * @param code the code + * @param cause the cause + * @param infoHash the info hash + * @param info the info + */ + public AAIExceptionWithInfo(String code, Throwable cause, HashMap<String, Object> infoHash, String info) { + super(code, cause); + setInfoHash(infoHash); + setInfo(info); + } + + /** + * Instantiates a new AAI exception with info. + * + * @param code the code + * @param cause the cause + * @param details the details + * @param infoHash the info hash + * @param info the info + */ + public AAIExceptionWithInfo(String code, Throwable cause, String details, HashMap<String, Object> infoHash, String info) { + super(code, cause, details); + setInfoHash(infoHash); + setInfo(info); + } + + /** + * Gets the info hash. + * + * @return the info hash + */ + public HashMap<String, Object> getInfoHash() { + return infoHash; + } + + /** + * Sets the info hash. + * + * @param infoHash the info hash + */ + public void setInfoHash(HashMap<String, Object> infoHash) { + this.infoHash = infoHash; + } + + /** + * Gets the info. + * + * @return the info + */ + public String getInfo() { + return info; + } + + /** + * Sets the info. + * + * @param info the new info + */ + public void setInfo(String info) { + this.info = info; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/ConvertXmlToJsonMoxyOxm.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/ConvertXmlToJsonMoxyOxm.java new file mode 100644 index 00000000..1af2df31 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/ConvertXmlToJsonMoxyOxm.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ingestModel; + +import java.io.File; +import java.io.StringWriter; +import java.util.ArrayList; + +import javax.xml.transform.stream.StreamSource; + +import org.eclipse.persistence.dynamic.DynamicEntity; +import org.eclipse.persistence.jaxb.JAXBMarshaller; +import org.eclipse.persistence.jaxb.JAXBUnmarshaller; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; + +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; + +/** + * The Class ConvertXmlToJsonMoxyOxm. + */ +public class ConvertXmlToJsonMoxyOxm +{ + /** + * The main method. + * + * @param args the arguments + * @throws Exception the exception + */ + public static void main(String[] args) throws Exception { + + String _apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + String fileName = null; + String dynamicType = null; + if (args.length > 0) { + if (args[0] != null) { + _apiVersion = args[0]; + } + if (args[1] != null) { + fileName = args[1]; + } + if (args[2] != null) { + dynamicType = args[2]; + } + } + + if (fileName == null) { + System.err.println("You must specify a fileName"); + System.exit(0); + } + if (dynamicType == null) { + System.err.println("You must specify a dynamic Type"); + System.exit(0); + } + + ArrayList<String> apiVersions = new ArrayList<String>(); + apiVersions.add(_apiVersion); + final IngestModelMoxyOxm m = new IngestModelMoxyOxm(); + m.init(apiVersions, false); + + DynamicJAXBContext jaxbContext = IngestModelMoxyOxm.aaiResourceContainer.get(_apiVersion).getJaxbContext(); + + JAXBUnmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + + Class<? extends DynamicEntity> resultClass = jaxbContext.newDynamicEntity(dynamicType).getClass(); + + DynamicEntity meObject = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(new File(fileName)), resultClass).getValue(); + + // put it out as JSON + + JAXBMarshaller marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(JAXBMarshaller.JAXB_FORMATTED_OUTPUT, true); + + marshaller.setProperty("eclipselink.media-type", "application/json"); + marshaller.setProperty("eclipselink.json.include-root", false); + marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ; + + StringWriter writer = new StringWriter(); + marshaller.marshal(meObject, writer); + + System.out.println(writer.toString()); + + System.exit(0); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/CreateWidgetModels.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/CreateWidgetModels.java new file mode 100644 index 00000000..549bff00 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/CreateWidgetModels.java @@ -0,0 +1,168 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ingestModel; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Map; +import java.util.UUID; + +import javax.xml.transform.stream.StreamSource; + +import org.eclipse.persistence.dynamic.DynamicEntity; +import org.eclipse.persistence.jaxb.JAXBMarshaller; +import org.eclipse.persistence.jaxb.JAXBUnmarshaller; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; + +import org.openecomp.aai.domain.model.AAIResource; +import org.openecomp.aai.domain.model.AAIResources; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import com.google.common.base.CaseFormat; + +/** + * The Class CreateWidgetModels. + */ +public class CreateWidgetModels +{ + /** + * The main method. + * + * @param args the arguments + * @throws Exception the exception + */ + public static void main(String[] args) throws Exception { + + String _apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + String widgetJsonDir = null; + String modelVersion = null; + if (args.length > 0) { + if (args[0] != null) { + _apiVersion = args[0]; + } + if (args[1] != null) { + widgetJsonDir = args[1]; + } + if (args[2] != null) { + modelVersion = args[2]; + } + } + + if (widgetJsonDir == null) { + System.err.println("You must specify a directory for widgetModelJson"); + System.exit(0); + } + if (modelVersion == null) { + System.err.println("You must specify a modelVersion"); + System.exit(0); + } + + ArrayList<String> apiVersions = new ArrayList<String>(); + apiVersions.add(_apiVersion); + final IngestModelMoxyOxm m = new IngestModelMoxyOxm(); + m.init(apiVersions, false); + + AAIResources aaiResources = IngestModelMoxyOxm.aaiResourceContainer.get(_apiVersion); + + DynamicJAXBContext jaxbContext = aaiResources.getJaxbContext(); + + // iterate the collection of resources + + ArrayList<String> processedWidgets = new ArrayList<String>(); + for (Map.Entry<String, AAIResource> aaiResEnt : aaiResources.getAaiResources().entrySet()) { + DynamicEntity meObject = jaxbContext.newDynamicEntity("inventory.aai.openecomp.org." + _apiVersion + ".Model"); + // no need for a ModelVers DynamicEntity + + AAIResource aaiRes = aaiResEnt.getValue(); + + if (aaiRes.getResourceType().equals("node")) { + String resource = aaiRes.getSimpleName(); + + if (processedWidgets.contains(resource)) { + continue; + } + processedWidgets.add(resource); + + String widgetName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, resource); + String filePathString = widgetJsonDir + "/" + widgetName + "-" + modelVersion + ".json"; + File f = new File(filePathString); + + String filePathString2 = widgetJsonDir + "/../widget-model-json-old/" + widgetName + "-" + modelVersion + ".json"; + File f2 = new File(filePathString2); + + if(!f.exists() && !f.isDirectory()) { + + if (f2.exists()) { + System.out.println("Using old file for " + resource + "."); + + JAXBUnmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + unmarshaller.setProperty("eclipselink.media-type", "application/json"); + unmarshaller.setProperty("eclipselink.json.include-root", false); + Class<? extends DynamicEntity> resultClass = meObject.getClass(); + meObject = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(f2), resultClass).getValue(); + // override, some of them are wrong + meObject.set("modelVersion", modelVersion); + } else { + + System.out.println("Making new file for " + resource + "."); + meObject.set("modelInvariantId", UUID.randomUUID().toString()); + meObject.set("modelType", "widget"); + DynamicEntity mevObject = jaxbContext.newDynamicEntity("inventory.aai.openecomp.org." + _apiVersion + ".ModelVer"); + DynamicEntity mevsObject = jaxbContext.newDynamicEntity("inventory.aai.openecomp.org." + _apiVersion + ".ModelVers"); + mevObject.set("modelVersionId", UUID.randomUUID().toString()); + mevObject.set("modelVersion", modelVersion); + mevObject.set("modelName", widgetName); + // make a list of dynamic Entities + ArrayList<DynamicEntity> mevsList = new ArrayList<DynamicEntity>(); + // add this one, it will be the only one in the list in this case + mevsList.add(mevObject); + mevsObject.set("modelVer", mevsList); + // Have to figure out how to add my mev object to the mevsObject, + // the modelVers is a list of dynamic entities so we can just attach the array here + meObject.set("modelVers",mevsObject); + } + + // put it out as JSON + + JAXBMarshaller marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(JAXBMarshaller.JAXB_FORMATTED_OUTPUT, true); + + marshaller.setProperty("eclipselink.media-type", "application/json"); + marshaller.setProperty("eclipselink.json.include-root", false); + marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ; + + StringWriter writer = new StringWriter(); + marshaller.marshal(meObject, writer); + PrintWriter out = new PrintWriter(f); + out.println(writer.toString()); + out.close(); + + } else { + System.out.println("File already exists for " + resource + ". Skipping."); + } + } + } + System.exit(0); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/DbMaps.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/DbMaps.java new file mode 100644 index 00000000..9d7fa4dc --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/DbMaps.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ingestModel; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +/** + * The Class DbMaps. + */ +public class DbMaps { + + // from oxm file + public Multimap<String, String> NodeAltKey1Props = ArrayListMultimap.create(); + + public Multimap<String, String> NodeDependencies = ArrayListMultimap.create(); + + public Multimap<String, String> NodeNameProps = ArrayListMultimap.create(); + + public Multimap<String, String> NodeMapIndexedProps = ArrayListMultimap.create(); + + public Multimap<String, String> NodeMapUniqueProps = ArrayListMultimap.create(); + + public Map<Integer, String> EdgeInfoMap = new LinkedHashMap<Integer, String>(); + + public Map<String, String> ReservedPropNames = new HashMap<String, String>(); + + // from AAIResources + public Multimap<String, String> NodeProps = ArrayListMultimap.create(); + + public Multimap<String, String> NodeKeyProps = ArrayListMultimap.create(); + + public Map<String, String> NodePlural = new HashMap<String, String>(); + + public Map<String, String> NodeNamespace = new HashMap<String, String>(); + + public Map<String, String> PropertyVersionInfoMap = new HashMap<String, String>(); + + public Map<String, String> NodeVersionInfoMap = new HashMap<String, String>(); + + public Map<String, String> PropertyDataTypeMap = new HashMap<String, String>(); + + } diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelListener.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelListener.java new file mode 100644 index 00000000..914e5a3b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelListener.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ingestModel; + +import java.util.ArrayList; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * The listener interface for receiving ingestModel events. + * The class that is interested in processing a ingestModel + * event implements this interface, and the object created + * with that class is registered with a component using the + * component's <code>addIngestModelListener<code> method. When + * the ingestModel event occurs, that object's appropriate + * method is invoked. + * + * @see IngestModelEvent + */ +public class IngestModelListener implements ServletContextListener { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IngestModelListener.class); + +/** + * Destroys context. + * + * @param arg0 the ServletContextEvent + */ +//@Override + public void contextDestroyed(ServletContextEvent arg0) { + IngestModelMoxyOxm m = new IngestModelMoxyOxm(); + m.cleanup(); + LOGGER.info("AAI Auth Listener contextDestroyed() complete."); + } + +//Run this before web application is started + /** + * Initializaes the context. + * + * @param arg0 the ServletContextEvent + */ +//@Override + public void contextInitialized(ServletContextEvent arg0) { + + LOGGER.info("IngestModel starts initialization..."); + try { + ArrayList<String> apiVersions = new ArrayList<String>(); + apiVersions.add("v10"); + apiVersions.add("v9"); + apiVersions.add("v8"); + apiVersions.add("v7"); + apiVersions.add("v2"); + IngestModelMoxyOxm m = new IngestModelMoxyOxm(); + m.init(apiVersions); + } catch (AAIException e) { + ErrorLogHelper.logException(e); + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelMoxyOxm.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelMoxyOxm.java new file mode 100644 index 00000000..1fa11c1b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelMoxyOxm.java @@ -0,0 +1,862 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ingestModel; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Vector; + +import org.eclipse.persistence.descriptors.ClassDescriptor; +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.internal.dynamic.DynamicTypeImpl; +import org.eclipse.persistence.internal.helper.DatabaseField; +import org.eclipse.persistence.jaxb.JAXBContextProperties; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory; +import org.eclipse.persistence.mappings.DatabaseMapping; +import org.eclipse.persistence.oxm.XMLField; +import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping; +import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping; + +import org.openecomp.aai.domain.model.AAIResource; +import org.openecomp.aai.domain.model.AAIResourceKey; +import org.openecomp.aai.domain.model.AAIResourceKeys; +import org.openecomp.aai.domain.model.AAIResources; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import org.openecomp.aai.util.FileWatcher; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.CaseFormat; +import com.google.common.base.Splitter; +import com.google.common.collect.Multimap; + +/** + * The Class IngestModelMoxyOxm. + */ +public class IngestModelMoxyOxm +{ + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IngestModelMoxyOxm.class); + + public static HashMap<String, AAIResources> aaiResourceContainer; + public static HashMap<String, DbMaps> dbMapsContainer; + + private static HashMap<String, Timer> timers = new HashMap<String,Timer>(); + + /** + * The main method. + * + * @param args the arguments + * @throws Exception the exception + */ + public static void main(String[] args) throws Exception { + + String _apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); + + if (args.length > 0) { + if (args[0] != null) { + _apiVersion = args[0]; + } + } + ArrayList<String> apiVersions = new ArrayList<String>(); + apiVersions.add(_apiVersion); + final IngestModelMoxyOxm m = new IngestModelMoxyOxm(); + m.init(apiVersions, false); + + ArrayList<String> endpoints = new ArrayList<String>(); + + for (Map.Entry<String, AAIResources> ent: aaiResourceContainer.entrySet()) { + + AAIResources aaiResources = ent.getValue(); + DynamicJAXBContext jaxbContext = aaiResources.getJaxbContext(); + for (Map.Entry<String, AAIResource> aaiResEnt : aaiResources.getAaiResources().entrySet()) { + AAIResource aaiRes = aaiResEnt.getValue(); + + String uri = aaiRes.getUri(); + if (uri != null) { + endpoints.add(uri); + DynamicType dt = jaxbContext.getDynamicType(aaiRes.getResourceClassName()); + if (dt.containsProperty("relationshipList")) { + endpoints.add(uri + "/relationship-list/relationship"); + } + } + } + Collections.sort(endpoints); + for (String endpoint : endpoints) { + if (!endpoint.contains("/aai-internal/")) { + System.out.println(endpoint); + } + } + } + + System.exit(0); + } + + /** + * Inits the. + * + * @param apiVersions the api versions + * @throws Exception the exception + */ + public synchronized void init(ArrayList<String> apiVersions) throws AAIException { + final IngestModelMoxyOxm m = new IngestModelMoxyOxm(); + m.init(apiVersions, true); + } + + /** + * Inits the. + * + * @param apiVersions the api versions + * @param setTimer the set timer + * @throws AAIException If AAIConfig is missing necessary properties + * @throws Exception the exception + */ + public synchronized void init(ArrayList<String> apiVersions, Boolean setTimer) throws AAIException { + + aaiResourceContainer = new HashMap<String, AAIResources>(); + dbMapsContainer = new HashMap<String, DbMaps>(); + + final IngestModelMoxyOxm m = new IngestModelMoxyOxm(); + + for (String apiVersion : apiVersions) { + + String relationshipUtils = "org.openecomp.aai.dbmap.RelationshipUtils"; + final String thisRelationshipUtils = relationshipUtils; + + final String thisApiVersion = apiVersion; + final String schemaFile = AAIConstants.AAI_HOME_ETC_OXM + "aai_oxm_" + apiVersion + ".xml"; + + m.loadSchema(apiVersion, schemaFile, relationshipUtils); + + if (!setTimer) continue; + + TimerTask task = null; + task = new FileWatcher ( new File(schemaFile)) { + protected void onChange( File file ) { + m.loadSchema(thisApiVersion, schemaFile, thisRelationshipUtils); + } + }; + + if (!timers.containsKey(apiVersion)) { + Timer timer = new Timer(); + timer.schedule( task , new Date(), 10000 ); + timers.put(apiVersion, timer); + + } + } + if (apiVersions.contains(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP))) { + m.createPropertyAndNodeVersionInfoMapFromDbMaps(); + + for (Map.Entry<String, AAIResources> ent: aaiResourceContainer.entrySet()) { + String apiVersion = ent.getKey(); + AAIResources aaiResources = ent.getValue(); + + DbMaps dbMap = dbMapsContainer.get(apiVersion); + + for (Map.Entry<String, AAIResource> aaiResEnt : aaiResources.getAaiResources().entrySet()) { + AAIResource aaiRes = aaiResEnt.getValue(); + aaiRes.setPropertyDataTypeMap(dbMap.PropertyDataTypeMap); + aaiRes.setNodeKeyProps(dbMap.NodeKeyProps); + aaiRes.setNodeNameProps(dbMap.NodeNameProps); + aaiRes.setNodeMapIndexedProps(dbMap.NodeMapIndexedProps); + } + } + } + } + + /** + * Load schema. + * + * @param apiVersion the api version + * @param schemaFile the schema file + * @param relationshipUtils the relationship utils + * @return the dynamic JAXB context + */ + private DynamicJAXBContext loadSchema(String apiVersion, + String schemaFile, + String relationshipUtils) { + + AAIResources aaiResources = new AAIResources(); + DbMaps dbMaps = new DbMaps(); + DynamicJAXBContext jaxbContext = null; + + try { + + InputStream iStream = new FileInputStream(new File(schemaFile)); + + Map<String, Object> properties = new HashMap<String, Object>(); + properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream); + + jaxbContext = + DynamicJAXBContextFactory.createContextFromOXM(IngestModelMoxyOxm.class.getClassLoader(), properties); + + aaiResources.setJaxbContext(jaxbContext); + String rootClassName = "inventory.aai.openecomp.org." + apiVersion + ".Inventory"; + + if ("v2".equals(apiVersion)) { + rootClassName = "inventory.aai.openecomp.org.Inventory"; + } + + DynamicTypeImpl t = (DynamicTypeImpl)jaxbContext.getDynamicType(rootClassName); + + lookAtDynamicResource("Inventory", + "inventory.aai.openecomp.org." + apiVersion, + jaxbContext, + t, + 1, "", "", apiVersion, "/" + apiVersion, false, aaiResources, dbMaps, relationshipUtils); + + } catch (Exception e) { + ErrorLogHelper.logException(new AAIException("AAI_3000", e)); + } + + LOGGER.info("---> Loading " + apiVersion + " in aaiResourceContainer"); + aaiResourceContainer.put(apiVersion, aaiResources); + + createDbMapsfromAAIResources(aaiResources, dbMaps); + + LOGGER.info("---> Loading " + apiVersion + " in dbMapsContainer"); + dbMapsContainer.put(apiVersion, dbMaps); + + return jaxbContext; + } + + /** + * Cleanup. + */ + public void cleanup() { + aaiResourceContainer.clear(); + dbMapsContainer.clear(); + } + + /** + * Look at dynamic resource. + * + * @param resource the resource + * @param pojoBase the pojo base + * @param jaxbContext the jaxb context + * @param t the t + * @param depth the depth + * @param parent the parent + * @param namespace the namespace + * @param apiVersion the api version + * @param url the url + * @param container the container + * @param aaiResources the aai resources + * @param dbMaps the db maps + * @param relationshipUtils the relationship utils + * @throws ClassNotFoundException the class not found exception + * @throws NoSuchFieldException the no such field exception + * @throws SecurityException the security exception + * @throws IOException Signals that an I/O exception has occurred. + */ + private void lookAtDynamicResource(String resource, + String pojoBase, + DynamicJAXBContext jaxbContext, + DynamicTypeImpl t, + int depth, + String parent, + String namespace, + String apiVersion, + String url, + boolean container, + AAIResources aaiResources, + DbMaps dbMaps, + String relationshipUtils + ) + throws ClassNotFoundException, NoSuchFieldException, SecurityException, IOException { + + String className = pojoBase + "." + CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL, resource); + + AAIResource parentResource = aaiResources.getAaiResources().get(parent); + + AAIResources siblings = null; + + if (parentResource == null) { + String fullName = "/" + resource; + AAIResource aaiRes = new AAIResource(); + aaiRes.setFullName(fullName); + aaiRes.setSimpleName(resource); + aaiRes.setResourceType("container"); + aaiRes.setResourceClassName(className); + aaiRes.setApiVersion(apiVersion); + + aaiResources.getAaiResources().put(fullName, aaiRes); + parentResource = aaiRes; + } + + if (depth >= 50) return; + + siblings = parentResource.getChildren(); + + if (depth == 2) { + namespace = resource; + } + if (depth >= 50) { + return; + } + + /* if ("Actions".equals(namespace) || "Search".equals(namespace)) { + return; + }*/ + + ClassDescriptor cd = t.getDescriptor(); + + createDbMapsfromOXM(cd.getProperties(), resource, dbMaps); + + + + Vector<DatabaseMapping> dm = cd.getMappings(); + + for (DatabaseMapping dmInst : dm) { + String dmName = dmInst.getAttributeName(); + + ClassDescriptor cd2 = dmInst.getReferenceDescriptor(); + if (cd2 != null) { + + String newClassName = cd2.getJavaClassName(); + // + if (newClassName.contains("RelationshipList")) { + continue; + } + + DynamicTypeImpl newDt = (DynamicTypeImpl)jaxbContext.getDynamicType(newClassName); + + if (dmInst instanceof XMLCompositeCollectionMapping) { + String simpleName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, dmName); + // System.out.println(spaces + "+ List of A&AI Object named " + simpleName); + + String hypName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleName); + + String fullName = parent + "/" + simpleName; + + //Class<?> newClazz = Class.forName(newClassName); + AAIResource aaiRes = new AAIResource(); + + if ("cvlan-tag-entry".equals(hypName)) { + } + + ClassDescriptor cd3 = newDt.getDescriptor(); + + boolean allowDirectWrite = true; + if (cd3.getProperties().containsKey("allowDirectWrite")) { + if (cd3.getProperties().get("allowDirectWrite").equals("false")) { + allowDirectWrite = false; + } + } + + + boolean allowDirectRead = true; + if (cd3.getProperties().containsKey("allowDirectRead")) { + if (cd3.getProperties().get("allowDirectRead").equals("false")) { + allowDirectRead = false; + } + } + + List<DatabaseField> dbfList = cd3.getPrimaryKeyFields(); + ArrayList<String> keyFields = new ArrayList<String>(); + + if (dbfList != null) { + for (DatabaseField dbf : dbfList) { + String name = dbf.getName(); + name = name.substring(0, name.indexOf('/')); + keyFields.add(name); + } + } + Vector<DatabaseMapping> dm2 = cd3.getMappings(); + for (DatabaseMapping dmInst2 : dm2) { + String dmName2= CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmInst2.getAttributeName()); + DatabaseField xf2 = dmInst2.getField(); + if (dmInst2.getProperties().containsKey("autoGenerateUuid")) { + if (dmInst2.getProperties().get("autoGenerateUuid").equals("true")) { + aaiRes.getAutoGenUuidFields().add(dmName2); + } + } + if (xf2 instanceof XMLField) { + XMLField x = (XMLField)xf2; + if (x != null) { + if (x.isRequired()) { + aaiRes.getRequiredFields().add(dmName2); + } + } + + } + try { + Class<?> xf2Clazz = xf2.getType(); + if (xf2Clazz.getSimpleName().equals("String")) { + if (dmInst2 instanceof XMLCompositeDirectCollectionMapping) { + aaiRes.getStringListFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2)); + } else { + aaiRes.getStringFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2)); + } + } else if (xf2Clazz.getSimpleName().toLowerCase().contains("long")) { + aaiRes.getLongFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2)); + } else if (xf2Clazz.getSimpleName().toLowerCase().contains("int")) { + aaiRes.getIntFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2)); + } else if (xf2Clazz.getSimpleName().toLowerCase().contains("short")) { + aaiRes.getShortFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2)); + } else if (xf2Clazz.getSimpleName().toLowerCase().contains("boolean")) { + aaiRes.getBooleanFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2)); + } + } catch (Exception e) { // this xf2.getType() throws null pointer when I try to get the type and it doesn't have one + ; + } + } + + // get the key(s) from DbRules + String uriKey = ""; + LinkedHashMap<String, ArrayList<String>> itemKeyList = new LinkedHashMap<String, ArrayList<String>>(); + + aaiRes.setApiVersion(apiVersion); + itemKeyList.put(hypName, new ArrayList<String>()); + for (String thisKey : keyFields) { + String pathParamName = hypName + "-" + thisKey; + + AAIResourceKey aaiResKey = new AAIResourceKey(); + aaiResKey.setKeyName(thisKey); + aaiResKey.setDnCamKeyName(CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, pathParamName)); + aaiResKey.setPathParamName(pathParamName); + + for (DatabaseMapping dmInst2 : dm2) { + String dmName2= CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmInst2.getAttributeName()); + if (dmName2.equals(thisKey)){ + DatabaseField xf2 = dmInst2.getField(); + aaiResKey.setKeyType(xf2.getType().getSimpleName()); + break; + } + } + + aaiRes.getAaiResourceKeys().getAaiResourceKey().add(aaiResKey); + + if (siblings != null) { + siblings.getAaiResources().put(fullName, aaiRes); + } + + uriKey += "/{" + pathParamName + "}"; + } + + String newUri = url + "/" + hypName + uriKey; + + + if ("v2".equals(apiVersion)) { + aaiRes.setResourceClassName("inventory.aai.openecomp.org." + simpleName); + } else { + aaiRes.setResourceClassName("inventory.aai.openecomp.org." + apiVersion + "." + simpleName); + } + + aaiRes.setAllowDirectWrite(allowDirectWrite); + aaiRes.setAllowDirectRead(allowDirectRead); + aaiRes.setNamespace(namespace); + aaiRes.setSimpleName(simpleName); + + if (!aaiResources.getResourceLookup().containsKey(simpleName)) { + aaiResources.getResourceLookup().put(simpleName, aaiRes); + } + + aaiRes.setFullName(fullName); + aaiRes.setUri(newUri); + aaiRes.setResourceType("node"); + if ("v2".equals(apiVersion)) { + aaiRes.setRelationshipListClass("inventory.aai.openecomp.org.RelationshipList"); + } else { + aaiRes.setRelationshipListClass("inventory.aai.openecomp.org." + apiVersion + ".RelationshipList"); + } + aaiRes.setRelationshipUtils(relationshipUtils); + + if (parentResource != null) { + aaiRes.setParent(parentResource); + } else { + aaiRes.setParent(aaiRes); + } + + aaiResources.getAaiResources().put(fullName, aaiRes); + + if (siblings != null) { + siblings.getAaiResources().put(fullName, aaiRes); + } +// AAIResource ancestor = parentResource; +// +// boolean recursiveEntity = false; +// while (ancestor != null) { +// +// if (ancestor.getSimpleName().equals(aaiRes.getSimpleName())) { +// recursiveEntity = true; +// // attach it to the container that contains the resource above this one with the same name +// if (ancestor.getParent() != null && ancestor.getParent().getResourceType().equals("container")) { +// AAIResource recurseHere = ancestor.getParent(); +// aaiRes.setRecurseToResource(recurseHere); +// } +// break; +// } +// ancestor = ancestor.getParent(); +// +// } +// if (recursiveEntity == false) { + lookAtDynamicResource(cd2.getJavaClass().getSimpleName(), + pojoBase, + jaxbContext, + newDt, + (depth + 1), fullName, namespace, apiVersion, newUri, false, aaiResources, dbMaps, + relationshipUtils); +// } + } else { + String simpleName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, dmName); + String fullName = parent + "/" + simpleName; + // System.out.println(spaces + "+ Container of A&AI Object named " + simpleName); + + AAIResource aaiRes = new AAIResource(); + if (parentResource != null) { + aaiRes.setParent(parentResource); + } else { + aaiRes.setParent(aaiRes); + } + aaiRes.setAllowDirectWrite(true); + aaiRes.setAllowDirectRead(true); + aaiRes.setFullName(fullName); + aaiRes.setSimpleName(simpleName); + if (!aaiResources.getResourceLookup().containsKey(simpleName)) { + aaiResources.getResourceLookup().put(simpleName, aaiRes); + } + aaiRes.setResourceType("container"); + + if ("v2".equals(apiVersion)) { + aaiRes.setResourceClassName("inventory.aai.openecomp.org." + simpleName); + aaiRes.setRelationshipListClass("inventory.aai.openecomp.org.RelationshipList"); + } else { + aaiRes.setResourceClassName("inventory.aai.openecomp.org." + apiVersion + "." + simpleName); + aaiRes.setRelationshipListClass("inventory.aai.openecomp.org." + apiVersion + ".RelationshipList"); + } + aaiRes.setApiVersion(apiVersion); + + aaiResources.getAaiResources().put(fullName, aaiRes); + aaiRes.setRelationshipUtils(relationshipUtils); + + String hypName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleName); + + if (siblings != null) { + siblings.getAaiResources().put(fullName, aaiRes); + } + + lookAtDynamicResource(cd2.getJavaClass().getSimpleName(), + pojoBase, + jaxbContext, + (DynamicTypeImpl)jaxbContext.getDynamicType(newClassName), + (depth + 1), fullName, namespace, apiVersion, url + "/" + hypName, false, aaiResources, dbMaps, + relationshipUtils); + + + } + } + } + } + + /** + * Creates the db mapsfrom OXM. + * + * @param propMap the prop map + * @param resource the resource + * @param dbMaps the db maps + */ + private void createDbMapsfromOXM(Map<?, ?> propMap, String resource, DbMaps dbMaps) { + String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, resource); + if ("cvlan-tag-entry".equals(nodeType)) { + nodeType = "cvlan-tag"; + } + + // if we have nodes dependent on multiple nodes we might revisit the node again - skip then + if (propMap.size() > 1 && !dbMaps.NodeMapIndexedProps.containsKey(nodeType)) { + + if (propMap.containsKey("nameProps")) + dbMaps.NodeNameProps.putAll(nodeType, + (Iterable<String>) fromCommaSeparatedString(propMap.get("nameProps").toString())); + + if (propMap.containsKey("indexedProps")) + dbMaps.NodeMapIndexedProps.putAll(nodeType, + (Iterable<String>) fromCommaSeparatedString(propMap.get("indexedProps").toString())); + + if (propMap.containsKey("dependentOn")) + dbMaps.NodeDependencies.putAll(nodeType, + (Iterable<String>) fromCommaSeparatedString(propMap.get("dependentOn").toString())); + + if (propMap.containsKey("alternateKeys1")) + dbMaps.NodeAltKey1Props.putAll(nodeType, + (Iterable<String>) fromCommaSeparatedString(propMap.get("alternateKeys1").toString())); + + if (propMap.containsKey("uniqueProps")) + dbMaps.NodeMapUniqueProps.putAll(nodeType, + (Iterable<String>) fromCommaSeparatedString(propMap.get("uniqueProps").toString())); + + // build EdgeInfoMap + if (propMap.containsKey("edgeInfo")) { + int i = 0; + Iterable<String> edgeInfoIterable = (Iterable<String>) fromCommaSeparatedString(propMap.get("edgeInfo").toString()); + Iterator<String> edgeInfoIterator = edgeInfoIterable.iterator(); + while(edgeInfoIterator.hasNext()) { + String propName = edgeInfoIterator.next(); + dbMaps.EdgeInfoMap.put(i++, propName); + } + } + } + } + + /** + * Creates the db mapsfrom AAI resources. + * + * @param aaiResources the aai resources + * @param dbMaps the db maps + */ + private void createDbMapsfromAAIResources(AAIResources aaiResources, DbMaps dbMaps) { + + for (String resource: aaiResources.getAaiResources().keySet()) { + + AAIResource aaiResource = aaiResources.getAaiResources().get(resource); + String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,aaiResource.getSimpleName()); + + if (nodeType.equals("cvlan-tag-entry")) + nodeType = "cvlan-tag"; + + // Build NodeNamespace + if (aaiResource.getNamespace() != null && !aaiResource.getNamespace().equalsIgnoreCase("search")) + // oamNetworks is also defined under the search namespace - do not want that namespace + dbMaps.NodeNamespace.put(nodeType, CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, aaiResource.getNamespace())); + + // only process one nodetype once + if (dbMaps.NodeProps.containsKey(nodeType)) + continue; + + // Build NodePlural + if (aaiResource.getPluralName() != null && !aaiResource.getPluralName().equals(aaiResource.getNamespace())) + // dont want resources which are namespaces themselves in map + dbMaps.NodePlural.put(nodeType, CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, aaiResource.getPluralName())); + + // Build NodeProps + dbMaps.NodeProps.putAll(nodeType, aaiResource.getAllFields()); + + // build ReservedNames + if (nodeType.equalsIgnoreCase("reserved-prop-names")) { + for (String propName: aaiResource.getAllFields()) { + dbMaps.ReservedPropNames.put(propName, ""); + } + } + + // Build NodekeyProps + AAIResourceKeys aaiResKeys = aaiResource.getAaiResourceKeys(); + List<String> keyList = new ArrayList<String>(); + for (AAIResourceKey rk : aaiResKeys.getAaiResourceKey()) { + String keyProp = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,rk.getKeyName()); + if (!keyList.contains(keyProp)) + keyList.add(keyProp); + } + dbMaps.NodeKeyProps.putAll(nodeType, (Iterable<String>)keyList); + + // Build PropertyDataTypeMap + for (String propName: aaiResource.getBooleanFields()) { + if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB + propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName); + if (propName.equals("sVCINFRA")) propName = "SVC-INFRA"; + if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV"; + if (!dbMaps.PropertyDataTypeMap.containsKey(propName)) + dbMaps.PropertyDataTypeMap.put(propName, "Boolean"); + else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Boolean")) + System.out.println(propName + "defined with mis-matched types in oxm file"); + } + for (String propName: aaiResource.getShortFields()) { + if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB + propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName); + if (propName.equals("sVCINFRA")) propName = "SVC-INFRA"; + if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV"; + if (!dbMaps.PropertyDataTypeMap.containsKey(propName)) + dbMaps.PropertyDataTypeMap.put(propName, "Integer"); + else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Integer")) + System.out.println(propName + "defined with mis-matched types in oxm file"); + } + for (String propName: aaiResource.getLongFields()) { + if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB + propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName); + if (propName.equals("sVCINFRA")) propName = "SVC-INFRA"; + if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV"; + if (!dbMaps.PropertyDataTypeMap.containsKey(propName)) { + if (propName.contains("-ts")) + dbMaps.PropertyDataTypeMap.put(propName, "Long"); + else + dbMaps.PropertyDataTypeMap.put(propName, "Integer"); + } else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Integer")) + System.out.println(propName + "defined with mis-matched types in oxm file"); + } + for (String propName: aaiResource.getIntFields()) { + if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB + propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName); + if (propName.equals("sVCINFRA")) propName = "SVC-INFRA"; + if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV"; + if (!dbMaps.PropertyDataTypeMap.containsKey(propName)) + dbMaps.PropertyDataTypeMap.put(propName, "Integer"); + else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Integer")) + System.out.println(propName + "defined with mis-matched types in oxm file"); + } + for (String propName: aaiResource.getStringFields()) { + if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB + propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName); + if (propName.equals("sVCINFRA")) propName = "SVC-INFRA"; + if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV"; + if (!dbMaps.PropertyDataTypeMap.containsKey(propName)) + dbMaps.PropertyDataTypeMap.put(propName, "String"); + else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("String")) + System.out.println(propName + "defined with mis-matched types in oxm file"); + } + for (String propName: aaiResource.getStringListFields()) { + if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB + propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName); + if (propName.equals("sVCINFRA")) propName = "SVC-INFRA"; + if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV"; + if (!dbMaps.PropertyDataTypeMap.containsKey(propName)) + dbMaps.PropertyDataTypeMap.put(propName, "Set<String>"); + else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Set<String>")) + System.out.println(propName + "defined with mis-matched types in oxm file"); + } + } + + } + + + /** + * Creates the property and node version info map from db maps. + */ + private void createPropertyAndNodeVersionInfoMapFromDbMaps() { + DbMaps dbMaps = null; + String previousApiVersion = null; + List<Integer> apiIntegerKeySet = new ArrayList<Integer>(); + for ( String vers : dbMapsContainer.keySet()) { + apiIntegerKeySet.add(Integer.valueOf(vers.substring(1))); + } + ArrayList<Integer> apiIntegerVersionsList = (ArrayList<Integer>) asSortedList(apiIntegerKeySet); + String apiVersion; + for ( Integer apiIntegerVersion : apiIntegerVersionsList) { + apiVersion = "v" + apiIntegerVersion; + System.out.println("apiVersion=" + apiVersion); + dbMaps = dbMapsContainer.get(apiVersion); + + if (previousApiVersion != null) { // when running more than one version + dbMaps.PropertyVersionInfoMap.putAll(dbMapsContainer.get(previousApiVersion).PropertyVersionInfoMap); + dbMaps.NodeVersionInfoMap.putAll(dbMapsContainer.get(previousApiVersion).NodeVersionInfoMap); + } + + Iterator<String> nodeTypeIterator = dbMaps.NodeProps.keySet().iterator(); + while( nodeTypeIterator.hasNext() ){ + String nType = nodeTypeIterator.next(); + if (!dbMaps.NodeVersionInfoMap.containsKey(nType)) { + dbMaps.NodeVersionInfoMap.put(nType, apiVersion); + } + Collection <String> nodePropsForType = dbMaps.NodeProps.get(nType); + Iterator <String> propIter = nodePropsForType.iterator(); + while( propIter.hasNext() ){ + String propName = propIter.next(); + String infoKey = nType + "|" + propName; + if( ! dbMaps.PropertyVersionInfoMap.containsKey(infoKey) ){ + // We haven't seen this one yet -- add it in. + dbMaps.PropertyVersionInfoMap.put(infoKey, apiVersion); + } + } + } + dbMapsContainer.put(apiVersion, dbMaps); + previousApiVersion = apiVersion; + } + } + + /** + * As sorted list. + * + * @param <T> the generic type + * @param c the c + * @return the list + */ + private <T extends Comparable<? super T>> List<T> asSortedList(Collection<T> c) { + List<T> list = new ArrayList<T>(c); + java.util.Collections.sort(list); + return list; + } + + /** + * From comma separated string. + * + * @param string the string + * @return the iterable + */ + public Iterable<String> fromCommaSeparatedString( String string ) { + Iterable<String> split = Splitter.on( "," ).omitEmptyStrings().trimResults().split( string ); + return split; + } + + /** + * Pretty print map. + * + * @param map the map + * @return the string + */ + public String prettyPrintMap(Multimap<String, String> map) { + StringBuilder sb = new StringBuilder(); + sb.append('\n'); + for (String key:map.keySet()) { + sb.append('\t'); + sb.append(key); + sb.append('=').append('"'); + sb.append(map.get(key)); + sb.append('"'); + sb.append('\n'); + } + return sb.toString(); + } + + /** + * Pretty print map. + * + * @param map the map + * @return the string + */ + public String prettyPrintMap(Map<?, String> map) { + StringBuilder sb = new StringBuilder(); + sb.append('\n'); + for (Object key:map.keySet()) { + sb.append('\t'); + sb.append(key); + sb.append('=').append('"'); + sb.append(map.get(key)); + sb.append('"'); + sb.append('\n'); + } + return sb.toString(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Introspector.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Introspector.java new file mode 100644 index 00000000..a62d5aee --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Introspector.java @@ -0,0 +1,616 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.apache.commons.lang.ClassUtils; +import org.eclipse.persistence.exceptions.DynamicException; + +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.restcore.MediaType; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.workarounds.NamingExceptions; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.CaseFormat; + +public abstract class Introspector implements Cloneable { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Introspector.class); + + protected String className; + protected String uriChain = ""; + protected Loader loader; + protected final NamingExceptions namingException = NamingExceptions.getInstance(); + private Set<String> uniqueProperties = null; + private Set<String> indexedProperties = null; + private Set<String> allKeys = null; + protected Introspector(Object obj) { + } + + public abstract boolean hasProperty(String name); + + protected String convertPropertyName (String name) { + return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name); + } + + protected abstract Object get(String name); + protected abstract void set(String name, Object value); + /** + * + * @param name the property name you'd like to retrieve the value for + * @return the value of the property + */ + public <T> T getValue(String name) { + String convertedName = convertPropertyName(name); + Object result = null; + + if (this.hasProperty(name)) { + result = this.get(convertedName); + } else { + /* property not found - slightly ambiguous */ + return null; + } + + Class<?> clazz = this.getClass(name); + if (this.isListType(name) && result == null) { + try { + this.set(convertedName, clazz.newInstance()); + result = this.get(convertedName); + } catch (DynamicException | InstantiationException | IllegalAccessException e) { + + } + } + + return (T)result; + } + + public Introspector getWrappedValue(String name) { + String convertedName = convertPropertyName(name); + Object value = null; + + if (this.hasProperty(name)) { + value = this.get(convertedName); + } else { + /* property not found - slightly ambiguous */ + return null; + } + + Class<?> clazz = this.getClass(name); + if (this.isListType(name) && value == null) { + try { + this.set(convertedName, clazz.newInstance()); + value = this.get(convertedName); + } catch (DynamicException | InstantiationException | IllegalAccessException e) { + + } + } + if (value != null) { + return IntrospectorFactory.newInstance(this.getModelType(), value); + } else { + //no value + return null; + } + + } + + public List<Introspector> getWrappedListValue(String name) { + String convertedName = convertPropertyName(name); + Object value = null; + List<Introspector> resultList = new ArrayList<>(); + if (this.hasProperty(name)) { + value = this.get(convertedName); + } else { + /* property not found - slightly ambiguous */ + return null; + } + boolean isListType = this.isListType(name); + if (!this.isListType(name)) { + return null; + } + Class<?> clazz = this.getClass(name); + if (isListType && value == null) { + try { + this.set(convertedName, clazz.newInstance()); + value = this.get(convertedName); + } catch (DynamicException | InstantiationException | IllegalAccessException e) { + + } + } + + List<Object> valueList = (List<Object>)value; + + for (Object item : valueList) { + resultList.add(IntrospectorFactory.newInstance(this.getModelType(), item)); + } + + return resultList; + + } + + public Object castValueAccordingToSchema(String name, Object obj) { + Object result = obj; + Class<?> nameClass = this.getClass(name); + if (nameClass == null) { + throw new IllegalArgumentException("property: " + name + " does not exist on " + this.getDbName()); + } + if (obj != null) { + + try { + if (!obj.getClass().getName().equals(nameClass.getName())) { + if (nameClass.isPrimitive()) { + nameClass = ClassUtils.primitiveToWrapper(nameClass); + result = nameClass.getConstructor(String.class).newInstance(obj.toString()); + } + if (obj.getClass().getName().equals("java.lang.String")) { + result = nameClass.getConstructor(String.class).newInstance(obj); + } else if (!this.isListType(name) && !this.isComplexType(name)){ + //box = obj.toString(); + result = nameClass.getConstructor(String.class).newInstance(obj.toString()); + } + } + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + ErrorLogHelper.logError("AAI_4017", e.getMessage()); + } + } + return result; + } + + public List<Object> castValueAccordingToSchema(String name, List<?> objs) { + List<Object> result = new ArrayList<>(); + + for (Object item : objs) { + result.add(this.castValueAccordingToSchema(name, item)); + } + + return result; + + } + /** + * + * @param name the property name you'd like to set the value of + * @param obj the value to be set + * @return + */ + public void setValue(String name, Object obj) throws IllegalArgumentException { + Object box = this.castValueAccordingToSchema(name, obj); + + name = convertPropertyName(name); + this.set(name, box); + } + /** + * + * @return a list of all the properties available on the object + */ + public abstract Set<String> getProperties(); + + public Set<String> getProperties(PropertyPredicate<Introspector, String> p) { + final Set<String> temp = new LinkedHashSet<>(); + this.getProperties().stream().filter(item -> { + return p.test(this, item); + }).forEach(item -> { + temp.add(item); + }); + final Set<String> result = Collections.unmodifiableSet(temp); + + return result; + + } + /** + * + * @return a list of the required properties on the object + */ + public abstract Set<String> getRequiredProperties(); + /** + * + * @return a list of the properties that can be used to query the object in the db + */ + public abstract Set<String> getKeys(); + /** + * + * @return a list of the all key properties for this object + */ + public Set<String> getAllKeys() { + Set<String> result = null; + if (this.allKeys == null) { + Set<String> keys = this.getKeys(); + result = new LinkedHashSet<>(); + result.addAll(keys); + String altKeys = this.getMetadata(ObjectMetadata.ALTERNATE_KEYS_1); + if (altKeys != null) { + String[] altKeysArray = altKeys.split(","); + for (String altKey : altKeysArray) { + result.add(altKey); + } + } + result = Collections.unmodifiableSet(result); + this.allKeys = result; + } + result = this.allKeys; + return result; + } + + public Set<String> getIndexedProperties() { + Set<String> result = null; + + if (this.indexedProperties == null) { + result = new LinkedHashSet<>(); + Set<String> keys = this.getKeys(); + result.addAll(keys); + String altKeys = this.getMetadata(ObjectMetadata.INDEXED_PROPS); + if (altKeys != null) { + String[] altKeysArray = altKeys.split(","); + for (String altKey : altKeysArray) { + result.add(altKey); + } + } + this.indexedProperties = Collections.unmodifiableSet(result); + } + result = this.indexedProperties; + return result; + } + + public Set<String> getUniqueProperties() { + Set<String> result = null; + if (this.uniqueProperties == null) { + String altKeys = this.getMetadata(ObjectMetadata.UNIQUE_PROPS); + result = new LinkedHashSet<>(); + if (altKeys != null) { + String[] altKeysArray = altKeys.split(","); + for (String altKey : altKeysArray) { + result.add(altKey); + } + } + this.uniqueProperties = Collections.unmodifiableSet(result); + + } + result = this.uniqueProperties; + return result; + } + /** + * + * @param name + * @return the string name of the java class of the named property + */ + public String getType(String name) { + Class<?> resultClass = this.getClass(name); + String result = ""; + + if (resultClass != null) { + result = resultClass.getName(); + if (result.equals("java.util.ArrayList")) { + result = "java.util.List"; + } + } + + return result; + } + /** + * This will returned the generic parameterized type of the underlying + * object if it exists + * @param name + * @return the generic type of the java class of the underlying object + */ + public String getGenericType(String name) { + Class<?> resultClass = this.getGenericTypeClass(name); + String result = ""; + + if (resultClass != null) { + result = resultClass.getName(); + } + + return result; + } + /** + * + * @return the string name of the java class of the underlying object + */ + public abstract String getJavaClassName(); + + /** + * + * @param name the property name + * @return the Class object + */ + public abstract Class<?> getClass(String name); + + public abstract Class<?> getGenericTypeClass(String name); + + /** + * + * @param name the property name + * @return a new instance of the underlying type of this property + * @throws AAIUnknownObjectException + */ + public Object newInstanceOfProperty(String name) throws AAIUnknownObjectException { + String type = this.getType(name); + return loader.objectFromName(type); + } + + public Object newInstanceOfNestedProperty(String name) throws AAIUnknownObjectException { + String type = this.getGenericType(name); + return loader.objectFromName(type); + } + + + public Introspector newIntrospectorInstanceOfProperty(String name) throws AAIUnknownObjectException { + + Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfProperty(name)); + + return result; + + } + + public Introspector newIntrospectorInstanceOfNestedProperty(String name) throws AAIUnknownObjectException { + + Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfNestedProperty(name)); + + return result; + + } + /** + * Is this type not a Java String or primitive + * @param name + * @return + */ + public boolean isComplexType(String name) { + String result = this.getType(name); + + if (result.contains("aai") || result.equals("java.lang.Object")) { + return true; + } else { + return false; + } + } + + public boolean isComplexGenericType(String name) { + String result = this.getGenericType(name); + + if (result.contains("aai")) { + return true; + } else { + return false; + } + } + + public boolean isSimpleType(String name) { + return !(this.isComplexType(name) || this.isListType(name)); + } + + public boolean isSimpleGenericType(String name) { + return !this.isComplexGenericType(name); + } + + public boolean isListType(String name) { + String result = this.getType(name); + + if (result.contains("java.util.List")) { + return true; + } else { + return false; + } + } + + public boolean isContainer() { + Set<String> props = this.getProperties(); + boolean result = false; + if (props.size() == 1 && this.isListType(props.iterator().next())) { + result = true; + } + + return result; + } + + public abstract String getChildName(); + public String getChildDBName() { + String result = this.getChildName(); + + result = namingException.getDBName(result); + return result; + } + public abstract String getName(); + + public String getDbName() { + String lowerHyphen = this.getName(); + + lowerHyphen = namingException.getDBName(lowerHyphen); + + return lowerHyphen; + } + + public abstract ModelType getModelType(); + + public boolean hasChild(Introspector child) { + boolean result = false; + //check all inheriting types for this child + if ("true".equals(this.getMetadata(ObjectMetadata.ABSTRACT))) { + String[] inheritors = this.getMetadata(ObjectMetadata.INHERITORS).split(","); + for (String inheritor : inheritors) { + try { + Introspector temp = this.loader.introspectorFromName(inheritor); + result = temp.hasProperty(child.getName()); + if (result) { + break; + } + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping inheritor " + inheritor + " (Unknown Object)", e); + } + } + } else { + result = this.hasProperty(child.getName()); + } + return result; + } + + public void setURIChain(String uri) { + this.uriChain = uri; + } + public abstract String getObjectId() throws UnsupportedEncodingException; + + public String getURI() throws UnsupportedEncodingException { + //String result = this.uriChain; + String result = ""; + String namespace = this.getMetadata(ObjectMetadata.NAMESPACE); + String container = this.getMetadata(ObjectMetadata.CONTAINER); + if (this.isContainer()) { + result += "/" + this.getName(); + } else { + + if (container != null) { + result += "/" + container; + } + result += "/" + this.getDbName() + "/" + this.findKey(); + + if (namespace != null && !namespace.equals("")) { + result = "/" + namespace + result; + } + } + + + return result; + } + + public String getGenericURI() { + String result = ""; + if (this.isContainer()) { + result += "/" + this.getName(); + } else { + result += "/" + this.getDbName(); + for (String key : this.getKeys()) { + result += "/{" + this.getDbName() + "-" + key + "}"; + } + } + + return result; + } + + public String getFullGenericURI() { + String result = ""; + String namespace = this.getMetadata(ObjectMetadata.NAMESPACE); + String container = this.getMetadata(ObjectMetadata.CONTAINER); + if (this.isContainer()) { + result += "/" + this.getName(); + } else { + + + if (container != null) { + result += "/" + container; + } + result += "/" + this.getDbName(); + + for (String key : this.getKeys()) { + result += "/{" + this.getDbName() + "-" + key + "}"; + } + if (namespace != null && !namespace.equals("")) { + result = "/" + namespace + result; + } + + } + + return result; + } + + public abstract String preProcessKey(String key); + + protected abstract String findKey() throws UnsupportedEncodingException; + + public abstract String marshal(MarshallerProperties properties); + + public abstract Object clone(); + + public abstract Object getUnderlyingObject(); + + public String marshal(boolean formatted) { + MarshallerProperties properties = + new MarshallerProperties.Builder(MediaType.APPLICATION_JSON_TYPE).formatted(formatted).build(); + + return marshal(properties); + } + public String makeSingular(String word) { + + String result = word; + result = result.replaceAll("(?:([ho])es|s)$", ""); + + if (result.equals("ClassesOfService")) { + result = "ClassOfService"; + } else if (result.equals("CvlanTag")) { + result = "CvlanTagEntry"; + } else if (result.equals("Metadata")) { + result = "Metadatum"; + } + return result; + } + + protected String makePlural(String word) { + String result = word; + + if (result.equals("cvlan-tag-entry")) { + return "cvlan-tags"; + } else if (result.equals("class-of-service")) { + return "classes-of-service"; + } else if (result.equals("metadatum")) { + return "metadata"; + } + result = result.replaceAll("([a-z])$", "$1s"); + result = result.replaceAll("([hox])s$", "$1es"); + /* + if (result.equals("classes-of-services")) { + result = "classes-of-service"; + }*/ + + return result; + } + + public abstract String getMetadata(ObjectMetadata metadataName); + public abstract Map<PropertyMetadata, String> getPropertyMetadata(String propName); + public Optional<String> getPropertyMetadata(String propName, PropertyMetadata metadataName) { + final String resultValue = this.getPropertyMetadata(propName).getOrDefault(metadataName, ""); + Optional<String> result = Optional.empty(); + + if (!resultValue.isEmpty()) { + result = Optional.of(resultValue); + } + return result; + + } + + public abstract Version getVersion(); + public Loader getLoader() { + return this.loader; + } + + public boolean isTopLevel() { + + return this.getMetadata(ObjectMetadata.NAMESPACE) != null; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorFactory.java b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorFactory.java new file mode 100644 index 00000000..016e089f --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorFactory.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +public class IntrospectorFactory { + + /** + * New instance. + * + * @param type the type + * @param o the o + * @param llBuilder the ll builder + * @return the introspector + */ + public static Introspector newInstance(ModelType type, Object o) { + + if (type.equals(ModelType.MOXY)) { + return new MoxyStrategy(o); + } else if (type.equals(ModelType.POJO)) { + return new PojoStrategy(o); + } else if (type.equals(ModelType.JSON)) { + return new JSONStrategy(o); + } else { + throw new IllegalArgumentException("Unknown class type: " + type); + } + + } + + /** + * New instance. + * + * @param type the type + * @param o the o + * @param namedType the named type + * @param llBuilder the ll builder + * @return the introspector + */ + public static Introspector newInstance(ModelType type, Object o, String namedType) { + + if (type.equals(ModelType.JSON)) { + return new JSONStrategy(o, namedType); + } else { + throw new IllegalArgumentException("Unknown class type: " + type); + } + + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorWalker.java b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorWalker.java new file mode 100644 index 00000000..12d545d2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorWalker.java @@ -0,0 +1,193 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +public class IntrospectorWalker { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IntrospectorWalker.class); + + private Wanderer w = null; + private Set<String> blacklist = null; + private boolean preventCycles = false; + private final PropertyPredicate<Introspector, String> propVisibility; + + /** + * Instantiates a new introspector walker. + * + * @param w the w + * @param llBuilder the ll builder + */ + public IntrospectorWalker(Wanderer w) { + this.w = w; + this.blacklist = new HashSet<>(); + this.propVisibility = null; + } + + public IntrospectorWalker(Wanderer w, PropertyPredicate<Introspector, String> p) { + this.w = w; + this.blacklist = new HashSet<>(); + this.propVisibility = p; + } + + + /** + * Sets the blacklist. + * + * @param list the new blacklist + */ + public void setBlacklist(List<String> list) { + blacklist.addAll(list); + } + + /** + * Prevent cycles. + * + * @param prevent the prevent + */ + public void preventCycles(boolean prevent) { + this.preventCycles = prevent; + } + + /** + * Walk. + * + * @param obj the obj + * @throws AAIException + */ + public void walk(Introspector obj) throws AAIException { + Set<String> visited = new HashSet<>(); + + walk(obj, null, visited); + } + + /** + * Walk. + * + * @param obj the obj + * @param parent the parent + * @throws AAIException + */ + private void walk(Introspector obj, Introspector parent, Set<String> visited) throws AAIException { + boolean stopRecursion = false; + Set<String> localVisited = new HashSet<>(); + localVisited.addAll(visited); + if (preventCycles) { + if (visited.contains(obj.getName())) { + stopRecursion = true; + } + if (!obj.isContainer()) { + localVisited.add(obj.getName()); //so we don't recurse while walking its children + } + } + Set<String> props; + //props must duplicate the result from getProperties because + //it is unmodifiable + if (this.propVisibility == null) { + props = new LinkedHashSet<>(obj.getProperties()); + } else { + props = new LinkedHashSet<>(obj.getProperties(this.propVisibility)); + } + + w.processComplexObj(obj); + props.removeAll(blacklist); + if (!obj.isContainer()) { + parent = obj; + } + for (String prop : props) { + + if (obj.isSimpleType(prop)) { + + w.processPrimitive(prop, obj); + } else if (obj.isListType(prop) && !stopRecursion) { + + List<Object> listReference = obj.getValue(prop); + boolean isComplexType = obj.isComplexGenericType(prop); + if (isComplexType) { + List<Introspector> list = obj.getWrappedListValue(prop); + try { + Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop); + w.modifyComplexList(list, listReference, parent, child); + for (Object item : listReference) { + child = IntrospectorFactory.newInstance(obj.getModelType(), item); + walk(child, parent, localVisited); + } + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e); + } + } else { + w.processPrimitiveList(prop, obj); + } + if (listReference.size() == 0) { + if (isComplexType) { + try { + Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop); + int size = w.createComplexListSize(parent, child); + for (int i = 0; i < size; i++) { + child = obj.newIntrospectorInstanceOfNestedProperty(prop); + walk(child, parent, localVisited); + listReference.add(child.getUnderlyingObject()); + } + + obj.setValue(prop, listReference); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e); + } + } else if (!isComplexType){ + w.processPrimitiveList(prop, obj); + } + } + + } else if (obj.isComplexType(prop) && !stopRecursion) { + Introspector child = null; + if (obj.getValue(prop) != null) { + child = IntrospectorFactory.newInstance(obj.getModelType(), obj.getValue(prop)); + } else { + if (w.createComplexObjIfNull()) { + try { + child = obj.newIntrospectorInstanceOfProperty(prop); + obj.setValue(prop, child.getUnderlyingObject()); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e); + } + } + } + if (child != null) { + walk(child, obj, localVisited); + } + } + + } + /* + if (preventCycles && !obj.isContainer()) { + visited.remove(obj.getName()); //so we can see it down another path that isn't in danger of recursing over it + }*/ + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/JSONStrategy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/JSONStrategy.java new file mode 100644 index 00000000..45ffaad6 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/JSONStrategy.java @@ -0,0 +1,360 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.json.simple.JSONObject; + +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.schema.enums.PropertyMetadata; + +public class JSONStrategy extends Introspector { + + private JSONObject json = null; + private String namedType = ""; + protected JSONStrategy(Object o) { + super(o); + json = (JSONObject)o; + //Assumes you provide a wrapper + Set<String> keySet = json.keySet(); + if (keySet.size() == 1) { + namedType = keySet.iterator().next(); + json = (JSONObject)json.get(namedType); + } else { + throw new IllegalArgumentException("This object has no named type."); + } + } + + protected JSONStrategy(Object o, String namedType) { + super(o); + json = (JSONObject)o; + this.namedType = namedType; + + } + + @Override + public boolean hasProperty(String name) { + //TODO + return true; + } + @Override + public Object getValue(String name) { + Object result = ""; + result = json.get(name); + + return result; + } + + @Override + public void setValue(String name, Object obj) { + json.put(name, obj); + + } + @Override + public Object getUnderlyingObject() { + return this.json; + } + + @Override + public Set<String> getProperties() { + Set<String> result = json.keySet(); + return result; + } + + @Override + public Set<String> getRequiredProperties() { + //unknowable + + return this.getProperties(); + } + + @Override + public Set<String> getKeys() { + //unknowable + return this.getProperties(); + } + + @Override + public Set<String> getAllKeys() { + //unknowable + return this.getProperties(); + } + + @Override + public String getType(String name) { + String result = ""; + Class<?> resultClass = this.getClass(name); + if (resultClass != null) { + result = resultClass.getName(); + } + + if (result.equals("org.json.simple.JSONArray")) { + result = "java.util.List"; + } + + return result; + } + + @Override + public String getGenericType(String name) { + String result = ""; + Class<?> resultClass = this.getGenericTypeClass(name); + if (resultClass != null) { + result = resultClass.getName(); + } + return result; + } + + @Override + public String getJavaClassName() { + return json.getClass().getName(); + } + + @Override + public Class<?> getClass(String name) { + Class<?> result = null; + result = json.get(name).getClass(); + + return result; + } + + @Override + public Class<?> getGenericTypeClass(String name) { + Object resultObject = null; + Class<?> resultClass = null; + resultObject = this.getValue(name); + if (resultObject.getClass().getName().equals("org.json.simple.JSONArray")) { + resultClass = ((List)resultObject).get(0).getClass(); + } + + return resultClass; + } + + @Override + public Object newInstanceOfProperty(String name) { + try { + return this.getClass(name).newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + return null; + } + } + + @Override + public Object newInstanceOfNestedProperty(String name) { + try { + return this.getGenericTypeClass(name).newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + return null; + } + } + + @Override + public boolean isComplexType(String name) { + String result = this.getType(name); + + if (result.contains("JSONObject")) { + return true; + } else { + return false; + } + + } + + @Override + public boolean isComplexGenericType(String name) { + String result = this.getGenericType(name); + + if (result.contains("JSONObject")) { + return true; + } else { + return false; + } + + } + + @Override + public boolean isListType(String name) { + String result = this.getType(name); + + if (result.contains("java.util.List")) { + return true; + } else { + return false; + } + + } + + @Override + public boolean isContainer() { + Set<String> props = this.getProperties(); + boolean result = false; + if (props.size() == 1 && this.isListType(props.iterator().next())) { + result = true; + } + + return result; + } + @Override + protected String findKey() { + return ""; + } + + @Override + public String getName() { + return this.namedType; + } + + @Override + public String getDbName() { + return this.getName(); + } + + @Override + public String getURI() { + + // use a UUID for now + return UUID.randomUUID().toString(); + } + + @Override + public String getGenericURI() { + + //there is none defined for this + return ""; + } + + @Override + public String preProcessKey (String key) { + + // don't do anything with it + return key; + + } + + @Override + public String marshal(MarshallerProperties properties) { + //TODO + return null; + } + + @Override + public Object clone() { + //TODO + return null; + } + + /*@Override + public String findEdgeName(String parent, String child) { + + // Always has for now + return "has"; + + }*/ + + @Override + public ModelType getModelType() { + return ModelType.JSON; + } + + @Override + public Set<String> getIndexedProperties() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getChildName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean hasChild(Introspector child) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isSimpleType(String name) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isSimpleGenericType(String name) { + // TODO Auto-generated method stub + return false; + } + + @Override + public Map<PropertyMetadata, String> getPropertyMetadata(String prop) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMetadata(ObjectMetadata metadataName) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getChildDBName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getFullGenericURI() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Object get(String name) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected void set(String name, Object value) { + // TODO Auto-generated method stub + + } + + @Override + public String getObjectId() throws UnsupportedEncodingException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Version getVersion() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Loader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Loader.java new file mode 100644 index 00000000..76f00390 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Loader.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.util.Map; + +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException; +import org.openecomp.aai.restcore.MediaType; + +public abstract class Loader { + + private final Version version; + private final ModelType modelType; + + /** + * Instantiates a new loader. + * + * @param version the version + * @param modelType the model type + * @param llBuilder the ll builder + */ + public Loader (Version version, ModelType modelType) { + this.version = version; + this.modelType = modelType; + } + + /** + * Process. + * + * @param version the version + */ + protected abstract void process(Version version); + + /** + * Object from name. + * + * @param name the name + * @return the object + * @throws AAIUnknownObjectException + */ + public abstract Object objectFromName(String name) throws AAIUnknownObjectException; + + /** + * Introspector from name. + * + * @param name the name + * @return the introspector + * @throws AAIUnknownObjectException + */ + public abstract Introspector introspectorFromName(String name) throws AAIUnknownObjectException; + + /** + * Unmarshal. + * + * @param type the type + * @param json the json + * @param mediaType the media type + * @return the introspector + */ + public abstract Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException; + + /** + * Unmarshal. + * + * @param type the type + * @param json the json + * @return the introspector + */ + public Introspector unmarshal(String type, String json) throws AAIUnmarshallingException { + return unmarshal(type, json, MediaType.APPLICATION_JSON_TYPE); + } + + + /** + * Gets the model type. + * + * @return the model type + */ + public ModelType getModelType() { + return this.modelType; + } + + /** + * Gets the version. + * + * @return the version + */ + public Version getVersion() { + return this.version; + } + + public abstract Map<String, Introspector> getAllObjects(); +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/LoaderFactory.java b/aai-core/src/main/java/org/openecomp/aai/introspection/LoaderFactory.java new file mode 100644 index 00000000..04cc00df --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/LoaderFactory.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +public class LoaderFactory { + + /** + * Creates a new Loader object. + * + * @param type the type + * @param version the version + * @param llBuilder the ll builder + * @return the loader + */ + public static Loader createLoaderForVersion(ModelType type, Version version) { + + if (type.equals(ModelType.MOXY)) { + return new MoxyLoader(version); + } else if (type.equals(ModelType.POJO)) { + return new PojoLoader(version); + } + + return null; + + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/MarshallerProperties.java b/aai-core/src/main/java/org/openecomp/aai/introspection/MarshallerProperties.java new file mode 100644 index 00000000..25156c7b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/MarshallerProperties.java @@ -0,0 +1,139 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import org.openecomp.aai.restcore.MediaType; + +public class MarshallerProperties { + + private final MediaType type; + private final boolean includeRoot; + private final boolean wrapperAsArrayName; + private final boolean formatted; + + /** + * Instantiates a new marshaller properties. + * + * @param builder the builder + */ + private MarshallerProperties(Builder builder) { + + this.type = builder.type; + this.includeRoot = builder.includeRoot; + this.wrapperAsArrayName = builder.wrapperAsArrayName; + this.formatted = builder.formatted; + } + + /** + * Gets the media type. + * + * @return the media type + */ + public MediaType getMediaType() { + return this.type; + } + + /** + * Gets the include root. + * + * @return the include root + */ + public boolean getIncludeRoot() { + return this.includeRoot; + } + + /** + * Gets the wrapper as array name. + * + * @return the wrapper as array name + */ + public boolean getWrapperAsArrayName() { + return this.wrapperAsArrayName; + } + + /** + * Gets the formatted. + * + * @return the formatted + */ + public boolean getFormatted() { + return this.formatted; + } + + public static class Builder { + + private final MediaType type; + private boolean includeRoot = false; + private boolean wrapperAsArrayName = true; + private boolean formatted = false; + + /** + * Instantiates a new builder. + * + * @param type the type + */ + public Builder(MediaType type) { + this.type = type; + } + + /** + * Include root. + * + * @param includeRoot the include root + * @return the builder + */ + public Builder includeRoot (boolean includeRoot) { + this.includeRoot = includeRoot; + return this; + } + + /** + * Wrapper as array name. + * + * @param wrapperAsArrayName the wrapper as array name + * @return the builder + */ + public Builder wrapperAsArrayName (boolean wrapperAsArrayName) { + this.wrapperAsArrayName = wrapperAsArrayName; + return this; + } + + /** + * Formatted. + * + * @param formatted the formatted + * @return the builder + */ + public Builder formatted (boolean formatted) { + this.formatted = formatted; + return this; + } + + /** + * Builds the properties. + * + * @return the marshaller properties + */ + public MarshallerProperties build() { + return new MarshallerProperties(this); + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/ModelInjestor.java b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelInjestor.java new file mode 100644 index 00000000..651b28d9 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelInjestor.java @@ -0,0 +1,176 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.bind.JAXBException; + +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.jaxb.JAXBContextProperties; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory; + +import org.openecomp.aai.util.AAIConstants; + + +public class ModelInjestor { + + private Map<Version, DynamicJAXBContext> versionContextMap = new HashMap<>(); + private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\."); + private static final Pattern uriPattern = Pattern.compile("(v\\d+)\\/"); + + + /** + * Instantiates a new model injestor. + */ + private ModelInjestor() { + try { + injestModels(); + } catch (FileNotFoundException | JAXBException e) { + throw new RuntimeException(e); + } + } + + private static class Helper { + private static final ModelInjestor INSTANCE = new ModelInjestor(); + } + + /** + * Gets the single instance of ModelInjestor. + * + * @return single instance of ModelInjestor + */ + public synchronized static ModelInjestor getInstance() { + return Helper.INSTANCE; + } + + /** + * Injest models. + * + * @throws FileNotFoundException the file not found exception + * @throws JAXBException the JAXB exception + */ + private void injestModels() throws FileNotFoundException, JAXBException { + + for (Version version : Version.values()) { + this.injestModel(version); + } + } + + /** + * Injest model. + * + * @param version the version + * @throws JAXBException the JAXB exception + * @throws FileNotFoundException the file not found exception + */ + private void injestModel (Version version) throws JAXBException, FileNotFoundException { + String fileName = this.getOXMFileName(version); + InputStream iStream = new FileInputStream(new File(fileName)); + Map<String, Object> properties = new HashMap<String, Object>(); + properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream); + final DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties); + versionContextMap.put(version, jaxbContext); + } + + /** + * Gets the version from class name. + * + * @param classname the classname + * @return the version from class name + */ + public Version getVersionFromClassName (String classname) { + Matcher m = classNamePattern.matcher(classname); + String version = "v2"; //for the OXM, only the v2 ones don't include a model name, hence this default + if (m.find()) { + version = m.group(1); + } + + return Version.valueOf(version); + } + + /** + * Gets the context for URI. + * + * @param uri the uri + * @return the context for URI + */ + public DynamicJAXBContext getContextForURI(String uri) { + DynamicJAXBContext result = null; + Matcher m = uriPattern.matcher(uri); + Version version = null; + if (m.find()) { + version = Version.valueOf(m.group(1)); + result = versionContextMap.get(version); + } + + return result; + } + + /** + * Gets the context for version. + * + * @param version the version + * @return the context for version + */ + public DynamicJAXBContext getContextForVersion(Version version) { + DynamicJAXBContext result = null; + + result = versionContextMap.get(version); + + + return result; + } + + /** + * Gets the dynamic type for class name. + * + * @param classname the classname + * @return the dynamic type for class name + */ + public DynamicType getDynamicTypeForClassName(String classname) { + DynamicType result = null; + DynamicJAXBContext context = null; + + Version version = this.getVersionFromClassName(classname); + + context = versionContextMap.get(version); + + if (context != null) { + result = context.getDynamicType(classname); + } + + return result; + } + + public String getOXMFileName(Version v) { + return AAIConstants.AAI_HOME_ETC_OXM + "aai_oxm_" + v.toString() + ".xml"; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/ModelType.java b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelType.java new file mode 100644 index 00000000..eddc9405 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelType.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +public enum ModelType { + MOXY, POJO, JSON +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyLoader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyLoader.java new file mode 100644 index 00000000..60fb47d3 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyLoader.java @@ -0,0 +1,190 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.io.IOException; +import java.io.StringReader; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.stream.StreamSource; + +import org.eclipse.persistence.dynamic.DynamicEntity; +import org.eclipse.persistence.jaxb.UnmarshallerProperties; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.restcore.MediaType; +import org.openecomp.aai.workarounds.NamingExceptions; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.CaseFormat; +import com.google.common.collect.ImmutableMap; + +public class MoxyLoader extends Loader { + + private DynamicJAXBContext jaxbContext = null; + private EELFLogger LOGGER = EELFManager.getInstance().getLogger(MoxyLoader.class); + private Map<String, Introspector> allObjs = null; + + /** + * Instantiates a new moxy loader. + * + * @param version the version + * @param llBuilder the ll builder + */ + protected MoxyLoader(Version version) { + super(version, ModelType.MOXY); + process(version); + } + + /** + * {@inheritDoc} + * @throws AAIUnknownObjectException + */ + @Override + public Introspector introspectorFromName(String name) throws AAIUnknownObjectException { + + return IntrospectorFactory.newInstance(ModelType.MOXY, objectFromName(name)); + } + + /** + * {@inheritDoc} + */ + @Override + public Object objectFromName(String name) throws AAIUnknownObjectException { + + final String sanitizedName = NamingExceptions.getInstance().getObjectName(name); + final String upperCamel; + + //Contains any uppercase, then assume it's upper camel + if (name.matches(".*[A-Z].*")) { + upperCamel = sanitizedName; + } else { + upperCamel = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, sanitizedName); + } + + try { + final DynamicEntity result = jaxbContext.newDynamicEntity(upperCamel); + + if (result == null) throw new AAIUnknownObjectException("Unrecognized AAI object " + name); + + return result; + } catch (IllegalArgumentException e) { + //entity does not exist + throw new AAIUnknownObjectException("Unrecognized AAI object " + name, e); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void process(Version version) { + ModelInjestor injestor = ModelInjestor.getInstance(); + jaxbContext = injestor.getContextForVersion(version); + + } + + /** + * {@inheritDoc} + */ + @Override + public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException { + try { + final Object clazz = objectFromName(type); + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + + if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) { + unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json"); + unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); + unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); + } + + final DynamicEntity entity = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(new StringReader(json)), clazz.getClass()).getValue(); + return IntrospectorFactory.newInstance(ModelType.MOXY, entity); + } catch (JAXBException e) { + AAIException ex = new AAIException("AAI_4007", e); + ErrorLogHelper.logException(ex); + throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), ex); + } catch (AAIUnknownObjectException e) { + throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), e); + } + } + + @Override + public Map<String, Introspector> getAllObjects() { + if (this.allObjs != null) { + return allObjs; + } else { + ImmutableMap.Builder<String, Introspector> map = new ImmutableMap.Builder<String, Introspector>(); + Set<String> objs = objectsInVersion(); + for (String objName : objs) { + try { + Introspector introspector = this.introspectorFromName(objName); + map.put(introspector.getDbName(), introspector); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Unexpected AAIUnknownObjectException while running getAllObjects()", e); + } + } + allObjs = map.build(); + return allObjs; + } + } + + private Set<String> objectsInVersion() { + final Set<String> result = new HashSet<>(); + + try { + final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + final String fileName = ModelInjestor.getInstance().getOXMFileName(getVersion()); + + docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + + final DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + final Document doc = docBuilder.parse(fileName); + final NodeList list = doc.getElementsByTagName("java-type"); + + for (int i = 0; i < list.getLength(); i++) { + result.add(list.item(i).getAttributes().getNamedItem("name").getNodeValue()); + } + } catch (ParserConfigurationException | SAXException | IOException e) { + LOGGER.warn("Exception while enumerating objects for API version " + getVersion() + " (returning partial results)", e); + } + + result.remove("EdgePropNames"); + return result; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyStrategy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyStrategy.java new file mode 100644 index 00000000..ebebf251 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyStrategy.java @@ -0,0 +1,394 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.io.StringReader; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamSource; + +import org.eclipse.persistence.descriptors.ClassDescriptor; +import org.eclipse.persistence.dynamic.DynamicEntity; +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.exceptions.DynamicException; +import org.eclipse.persistence.jaxb.UnmarshallerProperties; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.eclipse.persistence.mappings.DatabaseMapping; +import org.eclipse.persistence.oxm.XMLField; +import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping; +import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping; +import org.springframework.web.util.UriUtils; + +import org.openecomp.aai.restcore.MediaType; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import com.google.common.base.CaseFormat; +import com.google.common.base.Joiner; + +public class MoxyStrategy extends Introspector { + + private DynamicEntity internalObject = null; + private DynamicType internalType = null; + private DynamicJAXBContext jaxbContext = null; + private ClassDescriptor cd = null; + private Marshaller marshaller = null; + private Unmarshaller unmarshaller = null; + private Version version = null; + private Set<String> properties = null; + private Set<String> keys = null; + private Set<String> requiredProperties = null; + + private boolean isInitialized = false; + + protected MoxyStrategy(Object obj) { + super(obj); + /* must look up the correct jaxbcontext for this object */ + className = MoxyStrategy.class.getSimpleName(); + internalObject = (DynamicEntity)obj; + ModelInjestor injestor = ModelInjestor.getInstance(); + version = injestor.getVersionFromClassName(internalObject.getClass().getName()); + jaxbContext = injestor.getContextForVersion(version); + super.loader = LoaderFactory.createLoaderForVersion(getModelType(), version); + String simpleName = internalObject.getClass().getName(); + internalType = jaxbContext.getDynamicType(simpleName); + cd = internalType.getDescriptor(); + try { + marshaller = jaxbContext.createMarshaller(); + unmarshaller = jaxbContext.createUnmarshaller(); + } catch (JAXBException e) { + + } + + } + + private void init() { + isInitialized = true; + + Set<String> props = new LinkedHashSet<>(); + for (String s : internalType.getPropertiesNames()) { + props.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, s)); + + } + props = Collections.unmodifiableSet(props); + this.properties = props; + + Set<String> requiredProps = new LinkedHashSet<>(); + requiredProps = new LinkedHashSet<>(); + for (DatabaseMapping dm : cd.getMappings()) { + if (dm.getField() instanceof XMLField) { + XMLField x = (XMLField)dm.getField(); + if (x != null) { + if (x.isRequired()) { + requiredProps.add(this.removeXPathDescriptor(x.getName())); + } + } + } + } + requiredProps = Collections.unmodifiableSet(requiredProps); + this.requiredProperties = requiredProps; + + Set<String> keys = new LinkedHashSet<>(); + + for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) { + keys.add(this.removeXPathDescriptor(name)); + } + keys = Collections.unmodifiableSet(keys); + this.keys = keys; + + + } + + @Override + public boolean hasProperty(String name) { + String convertedName = convertPropertyName(name); + + return internalType.containsProperty(convertedName); + } + + @Override + public Object get(String name) { + return internalObject.get(name); + } + + @Override + public void set(String name, Object obj) throws IllegalArgumentException { + + internalObject.set(name, obj); + } + + @Override + public Set<String> getProperties() { + + if(!isInitialized){ + init(); + } + + return this.properties; + + } + + @Override + public Set<String> getRequiredProperties() { + + if(!isInitialized){ + init(); + } + + return this.requiredProperties; + } + + @Override + public Set<String> getKeys() { + + if(!isInitialized){ + init(); + } + + return this.keys; + } + + @Override + public Map<PropertyMetadata, String> getPropertyMetadata(String prop) { + String propName = this.convertPropertyName(prop); + DatabaseMapping mapping = cd.getMappingForAttributeName(propName); + Map<PropertyMetadata, String> result = new HashMap<>(); + if (mapping != null) { + Set<Entry> entrySet = mapping.getProperties().entrySet(); + for (Entry<?,?> entry : entrySet) { + result.put( + PropertyMetadata.valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, (String)entry.getKey())), (String)entry.getValue()); + } + } + + return result; + } + + @Override + public String getJavaClassName() { + return internalObject.getClass().getName(); + } + + + + @Override + public Class<?> getClass(String name) { + name = convertPropertyName(name); + Class<?> resultClass = null; + try { + if (internalType.getPropertyType(name) == null) { + if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) { + resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass(); + + } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) { + resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass(); + } else { + ClassDescriptor referenceDiscriptor = cd.getMappingForAttributeName(name).getReferenceDescriptor(); + if (referenceDiscriptor != null) { + resultClass = referenceDiscriptor.getJavaClass(); + } else { + resultClass = Object.class; + } + } + } else { + resultClass = internalType.getPropertyType(name); + } + } catch (DynamicException e) { + //property doesn't exist + } + return resultClass; + } + + @Override + public Class<?> getGenericTypeClass(String name) { + name = convertPropertyName(name); + Class<?> resultClass = null; + if (internalType.getPropertyType(name) == null) { + if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) { + resultClass = cd.getMappingForAttributeName(name).getFields().get(0).getType(); + + } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) { + resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass(); + } + } + + return resultClass; + } + + @Override + public Object getUnderlyingObject() { + return this.internalObject; + } + + @Override + public String getChildName() { + + String className = internalObject.getClass().getSimpleName(); + String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className); + + if (this.isContainer()) { + lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName()); + } + + return lowerHyphen; + } + + @Override + public String getName() { + String className = internalObject.getClass().getSimpleName(); + String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className); + /* + if (this.isContainer()) { + lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().get(0)).getSimpleName()); + }*/ + + + return lowerHyphen; + } + + @Override + public String getObjectId() throws UnsupportedEncodingException { + String result = ""; + String container = this.getMetadata(ObjectMetadata.CONTAINER); + if (this.isContainer()) { + result += "/" + this.getName(); + } else { + + if (container != null) { + result += "/" + container; + } + result += "/" + this.getDbName() + "/" + this.findKey(); + + } + + return result; + } + + @Override + protected String findKey() throws UnsupportedEncodingException { + Set<String> keys = null; + keys = this.getKeys(); + List<String> results = new ArrayList<>(); + for (String key : keys) { + if (this.getType(key).toLowerCase().contains("long")) { + key = ((Long)this.getValue(key)).toString(); + } else { + key = (String)this.getValue(key); + } + key = UriUtils.encode(key, "UTF-8"); + + results.add(key); + } + + return Joiner.on("/").join(results); + } + + @Override + public String preProcessKey (String key) { + String result = ""; + //String trimmedRestURI = restURI.replaceAll("/[\\w\\-]+?/[\\w\\-]+?$", ""); + String[] split = key.split("/"); + int i = 0; + for (i = split.length-1; i >= 0; i--) { + + if (jaxbContext.getDynamicType(split[i]) != null) { + break; + + } + + } + result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i)); + + return result; + + } + + @Override + public String marshal(MarshallerProperties properties) { + StringWriter result = new StringWriter(); + try { + if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) { + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json"); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, properties.getIncludeRoot()); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName()); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false); + } + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted()); + marshaller.marshal(this.internalObject, result); + } catch (JAXBException e) { + //e.printStackTrace(); + } + + return result.toString(); + } + + @Override + public Object clone() { + Object result = null; + try { + unmarshaller = jaxbContext.createUnmarshaller(); + + unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json"); + unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); + unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); + + result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue(); + } catch (JAXBException e) { + // TODO Auto-generated catch block + //e.printStackTrace(); + } + result = IntrospectorFactory.newInstance(getModelType(), result); + return result; + } + @Override + public ModelType getModelType() { + return ModelType.MOXY; + } + + private String removeXPathDescriptor(String name) { + + return name.replaceAll("/text\\(\\)", ""); + } + + @Override + public String getMetadata(ObjectMetadata name) { + + return (String)cd.getProperty(name.toString()); + } + + @Override + public Version getVersion() { + + return this.version; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PojoInjestor.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoInjestor.java new file mode 100644 index 00000000..116cb787 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoInjestor.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + +import org.eclipse.persistence.jaxb.JAXBContextFactory; + +import org.openecomp.aai.db.props.AAIProperties; + +public class PojoInjestor { + + private String POJO_CLASSPATH = "org.openecomp.aai.domain.yang"; + private final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\."); + + public PojoInjestor() { + } + + public JAXBContext getContextForVersion(Version v) { + JAXBContext context = null; + try { + if (!v.equals(AAIProperties.LATEST)) { + POJO_CLASSPATH += "." + v; + } + context = JAXBContextFactory.createContext(POJO_CLASSPATH, this.getClass().getClassLoader()); + } catch (JAXBException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return context; + } + public Version getVersion (String classname) { + Matcher m = classNamePattern.matcher(classname); + String version; + if (m.find()) { + version = m.group(1); + } else { + //only POJOs of old versions have the version number in their classnames + //so if we can't find a version, default to the latest + version = AAIProperties.LATEST.toString(); + } + + return Version.valueOf(version); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PojoLoader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoLoader.java new file mode 100644 index 00000000..ac63e981 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoLoader.java @@ -0,0 +1,136 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.io.StringReader; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamSource; + +import org.eclipse.persistence.jaxb.UnmarshallerProperties; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.restcore.MediaType; +import org.openecomp.aai.workarounds.NamingExceptions; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.CaseFormat; +import org.eclipse.persistence.jaxb.JAXBContextFactory; + +public class PojoLoader extends Loader { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(PojoLoader.class); + private static final String POJO_BASE_PACKAGE_NAME = "org.openecomp.aai.domain.yang"; + + protected JAXBContext context; + private final String pojoPackageName; + + protected PojoLoader(Version version) { + super(version, ModelType.POJO); + + if (!version.equals(AAIProperties.LATEST)) { + pojoPackageName = POJO_BASE_PACKAGE_NAME + "." + version; + } else { + pojoPackageName = POJO_BASE_PACKAGE_NAME; + } + + try { + context = JAXBContextFactory.createContext(pojoPackageName, this.getClass().getClassLoader()); + } catch (JAXBException e) { + LOGGER.error("JAXBException while instantiation contect for PojoLoader", e); + } + } + + @Override + public Introspector introspectorFromName(String name) throws AAIUnknownObjectException { + return IntrospectorFactory.newInstance(ModelType.POJO, objectFromName(name)); + } + + @Override + public Object objectFromName(String name) throws AAIUnknownObjectException { + + final String sanitizedName = NamingExceptions.getInstance().getObjectName(name); + final String upperCamel; + + //Contains any uppercase, then assume it's upper camel + if (sanitizedName.matches(".*[A-Z].*")) { + upperCamel = sanitizedName; + } else { + upperCamel = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, sanitizedName); + } + + final String objectClassName; + + if (!upperCamel.contains(pojoPackageName)) { + objectClassName = pojoPackageName + "." + upperCamel; + } else { + objectClassName = upperCamel; + } + + try { + return Class.forName(objectClassName).newInstance(); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + throw new AAIUnknownObjectException("Unrecognized AAI object " + name); + } + } + + @Override + protected void process(Version version) { + LOGGER.warn("PojoLoader.process(Version) has not been implemented"); + } + + @Override + public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException { + + try { + final Unmarshaller unmarshaller = context.createUnmarshaller(); + + if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) { + unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json"); + unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); + unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); + } + + final Object clazz = objectFromName(type); + final Object obj = unmarshaller.unmarshal(new StreamSource(new StringReader(json)), clazz.getClass()).getValue(); + + return IntrospectorFactory.newInstance(ModelType.POJO, obj); + } catch (JAXBException e) { + ErrorLogHelper.logError("AAI_4007", "Could not unmarshall: " + e.getMessage()); + throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage()); + } catch (AAIUnknownObjectException e) { + throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), e); + } + } + + @Override + public Map<String, Introspector> getAllObjects() { + //TODO + return null; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PojoStrategy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoStrategy.java new file mode 100644 index 00000000..5632ddf7 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoStrategy.java @@ -0,0 +1,389 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.transform.stream.StreamSource; + +import org.eclipse.persistence.jaxb.UnmarshallerProperties; + +import org.openecomp.aai.annotations.Metadata; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.restcore.MediaType; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import com.google.common.base.CaseFormat; +import com.google.common.base.Joiner; +import com.google.common.collect.Multimap; + +public class PojoStrategy extends Introspector { + + private Object internalObject = null; + private PojoInjestor injestor = null; + private Multimap<String, String> keyProps = null; + private Metadata classLevelMetadata = null; + private Version version; + private JAXBContext jaxbContext; + private Marshaller marshaller; + private Unmarshaller unmarshaller; + private Set<String> properties = null; + private Set<String> keys = null; + private Set<String> requiredProperties = null; + + private boolean isInitialized = false; + + protected PojoStrategy(Object obj) { + super(obj); + className = PojoStrategy.class.getSimpleName(); + this.internalObject = obj; + injestor = new PojoInjestor(); + classLevelMetadata = obj.getClass().getAnnotation(Metadata.class); + + version = injestor.getVersion(obj.getClass().getName()); + jaxbContext = injestor.getContextForVersion(version); + super.loader = LoaderFactory.createLoaderForVersion(getModelType(), version); + try { + marshaller = jaxbContext.createMarshaller(); + unmarshaller = jaxbContext.createUnmarshaller(); + } catch (JAXBException e) { + + } + + } + + private void init() { + + isInitialized = true; + + Set<String> properties = new LinkedHashSet<>(); + Set<String> keys = new LinkedHashSet<>(); + Set<String> required = new LinkedHashSet<>(); + + Field[] fields = this.internalObject.getClass().getDeclaredFields(); + + for (Field field : fields) { + if (!field.getName().equals("any")) { + properties.add(covertFieldToOutputFormat(field.getName())); + Metadata annotation = field.getAnnotation(Metadata.class); + XmlElement xmlAnnotation = field.getAnnotation(XmlElement.class); + if (annotation != null) { + if (annotation.isKey()) { + keys.add(covertFieldToOutputFormat(field.getName())); + } + } + if (xmlAnnotation != null) { + if (xmlAnnotation.required()) { + required.add(covertFieldToOutputFormat(field.getName())); + } + } + } + } + properties = Collections.unmodifiableSet(properties); + this.properties = properties; + + keys = Collections.unmodifiableSet(keys); + this.keys = keys; + + required = Collections.unmodifiableSet(required); + this.requiredProperties = required; + + } + private String covertFieldToOutputFormat(String propName) { + return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName); + } + + @Override + public boolean hasProperty(String name) { + //TODO + return true; + } + + @Override + /** + * Gets the value of the property via reflection + */ + public Object get(String name) { + String getMethodName = "get" + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name); + try { + return this.internalObject.getClass().getDeclaredMethod(getMethodName).invoke(this.internalObject); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + return null; + } + } + + @Override + public void set(String name, Object value) { + String setMethodName = "set" + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name); + try { + this.internalObject.getClass().getDeclaredMethod(setMethodName, value.getClass()).invoke(this.internalObject, value); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + ErrorLogHelper.logError("AAI_4017", "Error setting name/value pair on POJO: " + e.getMessage()); + } + } + + @Override + public Set<String> getProperties() { + + if(!isInitialized){ + this.init(); + } + return this.properties; + } + + + @Override + public Set<String> getRequiredProperties() { + + if(!isInitialized) { + this.init(); + } + return this.requiredProperties; + } + + @Override + public Set<String> getKeys() { + + if(!isInitialized){ + this.init(); + } + return this.keys; + } + + public Class<?> getClass(String name) { + + Field field = null; + try { + field = this.internalObject.getClass().getDeclaredField(CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name)); + } catch (NoSuchFieldException | SecurityException e) { + + return null; + } + + return field.getType(); + } + + public Class<?> getGenericTypeClass(String name) { + + try { + String getMethodName = "get" + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, name); + Method method = internalObject.getClass().getDeclaredMethod(getMethodName); + Type t = method.getGenericReturnType(); + if(t instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType)t; + return ((Class<?>)pt.getActualTypeArguments()[0]); + } else { + return null; + } + + } catch (Exception e) { + return null; + } + } + + @Override + public String getJavaClassName() { + return internalObject.getClass().getName(); + } + + @Override + public Object getUnderlyingObject() { + return this.internalObject; + } + + @Override + public String getName() { + String className = internalObject.getClass().getSimpleName(); + + return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className); + } + + @Override + protected String findKey() { + Set<String> keys = null; + keys = this.getKeys(); + List<String> results = new ArrayList<>(); + for (String key : keys) { + if (this.getType(key).toLowerCase().contains("long")) { + key = ((Long)this.getValue(key)).toString(); + } else { + key = (String)this.getValue(key); + } + results.add(key); + } + + return Joiner.on("/").join(results); + } + + @Override + public String marshal(MarshallerProperties properties) { + StringWriter result = new StringWriter(); + try { + if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) { + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json"); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, properties.getIncludeRoot()); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName()); + } + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted()); + marshaller.marshal(this.internalObject, result); + } catch (JAXBException e) { + //e.printStackTrace(); + } + + return result.toString(); + } + + @Override + public Object clone() { + Object result = null; + try { + unmarshaller = jaxbContext.createUnmarshaller(); + + unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json"); + unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); + unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); + + result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue(); + } catch (JAXBException e) { + // TODO Auto-generated catch block + //e.printStackTrace(); + } + result = IntrospectorFactory.newInstance(getModelType(), result); + return result; + } + + @Override + public String preProcessKey (String key) { + String result = ""; + //String trimmedRestURI = restURI.replaceAll("/[\\w\\-]+?/[\\w\\-]+?$", ""); + String[] split = key.split("/"); + int i = 0; + for (i = split.length-1; i >= 0; i--) { + + if (keyProps.containsKey(split[i])) { + break; + + } + + } + result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i)); + + return result; + + } + + @Override + public ModelType getModelType() { + return ModelType.POJO; + } + + @Override + public String getChildName() { + String className = internalObject.getClass().getSimpleName(); + String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className); + + if (this.isContainer()) { + lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName()); + } + + return lowerHyphen; + } + + @Override + public Map<PropertyMetadata, String> getPropertyMetadata(String prop) { + Field f; + Map<PropertyMetadata, String> result = new HashMap<>(); + try { + f = internalObject.getClass().getField(prop); + Metadata m = f.getAnnotation(Metadata.class); + if (m != null) { + Field[] fields = m.getClass().getFields(); + String fieldName; + for (Field field : fields) { + fieldName = field.getName(); + if (fieldName.equals("isAbstract")) { + fieldName = "abstract"; + } else if (fieldName.equals("extendsFrom")) { + fieldName = "extends"; + } + fieldName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, fieldName); + result.put(PropertyMetadata.valueOf(fieldName), (String)field.get(m)); + } + } + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + // TODO Auto-generated catch block + } + + return result; + } + + @Override + public String getObjectId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMetadata(ObjectMetadata metadataName) { + String value = null; + String methodName; + if (ObjectMetadata.ABSTRACT.equals(metadataName)) { + methodName = "isAbstract"; + } else if (ObjectMetadata.EXTENDS.equals(metadataName)) { + methodName = "extendsFrom"; + } else { + methodName = metadataName.toString(); + } + + try { + value = (String)this.classLevelMetadata.getClass().getMethod(methodName).invoke(classLevelMetadata); + } catch (IllegalArgumentException | IllegalAccessException | SecurityException | InvocationTargetException | NoSuchMethodException e) { + //TODO + } + + return value; + } + + @Override + public Version getVersion() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicate.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicate.java new file mode 100644 index 00000000..5d23aa60 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicate.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +public interface PropertyPredicate<T, U> extends BiPredicate<T, U> { + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicates.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicates.java new file mode 100644 index 00000000..eeca0864 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicates.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.util.Map; +import java.util.Set; + +import org.openecomp.aai.schema.enums.PropertyMetadata; + +public final class PropertyPredicates { + + private PropertyPredicates() { + + } + + public static PropertyPredicate<Introspector, String> includeInTestGeneration() { + return (obj, prop) -> { + final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop); + if (map.containsKey(PropertyMetadata.VISIBILITY)) { + return !(Visibility.internal.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY))) + || Visibility.deployment.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY)))); + } + if (map.containsKey("dataLocation")) { + return false; + } + return true; + }; + } + + public static PropertyPredicate<Introspector, String> isVisible() { + return (obj, prop) -> { + final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop); + if (map.containsKey(PropertyMetadata.VISIBILITY)) { + return !Visibility.internal.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY))); + } + return true; + }; + } + + public static PropertyPredicate<Introspector, String> includeInExamples() { + return (obj, prop) -> { + final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop); + if (map.containsKey(PropertyMetadata.VISIBILITY)) { + return !Visibility.internal.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY))); + } + if (map.containsKey("dataLocation")) { + return false; + } + return true; + }; + } + + public static PropertyPredicate<Introspector, String> isIndexed() { + return (obj, prop) -> { + Set<String> indexed = obj.getIndexedProperties(); + return indexed.contains(prop); + }; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java new file mode 100644 index 00000000..fdb7a91e --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +public enum Version { + v8, + v9, + v10; +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Visibility.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Visibility.java new file mode 100644 index 00000000..b9126c5b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Visibility.java @@ -0,0 +1,29 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +public enum Visibility { + + internal, + external, + deployment, + all +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Wanderer.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Wanderer.java new file mode 100644 index 00000000..217366d4 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Wanderer.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection; + +import java.util.List; + +import org.openecomp.aai.exceptions.AAIException; + +public interface Wanderer { + + /** + * Process primitive. + * + * @param propName the prop name + * @param obj the obj + */ + public void processPrimitive(String propName, Introspector obj); + + /** + * Process primitive list. + * + * @param propName the prop name + * @param obj the obj + */ + public void processPrimitiveList(String propName, Introspector obj); + + /** + * Process complex obj. + * + * @param obj the obj + * @throws AAIException + */ + public void processComplexObj(Introspector obj) throws AAIException; + + /** + * Modify complex list. + * + * @param list the list + * @param listReference TODO + * @param parent the parent + * @param child the child + */ + public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child); + + /** + * Creates the complex obj if null. + * + * @return true, if successful + */ + public default boolean createComplexObjIfNull() { + return false; + } + + /** + * Creates the complex list size. + * + * @param parent the parent + * @param child the child + * @return the int + */ + public default int createComplexListSize(Introspector parent, Introspector child) { + return 0; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnknownObjectException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnknownObjectException.java new file mode 100644 index 00000000..ed0b3207 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnknownObjectException.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.exceptions; + +import org.openecomp.aai.exceptions.AAIException; + +public class AAIUnknownObjectException extends AAIException { + + private static final long serialVersionUID = -504200228742133774L; + + public AAIUnknownObjectException() {} + + public AAIUnknownObjectException(String message) { + super("AAI_3000", message); + } + + public AAIUnknownObjectException(Throwable cause) { + super("AAI_3000", cause); + } + + public AAIUnknownObjectException(String message, Throwable cause) { + super("AAI_3000", cause, message); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnmarshallingException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnmarshallingException.java new file mode 100644 index 00000000..edc06b3a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnmarshallingException.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.exceptions; + +import org.openecomp.aai.exceptions.AAIException; + +public class AAIUnmarshallingException extends AAIException { + + private static final long serialVersionUID = -5615651557821878103L; + + public AAIUnmarshallingException() {} + + public AAIUnmarshallingException(String message) { + super("AAI_3000", message); + } + + public AAIUnmarshallingException(Throwable cause) { + super("AAI_3000",cause); + } + + public AAIUnmarshallingException(String message, Throwable cause) { + super("AAI_3000", cause, message); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/generator/CreateExample.java b/aai-core/src/main/java/org/openecomp/aai/introspection/generator/CreateExample.java new file mode 100644 index 00000000..fba4525e --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/generator/CreateExample.java @@ -0,0 +1,170 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.generator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.IntrospectorWalker; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.PropertyPredicates; +import org.openecomp.aai.introspection.Wanderer; + +public class CreateExample implements Wanderer { + + private Random rand = new Random(); + private final long range = 100000000L; + private Loader loader = null; + private Introspector result = null; + private String objectName = null; + private List<String> blacklist = null; + + /** + * Instantiates a new creates the example. + * + * @param loader the loader + * @param objectName the object name + */ + public CreateExample(Loader loader, String objectName) { + + this.loader = loader; + this.objectName = objectName; + this.blacklist = new ArrayList<>(); + + } + + /** + * Gets the example object. + * + * @return the example object + * @throws AAIException + */ + public Introspector getExampleObject() throws AAIException { + result = loader.introspectorFromName(objectName); + blacklist = new ArrayList<>(); + blacklist.add("any"); + blacklist.add("relationship-list"); + if (!result.isContainer()) { + blacklist.add("resource-version"); + } + IntrospectorWalker walker = new IntrospectorWalker(this, PropertyPredicates.includeInExamples()); + + walker.preventCycles(true); + walker.setBlacklist(blacklist); + walker.walk(result); + //this.getExampleObject(result); + + return result; + } + + /** + * Gets the value. + * + * @param property the property + * @param type the type + * @param suffix the suffix + * @return the value + */ + private Object getValue(String property, String type, String suffix) { + long randLong = (long)(rand.nextDouble()*range); + Integer randInt = rand.nextInt(100000); + Integer randShrt = rand.nextInt(20000); + short randShort = randShrt.shortValue(); + + Object newObj = null; + if (type.contains("java.lang.String")) { + newObj = "example-" + property + "-val-" + randInt + suffix; + } else if ( type.toLowerCase().equals("long") ||type.contains("java.lang.Long")) { + newObj = randLong; + } else if(type.toLowerCase().equals("boolean") || type.contains("java.lang.Boolean")){ + newObj = Boolean.TRUE; + } else if ( type.toLowerCase().equals("int") || type.contains("java.lang.Integer")){ + newObj = randInt; + } else if ( type.toLowerCase().equals("short") || type.contains("java.lang.Short")){ + newObj = randShort; + } + + return newObj; + } + + /** + * {@inheritDoc} + */ + @Override + public void processPrimitive(String propName, Introspector obj) { + String propType = obj.getType(propName); + + Object val = this.getValue(propName, propType, ""); + obj.setValue(propName, val); + } + + /** + * {@inheritDoc} + */ + @Override + public void processPrimitiveList(String propName, Introspector obj) { + int listSize = 2; + String propType = ""; + List<Object> list = new ArrayList<>(); + for (int i = 0; i < listSize; i++) { + propType = obj.getGenericType(propName); + Object val = this.getValue(propName, propType, "-" + (i + 1)); + list.add(val); + } + obj.setValue(propName, list); + } + + /** + * {@inheritDoc} + */ + @Override + public void processComplexObj(Introspector obj) { + + } + + /** + * {@inheritDoc} + */ + @Override + public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child) { + // TODO Auto-generated method stub + + } + + /** + * {@inheritDoc} + */ + @Override + public boolean createComplexObjIfNull() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int createComplexListSize(Introspector parent, Introspector child) { + return 1; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataCopy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataCopy.java new file mode 100644 index 00000000..98ff219c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataCopy.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException; +import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMultiplePropertiesException; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.restcore.util.URITools; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; + + +public class DataCopy extends SideEffect { + + + public DataCopy(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) { + super(obj, self, dbEngine, serializer); + } + + @Override + protected void processURI(Optional<String> completeUri, Entry<String, String> entry) throws URISyntaxException, UnsupportedEncodingException, AAIException { + if (completeUri.isPresent()) { + URI uri = new URI(completeUri.get()); + MultivaluedMap<String, String> map = URITools.getQueryMap(uri); + QueryParser uriQuery = dbEngine.getQueryBuilder(this.latestLoader).createQueryFromURI(uri, map); + List<Vertex> results = uriQuery.getQueryBuilder().toList(); + Introspector resultObj = this.latestLoader.introspectorFromName(uriQuery.getResultType()); + if (results.size() == 1) { + serializer.dbToObject(Collections.singletonList(results.get(0)), resultObj, 0, true, "false"); + try { + obj.setValue(entry.getKey(), Objects.requireNonNull(resultObj.getValue(uri.getFragment()), uri.getFragment() + " was null")); + } catch (NullPointerException e) { + throw new AAIMissingRequiredPropertyException("property " + uri.getFragment() + " not found at " + uri); + } + } else { + if (results.isEmpty()) { + throw new AAIException("AAI_6114", "object located at " + uri + " not found"); + } else if (results.size() > 1) { + throw new AAIMultiplePropertiesException("multiple values of " + entry.getKey() + " found when searching " + uri); + } + } + } else { + //skip processing because no required properties were specified + } + } + + @Override + protected PropertyMetadata getPropertyMetadata() { + return PropertyMetadata.DATA_COPY; + } + + @Override + protected boolean replaceWithWildcard() { + return false; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkReader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkReader.java new file mode 100644 index 00000000..81562f0b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkReader.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect; + +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.restcore.util.URITools; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; + +import javax.ws.rs.core.MultivaluedMap; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.regex.Matcher; + +public class DataLinkReader extends SideEffect { + + public DataLinkReader(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) { + super(obj, self, dbEngine, serializer); + } + + @Override + protected boolean replaceWithWildcard() { + return true; + } + + @Override + protected PropertyMetadata getPropertyMetadata() { + return PropertyMetadata.DATA_LINK; + } + + @Override + protected void processURI(Optional<String> completeUri, Entry<String, String> entry) + throws URISyntaxException, UnsupportedEncodingException, AAIException { + + if (completeUri.isPresent()) { + URI uri = new URI(completeUri.get()); + MultivaluedMap<String, String> map = URITools.getQueryMap(uri); + QueryParser uriQuery = dbEngine.getQueryBuilder(this.latestLoader).createQueryFromURI(uri, map); + List<Vertex> results = uriQuery.getQueryBuilder().getVerticesByProperty(AAIProperties.LINKED, true).toList(); + if (results.size() == 1) { + if (results.get(0).<Boolean>property(AAIProperties.LINKED).orElse(false) && obj.getValue(entry.getKey()) == null) { + obj.setValue(entry.getKey(), results.get(0).property(entry.getKey()).orElse(null)); + } + } else { + //log something about not being able to return any values because there was more than one + } + } + } + + /** + * always fuzzy search on reads + */ + @Override + protected Map<String, String> findProperties(Introspector obj, String uriString) throws AAIMissingRequiredPropertyException { + + final Map<String, String> result = new HashMap<>(); + Matcher m = template.matcher(uriString); + while (m.find()) { + String propName = m.group(1); + if (replaceWithWildcard()) { + result.put(propName, "*"); + } + } + return result; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkWriter.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkWriter.java new file mode 100644 index 00000000..09a1ce18 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkWriter.java @@ -0,0 +1,111 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Map.Entry; +import java.util.Optional; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMultiplePropertiesException; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.uri.URIToObject; +import org.openecomp.aai.restcore.util.URITools; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; + +public class DataLinkWriter extends SideEffect { + + public DataLinkWriter(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) { + super(obj, self, dbEngine, serializer); + } + + @Override + protected PropertyMetadata getPropertyMetadata() { + return PropertyMetadata.DATA_LINK; + } + + @Override + protected void processURI(Optional<String> completeUri, Entry<String, String> entry) + throws URISyntaxException, UnsupportedEncodingException, AAIException { + if (completeUri.isPresent()) { + URI uri = new URI(completeUri.get()); + MultivaluedMap<String, String> map = URITools.getQueryMap(uri); + QueryParser uriQuery = dbEngine.getQueryBuilder(this.latestLoader).createQueryFromURI(uri, map); + List<Vertex> results = uriQuery.getQueryBuilder().toList(); + if (results.size() == 1) { + if (results.get(0).<Boolean>property(AAIProperties.LINKED).orElse(false) && obj.getValue(entry.getKey()) == null) { + //delete vertex because property was removed + serializer.delete(results.get(0), "", false); + } else { + //link vertex that already exists + this.addLinkedProperty(results.get(0)); + } + } else { + if (results.isEmpty()) { + //locate previously linked vertex + List<Vertex> linkedVertices = uriQuery.getQueryBuilder().getContainerQuery().getVerticesByProperty(AAIProperties.LINKED, true).toList(); + if (!linkedVertices.isEmpty()) { + if (linkedVertices.size() > 1) { + throw new AAIMultiplePropertiesException("multiple vertices found for single cardinality propery found when searching " + uri); + } else { + //found one, remove the linked property because it didn't match the uri + linkedVertices.get(0).property(AAIProperties.LINKED).remove(); + } + } + if (obj.getValue(entry.getKey()) != null) { + //add new vertex to database if we have values + URIToObject parser = new URIToObject(this.latestLoader, uri); + Introspector resultObj = parser.getEntity(); + Vertex newV = serializer.createNewVertex(resultObj); + serializer.serializeToDb(resultObj, newV, uriQuery, completeUri.get(), this.latestLoader.getVersion().toString()); + this.addLinkedProperty(newV); + } + } else if (results.size() > 1) { + throw new AAIMultiplePropertiesException("multiple values of " + entry.getKey() + " found when searching " + uri); + } + } + } else { + //skip processing because no required properties were specified + } + } + + @Override + protected boolean replaceWithWildcard() { + return true; + } + + private void addLinkedProperty(Vertex v) { + v.property(AAIProperties.LINKED, true); + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffect.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffect.java new file mode 100644 index 00000000..3691651c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffect.java @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect; + +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; + +public abstract class SideEffect { + + protected static final Pattern template = Pattern.compile("\\{(.*?)\\}"); + protected final Introspector obj; + protected final TransactionalGraphEngine dbEngine; + protected final DBSerializer serializer; + protected final Loader latestLoader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, AAIProperties.LATEST); + protected final Vertex self; + public SideEffect (Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) { + this.obj = obj; + this.dbEngine = dbEngine; + this.serializer = serializer; + this.self = self; + } + + protected void execute() throws UnsupportedEncodingException, URISyntaxException, AAIException { + final Map<String, String> properties = this.findPopertiesWithMetadata(obj, this.getPropertyMetadata()); + for (Entry<String, String> entry : properties.entrySet()) { + Optional<String> populatedUri = this.replaceTemplates(obj, entry.getValue()); + Optional<String> completeUri = this.resolveRelativePath(populatedUri); + this.processURI(completeUri, entry); + } + } + + protected Map<String, String> findPopertiesWithMetadata(Introspector obj, PropertyMetadata metadata) { + final Map<String, String> result = new HashMap<>(); + for (String prop : obj.getProperties()) { + final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop); + if (map.containsKey(metadata)) { + result.put(prop, map.get(metadata)); + } + } + return result; + } + + protected Map<String, String> findProperties(Introspector obj, String uriString) throws AAIMissingRequiredPropertyException { + + final Map<String, String> result = new HashMap<>(); + final Set<String> missing = new LinkedHashSet<>(); + Matcher m = template.matcher(uriString); + int properties = 0; + while (m.find()) { + String propName = m.group(1); + String value = obj.getValue(propName); + properties++; + if (value != null) { + result.put(propName, value); + } else { + if (replaceWithWildcard()) { + result.put(propName, "*"); + } + missing.add(propName); + } + } + + if (!missing.isEmpty() && (properties != missing.size())) { + throw new AAIMissingRequiredPropertyException("Cannot complete " + this.getPropertyMetadata().toString() + " uri. Missing properties " + missing); + } + return result; + } + + private Optional<String> replaceTemplates(Introspector obj, String uriString) throws AAIMissingRequiredPropertyException { + String result = uriString; + final Map<String, String> propMap = this.findProperties(obj, uriString); + if (propMap.isEmpty()) { + return Optional.empty(); + } + for (Entry<String, String> entry : propMap.entrySet()) { + result = result.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue()); + } + //drop out wildcards if they exist + result = result.replaceFirst("/[^/]+?(?:/\\*)+", ""); + return Optional.of(result); + } + + private Optional<String> resolveRelativePath(Optional<String> populatedUri) throws UnsupportedEncodingException { + if (!populatedUri.isPresent()) { + return Optional.empty(); + } else { + return Optional.of(populatedUri.get().replaceFirst("\\./", this.serializer.getURIForVertex(self) + "/")); + } + } + + protected abstract boolean replaceWithWildcard(); + protected abstract PropertyMetadata getPropertyMetadata(); + protected abstract void processURI(Optional<String> completeUri, Entry<String, String> entry) throws URISyntaxException, UnsupportedEncodingException, AAIException; +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunner.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunner.java new file mode 100644 index 00000000..17127da7 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunner.java @@ -0,0 +1,99 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect; + +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; + +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.net.URISyntaxException; +import java.util.LinkedHashSet; +import java.util.Set; + +public class SideEffectRunner { + + protected final TransactionalGraphEngine dbEngine; + protected final DBSerializer serializer; + protected final Set<Class<? extends SideEffect>> sideEffects; + protected SideEffectRunner(Builder builder) { + this.dbEngine = builder.getDbEngine(); + this.serializer = builder.getSerializer(); + this.sideEffects = builder.getSideEffects(); + } + + public void execute(Introspector obj, Vertex self) throws AAIException { + + for (Class<? extends SideEffect> se : sideEffects) { + try { + se.getConstructor(Introspector.class, Vertex.class, TransactionalGraphEngine.class, DBSerializer.class) + .newInstance(obj, self, dbEngine, serializer).execute(); + } catch (UnsupportedEncodingException | InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException + | URISyntaxException e) { + throw new AAIException("strange exception", e); + } + } + } + + public static class Builder { + + private final TransactionalGraphEngine dbEngine; + private final DBSerializer serializer; + private final Set<Class<? extends SideEffect>> sideEffects; + + public Builder(final TransactionalGraphEngine dbEngine, final DBSerializer serializer) { + this.dbEngine = dbEngine; + this.serializer = serializer; + this.sideEffects = new LinkedHashSet<>(); + } + + public Builder addSideEffect(Class<? extends SideEffect> se) { + sideEffects.add(se); + return this; + } + + public Builder addSideEffects(Class<? extends SideEffect>... sideEffects) { + for (Class<? extends SideEffect> se : sideEffects) { + this.addSideEffect(se); + } + return this; + } + + public SideEffectRunner build() { + return new SideEffectRunner(this); + } + protected TransactionalGraphEngine getDbEngine() { + return dbEngine; + } + + protected DBSerializer getSerializer() { + return serializer; + } + + protected Set<Class<? extends SideEffect>> getSideEffects() { + return sideEffects; + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunnerHelper.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunnerHelper.java new file mode 100644 index 00000000..9d214623 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunnerHelper.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Wanderer; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; + +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Set; + +class SideEffectRunnerHelper implements Wanderer { + + + protected final TransactionalGraphEngine dbEngine; + protected final DBSerializer serializer; + protected final Set<Class<? extends SideEffect>> sideEffects; + protected SideEffectRunnerHelper(final TransactionalGraphEngine dbEngine, final DBSerializer serializer, final Set<Class<? extends SideEffect>> sideEffects) { + this.dbEngine = dbEngine; + this.serializer = serializer; + this.sideEffects = sideEffects; + } + + private void runSideEffects(Introspector obj) throws AAIException { + for (Class<? extends SideEffect> se : sideEffects) { + try { + se.getConstructor(Introspector.class, TransactionalGraphEngine.class, DBSerializer.class) + .newInstance(obj, dbEngine, serializer).execute(); + } catch (UnsupportedEncodingException | InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException + | URISyntaxException e) { + throw new AAIException("strange exception", e); + } + } + } + @Override + public void processPrimitive(String propName, Introspector obj) { + // TODO Auto-generated method stub + + } + + @Override + public void processPrimitiveList(String propName, Introspector obj) { + // TODO Auto-generated method stub + + } + + @Override + public void processComplexObj(Introspector obj) throws AAIException { + + runSideEffects(obj); + + } + + @Override + public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, + Introspector child) { + // TODO Auto-generated method stub + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMissingRequiredPropertyException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMissingRequiredPropertyException.java new file mode 100644 index 00000000..9131f249 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMissingRequiredPropertyException.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect.exceptions; + +import org.openecomp.aai.exceptions.AAIException; + +public class AAIMissingRequiredPropertyException extends AAIException { + + + private static final long serialVersionUID = -8907079650472014019L; + + public AAIMissingRequiredPropertyException() {} + + public AAIMissingRequiredPropertyException(String message) { + super("AAI_5107", message); + } + + public AAIMissingRequiredPropertyException(Throwable cause) { + super("AAI_5107",cause); + } + + public AAIMissingRequiredPropertyException(String message, Throwable cause) { + super("AAI_5107", cause, message); + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMultiplePropertiesException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMultiplePropertiesException.java new file mode 100644 index 00000000..0525b1b7 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMultiplePropertiesException.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.sideeffect.exceptions; + +import org.openecomp.aai.exceptions.AAIException; + +public class AAIMultiplePropertiesException extends AAIException { + + private static final long serialVersionUID = 2098371383166008345L; + + public AAIMultiplePropertiesException() {} + + public AAIMultiplePropertiesException(String message) { + super("AAI_6136", message); + } + + public AAIMultiplePropertiesException(Throwable cause) { + super("AAI_6136",cause); + } + + public AAIMultiplePropertiesException(String message, Throwable cause) { + super("AAI_6136", cause, message); + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/CreateUUID.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/CreateUUID.java new file mode 100644 index 00000000..8932da2c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/CreateUUID.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +import java.util.Map; +import java.util.UUID; + +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.schema.enums.PropertyMetadata; + +public class CreateUUID implements IssueResolver { + + /** + * {@inheritDoc} + */ + @Override + public boolean resolveIssue(Issue issue) { + + Introspector obj = issue.getIntrospector(); + if (issue.getType().equals(IssueType.MISSING_KEY_PROP)) { + Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(issue.getPropName()); + if (metadata.containsKey(PropertyMetadata.AUTO_GENERATE_UUID) && metadata.get(PropertyMetadata.AUTO_GENERATE_UUID).equals("true")) { + obj.setValue(issue.getPropName(), UUID.randomUUID().toString()); + return true; + } + } + + return false; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/DefaultFields.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/DefaultFields.java new file mode 100644 index 00000000..8a1143f0 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/DefaultFields.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +import java.util.Map; + +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.schema.enums.PropertyMetadata; + +public class DefaultFields implements IssueResolver { + + /** + * {@inheritDoc} + */ + @Override + public boolean resolveIssue(Issue issue) { + + Introspector obj = issue.getIntrospector(); + if (issue.getType().equals(IssueType.MISSING_REQUIRED_PROP)) { + Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(issue.getPropName()); + if (metadata.containsKey(PropertyMetadata.DEFAULT_VALUE)) { + obj.setValue(issue.getPropName(), metadata.get(PropertyMetadata.DEFAULT_VALUE)); + return true; + } + } + + return false; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/InjectKeysFromURI.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/InjectKeysFromURI.java new file mode 100644 index 00000000..23855363 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/InjectKeysFromURI.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +import java.net.URI; + +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.uri.URIToObject; + +public class InjectKeysFromURI implements IssueResolver { + + private URI uri = null; + private Loader loader = null; + + /** + * Instantiates a new inject keys from URI. + * + * @param loader the loader + * @param uri the uri + */ + public InjectKeysFromURI(Loader loader, URI uri) { + this.loader = loader; + this.uri = uri; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean resolveIssue(Issue issue) { + boolean result = false; + Introspector obj = issue.getIntrospector(); + if (issue.getType().equals(IssueType.MISSING_KEY_PROP)) { + try { + URIToObject toObject = new URIToObject(loader, uri); + Introspector minimumObj = toObject.getEntity(); + if (toObject.getEntityName().equals(obj.getDbName())) { + obj.setValue(issue.getPropName(), minimumObj.getValue(issue.getPropName())); + result = true; + } + } catch (Exception e) { + //log something probably + result = false; + } + } + + return result; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IntrospectorValidator.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IntrospectorValidator.java new file mode 100644 index 00000000..0e5b4bcd --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IntrospectorValidator.java @@ -0,0 +1,314 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.IntrospectorWalker; +import org.openecomp.aai.introspection.Visibility; +import org.openecomp.aai.introspection.Wanderer; +import org.openecomp.aai.schema.enums.PropertyMetadata; + +public class IntrospectorValidator implements Wanderer { + + + private List<Issue> issues = null; + private List<IssueResolver> issueResolvers = null; + private boolean validateRequired = true; + private final int maximumDepth; + private int currentDepth = 0; + + private final Set<String> relationshipChain; + /** + * Instantiates a new introspector validator. + * + * @param builder the builder + */ + private IntrospectorValidator(IntrospectorValidator.Builder builder) { + this.validateRequired = builder.getValidateRequired(); + this.issueResolvers = builder.getResolvers(); + this.maximumDepth = builder.getMaximumDepth(); + issues = new ArrayList<>(); + + relationshipChain = new HashSet<>(); + + relationshipChain.add("relationship-list"); + relationshipChain.add("relationship"); + relationshipChain.add("relationship-data"); + relationshipChain.add("related-to-property"); + + + } + + /** + * Validate. + * + * @param obj the obj + * @return true, if successful + * @throws AAIException + */ + public boolean validate(Introspector obj) throws AAIException { + IntrospectorWalker walker = new IntrospectorWalker(this); + this.currentDepth = 0; + walker.walk(obj); + + for (Issue m : issues) { + if (!m.getSeverity().equals(Severity.WARNING)) { + return false; + } + } + + return true; + } + + /** + * Gets the issues. + * + * @return the issues + */ + public List<Issue> getIssues() { + return this.issues; + } + + /** + * Sets the issue resolvers. + * + * @param resolvers the new issue resolvers + */ + public void setIssueResolvers(List<IssueResolver> resolvers) { + issueResolvers = new ArrayList<>(); + for (IssueResolver resolver : resolvers) { + issueResolvers.add(resolver); + } + } + + /** + * Resolve issues. + * + * @return true, if successful + */ + public boolean resolveIssues() { + boolean result = true; + for (Issue issue : issues) { + for (IssueResolver resolver : issueResolvers) { + if (resolver.resolveIssue(issue)) { + issue.setResolved(true); + } + } + if (!issue.isResolved()) { + result = false; + } + } + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public void processComplexObj(Introspector obj) { + + if (this.currentDepth > this.maximumDepth && !relationshipChain.contains(obj.getDbName())) { + Issue message = + this.buildMessage(Severity.CRITICAL, IssueType.EXCEEDED_ALLOWED_DEPTH, "Maximum allowed depth of this object has been exceeded on: " + obj.getDbName()); + message.setIntrospector(obj); + issues.add(message); + } + Set<String> requiredProps = obj.getRequiredProperties(); + Set<String> keys = obj.getKeys(); + Set<String> props = obj.getProperties(); + + for (String prop : props) { + Object value = obj.getValue(prop); + if (keys.contains(prop)) { + if (value == null) { + Issue message = + this.buildMessage(Severity.CRITICAL, IssueType.MISSING_KEY_PROP, "Missing key property: " + prop); + message.setIntrospector(obj); + message.setPropName(prop); + issues.add(message); + } + } else if (requiredProps.contains(prop)) { + if (value == null && validateRequired) { + Issue message = + this.buildMessage(Severity.CRITICAL, IssueType.MISSING_REQUIRED_PROP, "Missing required property: " + prop); + message.setIntrospector(obj); + message.setPropName(prop); + issues.add(message); + } + } + + final Optional<String> visibility = obj.getPropertyMetadata(prop, PropertyMetadata.VISIBILITY); + if(visibility.isPresent() && Visibility.internal.equals(Visibility.valueOf(visibility.get()))) { + Issue message = + this.buildMessage(Severity.ERROR, IssueType.PROPERTY_NOT_VISIBLE, "client attemptted to set property not visible: " + prop); + message.setIntrospector(obj); + message.setPropName(prop); + issues.add(message); + + } + } + + if (!relationshipChain.contains(obj.getDbName())) { + this.currentDepth++; + } + + } + + /** + * {@inheritDoc} + */ + @Override + public void processPrimitive(String propName, Introspector obj) { + //NO OP + } + + /** + * {@inheritDoc} + */ + @Override + public void processPrimitiveList(String propName, Introspector obj) { + //NO OP + } + + /** + * {@inheritDoc} + */ + @Override + public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child) { + //NO OP + } + + + /** + * Builds the message. + * + * @param severity the severity + * @param error the error + * @param detail the detail + * @return the issue + */ + private Issue buildMessage(Severity severity, IssueType error, String detail) { + Issue message = new Issue(); + message.setSeverity(severity); + message.setType(error); + message.setDetail(detail); + + return message; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean createComplexObjIfNull() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int createComplexListSize(Introspector parent, Introspector child) { + return 0; + } + + public static class Builder { + + private boolean validateRequired = true; + private List<IssueResolver> issueResolvers = null; + private int maximumDepth = AAIProperties.MAXIMUM_DEPTH; + /** + * Instantiates a new builder. + * + * @param llBuilder the ll builder + */ + public Builder() { + issueResolvers = new ArrayList<IssueResolver>(); + } + + /** + * Validate required. + * + * @param validateRequired the validate required + * @return the builder + */ + public Builder validateRequired(boolean validateRequired) { + this.validateRequired = validateRequired; + return this; + } + + public Builder restrictDepth(int depth) { + this.maximumDepth = depth; + return this; + } + /** + * Adds the resolver. + * + * @param resolver the resolver + * @return the builder + */ + public Builder addResolver(IssueResolver resolver) { + issueResolvers.add(resolver); + return this; + } + + /** + * Builds the. + * + * @return the introspector validator + */ + public IntrospectorValidator build() { + return new IntrospectorValidator(this); + } + + /** + * Gets the validate required. + * + * @return the validate required + */ + public boolean getValidateRequired() { + return this.validateRequired; + } + + /** + * Gets the resolvers. + * + * @return the resolvers + */ + public List<IssueResolver> getResolvers() { + return this.issueResolvers; + } + + public int getMaximumDepth() { + return this.maximumDepth; + } + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Issue.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Issue.java new file mode 100644 index 00000000..b95643c1 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Issue.java @@ -0,0 +1,144 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +import org.openecomp.aai.introspection.Introspector; + +public class Issue { + + private Severity severity; + private IssueType error; + private String detail; + private Introspector obj; + private String propName; + private boolean resolved = false; + + /** + * Sets the severity. + * + * @param severity the new severity + */ + public void setSeverity(Severity severity) { + + this.severity = severity; + } + + /** + * Sets the error. + * + * @param error the new error + */ + public void setType(IssueType error) { + this.error = error; + } + + /** + * Sets the detail. + * + * @param detail the new detail + */ + public void setDetail(String detail) { + this.detail = detail; + } + + /** + * Gets the severity. + * + * @return the severity + */ + public Object getSeverity() { + return this.severity; + } + + /** + * Sets the introspector. + * + * @param obj the new introspector + */ + public void setIntrospector(Introspector obj) { + this.obj = obj; + } + + /** + * Gets the introspector. + * + * @return the introspector + */ + public Introspector getIntrospector() { + return this.obj; + } + + /** + * Gets the detail. + * + * @return the detail + */ + public String getDetail() { + return this.detail; + } + + /** + * Gets the error. + * + * @return the error + */ + public IssueType getType() { + return this.error; + } + + /** + * Sets the prop name. + * + * @param prop the new prop name + */ + public void setPropName(String prop) { + this.propName= prop; + } + + /** + * Gets the prop name. + * + * @return the prop name + */ + public String getPropName() { + return this.propName; + } + + /** + * Checks if is resolved. + * + * @return true, if is resolved + */ + public boolean isResolved() { + return resolved; + } + + /** + * Sets the resolved. + * + * @param resolved the new resolved + */ + public void setResolved(boolean resolved) { + this.resolved = resolved; + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueResolver.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueResolver.java new file mode 100644 index 00000000..409a1c02 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueResolver.java @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +public interface IssueResolver { + + + /** + * Resolve issue. + * + * @param issue the issue + * @return true, if successful + */ + public boolean resolveIssue(Issue issue); +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueType.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueType.java new file mode 100644 index 00000000..fad06d9a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueType.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +public enum IssueType { + MISSING_REQUIRED_PROP, MISSING_KEY_PROP, EXCEEDED_ALLOWED_DEPTH, PROPERTY_NOT_VISIBLE +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/RemoveNonVisibleProperty.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/RemoveNonVisibleProperty.java new file mode 100644 index 00000000..2bf6afcc --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/RemoveNonVisibleProperty.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +public class RemoveNonVisibleProperty implements IssueResolver { + + @Override + public boolean resolveIssue(Issue issue) { + + if (IssueType.PROPERTY_NOT_VISIBLE.equals(issue.getType())) { + //remove property value + issue.getIntrospector().setValue(issue.getPropName(), null); + return true; + } + return false; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Severity.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Severity.java new file mode 100644 index 00000000..17663f16 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Severity.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.introspection.tools; + +public enum Severity { + WARNING, + ERROR, + CRITICAL +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/CNName.java b/aai-core/src/main/java/org/openecomp/aai/logging/CNName.java new file mode 100644 index 00000000..28afd56a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/CNName.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.access.pattern.AccessConverter; +import ch.qos.logback.access.spi.IAccessEvent; + +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; +import java.security.cert.X509Certificate; + +import static java.util.Base64.getDecoder; + +public class CNName extends AccessConverter { + + /** + * Converts access events to String response codes + * + * @param accessEvent the IAccessEvent + */ + public String convert(IAccessEvent accessEvent) { + if (!isStarted()) { + return "INACTIVE_HEADER_CONV"; + } + + String cipherSuite = (String) accessEvent.getRequest().getAttribute("javax.servlet.request.cipher_suite"); + String authUser = null; + if (cipherSuite != null) { + try { + X509Certificate certChain[] = (X509Certificate[]) accessEvent.getRequest() + .getAttribute("javax.servlet.request.X509Certificate"); + if(certChain == null || certChain.length == 0){ + + HttpServletRequest request = accessEvent.getRequest(); + + String authorization = request.getHeader("Authorization"); + + // Set the auth user to "-" so if the authorization header is not found + // Or if the decoded basic auth credentials are not found in the format required + // it should return "-" + // If the decoded string is in the right format, find the index of ":" + // Then get the substring of the starting point to the colon not including the colon + + authUser = "-"; + + if(authorization != null && authorization.startsWith("Basic ")){ + String credentials = authorization.replace("Basic ", ""); + byte[] userCredentials = getDecoder().decode(credentials.getBytes("utf-8")); + credentials = new String(userCredentials); + + int codePoint = credentials.indexOf(':'); + + if(codePoint != -1){ + authUser = credentials.substring(0, codePoint); + } + + } + + return authUser; + + } else { + X509Certificate clientCert = certChain[0]; + X500Principal subjectDN = clientCert.getSubjectX500Principal(); + authUser = subjectDN.toString(); + return authUser; + } + } catch(Exception ex){ + return "-"; + } + } else { + return "-"; + } + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayout.java b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayout.java new file mode 100644 index 00000000..0b2df03b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayout.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +public class CustomLogPatternLayout extends ch.qos.logback.access.PatternLayout { + static { + defaultConverterMap.put("z", CNName.class.getName()); + defaultConverterMap.put("y", DME2RestFlag.class.getName()); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayoutEncoder.java b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayoutEncoder.java new file mode 100644 index 00000000..b335109b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayoutEncoder.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.access.PatternLayout; + +public class CustomLogPatternLayoutEncoder extends ch.qos.logback.access.PatternLayoutEncoder { + +/** + * @{inheritDoc} + */ + @Override + public void start(){ + PatternLayout patternLayout = new CustomLogPatternLayout(); + patternLayout.setContext(context); + patternLayout.setPattern(getPattern()); + patternLayout.start(); + this.layout = patternLayout; + super.start(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/DME2RestFlag.java b/aai-core/src/main/java/org/openecomp/aai/logging/DME2RestFlag.java new file mode 100644 index 00000000..b5426452 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/DME2RestFlag.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.access.pattern.AccessConverter; +import ch.qos.logback.access.spi.IAccessEvent; + +public class DME2RestFlag extends AccessConverter { + + /** + * @{inheritDoc} + */ + @Override + public String convert(IAccessEvent accessEvent) { + if (!isStarted()) { + return "INACTIVE_HEADER_CONV"; + } + + String flag = "-"; + + if (accessEvent.getRequestParameter("envContext").length > 0 + && !accessEvent.getRequestParameter("envContext")[0].isEmpty() + && !accessEvent.getRequestParameter("envContext")[0].equals("-") + && accessEvent.getRequestParameter("routeOffer").length > 0 + && !accessEvent.getRequestParameter("routeOffer")[0].isEmpty() + && !accessEvent.getRequestParameter("routeOffer")[0].equals("-") + && accessEvent.getRequestParameter("version").length > 0 + && !accessEvent.getRequestParameter("version")[0].isEmpty() + && !accessEvent.getRequestParameter("version")[0].equals("-")) { + flag = "DME2"; + } else { + flag = "REST"; + } + + return flag; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompElapsedTime.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompElapsedTime.java new file mode 100644 index 00000000..1593e856 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompElapsedTime.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.classic.pattern.ClassicConverter; +import ch.qos.logback.classic.spi.ILoggingEvent; +import org.openecomp.aai.logging.LoggingContext.LoggingField; + +public class EcompElapsedTime extends ClassicConverter { + + private static final String DEFAULT_ELAPSED_TIME_FORMAT = "%d"; + + private String ELAPSED_TIME_FORMAT; + + @Override + public void start() { + ELAPSED_TIME_FORMAT = getFirstOption(); + } + + @Override + public String convert(ILoggingEvent event) { + final long end = event.getTimeStamp(); + + if (!event.getMDCPropertyMap().containsKey(LoggingField.START_TIME.toString())) { + return format(0); + } else if (event.getMDCPropertyMap().containsKey(LoggingField.ELAPSED_TIME.toString())) { + return format( + Integer.parseInt(event.getMDCPropertyMap().get(LoggingField.ELAPSED_TIME.toString())) + ); + } + + final long start = LogFormatTools.toTimestamp(event.getMDCPropertyMap().get(LoggingField.START_TIME.toString())); + + return format(end - start); + } + + private String format(long elapsedTime) { + if (ELAPSED_TIME_FORMAT == null) { + return format(DEFAULT_ELAPSED_TIME_FORMAT, elapsedTime); + } + + return format (ELAPSED_TIME_FORMAT, elapsedTime); + } + + private String format(String format, long elapsedTime) { + return String.format(format, elapsedTime); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompEncoder.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompEncoder.java new file mode 100644 index 00000000..daaa90de --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompEncoder.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.classic.PatternLayout; +import ch.qos.logback.classic.encoder.PatternLayoutEncoder; + +public class EcompEncoder extends PatternLayoutEncoder { + + @Override + public void start() { + PatternLayout patternLayout = new EcompPatternLayout(); + patternLayout.setContext(context); + patternLayout.setPattern(getPattern()); + patternLayout.setOutputPatternAsHeader(outputPatternAsHeader); + patternLayout.start(); + this.layout = patternLayout; + super.start(); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompPatternLayout.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompPatternLayout.java new file mode 100644 index 00000000..296e3b81 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompPatternLayout.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.classic.PatternLayout; + +public class EcompPatternLayout extends PatternLayout { + static { + PatternLayout.defaultConverterMap.put("ecompStartTime", EcompStartTime.class.getName()); + PatternLayout.defaultConverterMap.put("ecompElapsedTime", EcompElapsedTime.class.getName()); + PatternLayout.defaultConverterMap.put("eelfClassOfCaller", EelfClassOfCaller.class.getName()); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompStartTime.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompStartTime.java new file mode 100644 index 00000000..89cd81d2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompStartTime.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.classic.pattern.ClassicConverter; +import ch.qos.logback.classic.spi.ILoggingEvent; +import org.openecomp.aai.logging.LoggingContext.LoggingField; + +public class EcompStartTime extends ClassicConverter { + + @Override + public String convert(ILoggingEvent event) { + + if (!event.getMDCPropertyMap().containsKey(LoggingField.START_TIME.toString())) { + return LogFormatTools.toDate(event.getTimeStamp()); + } + + return event.getMDCPropertyMap().get(LoggingField.START_TIME.toString()); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EelfClassOfCaller.java b/aai-core/src/main/java/org/openecomp/aai/logging/EelfClassOfCaller.java new file mode 100644 index 00000000..a90fcc8d --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/EelfClassOfCaller.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import ch.qos.logback.classic.pattern.NamedConverter; +import ch.qos.logback.classic.spi.CallerData; +import ch.qos.logback.classic.spi.ILoggingEvent; + +public class EelfClassOfCaller extends NamedConverter { + protected String getFullyQualifiedName(ILoggingEvent event) { + + StackTraceElement[] cda = event.getCallerData(); + + //If using the EELFLogger, it "hides" the calling class because it wraps the logging calls + //Without this, you'd only ever see "com.att.eelf.configuration.SLF4jWrapper" when using the + // %C pattern converter + if (cda != null && cda.length > 2) { + return cda[2].getClassName(); + } else if (cda != null && cda.length > 0) { + return cda[0].getClassName(); + } else { + return CallerData.NA; + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorLogHelper.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorLogHelper.java new file mode 100644 index 00000000..dae30220 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorLogHelper.java @@ -0,0 +1,587 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.apache.commons.lang.StringUtils; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.LoggingContext.StatusCode; +import org.openecomp.aai.util.AAIConstants; +import org.openecomp.aai.util.MapperUtil; +import org.slf4j.MDC; + +import javax.ws.rs.core.MediaType; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.util.*; +import java.util.Map.Entry; + +/** + * + * This classes loads the application error properties file + * and provides a method that returns an ErrorObject + * + */ + +public class ErrorLogHelper { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ErrorLogHelper.class); + private static final HashMap<String, ErrorObject> ERROR_OBJECTS = new HashMap<String, ErrorObject> (); + + static { + try { + loadProperties(); + } catch (IOException e) { + throw new RuntimeException("Failed to load error.properties file", e); + } catch (ErrorObjectFormatException e) { + throw new RuntimeException("Failed to parse error.properties file", e); + } + } + + /** + * Load properties. + * @throws ErrorObjectFormatException + * @throws Exception the exception + */ + public static void loadProperties() throws IOException, ErrorObjectFormatException { + final String filePath = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "error.properties"; + final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath); + final Properties properties = new Properties(); + + if (is != null) { + properties.load(is); + } else { + try (final FileInputStream fis = new FileInputStream(filePath)) { + properties.load(fis); + } + } + + for (Entry<Object, Object> entry : properties.entrySet()) { + final String key = (String) entry.getKey(); + final String value = (String) entry.getValue(); + final String[] errorProperties = value.split(":"); + + if (errorProperties.length != 7) throw new ErrorObjectFormatException(); + + final ErrorObject errorObject = new ErrorObject(); + + errorObject.setDisposition(errorProperties[0].trim()); + errorObject.setCategory(errorProperties[1].trim()); + errorObject.setSeverity(errorProperties[2].trim()); + errorObject.setErrorCode(errorProperties[3].trim()); + errorObject.setHTTPResponseCode(errorProperties[4].trim()); + errorObject.setRESTErrorCode(errorProperties[5].trim()); + errorObject.setErrorText(errorProperties[6].trim()); + + ERROR_OBJECTS.put(key, errorObject); + } + } + + /** + * Logs a known A&AI exception (i.e. one that can be found in error.properties) + * + * @param key The key for the error in the error.properties file + * @throws IOException + * @throws ErrorObjectNotFoundException + * @throws ErrorObjectFormatException + */ + public static ErrorObject getErrorObject(String code) throws ErrorObjectNotFoundException { + + if (code == null) throw new IllegalArgumentException("Key cannot be null"); + + final ErrorObject errorObject = ERROR_OBJECTS.get(code); + + if (errorObject == null) { + LOGGER.warn("Unknown AAIException with code=" + code + ". Using default AAIException"); + return ERROR_OBJECTS.get(AAIException.DEFAULT_EXCEPTION_CODE); + } + + return errorObject; + } + + /** + * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error. + * The AAIRESTException may contain a different ErrorObject than that created with the REST error key. + * This allows lower level exception detail to be returned to the client to help troubleshoot the problem. + * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException. + * @param are must have a restError value whose numeric value must match what should be returned in the REST API + * @param variables optional list of variables to flesh out text in error string + * @return appropriately formatted JSON response per the REST API spec. + * @throws ErrorObjectFormatException + * @throws ErrorObjectNotFoundException + * @throws IOException + * @deprecated + */ + public static String getRESTAPIErrorResponse(AAIException are, ArrayList<String> variables) { + List<MediaType> acceptHeaders = new ArrayList<MediaType>(); + acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE); + + return getRESTAPIErrorResponse(acceptHeaders, are, variables); + } + + /** + * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error. + * The AAIRESTException may contain a different ErrorObject than that created with the REST error key. + * This allows lower level exception detail to be returned to the client to help troubleshoot the problem. + * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException. + * + * @param acceptHeadersOrig the accept headers orig + * @param are must have a restError value whose numeric value must match what should be returned in the REST API + * @param variables optional list of variables to flesh out text in error string + * @return appropriately formatted JSON response per the REST API spec. + * @throws ErrorObjectFormatException + * @throws ErrorObjectNotFoundException + * @throws IOException + */ + public static String getRESTAPIErrorResponse(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) { + + + StringBuilder text = new StringBuilder(); + String response = null; + + List<MediaType> acceptHeaders = new ArrayList<MediaType>(); + // we might have an exception but no accept header, so we'll set default to JSON + boolean foundValidAcceptHeader = false; + for (MediaType mt : acceptHeadersOrig) { + if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt) || + MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) { + acceptHeaders.add(mt); + foundValidAcceptHeader = true; + } + } + if (foundValidAcceptHeader == false) { + // override the exception, client needs to set an appropriate Accept header + are = new AAIException("AAI_4014"); + acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE); + } + + final ErrorObject eo = are.getErrorObject(); + + int restErrorCode = Integer.parseInt(eo.getRESTErrorCode()); + + ErrorObject restErrorObject; + + try { + restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode); + } catch (ErrorObjectNotFoundException e) { + LOGGER.warn("Failed to find related error object AAI_" + restErrorCode + " for error object " + eo.getErrorCode() + "; using AAI_" + restErrorCode); + restErrorObject = eo; + } + + text.append(restErrorObject.getErrorText()); + + // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n + // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the + // error, are ordered based on the error string. + int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%"); + text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")"); + + if (variables == null) + { + variables = new ArrayList<String>(); + } + + if (variables.size() < localDataIndex) { + ErrorLogHelper.logError("AAI_4011", "data missing for rest error"); + while (variables.size() < localDataIndex) { + variables.add("null"); + } + } + + // This will put the error code and error text into the right positions + if (are.getMessage() == null || are.getMessage().length() == 0) { + variables.add(localDataIndex++, eo.getErrorText()); + } + else { + variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage()); + } + variables.add(localDataIndex, eo.getErrorCodeString()); + + for (MediaType mediaType : acceptHeaders) { + if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) { + JAXBContext context = null; + try { + if(eo.getCategory().equals("1")) { + + context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class); + Marshaller m = context.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); + + org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory(); + org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault(); + org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError(); + org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException(); + org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables(); + + policyException.setMessageId("POL" + eo.getRESTErrorCode()); + policyException.setText(text.toString()); + for (int i=0;i<variables.size();i++) + { + polvariables.getVariable().add(variables.get(i)); + } + policyException.setVariables(polvariables); + requestError.setPolicyException(policyException); + fault.setRequestError(requestError); + + StringWriter sw = new StringWriter(); + m.marshal(fault, sw); + + response = sw.toString(); + + } else { + + context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class); + Marshaller m = context.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); + + org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory(); + org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault(); + org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError(); + org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException(); + org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables(); + serviceException.setMessageId("SVC" + eo.getRESTErrorCode()); + serviceException.setText(text.toString()); + for (int i=0;i<variables.size();i++) + { + svcvariables.getVariable().add(variables.get(i)); + } + serviceException.setVariables(svcvariables); + requestError.setServiceException(serviceException); + fault.setRequestError(requestError); + + StringWriter sw = new StringWriter(); + m.marshal(fault, sw); + + response = sw.toString(); + + } + } catch (Exception ex) { + LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex); + } + } + else { + try { + if(eo.getCategory().equals("1")) { + org.openecomp.aai.domain.restPolicyException.RESTResponse restresp = new org.openecomp.aai.domain.restPolicyException.RESTResponse(); + org.openecomp.aai.domain.restPolicyException.RequestError reqerr = new org.openecomp.aai.domain.restPolicyException.RequestError(); + org.openecomp.aai.domain.restPolicyException.PolicyException polexc = new org.openecomp.aai.domain.restPolicyException.PolicyException(); + polexc.setMessageId("POL" + eo.getRESTErrorCode()); + polexc.setText(text.toString()); + polexc.setVariables(variables); + reqerr.setPolicyException(polexc); + restresp.setRequestError(reqerr); + response = (MapperUtil.writeAsJSONString((Object) restresp)); + + } else { + org.openecomp.aai.domain.restServiceException.RESTResponse restresp = new org.openecomp.aai.domain.restServiceException.RESTResponse(); + org.openecomp.aai.domain.restServiceException.RequestError reqerr = new org.openecomp.aai.domain.restServiceException.RequestError(); + org.openecomp.aai.domain.restServiceException.ServiceException svcexc = new org.openecomp.aai.domain.restServiceException.ServiceException(); + svcexc.setMessageId("SVC" + eo.getRESTErrorCode()); + svcexc.setText(text.toString()); + svcexc.setVariables(variables); + reqerr.setServiceException(svcexc); + restresp.setRequestError(reqerr); + response = (MapperUtil.writeAsJSONString((Object) restresp)); + } + } catch (AAIException ex) { + LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex); + } + } + } + + + return response; + } + + /** + * Gets the RESTAPI error response with logging. + * + * @param acceptHeadersOrig the accept headers orig + * @param are the are + * @param variables the variables + * @param logline the logline + * @return the RESTAPI error response with logging + * @throws ErrorObjectFormatException + * @throws ErrorObjectNotFoundException + * @throws IOException + */ + public static String getRESTAPIErrorResponseWithLogging(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) { + String response = ErrorLogHelper.getRESTAPIErrorResponse(acceptHeadersOrig, are, variables); + + LOGGER.error(are.getMessage(), are); + + return response; + } + + /** + * Gets the RESTAPI info response. + * + * @param acceptHeaders the accept headers + * @param areList the are list + * @return the RESTAPI info response + * @throws ErrorObjectFormatException + * @throws ErrorObjectNotFoundException + * @throws IOException + */ + public static Object getRESTAPIInfoResponse(List<MediaType> acceptHeaders, HashMap<AAIException,ArrayList<String>> areList) { + + Object respObj = null; + + org.openecomp.aai.domain.restResponseInfo.ObjectFactory factory = new org.openecomp.aai.domain.restResponseInfo.ObjectFactory(); + org.openecomp.aai.domain.restResponseInfo.Info info = factory.createInfo(); + org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages responseMessages = factory.createInfoResponseMessages(); + Iterator<Entry<AAIException, ArrayList<String>>> it = areList.entrySet().iterator(); + + while (it.hasNext()) { + Entry<AAIException,ArrayList<String>> pair = (Entry<AAIException, ArrayList<String>>)it.next(); + AAIException are = pair.getKey(); + ArrayList<String> variables = pair.getValue(); + + StringBuilder text = new StringBuilder(); + + ErrorObject eo = are.getErrorObject(); + + int restErrorCode = Integer.parseInt(eo.getRESTErrorCode()); + ErrorObject restErrorObject; + try { + restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+String.format("%04d", restErrorCode)); + } catch (ErrorObjectNotFoundException e) { + restErrorObject = eo; + } + text.append(restErrorObject.getErrorText()); + + // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n + // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the + // error, are ordered based on the error string. + int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%"); + text.append(" (msg=%").append(localDataIndex+1).append(") (rc=%").append(localDataIndex+2).append(")"); + + if (variables == null) + { + variables = new ArrayList<String>(); + } + + if (variables.size() < localDataIndex) { + ErrorLogHelper.logError("AAI_4011", "data missing for rest error"); + while (variables.size() < localDataIndex) { + variables.add("null"); + } + } + + // This will put the error code and error text into the right positions + if (are.getMessage() == null) { + variables.add(localDataIndex++, eo.getErrorText()); + } + else { + variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage()); + } + variables.add(localDataIndex, eo.getErrorCodeString()); + + try { + org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage responseMessage = factory.createInfoResponseMessagesResponseMessage(); + org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage.Variables infovariables = factory.createInfoResponseMessagesResponseMessageVariables(); + + responseMessage.setMessageId("INF" + eo.getRESTErrorCode()); + responseMessage.setText(text.toString()); + for (int i=0;i<variables.size();i++) + { + infovariables.getVariable().add(variables.get(i)); + } + + responseMessage.setVariables(infovariables); + responseMessages.getResponseMessage().add(responseMessage); + + } catch (Exception ex) { + LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex); + } + } + + info.setResponseMessages(responseMessages); + respObj = (Object) info; + + return respObj; + } + + + /** + * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error. + * The AAIRESTException may contain a different ErrorObject than that created with the REST error key. + * This allows lower level exception detail to be returned to the client to help troubleshoot the problem. + * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException. + * @param are must have a restError value whose numeric value must match what should be returned in the REST API + * @param variables optional list of variables to flesh out text in error string + * @return appropriately formatted JSON response per the REST API spec. + * @throws ErrorObjectFormatException + * @throws ErrorObjectNotFoundException + * @throws IOException + */ + public static String getRESTAPIPolicyErrorResponseXML(AAIException are, ArrayList<String> variables) { + + StringBuilder text = new StringBuilder(); + String response = null; + JAXBContext context = null; + + ErrorObject eo = are.getErrorObject(); + + int restErrorCode = Integer.parseInt(eo.getRESTErrorCode()); + ErrorObject restErrorObject; + try { + restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode); + } catch (ErrorObjectNotFoundException e) { + restErrorObject = eo; + } + + text.append(restErrorObject.getErrorText()); + + // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n + // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the + // error, are ordered based on the error string. + int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%"); + text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")"); + + if (variables == null) + { + variables = new ArrayList<String>(); + } + + if (variables.size() < localDataIndex) { + ErrorLogHelper.logError("AAI_4011", "data missing for rest error"); + while (variables.size() < localDataIndex) { + variables.add("null"); + } + } + + // This will put the error code and error text into the right positions + if (are.getMessage() == null) { + variables.add(localDataIndex++, eo.getErrorText()); + } + else { + variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage()); + } + variables.add(localDataIndex, eo.getErrorCodeString()); + + try { + if(eo.getCategory().equals("1")) { + + context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class); + Marshaller m = context.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); + + org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory(); + org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault(); + org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError(); + org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException(); + org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables(); + + policyException.setMessageId("POL" + eo.getRESTErrorCode()); + policyException.setText(text.toString()); + for (int i=0;i<variables.size();i++) + { + polvariables.getVariable().add(variables.get(i)); + } + policyException.setVariables(polvariables); + requestError.setPolicyException(policyException); + fault.setRequestError(requestError); + + StringWriter sw = new StringWriter(); + m.marshal(fault, sw); + + response = sw.toString(); + + } else { + + context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class); + Marshaller m = context.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); + + org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory(); + org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault(); + org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError(); + org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException(); + org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables(); + serviceException.setMessageId("POL" + eo.getRESTErrorCode()); + serviceException.setText(text.toString()); + for (int i=0;i<variables.size();i++) + { + svcvariables.getVariable().add(variables.get(i)); + } + serviceException.setVariables(svcvariables); + requestError.setServiceException(serviceException); + fault.setRequestError(requestError); + + StringWriter sw = new StringWriter(); + m.marshal(fault, sw); + + response = sw.toString(); + + } + } catch (Exception ex) { + LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex); + } + return response; + } + + public static void logException(AAIException e) { + final ErrorObject errorObject = e.getErrorObject(); + + MDC.put("severity", errorObject.getSeverity()); //TODO Use LoggingContext.severity(int severity) + + final String errorMessage = new StringBuilder() + .append(errorObject.getErrorText()) + .append(":") + .append(errorObject.getRESTErrorCode()) + .append(":") + .append(errorObject.getHTTPResponseCode()) + .append(":") + .append(e.getMessage()) + .toString(); + + LoggingContext.responseCode(errorObject.getErrorCodeString()); + LoggingContext.responseDescription(errorMessage); + LoggingContext.statusCode(StatusCode.ERROR); + + if (errorObject.getSeverity().equalsIgnoreCase("WARN")) + LOGGER.warn(errorMessage, e); + else if (errorObject.getSeverity().equalsIgnoreCase("ERROR")) + LOGGER.error(errorMessage, e); + else if (errorObject.getSeverity().equalsIgnoreCase("FATAL")) + LOGGER.error(errorMessage, e); + else if (errorObject.getSeverity().equals("INFO")) + LOGGER.info(errorMessage + ", " + e.getMessage()); + } + + public static void logError(String code) { + logError(code, ""); + } + + public static void logError(String code, String message) { + logException(new AAIException(code, message)); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObject.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObject.java new file mode 100644 index 00000000..dc355cc7 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObject.java @@ -0,0 +1,308 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import javax.ws.rs.core.Response.Status; + +/** + * + * Contains the definition of all error message fields to be mapped from the Error + * properties file + * + */ +public class ErrorObject { + + private String disposition; + private String category; + private String severity; + private Status httpResponseCode = Status.INTERNAL_SERVER_ERROR; // default + private String restErrorCode = "3002"; + private String errorCode; + private String errorText; + + /** + * Instantiates a new error object. + */ + public ErrorObject() { + super(); + } + + /** + * Creates an error object with the default HTTP Error Code (Status.INTERNAL_SERVER_ERROR) + * + * @param disposition the disposition + * @param category the category + * @param severity the severity + * @param httpResponseCode the http response code + * @param restErrorCode the rest error code + * @param errorCode the error code + * @param errorText the error text + */ + public ErrorObject(String disposition, String category, String severity, Integer httpResponseCode, String restErrorCode, String errorCode, String errorText) { + super(); + this.setDisposition(disposition); + this.setCategory(category); + this.severity = severity; + this.setHTTPResponseCode(httpResponseCode); + this.setRESTErrorCode(restErrorCode); + this.setErrorCode(errorCode); + this.setErrorText(errorText); + } + + // OLD STARTS HERE + + /** + * Instantiates a new error object. + * + * @param severity the severity + * @param errorCode the error code + * @param errorText the error text + * @param disposition the disposition + * @param category the category + */ + public ErrorObject(String severity, String errorCode, String errorText, String disposition, String category) { + this(severity, Status.INTERNAL_SERVER_ERROR, errorCode, errorText, disposition, category); + } + + /** + * Instantiates a new error object. + * + * @param severity the severity + * @param httpResponseCode the http response code + * @param errorCode the error code + * @param errorText the error text + * @param disposition the disposition + * @param category the category + */ + public ErrorObject(String severity, Integer httpResponseCode, String errorCode, String errorText, String disposition, String category) { + super(); + this.severity = severity; + this.setHTTPResponseCode(httpResponseCode); + this.setErrorCode(errorCode); + this.setErrorText(errorText); + this.setDisposition(disposition); + this.setCategory(category); + } + + /** + * Instantiates a new error object. + * + * @param severity the severity + * @param httpResponseCode the http response code + * @param errorCode the error code + * @param errorText the error text + * @param disposition the disposition + * @param category the category + */ + public ErrorObject(String severity, Status httpResponseCode, String errorCode, String errorText, String disposition, String category) { + super(); + this.severity = severity; + this.setHTTPResponseCode(httpResponseCode); + this.setErrorCode(errorCode); + this.setErrorText(errorText); + this.setDisposition(disposition); + this.setCategory(category); + } + + /** + * Gets the disposition. + * + * @return the disposition + */ + public String getDisposition() { + return disposition; + } + + /** + * Sets the disposition. + * + * @param disposition the new disposition + */ + public void setDisposition(String disposition) { + this.disposition = disposition; + } + + /** + * Gets the category. + * + * @return the category + */ + public String getCategory() { + return category; + } + + /** + * Sets the category. + * + * @param category the new category + */ + public void setCategory(String category) { + this.category = category; + } + + /** + * Gets the severity. + * + * @return the severity + */ + public String getSeverity() { + return severity; + } + + /** + * Sets the severity. + * + * @param severity the new severity + */ + public void setSeverity(String severity) { + this.severity = severity; + } + + /** + * Gets the error code. + * + * @return the error code + */ + public String getErrorCode() { + return errorCode; + } + + /** + * Sets the error code. + * + * @param errorCode the new error code + */ + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + /** + * Gets the HTTP response code. + * + * @return the HTTP response code + */ + public Status getHTTPResponseCode() { + return httpResponseCode; + } + + /** + * Sets the HTTP response code. + * + * @param httpResponseCode the new HTTP response code + */ + public void setHTTPResponseCode(Integer httpResponseCode) { + this.httpResponseCode = Status.fromStatusCode(httpResponseCode); + if (this.httpResponseCode == null) { + throw new IllegalArgumentException("setHTTPResponseCode was passed an invalid Integer value, fix error.properties or your code "+httpResponseCode); + } + } + + /** + * Sets the HTTP response code. + * + * @param httpResponseCode the new HTTP response code + */ + public void setHTTPResponseCode(String httpResponseCode) { + this.httpResponseCode = Status.fromStatusCode(Integer.valueOf(httpResponseCode)); + if (this.httpResponseCode == null) { + throw new IllegalArgumentException("setHTTPResponseCode was passed an invalid String value, fix error.properties or your code "+httpResponseCode); + } + } + + /** + * Sets the REST error code. + * + * @param restErrorCode the new REST error code + */ + public void setRESTErrorCode(String restErrorCode) { + this.restErrorCode = restErrorCode; + } + + /** + * Gets the REST error code. + * + * @return the REST error code + */ + public String getRESTErrorCode() { + return this.restErrorCode; + } + + /** + * Sets the HTTP response code. + * + * @param httpResponseCode the new HTTP response code + */ + public void setHTTPResponseCode(Status httpResponseCode) { + this.httpResponseCode = httpResponseCode; + if (this.httpResponseCode == null) { + throw new IllegalArgumentException("setHTTPResponseCode was passed an invalid String value, fix error.properties or your code "+httpResponseCode); + } + } + + /** + * Gets the error text. + * + * @return the error text + */ + public String getErrorText() { + return errorText; + } + + /** + * Sets the error text. + * + * @param errorText the new error text + */ + public void setErrorText(String errorText) { + this.errorText = errorText; + } + + /** + * Gets the error code string. This is also the string + * configured in Nagios to alert on + * + * @return the error code string + */ + // Get the X.Y.Z representation of the error code + public String getErrorCodeString() { + String prefix = null; + switch (disposition) { + default: + prefix = ""; + break; + case "5": + prefix = "ERR."; + break; + } + return prefix + disposition + "." + category + "." + errorCode; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "ErrorObject [errorCode="+ errorCode + ", errorText=" + errorText + + ", restErrorCode=" + restErrorCode + ", httpResponseCode="+ httpResponseCode + + ", severity=" + severity + ", disposition=" + disposition + ", category=" + category +"]"; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectFormatException.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectFormatException.java new file mode 100644 index 00000000..0bedfca2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectFormatException.java @@ -0,0 +1,30 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +public class ErrorObjectFormatException extends Exception { + + private static final long serialVersionUID = 3732705544448553685L; + + public ErrorObjectFormatException() { + super(); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectNotFoundException.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectNotFoundException.java new file mode 100644 index 00000000..28290542 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectNotFoundException.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +public class ErrorObjectNotFoundException extends Exception { + + private static final long serialVersionUID = 4115316781400786740L; + + public ErrorObjectNotFoundException() { + // TODO Auto-generated constructor stub + } + + public ErrorObjectNotFoundException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ErrorObjectNotFoundException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ErrorObjectNotFoundException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ErrorObjectNotFoundException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/LogFormatTools.java b/aai-core/src/main/java/org/openecomp/aai/logging/LogFormatTools.java new file mode 100644 index 00000000..78ade267 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/LogFormatTools.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +public class LogFormatTools { + + private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DATE_FORMAT) + .withZone(ZoneOffset.UTC); + + public static String getCurrentDateTime() { + return DTF.format(ZonedDateTime.now()); + } + + public static String toDate(long timestamp) { + return DTF.format(Instant.ofEpochMilli(timestamp)); + } + + public static long toTimestamp(String date) { + return ZonedDateTime.parse(date, DTF).toInstant().toEpochMilli(); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContext.java b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContext.java new file mode 100644 index 00000000..17d94e61 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContext.java @@ -0,0 +1,299 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.MDC; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Iterator; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class LoggingContext { + + public enum StatusCode { + COMPLETE, + ERROR + } + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LoggingContext.class); + + private static final String PREVIOUS_CONTEXT_KEY = "_PREVIOUS_CONTEXT"; + + //ECOMP Specific Log Event Fields + public static enum LoggingField { + START_TIME("startTime"), + REQUEST_ID("requestId"), + SERVICE_INSTANCE_ID("serviceInstanceId"), + SERVER_NAME("serverName"), + SERVICE_NAME("serviceName"), + PARTNER_NAME("partnerName"), + STATUS_CODE("statusCode"), + RESPONSE_CODE("responseCode"), + RESPONSE_DESCRIPTION("responseDescription"), + INSTANCE_UUID("instanceUUID"), + SEVERITY("severity"), + SERVER_IP_ADDRESS("serverIpAddress"), + ELAPSED_TIME("elapsedTime"), + SERVER("server"), + CLIENT_IP_ADDRESS("clientIpAddress"), + UNUSED("unused"), + PROCESS_KEY("processKey"), + CUSTOM_FIELD_1("customField1"), + CUSTOM_FIELD_2("customField2"), + CUSTOM_FIELD_3("customField3"), + CUSTOM_FIELD_4("customField4"), + + //ECOMP Specific Metric Log Event Fields + TARGET_ENTITY("targetEntity"), + + //A&AI Specific Log Event Fields + COMPONENT("component"), + STOP_WATCH_START("stopWatchStart"); + + private final String text; + + private LoggingField(final String text) { + this.text = text; + } + + public String toString() { + return text; + } + } + + + public static void init() { + LoggingContext.clear(); + LoggingContext.startTime(); + LoggingContext.server(); + LoggingContext.serverIpAddress(); + } + + private static void startTime() { + MDC.put(LoggingField.START_TIME.toString(), LogFormatTools.getCurrentDateTime()); + } + + public static void requestId(UUID requestId) { + MDC.put(LoggingField.REQUEST_ID.toString(), requestId.toString()); + } + + public static void requestId(String requestId) { + try { + MDC.put(LoggingField.REQUEST_ID.toString(), UUID.fromString(requestId).toString()); + } catch (IllegalArgumentException e) { + final UUID generatedRequestUuid = UUID.randomUUID(); + MDC.put(LoggingField.REQUEST_ID.toString(), generatedRequestUuid.toString()); + LOGGER.warn("Unable to use UUID " + requestId + " (Not formatted properly). Using generated UUID=" + generatedRequestUuid); + } + } + + public static void serviceInstanceId(String serviceInstanceId) { + MDC.put(LoggingField.SERVICE_INSTANCE_ID.toString(), serviceInstanceId); + } + + public static void serverName(String serverName) { + MDC.put(LoggingField.SERVER_NAME.toString(), serverName); + } + + public static void serviceName(String serviceName) { + MDC.put(LoggingField.SERVICE_NAME.toString(), serviceName); + } + + public static void partnerName(String partnerName) { + MDC.put(LoggingField.PARTNER_NAME.toString(), partnerName); + } + + public static void statusCode(LoggingContext.StatusCode statusCode) { + MDC.put(LoggingField.STATUS_CODE.toString(), statusCode.toString()); + } + + public static String responseCode() { + return (String) MDC.get(LoggingField.RESPONSE_CODE.toString()); + } + + public static void responseCode(String responseCode) { + MDC.put(LoggingField.RESPONSE_CODE.toString(), responseCode); + } + + public static void responseDescription(String responseDescription) { + MDC.put(LoggingField.RESPONSE_DESCRIPTION.toString(), responseDescription); + } + + public static void instanceUuid(UUID instanceUuid) { + MDC.put(LoggingField.INSTANCE_UUID.toString(), instanceUuid.toString()); + } + + public static void severity(int severity) { + MDC.put(LoggingField.SEVERITY.toString(), String.valueOf(severity)); + } + + private static void serverIpAddress() { + try { + MDC.put(LoggingField.SERVER_IP_ADDRESS.toString(), InetAddress.getLocalHost().getHostAddress()); + } catch (UnknownHostException e) { + LOGGER.warn("Unable to resolve server IP address - will not be displayed in logged events"); + } + } + + public static void elapsedTime(long elapsedTime, TimeUnit timeUnit) { + MDC.put(LoggingField.ELAPSED_TIME.toString(), String.valueOf(TimeUnit.MILLISECONDS.convert(elapsedTime, timeUnit))); + } + + private static void server() { + try { + MDC.put(LoggingField.SERVER.toString(), InetAddress.getLocalHost().getCanonicalHostName()); + } catch (UnknownHostException e) { + LOGGER.warn("Unable to resolve server IP address - hostname will not be displayed in logged events"); + } + } + + public static void clientIpAddress(InetAddress clientIpAddress) { + MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), clientIpAddress.getHostAddress()); + } + + public static void clientIpAddress(String clientIpAddress) { + try { + MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), InetAddress.getByName(clientIpAddress).getHostAddress()); + } catch (UnknownHostException e) { + //Ignore, will not be thrown since InetAddress.getByName(String) only + //checks the validity of the passed in string + } + } + + public static void unused(String unused) { + LOGGER.warn("Using field '" + LoggingField.UNUSED + "' (seems like this should go unused...)"); + MDC.put(LoggingField.UNUSED.toString(), unused); + } + + public static void processKey(String processKey) { + MDC.put(LoggingField.PROCESS_KEY.toString(), processKey); + } + + public static void customField1(String customField1) { + MDC.put(LoggingField.CUSTOM_FIELD_1.toString(), customField1); + } + + public static void customField2(String customField2) { + MDC.put(LoggingField.CUSTOM_FIELD_2.toString(), customField2); + } + + public static void customField3(String customField3) { + MDC.put(LoggingField.CUSTOM_FIELD_3.toString(), customField3); + } + + public static void customField4(String customField4) { + MDC.put(LoggingField.CUSTOM_FIELD_4.toString(), customField4); + } + + public static void component(String component) { + MDC.put(LoggingField.COMPONENT.toString(), component); + } + + public static void targetEntity(String targetEntity) { + MDC.put(LoggingField.TARGET_ENTITY.toString(), targetEntity); + } + + public static void stopWatchStart() { + MDC.put(LoggingField.STOP_WATCH_START.toString(), String.valueOf(System.nanoTime())); + } + + public static double stopWatchStop() { + final long stopWatchEnd = System.nanoTime(); + final Long stopWatchStart = Long.valueOf(MDC.get(LoggingField.STOP_WATCH_START.toString())); + + if (stopWatchStart == null) throw new StopWatchNotStartedException(); + + MDC.remove(LoggingField.STOP_WATCH_START.toString()); + + final double elapsedTimeMillis = (stopWatchEnd - stopWatchStart) / 1000.0 / 1000.0; + + LoggingContext.elapsedTime((long) elapsedTimeMillis, TimeUnit.MILLISECONDS); + + return elapsedTimeMillis; + } + + public static void put(String key, String value) { + MDC.put(key, value); + } + + public static void clear() { + MDC.clear(); + } + + public static void remove(String key) { + MDC.remove(key); + } + + public static void save() { + final JSONObject context = new JSONObject(); + + for (LoggingField field : LoggingField.values()) { + if (field == LoggingField.ELAPSED_TIME) continue; + + try { + context.put(field.toString(), MDC.get(field.toString())); + } catch (JSONException e) { + //Ignore - only occurs when the key is null (which can't happen) + // or the value is invalid (everything is converted to a string + // before it get put() to the MDC) + } + } + + MDC.put("_PREVIOUS_CONTEXT", context.toString()); + } + + public static void restore() { + + final String rawPreviousContext = MDC.get(PREVIOUS_CONTEXT_KEY); + + if (rawPreviousContext == null) { + throw new LoggingContextNotExistsException(); + } + + try { + final JSONObject previousContext = new JSONObject(rawPreviousContext); + + @SuppressWarnings("unchecked") + final Iterator<String> keys = previousContext.keys(); + + while (keys.hasNext()) { + final String key = keys.next(); + + try { + MDC.put(key, previousContext.getString(key)); + } catch (JSONException e) { + //Ignore, only occurs when the key is null (cannot happen) + // or the value is invalid (they are all strings) + } + } + + MDC.remove(PREVIOUS_CONTEXT_KEY); + } catch (JSONException e) { + //Ignore, the previousContext is serialized from a JSONObject + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContextNotExistsException.java b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContextNotExistsException.java new file mode 100644 index 00000000..caba1df3 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContextNotExistsException.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +public class LoggingContextNotExistsException extends RuntimeException { + + private static final long serialVersionUID = -4965807709525739623L; +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/StopWatch.java b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatch.java new file mode 100644 index 00000000..0812698c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatch.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +import org.openecomp.aai.logging.LoggingContext.LoggingField; + +public final class StopWatch { + + private StopWatch() {} + + public static void start() { + LoggingContext.stopWatchStart(); + } + + public static double stop() { + return LoggingContext.stopWatchStop(); + } + + public static void clear() { + LoggingContext.remove(LoggingField.STOP_WATCH_START.toString()); + LoggingContext.remove(LoggingField.ELAPSED_TIME.toString()); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/StopWatchNotStartedException.java b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatchNotStartedException.java new file mode 100644 index 00000000..30a90e8e --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatchNotStartedException.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.logging; + +public class StopWatchNotStartedException extends RuntimeException { + + private static final long serialVersionUID = -4540164295822859408L; + + public StopWatchNotStartedException() { + super(); + } + + public StopWatchNotStartedException(String message) { + super(message); + } + + public StopWatchNotStartedException(Throwable cause) { + super(cause); + } + + public StopWatchNotStartedException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AAIIdentityMapParseException.java b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AAIIdentityMapParseException.java new file mode 100644 index 00000000..75ff6c42 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AAIIdentityMapParseException.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.exceptions; + +import org.openecomp.aai.exceptions.AAIException; + +public class AAIIdentityMapParseException extends AAIException { + + private static final long serialVersionUID = -888876613879411865L; + + public AAIIdentityMapParseException(String message) { + super("AAI_3000", message); + } + + public AAIIdentityMapParseException(Throwable cause) { + super("AAI_3000",cause); + } + + public AAIIdentityMapParseException(String message, Throwable cause) { + super("AAI_3000", cause, message); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AmbiguousMapAAIException.java b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AmbiguousMapAAIException.java new file mode 100644 index 00000000..2f2354c4 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AmbiguousMapAAIException.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.exceptions; + +import org.openecomp.aai.exceptions.AAIException; + +public class AmbiguousMapAAIException extends AAIException { + + private static final long serialVersionUID = -878581771971431246L; + + public AmbiguousMapAAIException(String message) { + super("AAI_6146", message); + } + + public AmbiguousMapAAIException(Throwable cause) { + super("AAI_6146",cause); + } + + public AmbiguousMapAAIException(String message, Throwable cause) { + super("AAI_6146", cause, message); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/LegacyQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/LegacyQueryParser.java new file mode 100644 index 00000000..8da382f7 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/LegacyQueryParser.java @@ -0,0 +1,233 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.parsers.uri.Parsable; +import org.openecomp.aai.parsers.uri.URIParser; +import org.openecomp.aai.parsers.uri.URIToObject; +import org.openecomp.aai.query.builder.QueryBuilder; +import org.openecomp.aai.restcore.util.URITools; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.EdgeType; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * The Class LegacyQueryParser. + */ +public class LegacyQueryParser extends QueryParser implements Parsable { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LegacyQueryParser.class); + + private Introspector previous = null; + + /** + * Instantiates a new legacy query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + * @param uri the uri + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public LegacyQueryParser(Loader loader, QueryBuilder queryBuilder, URI uri) throws UnsupportedEncodingException, AAIException { + super(loader, queryBuilder, uri); + URIParser parser = new URIParser(loader, uri); + parser.parse(this); + } + + /** + * Instantiates a new legacy query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + * @param uri the uri + * @param queryParams the query params + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public LegacyQueryParser(Loader loader, QueryBuilder queryBuilder, URI uri, MultivaluedMap<String, String> queryParams) throws UnsupportedEncodingException, AAIException { + super(loader, queryBuilder, uri); + URIParser parser = new URIParser(loader, uri, queryParams); + parser.parse(this); + } + + /** + * Instantiates a new legacy query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + */ + public LegacyQueryParser(Loader loader, QueryBuilder queryBuilder) { + super(loader, queryBuilder); + } + + /** + * @throws AAIException + * @{inheritDoc} + */ + @Override + public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException { + if (previous != null) { + this.parentResourceType = previous.getDbName(); + queryBuilder.createEdgeTraversal(EdgeType.TREE, previous, obj); + } + if (previous == null) { + queryBuilder.createDBQuery(obj); + this.handleUriKeys(obj, uriKeys); + } else { + queryBuilder.createKeyQuery(obj); + this.handleUriKeys(obj, uriKeys); + } + previous = obj; + this.resultResource = obj.getDbName(); + } + + /** + * @{inheritDoc} + */ + @Override + public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) throws AAIException { + if (isFinalContainer) { + if (previous != null) { + this.parentResourceType = previous.getDbName(); + queryBuilder.createEdgeTraversal(EdgeType.TREE, previous, obj); + } + + if (previous == null) { + queryBuilder.createContainerQuery(obj); + queryBuilder.markParentBoundary(); + } + if (!uriKeys.isEmpty()) { + + try { + Introspector child = obj.newIntrospectorInstanceOfNestedProperty(obj.getChildName()); + this.handleUriKeys(child, uriKeys); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Skipping container child " + obj.getChildName() + " (Unknown Object)", e); + } + } + + this.resultResource = obj.getChildDBName(); + this.containerResource = obj.getName(); + } + } + + private void handleUriKeys(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException { + for (String key : uriKeys.keySet()) { + //to validate whether this property exists + if (!obj.hasProperty(key)) { + throw new AAIException("AAI_3000", "property: " + key + " not found on " + obj.getDbName()); + } + + List<String> values = uriKeys.get(key); + String dbPropertyName = key; + Map<String, String> linkedProperties = new HashMap<>(); + final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(key); + if (metadata.containsKey(PropertyMetadata.DATA_LINK)) { + linkedProperties.put(key, metadata.get(PropertyMetadata.DATA_LINK)); + } + if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) { + dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS); + } + + if (!linkedProperties.containsKey(key)) { + if (values.size() > 1) { + queryBuilder.getVerticesByIndexedProperty(dbPropertyName, obj.castValueAccordingToSchema(key, values)); + } else { + queryBuilder.getVerticesByIndexedProperty(dbPropertyName, obj.castValueAccordingToSchema(key, values.get(0))); + } + } + handleLinkedProperties(obj, uriKeys, linkedProperties); + } + } + private void handleLinkedProperties(Introspector obj, MultivaluedMap<String, String> uriKeys, Map<String, String> linkedProperties) throws AAIException { + + QueryBuilder[] builders = new QueryBuilder[linkedProperties.keySet().size()]; + Set<Entry<String, String>> entrySet = linkedProperties.entrySet(); + int i = 0; + Iterator<Entry<String, String>> itr = entrySet.iterator(); + + while (itr.hasNext()) { + Entry<String, String> entry = itr.next(); + Introspector child; + try { + child = new URIToObject(this.latestLoader, new URI(URITools.replaceTemplates(obj, entry.getValue(), PropertyMetadata.DATA_LINK, true).orElse(""))).getEntity(); + } catch (IllegalArgumentException | UnsupportedEncodingException | URISyntaxException e) { + throw new AAIException("AAI_4000", e); + } + List<String> values = uriKeys.get(entry.getKey()); + QueryBuilder builder = queryBuilder.newInstance(); + builder.createEdgeTraversal(EdgeType.TREE, obj, child); + if (values.size() > 1) { + builder.getVerticesByIndexedProperty(entry.getKey(), obj.castValueAccordingToSchema(entry.getKey(), values)); + } else { + builder.getVerticesByIndexedProperty(entry.getKey(), obj.castValueAccordingToSchema(entry.getKey(), values.get(0))); + } + + builders[i] = builder; + i++; + } + + queryBuilder.where(builders); + + } + + /** + * @{inheritDoc} + */ + @Override + public void processNamespace(Introspector obj) { + + } + + /** + * @{inheritDoc} + */ + @Override + public String getCloudRegionTransform() { + return "add"; + } + + /** + * @{inheritDoc} + */ + @Override + public boolean useOriginalLoader() { + return false; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/ObjectNameQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/ObjectNameQueryParser.java new file mode 100644 index 00000000..6ea38893 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/ObjectNameQueryParser.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +/** + * + */ +package org.openecomp.aai.parsers.query; + +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.query.builder.QueryBuilder; + +public class ObjectNameQueryParser extends QueryParser { + + public ObjectNameQueryParser(Loader loader, QueryBuilder queryBuilder, String objName) { + super(loader, queryBuilder); + this.resultResource = objName; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParser.java new file mode 100644 index 00000000..4fd6c230 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParser.java @@ -0,0 +1,145 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.net.URI; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.query.builder.QueryBuilder; + +/** + * The Class QueryParser. + */ +public abstract class QueryParser { + + protected Loader loader = null; + protected Loader latestLoader = null; + protected QueryBuilder queryBuilder = null; + + protected QueryBuilder parentQueryBuilder = null; + + protected URI uri = null; + + protected String resultResource = ""; + + protected String parentResourceType = ""; + + protected String containerResource = ""; + + /** + * Instantiates a new query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + * @param uri the uri + */ + protected QueryParser(Loader loader, QueryBuilder queryBuilder, URI uri) { + this.uri = uri; + this.queryBuilder = queryBuilder; + this.loader = loader; + this.latestLoader = LoaderFactory.createLoaderForVersion(loader.getModelType(), AAIProperties.LATEST); + } + + /** + * Instantiates a new query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + */ + protected QueryParser(Loader loader, QueryBuilder queryBuilder) { + this.queryBuilder = queryBuilder; + this.loader = loader; + this.latestLoader = LoaderFactory.createLoaderForVersion(loader.getModelType(), AAIProperties.LATEST); + } + + /** + * Gets the container type. + * + * @return the container type + */ + public String getContainerType() { + + return this.containerResource; + } + + /** + * Gets the parent result type. + * + * @return the parent result type + */ + public String getParentResultType() { + return this.parentResourceType; + } + + /** + * Gets the result type. + * + * @return the result type + */ + public String getResultType() { + return this.resultResource; + } + + /** + * Gets the query builder. + * + * @return the query builder + */ + public QueryBuilder getQueryBuilder() { + return this.queryBuilder; + } + + /** + * Gets the uri. + * + * @return the uri + */ + public URI getUri() { + return this.uri; + } + + /** + * Gets the parent query builder. + * + * @return the parent query builder + */ + public QueryBuilder getParentQueryBuilder() { + if (this.parentQueryBuilder != null) { + return this.parentQueryBuilder; + } else { + return this.queryBuilder; + } + } + + /** + * Checks if is dependent. + * + * @return true, if is dependent + */ + public boolean isDependent() { + return !this.queryBuilder.getQuery().toString().equals(this.queryBuilder.getParentQuery().getQuery().toString()); + } + +} + + diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParserStrategy.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParserStrategy.java new file mode 100644 index 00000000..ea875f22 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParserStrategy.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.query.builder.QueryBuilder; + +/** + * The Class QueryParserStrategy. + */ +public abstract class QueryParserStrategy { + + protected Loader loader = null; + + protected QueryBuilder builder = null; + + /** + * Instantiates a new query parser strategy. + * + * @param loader the loader + * @param builder the builder + */ + public QueryParserStrategy(Loader loader, QueryBuilder builder) { + + this.loader = loader; + this.builder = builder; + } + + /** + * Builds the URI parser. + * + * @param uri the uri + * @return the query parser + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public abstract QueryParser buildURIParser(URI uri) throws UnsupportedEncodingException, AAIException; + + /** + * Builds the URI parser. + * + * @param uri the uri + * @param queryParams the query params + * @return the query parser + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public abstract QueryParser buildURIParser(URI uri,MultivaluedMap<String, String> queryParams) throws UnsupportedEncodingException, AAIException; + + /** + * Builds the relationship parser. + * + * @param obj the obj + * @return the query parser + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public abstract QueryParser buildRelationshipParser(Introspector obj) throws UnsupportedEncodingException, AAIException; + + /** + * Builds an ObjectNameQueryParser. + * + * @param objName - the name of the object type as used in the database + * @return + */ + public abstract QueryParser buildObjectNameParser(String objName); +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/RelationshipQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/RelationshipQueryParser.java new file mode 100644 index 00000000..7904f756 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/RelationshipQueryParser.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.IntrospectorFactory; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.parsers.relationship.RelationshipToURI; +import org.openecomp.aai.parsers.uri.URIParser; +import org.openecomp.aai.query.builder.QueryBuilder; +import org.openecomp.aai.serialization.db.EdgeRules; +import com.google.common.base.CaseFormat; + +/** + * The Class RelationshipQueryParser. + */ +public class RelationshipQueryParser extends LegacyQueryParser { + + private Introspector relationship = null; + + private ModelType modelType = null; + + private EdgeRules edgeRules = null; + + /** + * Instantiates a new relationship query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + * @param obj the obj + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public RelationshipQueryParser(Loader loader, QueryBuilder queryBuilder, Introspector obj) throws UnsupportedEncodingException, AAIException { + super(loader, queryBuilder); + this.relationship = obj; + this.modelType = obj.getModelType(); + this.edgeRules = EdgeRules.getInstance(); + RelationshipToURI rToUri = new RelationshipToURI(loader, obj); + this.uri = rToUri.getUri(); + URIParser parser = new URIParser(loader, uri); + parser.parse(this); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/TraversalStrategy.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/TraversalStrategy.java new file mode 100644 index 00000000..664a3274 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/TraversalStrategy.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.query.builder.QueryBuilder; + +/** + * The Class TraversalStrategy. + */ +public class TraversalStrategy extends QueryParserStrategy { + + + /** + * Instantiates a new traversal strategy. + * + * @param loader the loader + * @param builder the builder + */ + public TraversalStrategy(Loader loader, QueryBuilder builder) { + super(loader, builder); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildURIParser(URI uri) throws UnsupportedEncodingException, AAIException { + return new LegacyQueryParser(loader, builder, uri); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildRelationshipParser(Introspector obj) throws UnsupportedEncodingException, AAIException { + return new RelationshipQueryParser(loader, builder, obj); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildURIParser(URI uri, MultivaluedMap<String, String> queryParams) + throws UnsupportedEncodingException, AAIException { + return new LegacyQueryParser(loader, builder, uri, queryParams); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildObjectNameParser(String objName) { + return new ObjectNameQueryParser(loader, builder, objName); + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueRelationshipQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueRelationshipQueryParser.java new file mode 100644 index 00000000..e1502c31 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueRelationshipQueryParser.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.io.UnsupportedEncodingException; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.relationship.RelationshipToURI; +import org.openecomp.aai.query.builder.QueryBuilder; + +/** + * The Class UniqueRelationshipQueryParser. + */ +public class UniqueRelationshipQueryParser extends UniqueURIQueryParser { + + + /** + * Instantiates a new unique relationship query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + * @param obj the obj + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + */ + public UniqueRelationshipQueryParser(Loader loader, QueryBuilder queryBuilder, Introspector obj) throws UnsupportedEncodingException, IllegalArgumentException, AAIException { + super(loader, queryBuilder); + RelationshipToURI rToUri = new RelationshipToURI(loader, obj); + UniqueURIQueryParser parser = new UniqueURIQueryParser(loader, queryBuilder, rToUri.getUri()); + this.containerResource = parser.getContainerType(); + this.resultResource = parser.getResultType(); + this.queryBuilder = parser.getQueryBuilder(); + this.parentQueryBuilder = parser.getParentQueryBuilder(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueStrategy.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueStrategy.java new file mode 100644 index 00000000..6d594778 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueStrategy.java @@ -0,0 +1,82 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.query.builder.QueryBuilder; + +/** + * The Class UniqueStrategy. + */ +public class UniqueStrategy extends QueryParserStrategy { + + + + /** + * Instantiates a new unique strategy. + * + * @param loader the loader + * @param builder the builder + */ + public UniqueStrategy(Loader loader, QueryBuilder builder) { + super(loader, builder); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildURIParser(URI uri) throws UnsupportedEncodingException, IllegalArgumentException, AAIException { + return new UniqueURIQueryParser(loader, builder, uri); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildRelationshipParser(Introspector obj) throws UnsupportedEncodingException, AAIException { + return new UniqueRelationshipQueryParser(loader, builder, obj); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildURIParser(URI uri, MultivaluedMap<String, String> queryParams) + throws UnsupportedEncodingException, AAIException { + return new LegacyQueryParser(loader, builder, uri, queryParams); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser buildObjectNameParser(String objName) { + return new ObjectNameQueryParser(loader, builder, objName); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueURIQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueURIQueryParser.java new file mode 100644 index 00000000..c62d0469 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueURIQueryParser.java @@ -0,0 +1,171 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.query; + +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriBuilder; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.uri.Parsable; +import org.openecomp.aai.parsers.uri.URIParser; +import org.openecomp.aai.parsers.uri.URIToDBKey; +import org.openecomp.aai.query.builder.QueryBuilder; +import org.openecomp.aai.serialization.db.EdgeType; + + +/** + * The Class UniqueURIQueryParser. + */ +public class UniqueURIQueryParser extends QueryParser implements Parsable { + + + private URIToDBKey dbKeyParser = null; + + private Introspector previous = null; + + private boolean endsInContainer = false; + + private Introspector finalContainer = null; + + private String parentName = ""; + + /** + * Instantiates a new unique URI query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + * @param uri the uri + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + */ + public UniqueURIQueryParser(Loader loader, QueryBuilder queryBuilder, URI uri) throws UnsupportedEncodingException, IllegalArgumentException, AAIException { + super(loader, queryBuilder, uri); + URIParser parser = new URIParser(loader, uri); + parser.parse(this); + + if (!endsInContainer) { + this.dbKeyParser = new URIToDBKey(loader, uri); + String dbKey = (String)dbKeyParser.getResult(); + queryBuilder.getVerticesByIndexedProperty("aai-unique-key", dbKey); + queryBuilder.markParentBoundary(); + + if (!(parentName.equals("") || parentName.equals(this.resultResource))) { + URI parentUri = UriBuilder.fromPath(uri.getRawPath().substring(0, uri.getRawPath().indexOf(containerResource))).build(); + this.dbKeyParser = new URIToDBKey(loader, parentUri); + this.parentQueryBuilder = queryBuilder.newInstance().getVerticesByIndexedProperty("aai-unique-key", (String)dbKeyParser.getResult()); + this.parentResourceType = parentName; + } + this.containerResource = ""; + } else { + URI parentUri = UriBuilder.fromPath(uri.getRawPath().substring(0, uri.getRawPath().indexOf(this.finalContainer.getDbName()))).build(); + this.dbKeyParser = new URIToDBKey(loader, parentUri); + String dbKey = (String)dbKeyParser.getResult(); + this.parentResourceType = parentName; + + if (!dbKey.equals("")) { + queryBuilder.getVerticesByIndexedProperty("aai-unique-key", dbKey); + queryBuilder.markParentBoundary(); + queryBuilder.createEdgeTraversal(EdgeType.TREE, previous, finalContainer); + + } + + queryBuilder.createContainerQuery(finalContainer); + + + } + } + + + /** + * Instantiates a new unique URI query parser. + * + * @param loader the loader + * @param queryBuilder the query builder + */ + public UniqueURIQueryParser(Loader loader, QueryBuilder queryBuilder) { + super(loader, queryBuilder); + } + + + /** + * @{inheritDoc} + */ + @Override + public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) { + this.resultResource = obj.getDbName(); + if (previous != null) { + this.parentName = previous.getDbName(); + } + this.previous = obj; + + + } + + + /** + * @{inheritDoc} + */ + @Override + public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) { + this.containerResource = obj.getName(); + if (previous != null) { + this.parentName = previous.getDbName(); + } + if (isFinalContainer) { + this.endsInContainer = true; + this.resultResource = obj.getChildDBName(); + + this.finalContainer = obj; + } + + } + + /** + * @{inheritDoc} + */ + @Override + public void processNamespace(Introspector obj) { + + } + + /** + * @{inheritDoc} + */ + @Override + public String getCloudRegionTransform() { + return "add"; + } + + /** + * @{inheritDoc} + */ + @Override + public boolean useOriginalLoader() { + return false; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/relationship/RelationshipToURI.java b/aai-core/src/main/java/org/openecomp/aai/parsers/relationship/RelationshipToURI.java new file mode 100644 index 00000000..e6d09fbe --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/relationship/RelationshipToURI.java @@ -0,0 +1,284 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.relationship; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.tinkerpop.gremlin.structure.Direction; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.IntrospectorFactory; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.parsers.exceptions.AAIIdentityMapParseException; +import org.openecomp.aai.parsers.exceptions.AmbiguousMapAAIException; +import org.openecomp.aai.parsers.uri.URIParser; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.serialization.db.EdgeRule; +import org.openecomp.aai.serialization.db.EdgeRules; +import org.openecomp.aai.serialization.db.EdgeType; +import org.openecomp.aai.workarounds.LegacyURITransformer; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * The Class RelationshipToURI. + */ +public class RelationshipToURI { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RelationshipToURI.class); + + private Introspector relationship = null; + + private Loader loader = null; + + private ModelType modelType = null; + + private EdgeRules edgeRules = null; + + private URI uri = null; + + private LegacyURITransformer urlTransform = null; + + /** + * Instantiates a new relationship to URI. + * + * @param loader the loader + * @param relationship the relationship + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public RelationshipToURI(Loader loader, Introspector relationship) throws UnsupportedEncodingException, AAIException { + this.relationship = relationship; + this.modelType = relationship.getModelType(); + this.edgeRules = EdgeRules.getInstance(); + this.loader = loader; + this.urlTransform = LegacyURITransformer.getInstance(); + + this.parse(); + + } + + /** + * Parses the. + * @throws + * + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + protected void parse() throws AAIException { + String relatedLink = (String)relationship.getValue("related-link"); + Optional<URI> result; + try { + if (loader.getVersion().compareTo(Version.v10) >= 0) { + result = processRelatedLink(relatedLink); + if (!result.isPresent()) { + result = processRelationshipData(); + } + } else { + result = processRelationshipData(); + if (!result.isPresent()) { + result = processRelatedLink(relatedLink); + } + } + if (result.isPresent()) { + this.uri = result.get(); + } else { + throw new AAIIdentityMapParseException("nothing to parse"); + } + } catch (UnsupportedEncodingException | URISyntaxException e) { + throw new AAIIdentityMapParseException("Could not parse relationship-list object: " + e.getMessage(), e); + } + + } + + private Optional<URI> processRelationshipData() throws AAIException, UnsupportedEncodingException { + Optional<URI> result = Optional.empty(); + StringBuilder uriBuilder = new StringBuilder(); + List<Object> data = (List<Object>)relationship.getValue("relationship-data"); + Introspector wrapper; + String key; + String value; + String objectType; + String propertyName; + String topLevelType = null; + String[] split; + HashMap<String, Introspector> map = new HashMap<>(); + for (Object datum : data) { + wrapper = IntrospectorFactory.newInstance(modelType, datum); + key = (String)wrapper.getValue("relationship-key"); + value = (String)wrapper.getValue("relationship-value"); + split = key.split("\\."); + if (split == null || split.length != 2) { + throw new AAIIdentityMapParseException("incorrect format for key must be of the form {node-type}.{property-name}"); + } + //check node name ok + //check prop name ok + objectType = split[0]; + propertyName = split[1]; + + try { + Introspector wrappedObj = loader.introspectorFromName(objectType); + + if (!wrappedObj.hasProperty(propertyName)) { + throw new AAIIdentityMapParseException("invalid property name in map: " + propertyName); + } + if (map.containsKey(objectType)) { + wrappedObj = map.get(objectType); + } else { + map.put(objectType, wrappedObj); + } + if (wrappedObj.getValue(propertyName) == null) { + wrappedObj.setValue(propertyName, value); + } else { + throw new AmbiguousMapAAIException("cannot determine where key/value goes: " + propertyName + "/" + value); + } + + if (wrappedObj.getMetadata(ObjectMetadata.NAMESPACE) != null) { + if (topLevelType == null) { + topLevelType = objectType; + } else if (!topLevelType.equals(objectType)){ + throw new AmbiguousMapAAIException("found two top level nodes of different types: " + topLevelType + " and " + objectType); + } + } + } catch (AAIUnknownObjectException e) { + throw new AAIIdentityMapParseException("invalid object name in map: " + objectType, e); + } + + } + if (!map.isEmpty()) { + String startType = (String)relationship.getValue("related-to"); + List<String> nodeTypes = new ArrayList<>(); + nodeTypes.addAll(map.keySet()); + + String displacedType; + for (int i = 0; i < nodeTypes.size(); i++) { + if (nodeTypes.get(i).equals(startType)) { + displacedType = nodeTypes.set(nodeTypes.size() - 1, startType); + nodeTypes.set(i, displacedType); + break; + } + } + sortRelationships(nodeTypes, startType, 1); + int startTypeIndex = nodeTypes.indexOf(startType); + int topLevelIndex = 0; + if (topLevelType != null) { + topLevelIndex = nodeTypes.indexOf(topLevelType); + } + //remove additional types not needed if they are there + List<String> nodeTypesSubList = nodeTypes; + if (topLevelIndex != 0) { + nodeTypesSubList = nodeTypes.subList(topLevelIndex, startTypeIndex+1); + } + for (String type : nodeTypesSubList) { + uriBuilder.append(map.get(type).getURI()); + } + if (!nodeTypesSubList.isEmpty()) { + result = Optional.of(UriBuilder.fromPath(uriBuilder.toString()).build()); + } + } + return result; + } + + private Optional<URI> processRelatedLink(String relatedLink) throws URISyntaxException, UnsupportedEncodingException, AAIIdentityMapParseException { + Optional<URI> result = Optional.empty(); + if (relatedLink != null) { + URI resultUri = new URI(relatedLink); + String path = resultUri.toString(); + resultUri = UriBuilder.fromPath(resultUri.getRawPath()).build(); + URIParser uriParser = new URIParser(this.loader, resultUri); + try { + uriParser.validate(); + } catch (AAIException e) { + throw new AAIIdentityMapParseException("related link is invalid: " + relatedLink, e); + } + result = Optional.of(resultUri); + } + + return result; + } + + /** + * Sort relationships. + * + * @param data the data + * @param startType the start type + * @param i the i + * @return true, if successful + * @throws AAIException + */ + private boolean sortRelationships(List<String> data, String startType, int i) throws AAIException { + + if (i == data.size()) { + return true; + } + int j; + String objectType; + String displacedObject; + EdgeRule rule; + Direction direction; + for (j = (data.size() - i) - 1; j >= 0; j--) { + objectType = data.get(j); + try { + rule = edgeRules.getEdgeRule(EdgeType.TREE, startType, objectType); + direction = rule.getDirection(); + if (direction != null) { + if ((rule.getIsParent().equals("true") && direction.equals(Direction.IN)) || (rule.getIsParent().equals("reverse") && direction.equals(Direction.OUT))) { + displacedObject = data.set((data.size() - i) - 1, data.get(j)); + data.set(j, displacedObject); + if (sortRelationships(data, objectType, i+1)) { + return true; + } else { + //continue to process + } + } + } + } catch (AAIException e) { + //ignore exceptions generated + continue; + } + } + + + return false; + } + + /** + * Gets the uri. + * + * @return the uri + */ + public URI getUri() { + return uri; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/Parsable.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/Parsable.java new file mode 100644 index 00000000..0d24b7c1 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/Parsable.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.uri; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; + +/** + * The Interface Parsable. + */ +public interface Parsable { + + /** + * Process object. + * + * @param obj the obj + * @param uriKeys the uri keys + * @throws AAIException + */ + public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException; + + /** + * Process container. + * + * @param obj the obj + * @param uriKeys the uri keys + * @param isFinalContainer the is final container + * @throws AAIException the AAI exception + */ + public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) throws AAIException; + + /** + * Process namespace. + * + * @param obj the obj + */ + public void processNamespace(Introspector obj); + + /** + * Gets the cloud region transform. + * + * @return the cloud region transform + */ + public String getCloudRegionTransform(); + + /** + * Use original loader. + * + * @return true, if successful + */ + public boolean useOriginalLoader(); +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIParser.java new file mode 100644 index 00000000..87439774 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIParser.java @@ -0,0 +1,249 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.uri; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.Set; + +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriBuilder; + +import org.springframework.web.util.UriUtils; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.util.AAIConfig; + + +/** + * The Class URIParser. + */ +public class URIParser { + + private URI uri = null; + + protected Loader loader = null; + + protected Loader originalLoader = null; + + private URI originalURI = null; + + private MultivaluedMap<String, String> queryParams = null; + + + /** + * Instantiates a new URI parser. + * + * @param loader the loader + * @param uri the uri + */ + public URIParser(Loader loader, URI uri) { + this.uri = uri; + + String currentVersion = "v7"; + this.originalLoader = loader; + try { + currentVersion = AAIConfig.get("aai.default.api.version"); + } catch (AAIException e) { + ErrorLogHelper.logException(e); + } + + //Load the latest version because we need it for cloud region + + this.loader = loader; + } + + /** + * Instantiates a new URI parser. + * + * @param loader the loader + * @param uri the uri + * @param queryParams the query params + */ + public URIParser(Loader loader, URI uri, MultivaluedMap<String, String> queryParams) { + this(loader, uri); + this.queryParams = queryParams; + } + + public Loader getLoader() { + + return this.loader; + + } + + /** + * Gets the original URI. + * + * @return the original URI + */ + public URI getOriginalURI() { + return this.originalURI; + } + + /** + * Parses the. + * + * @param p the p + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public void parse(Parsable p) throws UnsupportedEncodingException, AAIException { + try { + boolean isRelative = false; + uri = this.trimURI(uri); + uri = handleCloudRegion(p.getCloudRegionTransform(), uri); + if (p.useOriginalLoader()) { + this.loader = this.originalLoader; + } + this.originalURI = UriBuilder.fromPath(uri.getRawPath()).build(); + if (uri.getRawPath().startsWith("./")) { + uri = new URI(uri.getRawPath().replaceFirst("\\./", "")); + isRelative = true; + } + String[] parts = uri.getRawPath().split("/"); + Introspector validNamespaces = loader.introspectorFromName("inventory"); + Set<String> keys = null; + String part = ""; + Introspector previousObj = null; + + for (int i = 0; i < parts.length;) { + part = parts[i]; + Introspector introspector = null; + introspector = loader.introspectorFromName(part); + if (introspector != null) { + + //previous has current as property + if (previousObj != null && !previousObj.hasChild(introspector) && !previousObj.getDbName().equals("nodes")) { + throw new AAIException("AAI_3001", uri + " not a valid path. " + part + " not valid"); + } else if (previousObj == null) { + String abstractType = introspector.getMetadata(ObjectMetadata.ABSTRACT); + if (abstractType == null) { + abstractType = ""; + } + //first time through, make sure it starts from a namespace + //ignore abstract types + if (!isRelative && !abstractType.equals("true") && !validNamespaces.hasChild(introspector)) { + throw new AAIException("AAI_3000", uri + " not a valid path. It does not start from a valid namespace"); + } + } + + keys = introspector.getKeys(); + if (keys.size() > 0) { + MultivaluedMap<String, String> uriKeys = new MultivaluedHashMap<>(); + i++; + if (i == parts.length && queryParams != null) { + Set<String> queryKeys = queryParams.keySet(); + for (String key : queryKeys) { + uriKeys.put(key, queryParams.get(key)); + } + } else { + for (String key : keys) { + part = UriUtils.decode(parts[i], "UTF-8"); + + introspector.setValue(key, part); + + //skip this for further processing + i++; + } + } + + p.processObject(introspector, uriKeys); + + } else if (introspector.isContainer()) { + boolean isFinalContainer = i == parts.length-1; + MultivaluedMap<String, String> uriKeys = new MultivaluedHashMap<>(); + + if (isFinalContainer && queryParams != null) { + Set<String> queryKeys = queryParams.keySet(); + for (String key : queryKeys) { + uriKeys.put(key, queryParams.get(key)); + + } + } + p.processContainer(introspector, uriKeys, isFinalContainer); + + i++; + } else { + p.processNamespace(introspector); + //namespace case + i++; + } + previousObj = introspector; + } else { + //invalid item found should log + //original said bad path + throw new AAIException("AAI_3001", "invalid item found in path: " + part); + } + } + } catch (AAIException e) { + throw e; + } catch (Exception e) { + throw new AAIException("AAI_3001", e); + } + } + + public boolean validate() throws UnsupportedEncodingException, AAIException { + this.parse(new URIValidate()); + return true; + } + /** + * Handle cloud region. + * + * @param action the action + * @param uri the uri + * @return the uri + */ + protected URI handleCloudRegion(String action, URI uri) { + + return uri; + + } + + /** + * Trim URI. + * + * @param uri the uri + * @return the uri + */ + protected URI trimURI(URI uri) { + + String result = uri.getRawPath(); + if (result.startsWith("/")) { + result = result.substring(1, result.length()); + } + + if (result.endsWith("/")) { + result = result.substring(0, result.length() - 1); + } + + result = result.replaceFirst("aai/v\\d+/", ""); + + return UriBuilder.fromPath(result).build(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToDBKey.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToDBKey.java new file mode 100644 index 00000000..e286a532 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToDBKey.java @@ -0,0 +1,127 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.uri; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import com.google.common.base.Joiner; + +/** + * Creates a Unique database key from a URI + * + * The key is of the form node-type/key(s). + */ +public class URIToDBKey implements Parsable { + + + private List<String> dbKeys = new ArrayList<>(); + + /** + * Instantiates a new URI to DB key. + * + * @param loader the loader + * @param uri the uri + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public URIToDBKey(Loader loader, URI uri) throws IllegalArgumentException, AAIException, UnsupportedEncodingException { + + URIParser parser = new URIParser(loader, uri); + parser.parse(this); + } + /* + public URIToDBKey(Version version, String uri) throws IllegalArgumentException { + + super(version, uri); + try { + context = ModelInjestor.getInstance().getContextForVersion(version); + if (context == null) { + throw new IllegalArgumentException("could not find a context for version: " + version); + } + this.parse(); + } catch (Exception e) { + throw new IllegalArgumentException("uri not valid against our model: " + uri); + } + }*/ + + /** + * @{inheritDoc} + */ + @Override + public void processObject (Introspector obj, MultivaluedMap<String, String> uriKeys) { + + dbKeys.add(obj.getDbName()); + + for (String key : uriKeys.keySet()) { + dbKeys.add(uriKeys.getFirst(key).toString()); + } + } + + /** + * @{inheritDoc} + */ + @Override + public void processContainer (Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) { + + } + + /** + * @{inheritDoc} + */ + @Override + public void processNamespace(Introspector obj) { + + } + + /** + * @{inheritDoc} + */ + @Override + public String getCloudRegionTransform() { + return "add"; + } + + /** + * Gets the result. + * + * @return the result + */ + public Object getResult() { + return Joiner.on("/").join(this.dbKeys); + } + + /** + * @{inheritDoc} + */ + @Override + public boolean useOriginalLoader() { + return false; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToExtensionInformation.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToExtensionInformation.java new file mode 100644 index 00000000..26cf4a54 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToExtensionInformation.java @@ -0,0 +1,169 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.uri; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.restcore.HttpMethod; +import com.google.common.base.CaseFormat; +import com.google.common.base.Joiner; + +/** + * The Class URIToExtensionInformation. + */ +public class URIToExtensionInformation implements Parsable { + + private String namespace = ""; + + private String methodName = ""; + + private String topObject = ""; + + private List<String> pieces = null; + + /** + * Instantiates a new URI to extension information. + * + * @param loader the loader + * @param uri the uri + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public URIToExtensionInformation(Loader loader, URI uri) throws IllegalArgumentException, AAIException, UnsupportedEncodingException { + pieces = new ArrayList<>(); + URIParser parser = new URIParser(loader, uri); + parser.parse(this); + + this.methodName = Joiner.on("").join(this.pieces); + } + + /** + * @{inheritDoc} + */ + @Override + public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) { + String upperCamel = toUpperCamel(obj.getDbName()); + if (topObject.equals("")) { + topObject = upperCamel; + } + pieces.add(upperCamel); + + } + + /** + * @{inheritDoc} + */ + @Override + public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) { + pieces.add(toUpperCamel(obj.getName())); + } + + /** + * @{inheritDoc} + */ + @Override + public void processNamespace(Introspector obj) { + this.namespace = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, obj.getDbName()); + pieces.add(toUpperCamel(obj.getDbName())); + + } + + /** + * @{inheritDoc} + */ + @Override + public String getCloudRegionTransform() { + return "remove"; + } + + /** + * @{inheritDoc} + */ + @Override + public boolean useOriginalLoader() { + return true; + } + + /** + * Gets the namespace. + * + * @return the namespace + */ + public String getNamespace() { + return this.namespace; + } + + /** + * Gets the top object. + * + * @return the top object + */ + public String getTopObject() { + return this.topObject; + } + + /** + * Gets the method name. + * + * @param httpMethod the http method + * @param isPreprocess the is preprocess + * @return the method name + */ + public String getMethodName(HttpMethod httpMethod, boolean isPreprocess) { + String result = "Dynamic"; + if (httpMethod.equals(HttpMethod.PUT)) { + result += "Add"; + } else if (httpMethod.equals(HttpMethod.DELETE)) { + result += "Del"; + } else { + throw new IllegalArgumentException("http method not supported: " + httpMethod); + } + result += this.methodName; + + if (isPreprocess) { + result += "PreProc"; + } else { + result += "PostProc"; + } + return result; + } + + /** + * To upper camel. + * + * @param name the name + * @return the string + */ + private String toUpperCamel(String name) { + String result = ""; + result = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, name); + return result; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToObject.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToObject.java new file mode 100644 index 00000000..3242adb0 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToObject.java @@ -0,0 +1,229 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.uri; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.HashMap; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.schema.enums.ObjectMetadata; + +/** + * Given a URI this class returns an object, or series of nested objects + * with their keys populated based off the values in the URI. + * + * It populates the keys in the order they are listed in the model. + * + + * + */ +public class URIToObject implements Parsable { + + + private Introspector topEntity = null; + + private String topEntityName = null; + + private String entityName = null; + + private Introspector entity = null; + + private Introspector previous = null; + + private List<Object> parentList = null; + + private Version version = null; + private Loader loader = null; + private final HashMap<String, Introspector> relatedObjects; + + /** + * Instantiates a new URI to object. + * + * @param loader the loader + * @param uri the uri + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public URIToObject(Loader loader, URI uri) throws IllegalArgumentException, AAIException, UnsupportedEncodingException { + + URIParser parser = new URIParser(loader, uri); + this.relatedObjects = new HashMap<>(); + + parser.parse(this); + this.loader = parser.getLoader(); + this.version = loader.getVersion(); + } + public URIToObject(Loader loader, URI uri, HashMap<String, Introspector> relatedObjects) throws IllegalArgumentException, AAIException, UnsupportedEncodingException { + + URIParser parser = new URIParser(loader, uri); + this.relatedObjects = relatedObjects; + + parser.parse(this); + this.loader = parser.getLoader(); + this.version = loader.getVersion(); + + } + + /** + * @{inheritDoc} + */ + @Override + public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) { + + if (this.entityName == null) { + this.topEntityName = obj.getDbName(); + this.topEntity = obj; + } + this.entityName = obj.getDbName(); + this.entity = obj; + this.parentList = (List<Object>)this.previous.getValue(obj.getName()); + this.parentList.add(entity.getUnderlyingObject()); + + for (String key : uriKeys.keySet()) { + entity.setValue(key, uriKeys.getFirst(key)); + } + try { + if (relatedObjects.containsKey(entity.getObjectId())) { + Introspector relatedObject = relatedObjects.get(entity.getObjectId()); + String nameProp = relatedObject.getMetadata(ObjectMetadata.NAME_PROPS); + if (nameProp == null) { + nameProp = ""; + } + if (nameProp != null && !nameProp.equals("")) { + String[] nameProps = nameProp.split(","); + for (String prop : nameProps) { + entity.setValue(prop, relatedObject.getValue(prop)); + } + } + } + } catch (UnsupportedEncodingException e) { + } + this.previous = entity; + + } + + /** + * @{inheritDoc} + */ + @Override + public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) { + + this.previous = obj; + + if (this.entity != null) { + this.entity.setValue(obj.getName(), obj.getUnderlyingObject()); + } else { + this.entity = obj; + this.topEntity = obj; + } + + } + + /** + * @{inheritDoc} + */ + @Override + public void processNamespace(Introspector obj) { + + } + + /** + * @{inheritDoc} + */ + @Override + public String getCloudRegionTransform() { + return "add"; + } + + /** + * @{inheritDoc} + */ + @Override + public boolean useOriginalLoader() { + // TODO Auto-generated method stub + return false; + } + + /** + * Gets the top entity. + * + * @return the top entity + */ + public Introspector getTopEntity() { + return this.topEntity; + } + + /** + * Gets the entity. + * + * @return the entity + */ + public Introspector getEntity() { + return this.entity; + } + + /** + * Gets the parent list. + * + * @return the parent list + */ + public List<Object> getParentList() { + return this.parentList; + } + + /** + * Gets the entity name. + * + * @return the entity name + */ + public String getEntityName() { + return this.entityName; + } + + /** + * Gets the top entity name. + * + * @return the top entity name + */ + public String getTopEntityName() { + return this.topEntityName; + } + + /** + * Gets the object version. + * + * @return the object version + */ + public Version getObjectVersion() { + return this.loader.getVersion(); + } + public Loader getLoader() { + return this.loader; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToRelationshipObject.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToRelationshipObject.java new file mode 100644 index 00000000..6888dec6 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToRelationshipObject.java @@ -0,0 +1,171 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.uri; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.util.AAIApiServerURLBase; +import org.openecomp.aai.workarounds.LegacyURITransformer; + +/** + * Given a URI a Relationship Object is returned. + * + * The relationship-data objects are created from the keys in the model. + * The keys are processed in the order they appear in the model. + + * + */ +public class URIToRelationshipObject implements Parsable { + + private Introspector result = null; + + private LegacyURITransformer uriTransformer = null; + + private Version originalVersion = null; + + private Introspector relationship = null; + + private Loader loader = null; + + private String baseURL; + + private final URI uri; + /** + * Instantiates a new URI to relationship object. + * + * @param loader the loader + * @param uri the uri + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws MalformedURLException the malformed URL exception + */ + public URIToRelationshipObject(Loader loader, URI uri) throws AAIException { + + this.loader = loader; + uriTransformer = LegacyURITransformer.getInstance(); + originalVersion = loader.getVersion(); + + try { + relationship = loader.introspectorFromName("relationship"); + } catch (AAIUnknownObjectException e1) { + throw new RuntimeException("Fatal error - could not load relationship object!", e1); + } + + this.baseURL = AAIApiServerURLBase.get(originalVersion); + this.uri = uri; + + } + + public URIToRelationshipObject(Loader loader, URI uri, String baseURL) throws AAIException { + this(loader, uri); + + if (baseURL != null) { + this.baseURL = baseURL; + } + } + + + /** + * @{inheritDoc} + */ + @Override + public String getCloudRegionTransform(){ + return "remove"; + } + + /** + * @{inheritDoc} + */ + @Override + public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) { + + + for (String key : obj.getKeys()) { + try { + Introspector data = loader.introspectorFromName("relationship-data"); + data.setValue("relationship-key", obj.getDbName() + "." + key); + data.setValue("relationship-value", obj.getValue(key)); + + ((List<Object>)relationship.getValue("relationship-data")).add(data.getUnderlyingObject()); + } catch (AAIUnknownObjectException e) { + throw new RuntimeException("Fatal error - relationship-data object not found!"); + } + } + relationship.setValue("related-to", obj.getDbName()); + } + + /** + * @{inheritDoc} + */ + @Override + public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) { + + } + + /** + * @{inheritDoc} + */ + @Override + public void processNamespace(Introspector obj) { + + } + + /** + * @{inheritDoc} + */ + @Override + public boolean useOriginalLoader() { + return true; + } + + /** + * Gets the result. + * + * @return the result + * @throws AAIException + * @throws UnsupportedEncodingException + * @throws URISyntaxException + */ + public Introspector getResult() throws UnsupportedEncodingException, AAIException, URISyntaxException { + URIParser parser = new URIParser(this.loader, this.uri); + parser.parse(this); + URI originalUri = parser.getOriginalURI(); + + URI relatedLink = new URI(this.baseURL + this.originalVersion + "/" + originalUri); + this.relationship.setValue("related-link", relatedLink); + + + this.result = relationship; + return this.result; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIValidate.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIValidate.java new file mode 100644 index 00000000..1a7ac0b2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIValidate.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.parsers.uri; + +import javax.ws.rs.core.MultivaluedMap; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; + +class URIValidate implements Parsable { + + @Override + public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException { + //NO-OP + //just want to make sure this URI has valid tokens + } + + @Override + public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) + throws AAIException { + //NO-OP + //just want to make sure this URI has valid tokens + + } + + @Override + public void processNamespace(Introspector obj) { + //NO-OP + //just want to make sure this URI has valid tokens + + } + + @Override + public String getCloudRegionTransform() { + return "none"; + } + + @Override + public boolean useOriginalLoader() { + + return true; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GraphTraversalBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GraphTraversalBuilder.java new file mode 100644 index 00000000..336114f0 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GraphTraversalBuilder.java @@ -0,0 +1,491 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.query.builder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.EdgeRule; +import org.openecomp.aai.serialization.db.EdgeRules; +import org.openecomp.aai.serialization.db.EdgeType; +import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException; + +/** + * The Class GraphTraversalBuilder. + */ +public abstract class GraphTraversalBuilder extends QueryBuilder { + + protected GraphTraversal<Vertex, Vertex> traversal = null; + protected Admin<Vertex, Vertex> completeTraversal = null; + private EdgeRules edgeRules = EdgeRules.getInstance(); + + protected int parentStepIndex = 0; + protected int containerStepIndex = 0; + protected int stepIndex = 0; + + /** + * Instantiates a new graph traversal builder. + * + * @param loader the loader + */ + public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) { + super(loader, source); + + traversal = __.start(); + + } + + /** + * Instantiates a new graph traversal builder. + * + * @param loader the loader + * @param start the start + */ + public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); + + traversal = __.start(); + + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByIndexedProperty(String key, Object value) { + + return this.getVerticesByProperty(key, value); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByIndexedProperty(String key, List<?> values) { + return this.getVerticesByProperty(key, values); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByProperty(String key, Object value) { + + //this is because the index is registered as an Integer + value = this.correctObjectType(value); + + traversal.has(key, value); + + stepIndex++; + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByProperty(final String key, final List<?> values) { + + //this is because the index is registered as an Integer + List<Object> correctedValues = new ArrayList<>(); + for (Object item : values) { + correctedValues.add(this.correctObjectType(item)); + } + + traversal.has(key, P.within(correctedValues)); + + stepIndex++; + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) { + traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType); + stepIndex++; + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) { + + for (String key : map.keySet()) { + traversal.has(key, map.get(key)); + stepIndex++; + } + traversal.has(AAIProperties.NODE_TYPE, type); + stepIndex++; + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder createDBQuery(Introspector obj) { + this.createKeyQuery(obj); + this.createContainerQuery(obj); + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder createKeyQuery(Introspector obj) { + Set<String> keys = obj.getKeys(); + Object val; + for (String key : keys) { + val = obj.getValue(key); + Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS); + if (metadata.isPresent()) { + //use the db name for the field rather than the object model + key = metadata.get(); + } + if (val != null) { + //this is because the index is registered as an Integer + if (val.getClass().equals(Long.class)) { + traversal.has(key,new Integer(val.toString())); + } else { + traversal.has(key, val); + } + stepIndex++; + } + } + return this; + } + + @Override + public QueryBuilder exactMatchQuery(Introspector obj) { + this.createKeyQuery(obj); + allPropertiesQuery(obj); + this.createContainerQuery(obj); + return this; + } + + private void allPropertiesQuery(Introspector obj) { + Set<String> props = obj.getProperties(); + Set<String> keys = obj.getKeys(); + Object val; + for (String prop : props) { + if (obj.isSimpleType(prop) && !keys.contains(prop)) { + val = obj.getValue(prop); + if (val != null) { + Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS); + if (metadata.isPresent()) { + //use the db name for the field rather than the object model + prop = metadata.get(); + } + //this is because the index is registered as an Integer + if (val != null && val.getClass().equals(Long.class)) { + traversal.has(prop,new Integer(val.toString())); + } else { + traversal.has(prop, val); + } + stepIndex++; + } + } + } + } + + /** + * @{inheritDoc} + */ + @Override + + public QueryBuilder createContainerQuery(Introspector obj) { + String type = obj.getChildDBName(); + String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT); + if (abstractType != null) { + String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(","); + traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors)); + } else { + traversal.has(AAIProperties.NODE_TYPE, type); + } + stepIndex++; + markContainer(); + return this; + } + + /** + * @throws NoEdgeRuleFoundException + * @throws AAIException + * @{inheritDoc} + */ + @Override + public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException { + String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT); + if ("true".equals(isAbstractType)) { + markParentBoundary(); + traversal.union(handleAbstractEdge(type, parent, child)); + stepIndex += 1; + } else { + this.edgeQuery(type, parent, child); + } + return this; + + } + + private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException { + String childName = child.getDbName(); + String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS); + String[] inheritors = inheritorMetadata.split(","); + Traversal<Vertex, Vertex>[] unionTraversals = new Traversal[inheritors.length]; + int traversalIndex = 0; + for (int i = 0; i < inheritors.length; i++) { + String inheritor = inheritors[i]; + if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) { + EdgeRule rule = edgeRules.getEdgeRule(type, inheritor, childName); + GraphTraversal<Vertex, Vertex> innerTraversal = __.start(); + if (rule.getDirection().equals(Direction.OUT)) { + innerTraversal.out(rule.getLabel()); + } else { + innerTraversal.in(rule.getLabel()); + } + innerTraversal.has(AAIProperties.NODE_TYPE, childName); + unionTraversals[traversalIndex] = innerTraversal; + traversalIndex++; + } + } + if (traversalIndex < inheritors.length) { + Traversal<Vertex, Vertex>[] temp = Arrays.copyOfRange(unionTraversals, 0, traversalIndex); + unionTraversals = temp; + } + return unionTraversals; + } + /** + * @throws NoEdgeRuleFoundException + * @throws AAIException + * @{inheritDoc} + */ + @Override + public QueryBuilder createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException { + + String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null); + Introspector parentObj = loader.introspectorFromName(nodeType); + this.edgeQuery(type, parentObj, child); + return this; + + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder union(QueryBuilder... builder) { + GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length]; + for (int i = 0; i < builder.length; i++) { + traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery(); + } + this.traversal.union(traversals); + stepIndex++; + + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder where(QueryBuilder... builder) { + GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length]; + for (int i = 0; i < builder.length; i++) { + this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery()); + stepIndex++; + } + + return this; + } + + /** + * Edge query. + * + * @param outType the out type + * @param inType the in type + * @throws NoEdgeRuleFoundException + * @throws AAIException + */ + private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException { + String outType = outObj.getDbName(); + String inType = inObj.getDbName(); + + if (outObj.isContainer()) { + outType = outObj.getChildDBName(); + } + if (inObj.isContainer()) { + inType = inObj.getChildDBName(); + } + markParentBoundary(); + EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType); + if (rule.getDirection().equals(Direction.OUT)) { + traversal.out(rule.getLabel()); + } else { + traversal.in(rule.getLabel()); + } + stepIndex++; + this.createContainerQuery(inObj); + } + + @Override + public QueryBuilder limit(long amount) { + traversal.limit(amount); + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public <T> T getQuery() { + return (T)this.traversal; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getParentQuery() { + + return cloneQueryAtStep(parentStepIndex); + } + + @Override + public QueryBuilder getContainerQuery() { + + if (this.parentStepIndex == 0) { + return removeQueryStepsBetween(0, containerStepIndex); + } else { + return cloneQueryAtStep(containerStepIndex); + } + } + + /** + * @{inheritDoc} + */ + @Override + public void markParentBoundary() { + parentStepIndex = stepIndex; + } + + @Override + public void markContainer() { + containerStepIndex = stepIndex; + } + + + /** + * @{inheritDoc} + */ + @Override + public Vertex getStart() { + return this.start; + } + + protected int getParentStepIndex() { + return parentStepIndex; + } + + protected int getContainerStepIndex() { + return containerStepIndex; + } + + protected int getStepIndex() { + return stepIndex; + } + + protected abstract QueryBuilder cloneQueryAtStep(int index); + /** + * end is exclusive + * + * @param start + * @param end + * @return + */ + protected abstract QueryBuilder removeQueryStepsBetween(int start, int end); + + private void executeQuery() { + + Admin<Vertex, Vertex> admin; + if (start != null) { + admin = source.V(start).asAdmin(); + } else { + admin = source.V().asAdmin(); + + } + + TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin); + + this.completeTraversal = admin; + } + + @Override + public boolean hasNext() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return this.completeTraversal.hasNext(); + } + + @Override + public Vertex next() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return this.completeTraversal.next(); + } + + @Override + public List<Vertex> toList() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return this.completeTraversal.toList(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineBuilder.java new file mode 100644 index 00000000..d06e1e18 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineBuilder.java @@ -0,0 +1,214 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +/* +package org.openecomp.aai.query.builder; + +import java.util.LinkedHashMap; +import java.util.List; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.serialization.db.EdgeRule; +import org.openecomp.aai.serialization.db.EdgeRules; + +public abstract class GremlinPipelineBuilder extends QueryBuilder { + + private GremlinPipeline pipeline = null; + private EdgeRules edgeRules = EdgeRules.getInstance(); + private int parentStepIndex = 0; + private int stepIndex = 0; + + public GremlinPipelineBuilder(Loader loader) { + super(loader); + + pipeline = new GremlinPipeline(new IdentityPipe()).V(); + + } + + public GremlinPipelineBuilder(Loader loader, Vertex start) { + super(loader, start); + + pipeline = new GremlinPipeline(start); + + } + + @Override + public QueryBuilder getVerticesByIndexedProperty(String key, Object value) { + + return this.getVerticesByProperty(key, value); + } + + @Override + public QueryBuilder getVerticesByProperty(String key, Object value) { + + //this is because the index is registered as an Integer + if (value != null && value.getClass().equals(Long.class)) { + pipeline.has(key,new Integer(value.toString())); + } else { + pipeline.has(key, value); + } + stepIndex++; + return this; + } + + @Override + public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) { + pipeline.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType); + stepIndex++; + return this; + } + + @Override + public QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) { + + for (String key : map.keySet()) { + pipeline.has(key, map.get(key)); + stepIndex++; + } + pipeline.has(AAIProperties.NODE_TYPE, type); + stepIndex++; + return this; + } + + @Override + public QueryBuilder createDBQuery(Introspector obj) { + this.createKeyQuery(obj); + this.createContainerQuery(obj); + return this; + } + + @Override + public QueryBuilder createKeyQuery(Introspector obj) { + List<String> keys = obj.getKeys(); + Object val = null; + for (String key : keys) { + val = obj.getValue(key); + //this is because the index is registered as an Integer + if (val != null && val.getClass().equals(Long.class)) { + pipeline.has(key,new Integer(val.toString())); + } else { + pipeline.has(key, val); + } + stepIndex++; + } + return this; + } + + @Override + + public QueryBuilder createContainerQuery(Introspector obj) { + String type = obj.getChildDBName(); + String abstractType = obj.getMetadata("abstract"); + if (abstractType != null) { + String[] inheritors = obj.getMetadata("inheritors").split(","); + GremlinPipeline[] pipes = new GremlinPipeline[inheritors.length]; + for (int i = 0; i < inheritors.length; i++) { + pipes[i] = new GremlinPipeline(new IdentityPipe()).has(AAIProperties.NODE_TYPE, inheritors[i]); + } + pipeline.or(pipes); + } else { + pipeline.has(AAIProperties.NODE_TYPE, type); + } + stepIndex++; + return this; + } + + @Override + public QueryBuilder createEdgeTraversal(Introspector parent, Introspector child) { + String parentName = parent.getDbName(); + String childName = child.getDbName(); + String isAbstractType = parent.getMetadata("abstract"); + if ("true".equals(isAbstractType)) { + formBoundary(); + pipeline.outE().has("isParent", true).inV(); + } else { + if (parent.isContainer()) { + parentName = parent.getChildDBName(); + } + if (child.isContainer()) { + childName = child.getChildDBName(); + } + this.edgeQuery(parentName, childName); + } + return this; + + } + + @Override + public QueryBuilder createEdgeTraversal(Vertex parent, Introspector child) { + + String nodeType = parent.getProperty(AAIProperties.NODE_TYPE); + this.edgeQuery(nodeType, child.getDbName()); + return this; + + } + + private void edgeQuery(String outType, String inType) { + formBoundary(); + EdgeRule rule; + String label = ""; + try { + rule = edgeRules.getEdgeRule(outType, inType); + label = rule.getLabel(); + } catch (AAIException e) { + // TODO Auto-generated catch block + } + pipeline = pipeline.out(label); + stepIndex++; + } + + @Override + public Object getQuery() { + return this.pipeline; + } + + @Override + public Object getParentQuery() { + GremlinPipeline parent = new GremlinPipeline(); + if (parentStepIndex == 0) { + parentStepIndex = stepIndex; + } + List<Pipe> pipes = this.pipeline.getPipes(); + //add two for the garbage identity pipes + for (int i = 0; i < parentStepIndex + 2; i++) { + parent.add(pipes.get(i)); + } + + return parent; + } + + @Override + public void formBoundary() { + parentStepIndex = stepIndex; + } + + + @Override + public Vertex getStart() { + return this.start; + } + +} +*/ diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineTraversal.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineTraversal.java new file mode 100644 index 00000000..c8147ed4 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineTraversal.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +/* +package org.openecomp.aai.query.builder; + +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.query.TraversalStrategy; + +public class GremlinPipelineTraversal extends GremlinPipelineBuilder { + + public GremlinPipelineTraversal(Loader loader) { + super(loader); + this.factory = new TraversalStrategy(this.loader, this); + } + + public GremlinPipelineTraversal(Loader loader, Vertex start) { + super(loader, start); + this.factory = new TraversalStrategy(this.loader, this); + } + + @Override + public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri); + } + + @Override + public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException { + return factory.buildRelationshipParser(relationship); + } + + @Override + public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) + throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri, queryParams); + } + + @Override + public QueryBuilder newInstance(Vertex start) { + return new GremlinPipelineTraversal(loader, start); + } + + @Override + public QueryBuilder newInstance() { + return new GremlinPipelineTraversal(loader); + } + +} +*/ diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinQueryBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinQueryBuilder.java new file mode 100644 index 00000000..9c313ca8 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinQueryBuilder.java @@ -0,0 +1,416 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.query.builder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.restcore.search.GremlinGroovyShellSingleton; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.serialization.db.EdgeRule; +import org.openecomp.aai.serialization.db.EdgeRules; +import org.openecomp.aai.serialization.db.EdgeType; +import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException; +import com.google.common.base.Joiner; + +/** + * The Class GremlinQueryBuilder. + */ +public abstract class GremlinQueryBuilder extends QueryBuilder { + + private EdgeRules edgeRules = EdgeRules.getInstance(); + private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance(); + private GraphTraversal<?, ?> completeTraversal = null; + protected List<String> list = null; + + protected int parentStepIndex = 0; + protected int containerStepIndex = 0; + protected int stepIndex = 0; + + /** + * Instantiates a new gremlin query builder. + * + * @param loader the loader + */ + public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) { + super(loader, source); + list = new ArrayList<String>(); + } + + /** + * Instantiates a new gremlin query builder. + * + * @param loader the loader + * @param start the start + */ + public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); + list = new ArrayList<String>(); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder createDBQuery(Introspector obj) { + this.createKeyQuery(obj); + this.createContainerQuery(obj); + return this; + } + + @Override + public QueryBuilder exactMatchQuery(Introspector obj) { + // TODO not implemented because this is implementation is no longer used + this.createKeyQuery(obj); + //allPropertiesQuery(obj); + this.createContainerQuery(obj); + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByIndexedProperty(String key, Object value) { + return this.getVerticesByProperty(key, value); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByIndexedProperty(String key, List<?> values) { + return this.getVerticesByProperty(key, values); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByProperty(String key, Object value) { + + String term = ""; + if (value != null && !value.getClass().getName().equals("java.lang.String")) { + term = value.toString(); + } else { + term = "'" + value + "'"; + } + list.add(".has('" + key + "', " + term + ")"); + stepIndex++; + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByProperty(String key, List<?> values) { + + String term = ""; + String predicate = "P.within(#!#argument#!#)"; + List<String> arguments = new ArrayList<>(); + for (Object item : values) { + if (item != null && !item.getClass().getName().equals("java.lang.String")) { + arguments.add(item.toString()); + } else { + arguments.add("'" + item + "'"); + } + } + String argument = Joiner.on(",").join(arguments); + predicate = predicate.replace("#!#argument#!#", argument); + list.add(".has('" + key + "', " + predicate + ")"); + stepIndex++; + return this; + } + + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) { + /* + String query = ".has('aai-node-type', '" + childType + "')"; + + return this.processGremlinQuery(parentKey, parentValue, query); + */ + //TODO + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) { + + for (String key : map.keySet()) { + list.add(".has('" + key + "', '" + map.get(key) + "')"); + stepIndex++; + } + list.add(".has('aai-node-type', '" + type + "')"); + stepIndex++; + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder createKeyQuery(Introspector obj) { + Set<String> keys = obj.getKeys(); + + for (String key : keys) { + + this.getVerticesByProperty(key, obj.<Object>getValue(key)); + + } + return this; + } + + /** + * @throws NoEdgeRuleFoundException + * @throws AAIException + * @{inheritDoc} + */ + @Override + public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException { + String parentName = parent.getDbName(); + String childName = child.getDbName(); + if (parent.isContainer()) { + parentName = parent.getChildDBName(); + } + if (child.isContainer()) { + childName = child.getChildDBName(); + } + this.edgeQuery(type, parentName, childName); + return this; + + } + + /** + * @throws NoEdgeRuleFoundException + * @throws AAIException + * @{inheritDoc} + */ + @Override + public QueryBuilder createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException { + String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null); + this.edgeQuery(type, nodeType, child.getDbName()); + + return this; + + } + + /** + * Edge query. + * + * @param outType the out type + * @param inType the in type + * @throws NoEdgeRuleFoundException + * @throws AAIException + */ + private void edgeQuery(EdgeType type, String outType, String inType) throws AAIException, NoEdgeRuleFoundException { + markParentBoundary(); + EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType); + if (rule.getDirection().equals(Direction.OUT)) { + list.add(".out('" + rule.getLabel() + "')"); + } else { + list.add(".in('" + rule.getLabel() + "')"); + } + list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')"); + stepIndex += 2; + } + @Override + public QueryBuilder limit(long amount) { + list.add(".limit(" + amount + ")"); + return this; + } + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder createContainerQuery(Introspector obj) { + String type = obj.getChildDBName(); + String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT); + if (abstractType != null) { + String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(","); + String[] wrapped = new String[inheritors.length]; + StringBuilder command = new StringBuilder(); + command.append("P.within("); + for (int i = 0; i < inheritors.length; i++) { + wrapped[i] = "'" + inheritors[i] + "'"; + } + command.append(Joiner.on(",").join(wrapped)); + command.append(")"); + list.add(".has('aai-node-type', " + command + ")"); + + } else { + list.add(".has('aai-node-type', '" + type + "')"); + } + stepIndex++; + this.markContainer(); + return this; + } + + @Override + public QueryBuilder union(QueryBuilder... builder) { + markParentBoundary(); + String[] traversals = new String[builder.length]; + StringBuilder command = new StringBuilder(); + for (int i = 0; i < builder.length; i++) { + traversals[i] = "__" + (String)builder[i].getQuery(); + } + command.append(".union("); + command.append(Joiner.on(",").join(traversals)); + command.append(")"); + list.add(command.toString()); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder where(QueryBuilder... builder) { + markParentBoundary(); + List<String> traversals = new ArrayList<>(); + for (int i = 0; i < builder.length; i++) { + traversals.add(".where(__" + (String)builder[i].getQuery() + ")"); + stepIndex++; + } + list.addAll(traversals); + + + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getParentQuery() { + return cloneQueryAtStep(parentStepIndex); + } + + @Override + public QueryBuilder getContainerQuery() { + return cloneQueryAtStep(containerStepIndex); + } + + /** + * @{inheritDoc} + */ + @Override + public <T> T getQuery() { + StringBuilder sb = new StringBuilder(); + + for (String piece : this.list) { + sb.append(piece); + } + + return (T)sb.toString(); + } + + /** + * @{inheritDoc} + */ + @Override + public void markParentBoundary() { + parentStepIndex = stepIndex; + } + + @Override + public void markContainer() { + this.containerStepIndex = stepIndex; + } + + protected abstract QueryBuilder cloneQueryAtStep(int index); + /** + * @{inheritDoc} + */ + @Override + public Vertex getStart() { + return this.start; + } + + protected int getParentStepIndex() { + return parentStepIndex; + } + + protected int getContainerStepIndex() { + return containerStepIndex; + } + + protected int getStepIndex() { + return stepIndex; + } + + private void executeQuery() { + String queryString = "g" + Joiner.on("").join(list); + Map<String, Object> params = new HashMap<>(); + if (this.start == null) { + params.put("g", source.V()); + } else { + params.put("g", source.V(this.start)); + } + this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params); + } + @Override + public boolean hasNext() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return this.completeTraversal.hasNext(); + } + + @Override + public Vertex next() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return (Vertex)this.completeTraversal.next(); + } + + @Override + public List<Vertex> toList() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return (List<Vertex>)this.completeTraversal.toList(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinTraversal.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinTraversal.java new file mode 100644 index 00000000..5b70d43d --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinTraversal.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.query.builder; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.query.TraversalStrategy; + +/** + * The Class GremlinTraversal. + */ +public class GremlinTraversal extends GremlinQueryBuilder { + + /** + * Instantiates a new gremlin traversal. + * + * @param loader the loader + */ + public GremlinTraversal(Loader loader, GraphTraversalSource source) { + super(loader, source); + this.factory = new TraversalStrategy(this.loader, this); + } + + /** + * Instantiates a new gremlin traversal. + * + * @param loader the loader + * @param start the start + */ + public GremlinTraversal(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); + this.factory = new TraversalStrategy(this.loader, this); + } + + protected GremlinTraversal(List<String> traversal, Loader loader, GraphTraversalSource source, GremlinQueryBuilder gtb) { + super(loader, source); + this.list = traversal; + this.stepIndex = gtb.getStepIndex(); + this.parentStepIndex = gtb.getParentStepIndex(); + this.containerStepIndex = gtb.getContainerStepIndex(); + this.factory = new TraversalStrategy(this.loader, this); + this.start = gtb.getStart(); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException { + return factory.buildRelationshipParser(relationship); + } + + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) + throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri, queryParams); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromObjectName(String objName) { + return factory.buildObjectNameParser(objName); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder newInstance(Vertex start) { + return new GremlinTraversal(loader, source, start); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder newInstance() { + return new GremlinTraversal(loader, source); + } + + @Override + protected QueryBuilder cloneQueryAtStep(int index) { + if (index == 0) { + index = stepIndex; + } + List<String> newList = new ArrayList<>(); + for (int i = 0; i < index; i++) { + newList.add(this.list.get(i)); + } + + return new GremlinTraversal(newList, loader, source, this); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinUnique.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinUnique.java new file mode 100644 index 00000000..d9fb06b8 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinUnique.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.query.builder; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.query.TraversalStrategy; +import org.openecomp.aai.parsers.query.UniqueStrategy; + +/** + * The Class GremlinUnique. + */ +public class GremlinUnique extends GremlinQueryBuilder { + + /** + * Instantiates a new gremlin unique. + * + * @param loader the loader + */ + public GremlinUnique(Loader loader, GraphTraversalSource source) { + super(loader, source); + this.factory = new UniqueStrategy(this.loader, this); + } + + /** + * Instantiates a new gremlin unique. + * + * @param loader the loader + * @param start the start + */ + public GremlinUnique(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); + this.factory = new UniqueStrategy(this.loader, this); + } + + protected GremlinUnique(List<String> traversal, Loader loader, GraphTraversalSource source, GremlinQueryBuilder gtb) { + super(loader, source); + this.list = traversal; + this.stepIndex = gtb.getStepIndex(); + this.parentStepIndex = gtb.getParentStepIndex(); + this.containerStepIndex = gtb.getContainerStepIndex(); + this.factory = new TraversalStrategy(this.loader, this); + this.start = gtb.getStart(); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException { + return factory.buildRelationshipParser(relationship); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) + throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri, queryParams); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromObjectName(String objName) { + return factory.buildObjectNameParser(objName); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder newInstance() { + return new GremlinUnique(loader, source); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder newInstance(Vertex start) { + return new GremlinUnique(loader, source, start); + } + + @Override + protected QueryBuilder cloneQueryAtStep(int index) { + if (index == 0) { + index = stepIndex; + } + List<String> newList = new ArrayList<>(); + for (int i = 0; i < index; i++) { + newList.add(this.list.get(i)); + } + + return new GremlinUnique(newList, loader, source, this); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/QueryBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/QueryBuilder.java new file mode 100644 index 00000000..ad9f3082 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/QueryBuilder.java @@ -0,0 +1,293 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.query.builder; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.query.QueryParserStrategy; +import org.openecomp.aai.serialization.db.EdgeType; +import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException; + +/** + * The Class QueryBuilder. + */ +public abstract class QueryBuilder implements Iterator<Vertex> { + + protected QueryParserStrategy factory = null; + + protected Loader loader = null; + + protected boolean optimize = false; + + protected Vertex start = null; + protected final GraphTraversalSource source; + + /** + * Instantiates a new query builder. + * + * @param loader the loader + */ + public QueryBuilder(Loader loader, GraphTraversalSource source) { + this.loader = loader; + this.source = source; + } + + /** + * Instantiates a new query builder. + * + * @param loader the loader + * @param start the start + */ + public QueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) { + this.loader = loader; + this.start = start; + this.source = source; + } + + /** + * Gets the vertices by indexed property. + * + * @param key the key + * @param value the value + * @return the vertices by indexed property + */ + public abstract QueryBuilder getVerticesByIndexedProperty(String key, Object value); + + /** + * Gets the vertices by property. + * + * @param key the key + * @param value the value + * @return the vertices by property + */ + public abstract QueryBuilder getVerticesByProperty(String key, Object value); + + /** + * filters by all the values for this property + * @param key + * @param values + * @return vertices that match these values + */ + public abstract QueryBuilder getVerticesByIndexedProperty(String key, List<?> values); + + /** + * filters by all the values for this property + * @param key + * @param values + * @return vertices that match these values + */ + public abstract QueryBuilder getVerticesByProperty(String key, List<?> values); + + /** + * Gets the child vertices from parent. + * + * @param parentKey the parent key + * @param parentValue the parent value + * @param childType the child type + * @return the child vertices from parent + */ + public abstract QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType); + + /** + * Gets the typed vertices by map. + * + * @param type the type + * @param map the map + * @return the typed vertices by map + */ + public abstract QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map); + + /** + * Creates the DB query. + * + * @param obj the obj + * @return the query builder + */ + public abstract QueryBuilder createDBQuery(Introspector obj); + + /** + * Creates the key query. + * + * @param obj the obj + * @return the query builder + */ + public abstract QueryBuilder createKeyQuery(Introspector obj); + + /** + * Creates the container query. + * + * @param obj the obj + * @return the query builder + */ + public abstract QueryBuilder createContainerQuery(Introspector obj); + + /** + * Creates the edge traversal. + * + * @param parent the parent + * @param child the child + * @return the query builder + */ + public abstract QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException; + + /** + * Creates the edge traversal. + * + * @param parent the parent + * @param child the child + * @return the query builder + */ + public abstract QueryBuilder createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException; + + public QueryBuilder createEdgeTraversal(EdgeType type, String outNodeType, String inNodeType) throws NoEdgeRuleFoundException, AAIException { + Introspector out = loader.introspectorFromName(outNodeType); + Introspector in = loader.introspectorFromName(inNodeType); + + return createEdgeTraversal(type, out, in); + } + + /** + * Creates the query from URI. + * + * @param uri the uri + * @return the query parser + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public abstract QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException; + + /** + * Creates the query from URI. + * + * @param uri the uri + * @param queryParams the query params + * @return the query parser + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public abstract QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) throws UnsupportedEncodingException, AAIException; + + /** + * Creates a queryparser from a given object name. + * + * @param objName - name of the object type as it appears in the database + * @return + */ + public abstract QueryParser createQueryFromObjectName(String objName); + + /** + * Creates the query from relationship. + * + * @param relationship the relationship + * @return the query parser + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public abstract QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException; + + /** + * Gets the parent query. + * + * @return the parent query + */ + public abstract QueryBuilder getParentQuery(); + + /** + * Gets the query. + * + * @return the query + */ + public abstract <T> T getQuery(); + + /** + * Form boundary. + */ + public abstract void markParentBoundary(); + + public abstract QueryBuilder limit(long amount); + /** + * New instance. + * + * @param start the start + * @return the query builder + */ + public abstract QueryBuilder newInstance(Vertex start); + + /** + * New instance. + * + * @return the query builder + */ + public abstract QueryBuilder newInstance(); + + /** + * Gets the start. + * + * @return the start + */ + public abstract Vertex getStart(); + + protected Object correctObjectType(Object obj) { + + if (obj != null && obj.getClass().equals(Long.class)) { + return new Integer(obj.toString()); + } + + return obj; + } + /** + * uses all fields in the introspector to create a query + * + * @param obj + * @return + */ + public abstract QueryBuilder exactMatchQuery(Introspector obj); + + /** + * lets you join any number of QueryBuilders + * <b>be careful about starting with a union it will not use indexes</b> + * @param builder + * @return + */ + public abstract QueryBuilder union(QueryBuilder[] builder); + + public abstract QueryBuilder where(QueryBuilder[] builder); + public abstract void markContainer(); + + public abstract QueryBuilder getContainerQuery(); + + public abstract List<Vertex> toList(); + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/TraversalQuery.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/TraversalQuery.java new file mode 100644 index 00000000..84e72860 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/TraversalQuery.java @@ -0,0 +1,150 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.query.builder; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.tinkerpop.gremlin.process.traversal.Step; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.query.TraversalStrategy; + +/** + * The Class TraversalQuery. + */ +public class TraversalQuery extends GraphTraversalBuilder { + + /** + * Instantiates a new traversal query. + * + * @param loader the loader + */ + public TraversalQuery(Loader loader, GraphTraversalSource source) { + super(loader, source); + this.factory = new TraversalStrategy(this.loader, this); + } + + /** + * Instantiates a new traversal query. + * + * @param loader the loader + * @param start the start + */ + public TraversalQuery(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); + this.factory = new TraversalStrategy(this.loader, this); + } + + protected TraversalQuery(GraphTraversal<Vertex, Vertex> traversal, Loader loader, GraphTraversalSource source, GraphTraversalBuilder gtb) { + super(loader, source); + this.traversal = traversal; + this.stepIndex = gtb.getStepIndex(); + this.parentStepIndex = gtb.getParentStepIndex(); + this.containerStepIndex = gtb.getContainerStepIndex(); + this.factory = new TraversalStrategy(this.loader, this); + this.start = gtb.getStart(); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException { + return factory.buildRelationshipParser(relationship); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) + throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri, queryParams); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromObjectName(String objName) { + return factory.buildObjectNameParser(objName); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder newInstance(Vertex start) { + return new TraversalQuery(loader, source, start); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder newInstance() { + return new TraversalQuery(loader, source); + } + + @Override + protected QueryBuilder cloneQueryAtStep(int index) { + if (index == 0) { + index = stepIndex; + } + GraphTraversal<Vertex, Vertex> clone = this.traversal.asAdmin().clone(); + GraphTraversal.Admin<Vertex, Vertex> cloneAdmin = clone.asAdmin(); + List<Step> steps = cloneAdmin.getSteps(); + + for (int i = steps.size()-1; i >= index; i--) { + cloneAdmin.removeStep(i); + } + return new TraversalQuery(cloneAdmin, loader, source, this); + } + + @Override + protected QueryBuilder removeQueryStepsBetween(int start, int end) { + GraphTraversal<Vertex, Vertex> clone = this.traversal.asAdmin().clone(); + GraphTraversal.Admin<Vertex, Vertex> cloneAdmin = clone.asAdmin(); + + for (int i = end-2; i >= start; i--) { + cloneAdmin.removeStep(i); + } + return new TraversalQuery(cloneAdmin, loader, source, this); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/CustomJacksonJaxBJsonProvider.java b/aai-core/src/main/java/org/openecomp/aai/restcore/CustomJacksonJaxBJsonProvider.java new file mode 100644 index 00000000..b7360b1c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/CustomJacksonJaxBJsonProvider.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore; + +import javax.ws.rs.ext.Provider; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; + +/** + * The Class CustomJacksonJaxBJsonProvider. + */ +@Provider +public class CustomJacksonJaxBJsonProvider extends JacksonJaxbJsonProvider { + + private static ObjectMapper commonMapper = null; + + /** + * Instantiates a new custom jackson jax B json provider. + */ + public CustomJacksonJaxBJsonProvider() { + if (commonMapper == null) { + ObjectMapper mapper = new ObjectMapper(); + + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.configure(SerializationFeature.INDENT_OUTPUT, false); + mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false); + + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false); + + mapper.registerModule(new JaxbAnnotationModule()); + + commonMapper = mapper; + } + super.setMapper(commonMapper); + } + + /** + * Gets the mapper. + * + * @return the mapper + */ + public ObjectMapper getMapper() { + return commonMapper; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/HttpMethod.java b/aai-core/src/main/java/org/openecomp/aai/restcore/HttpMethod.java new file mode 100644 index 00000000..0acaf35f --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/HttpMethod.java @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore; + +/** + * The Enum HttpMethod. + */ +public enum HttpMethod { + PUT, + MERGE_PATCH, + DELETE, + PUT_EDGE, + DELETE_EDGE, + GET; +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/JettyObfuscationConversionCommandLineUtil.java b/aai-core/src/main/java/org/openecomp/aai/restcore/JettyObfuscationConversionCommandLineUtil.java new file mode 100644 index 00000000..8a81ee44 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/JettyObfuscationConversionCommandLineUtil.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore; + +import org.apache.commons.cli.BasicParser; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.eclipse.jetty.util.security.Password; + +/* + * The purpose of this class is to be a tool for + * manually applying jetty obfuscation/deobfuscation + * so that one can obfuscate the various passwords/secrets + * in aaiconfig.properties. + * + * Originally, they were being encrypted by a similar + * command line utility, however the encryption key + * was being hardcoded in the src package + * which is a security violation. + * Since this ultimately just moved the problem of how + * to hide secrets to a different secret in a different file, + * and since that encryption was really just being done to + * obfuscate those values in case someone needed to look at + * properties with others looking at their screen, + * we decided that jetty obfuscation would be adequate + * for that task as well as + * removing the "turtles all the way down" secret-to-hide- + * the-secret-to-hide-the-secret problem. + */ +public class JettyObfuscationConversionCommandLineUtil { + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args){ + Options options = new Options(); + options.addOption("e", true, "obfuscate the given string"); + options.addOption("d", true, "deobfuscate the given string"); + + CommandLineParser parser = new BasicParser(); + + try { + CommandLine cmd = parser.parse(options, args); + String toProcess = null; + + if (cmd.hasOption("e")){ + toProcess = cmd.getOptionValue("e"); + String encoded = Password.obfuscate(toProcess); + System.out.println(encoded); + } else if (cmd.hasOption("d")) { + toProcess = cmd.getOptionValue("d"); + String decoded_str = Password.deobfuscate(toProcess); + System.out.println(decoded_str); + } else { + usage(); + } + } catch (ParseException e) { + System.out.println("failed to parse input"); + System.out.println(e.toString()); + usage(); + } catch (Exception e) { + System.out.println("exception:" + e.toString()); + } + } + + /** + * Usage. + */ + private static void usage(){ + System.out.println("usage:");; + System.out.println("-e [string] to obfuscate"); + System.out.println("-d [string] to deobfuscate"); + System.out.println("-h help"); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/MediaType.java b/aai-core/src/main/java/org/openecomp/aai/restcore/MediaType.java new file mode 100644 index 00000000..73cb0f22 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/MediaType.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore; + +/** + * The Enum MediaType. + */ +public enum MediaType { + APPLICATION_JSON_TYPE("application/json"), + APPLICATION_XML_TYPE("application/xml"); + + private final String text; + + /** + * Instantiates a new media type. + * + * @param text the text + */ + private MediaType(final String text) { + this.text = text; + } + + /** + * Gets the enum. + * + * @param value the value + * @return the enum + */ + public static MediaType getEnum(String value) { + + for(MediaType v : values()) { + if(v.toString().equalsIgnoreCase(value)) { + return v; + } + } + + throw new IllegalArgumentException("bad value: " + value); + + } + + /** + * @{inheritDoc} + */ + @Override + public String toString() { + return text; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/RESTAPI.java b/aai-core/src/main/java/org/openecomp/aai/restcore/RESTAPI.java new file mode 100644 index 00000000..59d35ff2 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/RESTAPI.java @@ -0,0 +1,343 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.Joiner; +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.tools.*; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import org.openecomp.aai.util.AAITxnLog; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + + +/** + * Base class for AAI REST API classes. + * Provides method to validate header information + * TODO should authenticate caller and authorize them for the API they are calling + * TODO should store the transaction + + * + */ +public class RESTAPI { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RESTAPI.class); + + protected final String COMPONENT = "aairest"; + + /** + * The Enum Action. + */ + public enum Action { + GET, PUT, POST, DELETE + }; + + + public AAITxnLog txn = null; + + /** + * Gets the from app id. + * + * @param headers the headers + * @param logline the logline + * @return the from app id + * @throws AAIException the AAI exception + */ + protected String getFromAppId(HttpHeaders headers) throws AAIException { + String fromAppId = null; + if (headers != null) { + List<String> fromAppIdHeader = headers.getRequestHeader("X-FromAppId"); + if (fromAppIdHeader != null) { + for (String fromAppIdValue : fromAppIdHeader) { + fromAppId = fromAppIdValue; + } + } + } + + if (fromAppId == null) { + throw new AAIException("AAI_4009"); + } + + return fromAppId; + } + + /** + * Gets the trans id. + * + * @param headers the headers + * @param logline the logline + * @return the trans id + * @throws AAIException the AAI exception + */ + protected String getTransId(HttpHeaders headers) throws AAIException { + String transId = null; + if (headers != null) { + List<String> transIdHeader = headers.getRequestHeader("X-TransactionId"); + if (transIdHeader != null) { + for (String transIdValue : transIdHeader) { + transId = transIdValue; + } + } + } + + if (transId == null) { + throw new AAIException("AAI_4010"); + } + + return transId; + } + + + /** + * Gen date. + * + * @return the string + */ + protected String genDate() { + Date date = new Date(); + DateFormat formatter = null; + try { + formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT)); + } catch (AAIException ex) { + ErrorLogHelper.logException(ex); + } finally { + if (formatter == null) { + formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS"); + } + } + + return formatter.format(date); + } + + /** + * Gets the media type. + * + * @param mediaTypeList the media type list + * @return the media type + */ + protected String getMediaType(List <MediaType> mediaTypeList) { + String mediaType = MediaType.APPLICATION_JSON; // json is the default + for (MediaType mt : mediaTypeList) { + if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) { + mediaType = MediaType.APPLICATION_XML; + } + } + return mediaType; + } + + + /** + * Log transaction. + * + * @param appId the app id + * @param tId the t id + * @param action the action + * @param input the input + * @param rqstTm the rqst tm + * @param respTm the resp tm + * @param request the request + * @param response the response + */ + /* ---------------- Log Transaction into HBase --------------------- */ + public void logTransaction( String appId, String tId, String action, + String input, String rqstTm, String respTm, String request, Response response) { + String respBuf = ""; + int status = 0; + + if (response != null && response.getEntity() != null) { + respBuf = response.getEntity().toString(); + status = response.getStatus(); + } + logTransaction(appId, tId, action, input, rqstTm, respTm, request, respBuf, String.valueOf(status)); + } + + /** + * Log transaction. + * + * @param appId the app id + * @param tId the t id + * @param action the action + * @param input the input + * @param rqstTm the rqst tm + * @param respTm the resp tm + * @param request the request + * @param respBuf the resp buf + * @param status the status + * @param logline the logline + */ + public void logTransaction( String appId, String tId, String action, + String input, String rqstTm, String respTm, String request, String respBuf, String status) { + try { + // we only run this way if we're not doing it in the CXF interceptor + if (!AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_INTERCEPTOR).equalsIgnoreCase("true")) { + if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_ENABLED).equalsIgnoreCase("true")) { + txn = new AAITxnLog(tId, appId); + // tid, status, rqstTm, respTm, srcId, rsrcId, rsrcType, rqstBuf, respBuf + String hbtid = txn.put(tId, status, + rqstTm, respTm, appId, input, action, request, respBuf); + + LOGGER.debug("HbTransId={}",hbtid); + LOGGER.debug("action={}", action); + LOGGER.debug("urlin={}", input); + } + + } + } catch (AAIException e) { + // i think we do nothing + } + } + + /* ----------helpers for common consumer actions ----------- */ + + /** + * Sets the depth. + * + * @param depthParam the depth param + * @return the int + * @throws AAIException the AAI exception + */ + protected int setDepth(String depthParam) throws AAIException { + int depth = AAIProperties.MAXIMUM_DEPTH; //default + if (depthParam != null && depthParam.length() > 0 && !depthParam.equals("all")){ + try { + depth = Integer.valueOf(depthParam); + } catch (Exception e) { + throw new AAIException("AAI_4016"); + } + } + return depth; + } + + /** + * Consumer exception response generator. + * + * @param headers the headers + * @param info the info + * @param templateAction the template action + * @param e the e + * @return the response + */ + protected Response consumerExceptionResponseGenerator(HttpHeaders headers, UriInfo info, HttpMethod templateAction, AAIException e) { + ArrayList<String> templateVars = new ArrayList<String>(); + templateVars.add(templateAction.toString()); //GET, PUT, etc + templateVars.add(info.getPath().toString()); + templateVars.addAll(e.getTemplateVars()); + + return Response + .status(e.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } + + /** + * Validate introspector. + * + * @param obj the obj + * @param loader the loader + * @param uri the uri + * @param validateRequired the validate required + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + protected void validateIntrospector(Introspector obj, Loader loader, URI uri, HttpMethod method) throws AAIException, UnsupportedEncodingException { + + int maximumDepth = AAIProperties.MAXIMUM_DEPTH; + boolean validateRequired = true; + if (method.equals(HttpMethod.MERGE_PATCH)) { + validateRequired = false; + maximumDepth = 0; + } + IntrospectorValidator validator = new IntrospectorValidator.Builder() + .validateRequired(validateRequired) + .restrictDepth(maximumDepth) + .addResolver(new RemoveNonVisibleProperty()) + .addResolver(new CreateUUID()) + .addResolver(new DefaultFields()) + .addResolver(new InjectKeysFromURI(loader, uri)) + .build(); + boolean result = validator.validate(obj); + if (!result) { + result = validator.resolveIssues(); + } + if (!result) { + List<String> messages = new ArrayList<>(); + for (Issue issue : validator.getIssues()) { + if (!issue.isResolved()) { + messages.add(issue.getDetail()); + } + } + String errors = Joiner.on(",").join(messages); + throw new AAIException("AAI_3000", errors); + } + //check that key in payload and key in request uri are the same + String objURI = obj.getURI(); + //if requested object is a parent objURI will have a leading slash the input uri will lack + //this adds that leading slash for the comparison + String testURI = "/" + uri.getRawPath(); + if (!testURI.endsWith(objURI)) { + throw new AAIException("AAI_3000", "uri and payload keys don't match"); + } + } + + protected DBConnectionType determineConnectionType(String fromAppId, String realTime) { + DBConnectionType type = DBConnectionType.REALTIME; + boolean isRealTimeClient = AAIConfig.get("aai.realtime.clients", "").contains(fromAppId); + if (isRealTimeClient || realTime != null) { + type = DBConnectionType.REALTIME; + } else { + type = DBConnectionType.CACHED; + } + + return type; + } + + /** + * Gets the input media type. + * + * @param mediaType the media type + * @return the input media type + */ + protected String getInputMediaType(MediaType mediaType) { + String result = mediaType.getType() + "/" + mediaType.getSubtype(); + + return result; + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/search/GremlinGroovyShellSingleton.java b/aai-core/src/main/java/org/openecomp/aai/restcore/search/GremlinGroovyShellSingleton.java new file mode 100644 index 00000000..b80884b7 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/search/GremlinGroovyShellSingleton.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore.search; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.expr.ClassExpression; +import org.codehaus.groovy.ast.expr.PropertyExpression; +import org.codehaus.groovy.control.CompilerConfiguration; +import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer; +import org.codehaus.groovy.control.customizers.ImportCustomizer; + +import groovy.lang.Binding; +import groovy.lang.GroovyShell; +import groovy.lang.Script; +import groovy.transform.TimedInterrupt; + +/** + * Creates and returns a groovy shell with the + * configuration to statically import graph classes + * + */ +public class GremlinGroovyShellSingleton { + + private final GroovyShell shell; + private GremlinGroovyShellSingleton() { + Map<String, Object> parameters = new HashMap<>(); + parameters.put("value", 30000); + parameters.put("unit", new PropertyExpression(new ClassExpression(ClassHelper.make(TimeUnit.class)),"MILLISECONDS")); + + ASTTransformationCustomizer custom = new ASTTransformationCustomizer(parameters, TimedInterrupt.class); + ImportCustomizer imports = new ImportCustomizer(); + imports.addStaticStars( + "org.apache.tinkerpop.gremlin.process.traversal.P" + ); + imports.addImports( + "org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__", + "org.apache.tinkerpop.gremlin.structure.T", + "org.apache.tinkerpop.gremlin.process.traversal.P"); + CompilerConfiguration config = new CompilerConfiguration(); + config.addCompilationCustomizers(custom, imports); + + this.shell = new GroovyShell(config); + } + + private static class Helper { + private static final GremlinGroovyShellSingleton INSTANCE = new GremlinGroovyShellSingleton(); + } + + public static GremlinGroovyShellSingleton getInstance() { + + return Helper.INSTANCE; + } + + /** + * @param traversal + * @param params + * @return result of graph traversal + */ + public GraphTraversal<?, ?> executeTraversal (String traversal, Map<String, Object> params) { + Binding binding = new Binding(params); + Script script = shell.parse(traversal); + script.setBinding(binding); + return (GraphTraversal<?, ?>) script.run(); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/util/GenerateEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/restcore/util/GenerateEdgeRules.java new file mode 100644 index 00000000..3bbe7dec --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/util/GenerateEdgeRules.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; + +import java.io.*; +import java.util.*; + +public class GenerateEdgeRules { + + private static final EELFLogger LOG = EELFManager.getInstance().getLogger(GenerateEdgeRules.class); + + public static void main(String[] args) throws IOException, TemplateException { + + String filename = "/AAI8032.csv"; + InputStream inputStream = GenerateEdgeRules.class.getResourceAsStream(filename); + Map<String, Integer> headers = new HashMap<>(); + Map<String, Object> edgeRulesMap = new TreeMap<String, Object>(); + List<Map<String, String>> edgeRules = new ArrayList<>(); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + + String line = null; + + int rowNum = 0; + + // Retrieve the header line to map the indexes to their column names + + while ((line = reader.readLine()) != null) { + + if (rowNum == 0) { + headers = retrieveHeaderMap(line); + } else { + String[] columns = line.split(","); + + String originalNode = columns[headers.get("Orig NodeA|NodeB")]; + String finalNode = columns[headers.get("Final NodeA|NodeB")]; + String originalEdge = columns[headers.get("Orig EdgeLabel")]; + String finalEdge = columns[headers.get("Final EdgeLabel")]; + + String lineage = columns[headers.get("Final Lineage")]; + String originalParent = columns[headers.get("Orig ParentOf")]; + String usesResource = columns[headers.get("Revised UsesResource")]; + String hasDelTarget = columns[headers.get("Revised hasDelTarget")]; + String svcInfra = columns[headers.get("Final SVC-INFRA")]; + String svcInfraRev = ""; + + if(usesResource.equals("T")) + usesResource = "true"; + else if(usesResource.equals("F")) + usesResource = "false"; + + if (hasDelTarget.equals("T") || hasDelTarget.equals("AB")) { + hasDelTarget = "true"; + } else if (hasDelTarget.equals("F")) { + hasDelTarget = "false"; + } + + if (svcInfra.equals("T")) { + svcInfra = "true"; + } else if (svcInfra.equals("F")) { + svcInfra = "false"; + } else if (svcInfra.equals("R")) { + svcInfra = "reverse"; + } + + if (originalParent.equals("T")) { + if (lineage.trim().equalsIgnoreCase("CHILD")) { + lineage = "true"; + } else if (lineage.trim().equalsIgnoreCase("PARENT")) { + lineage = "reverse"; + } + } else { + lineage = "false"; + } + + Map<String, String> edgeMap = new HashMap<String, String>(); + + edgeMap.put("lineage", lineage); + edgeMap.put("usesResource", usesResource); + edgeMap.put("hasDelTarget", hasDelTarget); + edgeMap.put("SVC-INFRA", svcInfra); + edgeMap.put("SVC-INFRA-REV", svcInfraRev); + edgeMap.put("nodes", finalNode); + edgeMap.put("edge", finalEdge); + edgeMap.put("direction", columns[headers.get("Orig Direction")]); + edgeMap.put("multiplicity", columns[headers.get("Revised Multiplicity")]); + + edgeRules.add(edgeMap); + + } + ++rowNum; + } + } catch(Exception ex){ + ex.printStackTrace(); + } + + edgeRulesMap.put("edgeRules", edgeRules); + + Collections.sort(edgeRules, new Comparator<Map<String, String>>() { + @Override + public int compare(Map<String, String> o1, Map<String, String> o2) { + return o1.get("nodes").compareTo(o2.get("nodes")); + } + }); + + Configuration configuration = new Configuration(); + Template template = configuration.getTemplate("ajsc-aai/src/main/resources/EdgeRules.ftl"); + Writer file = new FileWriter(new File("ajsc-aai/src/main/resources" + "/" + "EdgeRules.txt")); + template.process(edgeRulesMap, file); + } + + private static Map<String, Integer> retrieveHeaderMap(String line){ + + if(line == null) + throw new NullPointerException(); + + String[] columnNames = line.split(","); + + Map<String, Integer> map = new HashMap<String, Integer>(); + + int index = 0; + + for(String columnName : columnNames){ + map.put(columnName, index++); + } + + return map; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/util/URITools.java b/aai-core/src/main/java/org/openecomp/aai/restcore/util/URITools.java new file mode 100644 index 00000000..2683240a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/restcore/util/URITools.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.restcore.util; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; + +import org.springframework.web.util.UriUtils; + +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException; +import org.openecomp.aai.schema.enums.PropertyMetadata; + +public class URITools { + + protected static final Pattern template = Pattern.compile("\\{(.*?)\\}"); + + public static MultivaluedMap<String, String> getQueryMap(URI uri) { + MultivaluedMap<String, String> result = new MultivaluedHashMap<>(); + String queryParams = uri.getRawQuery(); + if (queryParams != null) { + try { + String[] sections = queryParams.split("&"); + String[] query = null; + String key, value = ""; + for (String section : sections) { + query = section.split("="); + key = UriUtils.decode(query[0], "UTF-8"); + value = UriUtils.decode(query[1], "UTF-8"); + if (result.containsKey(key)) { + result.add(key, value); + } else { + result.putSingle(key, value); + } + } + } catch (UnsupportedEncodingException e ) { + + } + } + return result; + + } + + public static Optional<String> replaceTemplates(Introspector obj, String uriString, PropertyMetadata metadata, boolean replaceWithWildcard) throws AAIMissingRequiredPropertyException { + String result = uriString; + final Map<String, String> propMap = URITools.findProperties(obj, uriString, metadata, replaceWithWildcard); + if (propMap.isEmpty()) { + return Optional.empty(); + } + for (Entry<String, String> entry : propMap.entrySet()) { + result = result.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue()); + } + //drop out wildcards if they exist + result = result.replaceFirst("/[^/]+?(?:/\\*)+", ""); + return Optional.of(result); + } + + private static Map<String, String> findProperties(Introspector obj, String uriString, PropertyMetadata metadata, boolean replaceWithWildcard) throws AAIMissingRequiredPropertyException { + + final Map<String, String> result = new HashMap<>(); + final Set<String> missing = new LinkedHashSet<>(); + Matcher m = template.matcher(uriString); + int properties = 0; + while (m.find()) { + String propName = m.group(1); + String value = obj.getValue(propName); + properties++; + if (value != null) { + result.put(propName, value); + } else { + if (replaceWithWildcard) { + result.put(propName, "*"); + } + missing.add(propName); + } + } + + if (!missing.isEmpty() && (properties != missing.size())) { + throw new AAIMissingRequiredPropertyException("Cannot complete " + metadata.toString() + " uri. Missing properties " + missing); + } + return result; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/DBSerializer.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DBSerializer.java new file mode 100644 index 00000000..fb3300e3 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DBSerializer.java @@ -0,0 +1,1484 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.CaseFormat; +import com.thinkaurelius.titan.core.SchemaViolationException; +import org.apache.commons.collections.IteratorUtils; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.*; +import org.javatuples.Pair; +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.*; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.introspection.sideeffect.DataCopy; +import org.openecomp.aai.introspection.sideeffect.DataLinkReader; +import org.openecomp.aai.introspection.sideeffect.DataLinkWriter; +import org.openecomp.aai.introspection.sideeffect.SideEffectRunner; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.uri.URIParser; +import org.openecomp.aai.parsers.uri.URIToRelationshipObject; +import org.openecomp.aai.query.builder.QueryBuilder; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.schema.enums.PropertyMetadata; +import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; +import org.openecomp.aai.serialization.tinkerpop.TreeBackedVertex; +import org.openecomp.aai.util.AAIApiServerURLBase; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import org.openecomp.aai.workarounds.NamingExceptions; + +import javax.ws.rs.core.UriBuilder; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +public class DBSerializer { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class); + + private final TransactionalGraphEngine engine; + private final String sourceOfTruth; + private final ModelType introspectionType; + private final Version version; + private final Loader latestLoader; + private final EdgeRules edgeRules = EdgeRules.getInstance(); + private final Loader loader; + private final String baseURL; + /** + * Instantiates a new DB serializer. + * + * @param version the version + * @param engine the engine + * @param g the g + * @param introspectionType the introspection type + * @param sourceOfTruth the source of truth + * @param llBuilder the ll builder + * @throws AAIException + */ + public DBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException { + this.engine = engine; + this.sourceOfTruth = sourceOfTruth; + this.introspectionType = introspectionType; + this.latestLoader = LoaderFactory.createLoaderForVersion(introspectionType, AAIProperties.LATEST); + this.version = version; + this.loader = LoaderFactory.createLoaderForVersion(introspectionType, version); + this.baseURL = AAIApiServerURLBase.get(version); + } + + /** + * Touch standard vertex properties. + * + * @param v the v + * @param isNewVertex the is new vertex + */ + /* + * to be defined and expanded later + */ + public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) { + + long unixTimeNow = System.currentTimeMillis(); + String timeNowInSec = "" + unixTimeNow; + if (isNewVertex) { + v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth); + v.property(AAIProperties.CREATED_TS, timeNowInSec); + } + v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec ); + v.property(AAIProperties.LAST_MOD_TS, timeNowInSec); + v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth); + + } + + + + /** + * Creates the new vertex. + * + * @param wrappedObject the wrapped object + * @return the vertex + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public Vertex createNewVertex(Introspector wrappedObject) { + + + Vertex v = this.engine.tx().addVertex(); + v.property(AAIProperties.NODE_TYPE, wrappedObject.getDbName()); + touchStandardVertexProperties(v, true); + + return v; + } + + /** + * Trim class name. + * + * @param className the class name + * @return the string + */ + /* + * Removes the classpath from a class name + */ + public String trimClassName (String className) { + String returnValue = ""; + + if (className.lastIndexOf('.') == -1) { + return className; + } + returnValue = className.substring(className.lastIndexOf('.') + 1, className.length()); + + return returnValue; + } + + /** + * Serialize to db. + * + * @param obj the obj + * @param v the v + * @param uriQuery the uri query + * @param identifier the identifier + * @throws SecurityException the security exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws InstantiationException the instantiation exception + * @throws InterruptedException the interrupted exception + * @throws NoSuchMethodException the no such method exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIUnknownObjectException + */ + public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException { + + try { + if (uriQuery.isDependent()) { + //try to find the parent + List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList(); + if (!vertices.isEmpty()) { + Vertex parent = vertices.get(0); + this.reflectDependentVertex(parent, v, obj, requestContext); + } else { + throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier); + } + } else { + serializeSingleVertex(v, obj, requestContext); + } + + } catch (SchemaViolationException e) { + throw new AAIException("AAI_6117", e); + } + + } + + public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException { + try { + boolean isTopLevel = obj.isTopLevel(); + if (isTopLevel) { + v.property(AAIProperties.AAI_URI, obj.getURI()); + } + processObject(obj, v, requestContext); + if (!isTopLevel) { + URI uri = this.getURIForVertex(v); + URIParser parser = new URIParser(this.loader, uri); + if (parser.validate()) { + VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI); + if (!uriProp.isPresent() || uriProp.isPresent() && !uriProp.value().equals(uri.toString())) { + v.property(AAIProperties.AAI_URI, uri.toString()); + } + } + } + } catch (SchemaViolationException e) { + throw new AAIException("AAI_6117", e); + } + } + + /** + * Process object. + * + * @param <T> the generic type + * @param obj the obj + * @param v the v + * @return the list + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIUnknownObjectException + */ + /* + * Helper method for reflectToDb + * Handles all the property setting + */ + private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException { + Set<String> properties = new LinkedHashSet<>(obj.getProperties()); + properties.remove(AAIProperties.RESOURCE_VERSION); + List<Vertex> dependentVertexes = new ArrayList<>(); + List<Vertex> processedVertexes = new ArrayList<>(); + boolean isComplexType = false; + boolean isListType = false; + this.executePreSideEffects(obj, v); + for (String property : properties) { + Object value = null; + final String propertyType; + propertyType = obj.getType(property); + isComplexType = obj.isComplexType(property); + isListType = obj.isListType(property); + value = obj.getValue(property); + + if (!(isComplexType || isListType)) { + boolean canModify = this.canModify(obj, property, requestContext); + + if (canModify) { + final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property); + String dbProperty = property; + if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) { + dbProperty = metadata.get(PropertyMetadata.DB_ALIAS); + } + if (metadata.containsKey(PropertyMetadata.DATA_LINK)) { + //data linked properties are ephemeral + //they are populated dynamically on GETs + continue; + } + if (value != null) { + if (propertyType.toLowerCase().contains(".long")) { + v.property(dbProperty, new Integer(((Long)value).toString())); + } else { + v.property(dbProperty, value); + } + } else { + v.property(dbProperty).remove(); + } + } + } else if (isListType) { + List<Object> list = (List<Object>)value; + if (obj.isComplexGenericType(property)) { + if (list != null) { + for (Object o : list) { + Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o); + child.setURIChain(obj.getURI()); + processedVertexes.add(reflectDependentVertex(v, child, requestContext)); + } + } + } else { + //simple list case + engine.setListProperty(v, property, list); + } + } else { + //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method + if (value != null) { //effectively ignore complex properties not included in the object we're processing + if (value.getClass().isArray()) { + + int length = Array.getLength(value); + for (int i = 0; i < length; i ++) { + Object arrayElement = Array.get(value, i); + Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement); + child.setURIChain(obj.getURI()); + processedVertexes.add(reflectDependentVertex(v, child, requestContext)); + + } + } else if (!property.equals("relationship-list")) { + // container case + Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value); + if (introspector.isContainer()) { + dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName())); + introspector.setURIChain(obj.getURI()); + + processedVertexes.addAll(processObject(introspector, v, requestContext)); + + } else { + dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName())); + processedVertexes.add(reflectDependentVertex(v, introspector, requestContext)); + + } + } else if (property.equals("relationship-list")) { + handleRelationships(obj, v); + } + } + } + } + this.writeThroughDefaults(v, obj); + /* handle those vertexes not touched */ + for (Vertex toBeRemoved : processedVertexes) { + dependentVertexes.remove(toBeRemoved); + } + this.deleteItemsWithTraversal(dependentVertexes); + + this.executePostSideEffects(obj, v); + return processedVertexes; + } + + /** + * Handle relationships. + * + * @param obj the obj + * @param vertex the vertex + * @throws SecurityException the security exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + /* + * Handles the explicit relationships defined for an obj + */ + private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException { + + + + Introspector wrappedRl = obj.getWrappedValue("relationship-list"); + processRelationshipList(wrappedRl, vertex); + + + } + + + /** + * Process relationship list. + * + * @param wrapped the wrapped + * @param v the v + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException { + + List<Object> relationships = (List<Object>)wrapped.getValue("relationship"); + + List<Pair<Vertex, Vertex>> addEdges = new ArrayList<>(); + List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader()); + + for (Object relationship : relationships) { + Edge e = null; + Vertex cousinVertex = null; + Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship); + QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel); + + List<Vertex> results = parser.getQueryBuilder().toList(); + if (results.isEmpty()) { + final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri()); + ex.getTemplateVars().add(parser.getResultType()); + ex.getTemplateVars().add(parser.getUri().toString()); + throw ex; + } else { + //still an issue if there's more than one + cousinVertex = results.get(0); + } + + if (cousinVertex != null) { + try { + e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex); + + if (e == null) { + addEdges.add(new Pair<>(v, cousinVertex)); + } else { + existingEdges.remove(e); + } + } catch (NoEdgeRuleFoundException e1) { + throw new AAIException("AAI_6145"); + } + } + } + + for (Edge edge : existingEdges) { + edge.remove(); + } + for (Pair<Vertex, Vertex> pair : addEdges) { + try { + edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), pair.getValue0(), pair.getValue1()); + } catch (NoEdgeRuleFoundException e) { + throw new AAIException("AAI_6129", e); + } + } + + } + + /** + * Write through defaults. + * + * @param v the v + * @param obj the obj + * @throws AAIUnknownObjectException + */ + private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException { + Introspector latest = this.latestLoader.introspectorFromName(obj.getName()); + if (latest != null) { + Set<String> required = latest.getRequiredProperties(); + + for (String field : required) { + String defaultValue = null; + Object vertexProp = null; + defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE); + if (defaultValue != null) { + vertexProp = v.<Object>property(field).orElse(null); + if (vertexProp == null) { + v.property(field, defaultValue); + } + } + } + } + + } + + + /** + * Reflect dependent vertex. + * + * @param v the v + * @param dependentObj the dependent obj + * @return the vertex + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIUnknownObjectException + */ + private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException { + + //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI()); + //List<Vertex> items = p.getQuery().toList(); + QueryBuilder query = this.engine.getQueryBuilder(v); + query.createEdgeTraversal(EdgeType.TREE, v, dependentObj); + query.createKeyQuery(dependentObj); + + List<Vertex> items = query.toList(); + + Vertex dependentVertex = null; + if (items.size() == 1) { + dependentVertex = items.get(0); + this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI()); + } else { + this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI()); + dependentVertex = createNewVertex(dependentObj); + } + + return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext); + + } + + /** + * Reflect dependent vertex. + * + * @param parent the parent + * @param child the child + * @param obj the obj + * @return the vertex + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIUnknownObjectException + */ + private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException { + + String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null); + if (parentUri != null) { + child.property(AAIProperties.AAI_URI, parentUri + obj.getURI()); + } + processObject(obj, child, requestContext); + + Edge e; + e = this.getEdgeBetween(EdgeType.TREE, parent, child); + if (e == null) { + String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED); + if (canBeLinked != null && canBeLinked.equals("true")) { + boolean isFirst = !this.engine.getQueryBuilder(parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext(); + if (isFirst) { + child.property(AAIProperties.LINKED, true); + } + } + edgeRules.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child); + } + return child; + + } + + /** + * Db to object. + * + * @param vertices the vertices + * @param obj the obj + * @param depth the depth + * @param cleanUp the clean up + * @return the introspector + * @throws AAIException the AAI exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws SecurityException the security exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws MalformedURLException the malformed URL exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException + */ + public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException { + + final int internalDepth; + if (depth == Integer.MAX_VALUE) { + internalDepth = depth--; + } else { + internalDepth = depth; + } + if (vertices.size() > 1 && !obj.isContainer()) { + throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName()); + } else if (obj.isContainer()) { + final List getList; + String listProperty = null; + for (String property : obj.getProperties()) { + if (obj.isListType(property) && obj.isComplexGenericType(property)) { + listProperty = property; + break; + } + } + final String propertyName = listProperty; + getList = (List)obj.getValue(listProperty); + + /* This is an experimental multithreading experiment + * on get alls. + */ + ExecutorService pool = GetAllPool.getInstance().getPool(); + + List<Future<Object>> futures = new ArrayList<>(); + for (Vertex v : vertices) { + Callable<Object> task = () -> { + Set<Vertex> seen = new HashSet<>(); + Introspector childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName); + Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, internalDepth, nodeOnly); + TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree); + dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp); + return childObject.getUnderlyingObject(); + //getList.add(childObject.getUnderlyingObject()); + }; + futures.add(pool.submit(task)); + } + + for (Future<Object> future : futures) { + try { + getList.add(future.get()); + } catch (ExecutionException e) { + throw new AAIException("AAI_4000", e); + } catch (InterruptedException e) { + throw new AAIException("AAI_4000", e); + } + } + } else if (vertices.size() == 1) { + Set<Vertex> seen = new HashSet<>(); + Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly); + TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree); + dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp); + } else { + //obj = null; + } + + + return obj; + } + + /** + * Db to object. + * + * @param obj the obj + * @param v the v + * @param seen the seen + * @param depth the depth + * @param cleanUp the clean up + * @return the introspector + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws SecurityException the security exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + * @throws MalformedURLException the malformed URL exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException + */ + private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException { + + if (depth < 0) { + return null; + } + depth--; + seen.add(v); + + boolean modified = false; + for (String property : obj.getProperties(PropertyPredicates.isVisible())) { + List<Object> getList = null; + Vertex[] vertices = null; + + if (!(obj.isComplexType(property) || obj.isListType(property))) { + this.copySimpleProperty(property, obj, v); + modified = true; + } else { + if (obj.isComplexType(property)) { + /* container case */ + + if (!property.equals("relationship-list") && depth >= 0) { + Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property); + Object result = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp); + if (result != null) { + obj.setValue(property, argumentObject.getUnderlyingObject()); + modified = true; + } + } else if (property.equals("relationship-list") && !nodeOnly){ + /* relationships need to be handled correctly */ + Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property); + relationshipList = createRelationshipList(v, relationshipList, cleanUp); + if (relationshipList != null) { + modified = true; + obj.setValue(property, relationshipList.getUnderlyingObject()); + modified = true; + } + + } + } else if (obj.isListType(property)) { + + if (property.equals("any")) { + continue; + } + String genericType = obj.getGenericTypeClass(property).getSimpleName(); + if (obj.isComplexGenericType(property) && depth >= 0) { + final String childDbName = convertFromCamelCase(genericType); + String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + EdgeRule rule; + + rule = edgeRules.getEdgeRule(EdgeType.TREE, vType, childDbName); + if (rule.getIsParent().equals("true") || rule.getIsParent().equals("reverse")) { + //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName); + Direction ruleDirection = rule.getDirection(); + Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel()); + List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr); + itr = verticesList.stream().filter(item -> { + return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName); + }).iterator(); + if (itr.hasNext()) { + getList = (List<Object>)obj.getValue(property); + } + int processed = 0; + int removed = 0; + while (itr.hasNext()) { + Vertex childVertex = itr.next(); + if (!seen.contains(childVertex)) { + Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property); + + Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp); + if (result != null) { + getList.add(argumentObject.getUnderlyingObject()); + } + + processed++; + } else { + removed++; + LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString()); + } + } + if (processed == 0) { + //vertices were all seen, reset the list + getList = null; + } + if (processed > 0) { + modified = true; + } + } + } else if (obj.isSimpleGenericType(property)) { + List<Object> temp = this.engine.getListProperty(v, property); + if (temp != null) { + getList = (List<Object>)obj.getValue(property); + getList.addAll(temp); + modified = true; + } + + } + + } + + } + } + + //no changes were made to this obj, discard the instance + if (!modified) { + return null; + } + this.enrichData(obj, v); + return obj; + + } + + + public Introspector getVertexProperties(Vertex v) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException { + String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + if (nodeType == null) { + throw new AAIException("AAI_6143"); + } + Introspector obj = this.latestLoader.introspectorFromName(nodeType); + Set<Vertex> seen = new HashSet<>(); + int depth = 0; + String cleanUp = "false"; + boolean nodeOnly = true; + this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp); + + return obj; + + } + public Introspector getLatestVersionView(Vertex v) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException { + String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + if (nodeType == null) { + throw new AAIException("AAI_6143"); + } + Introspector obj = this.latestLoader.introspectorFromName(nodeType); + Set<Vertex> seen = new HashSet<>(); + int depth = AAIProperties.MAXIMUM_DEPTH; + String cleanUp = "false"; + boolean nodeOnly = false; + Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly); + TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree); + this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp); + + return obj; + } + /** + * Copy simple property. + * + * @param property the property + * @param obj the obj + * @param v the v + * @throws InstantiationException the instantiation exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + */ + private void copySimpleProperty(String property, Introspector obj, Vertex v) { + final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property); + String dbPropertyName = property; + if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) { + dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS); + } + final Object temp = v.<Object>property(dbPropertyName).orElse(null); + if (temp != null) { + + obj.setValue(property, temp); + } + } + + /** + * Simple db to object. + * + * @param obj the obj + * @param v the v + * @throws InstantiationException the instantiation exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + */ + private void simpleDbToObject (Introspector obj, Vertex v) { + for (String property : obj.getProperties()) { + + + if (!(obj.isComplexType(property) || obj.isListType(property))) { + this.copySimpleProperty(property, obj, v); + } + } + } + + /** + * Creates the relationship list. + * + * @param v the v + * @param obj the obj + * @param cleanUp the clean up + * @return the object + * @throws InstantiationException the instantiation exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + * @throws MalformedURLException the malformed URL exception + * @throws URISyntaxException + */ + private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException { + + + List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v); + + List<Object> relationshipObjList = obj.getValue("relationship"); + + for (Vertex cousin : cousins) { + + Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); + Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp); + if (result != null) { + relationshipObjList.add(result); + } + + } + + if (relationshipObjList.isEmpty()) { + return null; + } else { + return obj; + } + } + + /** + * Process edge relationship. + * + * @param relationshipObj the relationship obj + * @param edge the edge + * @param direction the direction + * @param cleanUp the clean up + * @return the object + * @throws InstantiationException the instantiation exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + * @throws MalformedURLException the malformed URL exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException + */ + private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp) throws UnsupportedEncodingException, AAIUnknownObjectException { + + + //we must look up all parents in this case because we need to compute name-properties + //we cannot used the cached aaiUri to perform this action currently + Pair<Vertex, List<Introspector>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp)); + //damaged vertex found, ignore + if (tuple == null) { + return null; + } + List<Introspector> list = tuple.getValue1(); + URI uri = this.getURIFromList(list); + + URIToRelationshipObject uriParser = null; + Introspector result = null; + try { + uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL); + result = uriParser.getResult(); + } catch (AAIException | URISyntaxException e) { + LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.getValue0().id().toString() + ": " + e.getMessage(), e); + if ("true".equals(cleanUp)) { + this.deleteWithTraversal(tuple.getValue0()); + } + return null; + } + return result.getUnderlyingObject(); + } + + /** + * Gets the URI for vertex. + * + * @param v the v + * @return the URI for vertex + * @throws InstantiationException the instantiation exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIUnknownObjectException + */ + public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException { + + return getURIForVertex(v, false); + } + + public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException { + URI uri = null; + + String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null); + + if (aaiUri != null && !overwrite) { + uri = UriBuilder.fromPath(aaiUri).build(); + } else { + Pair<Vertex, List<Introspector>> tuple = this.getParents(this.loader, v, false); + List<Introspector> list = tuple.getValue1(); + uri = this.getURIFromList(list); + } + return uri; + } + /** + * Gets the URI from list. + * + * @param list the list + * @return the URI from list + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException { + String uri = ""; + StringBuilder sb = new StringBuilder(); + for (Introspector i : list) { + sb.insert(0, i.getURI()); + } + + uri = sb.toString(); + URI result = UriBuilder.fromPath(uri).build(); + return result; + } + + /** + * Gets the parents. + * + * @param start the start + * @param removeDamaged the remove damaged + * @return the parents + * @throws InstantiationException the instantiation exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIUnknownObjectException + */ + private Pair<Vertex, List<Introspector>> getParents(Loader loader, Vertex start, boolean removeDamaged) { + + List<Vertex> results = this.engine.getQueryEngine().findParents(start); + List<Introspector> objs = new ArrayList<>(); + boolean shortCircuit = false; + for (Vertex v : results) { + String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + Introspector obj = null; + //vertex on the other end of this edge is bad + if (nodeType == null) { + //log something here about what was found and that it was removed + ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString()); + if (removeDamaged) { + this.deleteWithTraversal(v); + } + shortCircuit = true; + } else { + try { + obj = loader.introspectorFromName(nodeType); + } catch (AAIUnknownObjectException e) { + LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion()); + obj = null; + } + } + + if (obj == null) { + //can't make a valid path because we don't understand this object + // don't include it + } else { + this.simpleDbToObject(obj, v); + objs.add(obj); + } + } + + //stop processing and don't return anything for this bad vertex + if (shortCircuit) { + return null; + } + + return new Pair<>(results.get(results.size()-1), objs); + } + /** + * Takes a list of vertices and a list of objs and assumes they are in + * the order you want the URIs to be nested. + * [A,B,C] creates uris [A, AB, ABC] + * @param vertices + * @param objs + * @throws UnsupportedEncodingException + * @throws URISyntaxException + */ + public void setCachedURIs(List<Vertex> vertices, List<Introspector> objs) throws UnsupportedEncodingException, URISyntaxException { + + String uriChain = ""; + for (int i = 0; i < vertices.size(); i++) { + String aaiUri = ""; + Vertex v = null; + v = vertices.get(i); + aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null); + if (aaiUri != null) { + uriChain += aaiUri; + } else { + URI uri = UriBuilder.fromPath(objs.get(i).getURI()).build(); + aaiUri = uri.toString(); + uriChain += aaiUri; + v.property(AAIProperties.AAI_URI, uriChain); + } + } + + + + } + + + /** + * Adds the r + * @throws AAIUnknownObjectException + * @throws IllegalArgumentException elated to property. + * + * @param relationship the relationship + * @param child the throws IllegalArgumentException, AAIUnknownObjectException child + */ + public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException { + String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS); + List<Introspector> relatedToProperties = new ArrayList<>(); + + if (nameProps != null) { + String[] props = nameProps.split(","); + for (String prop : props) { + Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property"); + relatedTo.setValue("property-key", child.getDbName() + "." + prop); + relatedTo.setValue("property-value", child.getValue(prop)); + relatedToProperties.add(relatedTo); + } + } + + if (relatedToProperties.size() > 0) { + List relatedToList = (List)relationship.getValue("related-to-property"); + for (Introspector obj : relatedToProperties) { + relatedToList.add(obj.getUnderlyingObject()); + } + } + + } + + /** + * Creates the edge. + * + * @param relationship the relationship + * @param inputVertex the input vertex + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { + + Vertex relatedVertex = null; + + QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship); + + List<Vertex> results = parser.getQueryBuilder().toList(); + if (results.size() == 0) { + AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri()); + e.getTemplateVars().add(parser.getResultType()); + e.getTemplateVars().add(parser.getUri().toString()); + throw e; + } else { + //still an issue if there's more than one + relatedVertex = results.get(0); + } + + if (relatedVertex != null) { + + Edge e; + try { + e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex); + if (e == null) { + edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex); + + } else { + //attempted to link two vertexes already linked + } + } catch (NoEdgeRuleFoundException e1) { + throw new AAIException("AAI_6129", e1); + } + + + + + } + + return true; + } + + /** + * Gets the edges between. + * + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return the edges between + * @throws AAIException the AAI exception + * @throws NoEdgeRuleFoundException + */ + private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException { + + List<Edge> result = new ArrayList<>(); + + if (bVertex != null) { + EdgeRule rule = edgeRules.getEdgeRule(type, aVertex, bVertex); + GraphTraversal<Vertex, Edge> findEdgesBetween = null; + findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(rule.getLabel()).filter(__.otherV().hasId(bVertex.id())); + List<Edge> edges = findEdgesBetween.toList(); + for (Edge edge : edges) { + if (edge.label().equals(rule.getLabel())) { + result.add(edge); + } + } + + } + + return result; + } + + /** + * Gets the edge between. + * + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return the edge between + * @throws AAIException the AAI exception + * @throws NoEdgeRuleFoundException + */ + private Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException { + + + + if (bVertex != null) { + + List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex); + + if (edges.size() > 0) { + return edges.get(0); + } + + } + + return null; + } + + + /** + * Delete edge. + * + * @param relationship the relationship + * @param inputVertex the input vertex + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { + + Vertex relatedVertex = null; + + QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship); + + List<Vertex> results = parser.getQueryBuilder().toList(); + + if (results.size() == 0) { + return false; + } + + relatedVertex = results.get(0); + Edge edge; + try { + edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex); + } catch (NoEdgeRuleFoundException e) { + throw new AAIException("AAI_6129", e); + } + if (edge != null) { + edge.remove(); + return true; + } else { + return false; + } + + } + + /** + * Delete items with traversal. + * + * @param vertexes the vertexes + * @throws IllegalStateException the illegal state exception + */ + public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException { + for (Vertex v : vertexes) { + LOGGER.debug("About to delete the vertex with id: " + v.id()); + deleteWithTraversal(v); + } + } + + /** + * Delete with traversal. + * + * @param startVertex the start vertex + */ + public void deleteWithTraversal(Vertex startVertex) { + + List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex); + + for (Vertex v : results) { + LOGGER.warn("Removing vertex " + v.id().toString()); + + v.remove(); + } + + } + + /** + * Delete. + * + * @param v the v + * @param resourceVersion the resource version + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + * @throws InterruptedException the interrupted exception + */ + public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException { + + boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion); + if (result) { + try { + deleteWithTraversal(v); + } catch (IllegalStateException e) { + throw new AAIException("AAI_6110", e); + } + + } + + } + + + /** + * Verify delete semantics. + * + * @param vertex the vertex + * @param resourceVersion the resource version + * @return true, if successful + * @throws AAIException the AAI exception + */ + private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException { + boolean result = false; + String nodeType = ""; + DeleteSemantic semantic = null; + List<Edge> inEdges = null; + List<Edge> outEdges = null; + String errorDetail = " unknown delete semantic found"; + String aaiExceptionCode = ""; + nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); + if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) { + } + semantic = edgeRules.getDeleteSemantic(nodeType); + inEdges = (List<Edge>) IteratorUtils.toList(vertex.edges(Direction.IN)); + outEdges = (List<Edge>) IteratorUtils.toList(vertex.edges(Direction.OUT)); + if (semantic.equals(DeleteSemantic.CASCADE_TO_CHILDREN)) { + result = true; + } else if (semantic.equals(DeleteSemantic.ERROR_IF_ANY_EDGES)) { + if (inEdges.isEmpty() && outEdges.isEmpty()) { + result = true; + } else { + errorDetail = " Node cannot be deleted because it still has Edges and the " + semantic + " scope was used.\n"; + aaiExceptionCode = "AAI_6110"; + } + } else if (semantic.equals(DeleteSemantic.ERROR_IF_ANY_IN_EDGES) || semantic.equals(DeleteSemantic.ERROR_4_IN_EDGES_OR_CASCADE)) { + + if (inEdges.isEmpty()) { + result = true; + } else { + //are there any cousin edges? + long children = 0; + for (Edge e : inEdges) { + if (e.<Boolean>property("isParent").orElse(false)) { + children++; + } + } + + result = children == inEdges.size(); + } + + if (!result) { + errorDetail = " Node cannot be deleted because it still has Edges and the " + semantic + " scope was used.\n"; + aaiExceptionCode = "AAI_6110"; + } + } else if (semantic.equals(DeleteSemantic.THIS_NODE_ONLY)) { + if (outEdges.isEmpty() && inEdges.isEmpty()) { + result = true; + } else { + result = true; + for (Edge edge : outEdges) { + Object property = edge.<Boolean>property("isParent").orElse(null); + if (property != null && property.equals(Boolean.TRUE)) { + Vertex v = edge.inVertex(); + String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + errorDetail = " Node cannot be deleted using scope = " + semantic + + " another node (type = " + vType + ") depends on it for uniqueness."; + aaiExceptionCode = "AAI_6110"; + result = false; + break; + } + } + + for (Edge edge : inEdges) { + Object property = edge.<Boolean>property("isParent-REV").orElse(null); + if (property != null && property.equals(Boolean.TRUE)) { + Vertex v = edge.outVertex(); + String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + errorDetail = " Node cannot be deleted using scope = " + semantic + + " another node (type = " + vType + ") depends on it for uniqueness."; + aaiExceptionCode = "AAI_6110"; + result = false; + break; + } + } + } + } + + + if (!result) { + throw new AAIException(aaiExceptionCode, errorDetail); + } + return result; + } + + /** + * Verify resource version. + * + * @param action the action + * @param nodeType the node type + * @param currentResourceVersion the current resource version + * @param resourceVersion the resource version + * @param uri the uri + * @return true, if successful + * @throws AAIException the AAI exception + */ + public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException { + String enabled = ""; + String errorDetail = ""; + String aaiExceptionCode = ""; + if (currentResourceVersion == null) { + currentResourceVersion = ""; + } + + if (resourceVersion == null) { + resourceVersion = ""; + } + try { + enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG); + } catch (AAIException e) { + ErrorLogHelper.logException(e); + } + // We're only doing the resource version checks for v5 and later + if (enabled.equals("true") && this.version.compareTo(Version.v8) > 0) { + if (!currentResourceVersion.equals(resourceVersion)) { + if (action.equals("create") && !resourceVersion.equals("")) { + errorDetail = "resource-version passed for " + action + " of " + uri; + aaiExceptionCode = "AAI_6135"; + } else if (resourceVersion.equals("")) { + errorDetail = "resource-version not passed for " + action + " of " + uri; + aaiExceptionCode = "AAI_6130"; + } else { + errorDetail = "resource-version MISMATCH for " + action + " of " + uri; + aaiExceptionCode = "AAI_6131"; + } + + throw new AAIException(aaiExceptionCode, errorDetail); + + } + } + return true; + } + + /** + * Convert from camel case. + * + * @param name the name + * @return the string + */ + private String convertFromCamelCase (String name) { + String result = ""; + result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name); + + NamingExceptions exceptions = NamingExceptions.getInstance(); + result = exceptions.getDBName(result); + + return result; + } + + private boolean canModify(Introspector obj, String propName, String requestContext) { + final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY); + if (readOnly != null) { + final String[] items = readOnly.split(","); + for (String item : items) { + if (requestContext.equals(item)) { + return false; + } + } + } + return true; + } + + private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException { + + SideEffectRunner runner = new SideEffectRunner + .Builder(this.engine, this).addSideEffect(DataCopy.class).build(); + + runner.execute(obj, self); + } + + private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException { + + SideEffectRunner runner = new SideEffectRunner + .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build(); + + runner.execute(obj, self); + } + + private void enrichData(Introspector obj, Vertex self) throws AAIException { + + SideEffectRunner runner = new SideEffectRunner + .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build(); + + runner.execute(obj, self); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/DeleteSemantic.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DeleteSemantic.java new file mode 100644 index 00000000..65a39497 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DeleteSemantic.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + + +/** + * Possible values for deleteScope can be: + * USE_DEFAULT - Get the scope from ref data for this node + * THIS_NODE_ONLY (but should fail if it there are nodes that depend on it for uniqueness) + * CASCADE_TO_CHILDREN - will look for OUT-Edges that have parentOf/hasDelTarget = true and follow those down + * ERROR_4_IN_EDGES_OR_CASCADE - combo of error-if-any-IN-edges + CascadeToChildren + * ERROR_IF_ANY_IN_EDGES - Fail if this node has any existing IN edges + * ERROR_IF_ANY_EDGES - Fail if this node has any existing edges at all! + */ +public enum DeleteSemantic { + USE_DEFAULT, + THIS_NODE_ONLY, + CASCADE_TO_CHILDREN, + ERROR_4_IN_EDGES_OR_CASCADE, + ERROR_IF_ANY_IN_EDGES, + ERROR_IF_ANY_EDGES, +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java new file mode 100644 index 00000000..d7abfdc0 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java @@ -0,0 +1,202 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.tinkerpop.gremlin.structure.Direction; + +public class EdgeRule { + + private String label = ""; + private MultiplicityRule multiplicityRule = null; + private Direction direction = null; + private Map<String, String> edgeProperties = null; + private final String IS_PARENT = "isParent"; + private final String USES_RESOURCE = "usesResource"; + private final String HAS_DEL_TARGET = "hasDelTarget"; + private final String SVC_INFRA = "SVC-INFRA"; + + /** + * Instantiates a new edge rule. + */ + public EdgeRule() { + edgeProperties = new HashMap<>(); + } + + /** + * Gets the label. + * + * @return the label + */ + public String getLabel() { + return label; + } + + /** + * Sets the label. + * + * @param label the new label + */ + public void setLabel(String label) { + this.label = label; + } + + /** + * Gets the multiplicity rule. + * + * @return the multiplicity rule + */ + public MultiplicityRule getMultiplicityRule() { + return multiplicityRule; + } + + /** + * Sets the multiplicity rule. + * + * @param multiplicityRule the new multiplicity rule + */ + public void setMultiplicityRule(MultiplicityRule multiplicityRule) { + this.multiplicityRule = multiplicityRule; + } + + /** + * Gets the direction. + * + * @return the direction + */ + public Direction getDirection() { + return direction; + } + + /** + * Sets the direction. + * + * @param direction the new direction + */ + public void setDirection(Direction direction) { + this.direction = direction; + } + + /** + * Gets the checks if is parent. + * + * @return the checks if is parent + */ + public String getIsParent() { + return this.getProp(this.IS_PARENT); + } + + /** + * Sets the checks if is parent. + * + * @param isParent the new checks if is parent + */ + public void setIsParent(String isParent) { + this.setProp(this.IS_PARENT, isParent); + } + + /** + * Gets the uses resource. + * + * @return the uses resource + */ + public String getUsesResource() { + return this.getProp(this.USES_RESOURCE); + } + + /** + * Sets the uses resource. + * + * @param usesResource the new uses resource + */ + public void setUsesResource(String usesResource) { + this.setProp(this.USES_RESOURCE, usesResource); + } + + /** + * Gets the checks for del target. + * + * @return the checks for del target + */ + public String getHasDelTarget() { + return this.getProp(this.HAS_DEL_TARGET); + } + + /** + * Sets the checks for del target. + * + * @param hasDelTarget the new checks for del target + */ + public void setHasDelTarget(String hasDelTarget) { + this.setProp(this.HAS_DEL_TARGET, hasDelTarget); + } + + /** + * Gets the service infrastructure. + * + * @return the service infrastructure + */ + public String getServiceInfrastructure() { + return this.getProp(this.SVC_INFRA); + } + + /** + * Sets the service infrastructure. + * + * @param serviceInfrastructure the new service infrastructure + */ + public void setServiceInfrastructure(String serviceInfrastructure) { + this.setProp(this.SVC_INFRA, serviceInfrastructure); + } + + /** + * Gets the edge properties. + * + * @return the edge properties + */ + public Map<String, String> getEdgeProperties() { + return this.edgeProperties; + } + + /** + * Sets the prop. + * + * @param key the key + * @param value the value + */ + private void setProp(String key, String value) { + this.edgeProperties.put(key, value); + } + + /** + * Gets the prop. + * + * @param key the key + * @return the prop + */ + private String getProp(String key) { + return this.edgeProperties.get(key); + } + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java new file mode 100644 index 00000000..06dfe564 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java @@ -0,0 +1,379 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.dbmodel.DbEdgeRules; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +public class EdgeRules { + + private Multimap<String, String> rules = DbEdgeRules.EdgeRules; + private Multimap<String, String> deleteScope = DbEdgeRules.DefaultDeleteScope; + private final int EDGE_NAME = 0; + private final int DIRECTION = 1; + private final int MULTIPLICITY_RULE = 2; + private final int IS_PARENT = 3; + private final int USES_RESOURCE = 4; + private final int HAS_DEL_TARGET = 5; + private final int SVC_INFRA = 6; + + /** + * Instantiates a new edge rules. + */ + private EdgeRules() { + + } + private static class Helper { + private static final EdgeRules INSTANCE = new EdgeRules(); + + } + + /** + * Gets the single instance of EdgeRules. + * + * @return single instance of EdgeRules + */ + public static EdgeRules getInstance() { + return Helper.INSTANCE; + + } + + /** + * Adds the tree edge. + * + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return the edge + * @throws AAIException the AAI exception + * @throws NoEdgeRuleFoundException + */ + public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException { + return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex); + } + + /** + * Adds the edge. + * + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return the edge + * @throws AAIException the AAI exception + * @throws NoEdgeRuleFoundException + */ + public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException { + return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex); + } + + /** + * Adds the edge. + * + * @param type the type + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return the edge + * @throws AAIException the AAI exception + * @throws NoEdgeRuleFoundException + */ + private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException { + + EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex); + + Edge e = null; + if (this.validateMultiplicity(rule, traversalSource, aVertex, bVertex)) { + if (rule.getDirection().equals(Direction.OUT)) { + e = aVertex.addEdge(rule.getLabel(), bVertex); + } else if (rule.getDirection().equals(Direction.IN)) { + e = bVertex.addEdge(rule.getLabel(), aVertex); + } + + this.addProperties(e, rule); + } + return e; + } + + /** + * Adds the properties. + * + * @param edge the edge + * @param rule the rule + */ + public void addProperties(Edge edge, EdgeRule rule) { + + // In DbEdgeRules.EdgeRules -- What we have as "edgeRule" is a comma-delimited set of strings. + // The first item is the edgeLabel. + // The second in the list is always "direction" which is always OUT for the way we've implemented it. + // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to + // tags as defined in EdgeInfoMap. + // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it + Map<String, String> propMap = rule.getEdgeProperties(); + + for (String key : propMap.keySet()) { + String revKeyname = key + "-REV"; + String triple = propMap.get(key); + if(triple.equals("true")){ + edge.property(key, true); + edge.property(revKeyname,false); + } else if (triple.equals("false")) { + edge.property(key, false); + edge.property(revKeyname,false); + } else if (triple.equals("reverse")) { + edge.property(key, false); + edge.property(revKeyname,true); + } + } + } + + /** + * Checks for edge rule. + * + * @param outType the out type + * @param inType the in type + * @return true, if successful + */ + public boolean hasEdgeRule(String outType, String inType) { + + Collection<String> collection = rules.get(outType + "|" + inType); + + return !collection.isEmpty(); + + } + + /** + * Checks for edge rule. + * + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return true, if successful + */ + public boolean hasEdgeRule(Vertex aVertex, Vertex bVertex) { + String outType = (String)aVertex.<String>property("aai-node-type").orElse(null); + String inType = (String)bVertex.<String>property("aai-node-type").orElse(null); + + return this.hasEdgeRule(outType, inType); + + } + + public Map<String, EdgeRule> getEdgeRules(String outType, String inType) throws AAIException { + Map<String, EdgeRule> result = new HashMap<>(); + EdgeRule rule = null; + for (EdgeType type : EdgeType.values()) { + try { + rule = this.getEdgeRule(type, outType, inType); + result.put(rule.getLabel(), rule); + } catch (NoEdgeRuleFoundException e) { + continue; + } + } + + return result; + } + /** + * Gets the edge rule. + * + * @param outType the out type + * @param inType the in type + * @return the edge rule + * @throws AAIException the AAI exception + */ + public EdgeRule getEdgeRule(EdgeType type, String outType, String inType) throws AAIException { + EdgeRule rule = new EdgeRule(); + Collection<String> collection = null; + boolean isFlipped = false; + if (this.hasEdgeRule(outType, inType) || this.hasEdgeRule(inType, outType)) { + } else { + String detail = "No EdgeRule found for passed nodeTypes: " + outType + ", " + inType + "."; + throw new AAIException("AAI_6120", detail); + } + String key = outType + "|" + inType; + collection = rules.get(key); + + String[] info = null; + Iterator<String> iterator = collection.iterator(); + info = this.findRuleForContext(type, key, iterator); + if (info == null) { //didn't find anything in that order, look again + key = inType + "|" + outType; + collection = rules.get(key); + iterator = collection.iterator(); + info = this.findRuleForContext(type, key, iterator); + isFlipped = true; + } + if (info == null) { + throw new NoEdgeRuleFoundException("No EdgeRule found for EdgeType: " + type + " and node types: " + outType + " " + inType); + } + rule.setLabel(info[this.EDGE_NAME]); + rule.setMultiplicityRule(MultiplicityRule.valueOf(info[this.MULTIPLICITY_RULE].toUpperCase())); + rule.setHasDelTarget(info[this.HAS_DEL_TARGET]); + rule.setUsesResource(info[this.USES_RESOURCE]); + rule.setIsParent(info[this.IS_PARENT]); + rule.setServiceInfrastructure(info[this.SVC_INFRA]); + Direction direction = Direction.valueOf(info[this.DIRECTION]); + if (isFlipped && direction.equals(Direction.OUT)) { + rule.setDirection(Direction.IN); + } else if (isFlipped && direction.equals(Direction.IN)){ + rule.setDirection(Direction.OUT); + } else { + rule.setDirection(direction); + } + + return rule; + } + + private String[] findRuleForContext (EdgeType type, String key, Iterator<String> itr) { + String[] result = null; + String s = ""; + String isParent = ""; + String[] info = new String[10]; + while (itr.hasNext()) { + s = itr.next(); + info = s.split(","); + isParent = info[this.IS_PARENT]; + //lazily stop iterating if we find a match + //should there be a mismatch between type and isParent, + //the caller will receive something. + //this operates on the assumption that there are at most two rules + //for a given vertex pair + if (type.equals(EdgeType.TREE) && (isParent.equals("true") || isParent.equals("reverse"))) { + result = info; + break; + } else if (type.equals(EdgeType.COUSIN) && isParent.equals("false")) { + result = info; + break; + } + } + + + return result; + } + /** + * Gets the edge rule. + * + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return the edge rule + * @throws AAIException the AAI exception + * @throws NoEdgeRuleFoundException + */ + public EdgeRule getEdgeRule(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException { + String outType = (String)aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); + String inType = (String)bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); + + return this.getEdgeRule(type, outType, inType); + + + } + + /** + * Gets the delete semantic. + * + * @param nodeType the node type + * @return the delete semantic + */ + public DeleteSemantic getDeleteSemantic(String nodeType) { + Collection<String> semanticCollection = deleteScope.get(nodeType); + String semantic = semanticCollection.iterator().next(); + + return DeleteSemantic.valueOf(semantic); + + } + + /** + * Validate multiplicity. + * + * @param rule the rule + * @param aVertex the out vertex + * @param bVertex the in vertex + * @return true, if successful + * @throws AAIException the AAI exception + */ + private boolean validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException { + + if (rule.getDirection().equals(Direction.OUT)) { + + } else if (rule.getDirection().equals(Direction.IN)) { + Vertex tempV = bVertex; + bVertex = aVertex; + aVertex = tempV; + } + + String aVertexType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); + String bVertexType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); + String label = rule.getLabel(); + MultiplicityRule multiplicityRule = rule.getMultiplicityRule(); + List<Edge> outEdges = traversalSource.V(aVertex).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList(); + List<Edge> inEdges = traversalSource.V(bVertex).inE(label).where(__.outV().has(AAIProperties.NODE_TYPE, aVertexType)).toList(); + String detail = ""; + if (multiplicityRule.equals(MultiplicityRule.ONE2ONE)) { + if (inEdges.size() >= 1 || outEdges.size() >= 1 ) { + detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType; + } + } else if (multiplicityRule.equals(MultiplicityRule.ONE2MANY)) { + if (inEdges.size() >= 1) { + detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType; + } + } else if (multiplicityRule.equals(MultiplicityRule.MANY2ONE)) { + if (outEdges.size() >= 1) { + detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType; + } + } else { + + } + + if (!detail.equals("")) { + throw new AAIException("AAI_6140", detail); + } + + return true; + + } + + public Multimap<String, EdgeRule> getAllRules() throws AAIException { + + Multimap<String, EdgeRule> result = ArrayListMultimap.create(); + + for (String key : this.rules.keySet()) { + String outType = ""; + String inType = ""; + String[] split = key.split("\\|"); + outType = split[0]; + inType = split[1]; + result.putAll(key,this.getEdgeRules(outType, inType).values()); + } + + return result; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeType.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeType.java new file mode 100644 index 00000000..aabd74fe --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeType.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +public enum EdgeType { + COUSIN, + TREE; +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/GetAllPool.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GetAllPool.java new file mode 100644 index 00000000..356f70ae --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GetAllPool.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class GetAllPool { + + private ExecutorService pool; + + private GetAllPool() { + pool = Executors.newWorkStealingPool(Runtime.getRuntime().availableProcessors()); + } + + private static class Helper { + private static final GetAllPool INSTANCE = new GetAllPool(); + } + + public static GetAllPool getInstance() { + return Helper.INSTANCE; + } + + public ExecutorService getPool() { + + return this.pool; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/GraphSingleton.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GraphSingleton.java new file mode 100644 index 00000000..9f226dc1 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GraphSingleton.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.openecomp.aai.dbmap.AAIGraph; +import org.openecomp.aai.dbmap.DBConnectionType; +import com.thinkaurelius.titan.core.TitanGraph; + +/* This class simply calls AAIGraph under the covers for now */ +public class GraphSingleton { + + protected AtomicInteger totalCount = new AtomicInteger(); + + private static class Helper { + private static final GraphSingleton INSTANCE = new GraphSingleton(); + } + + /** + * Gets the single instance of GraphSingleton. + * + * @return single instance of GraphSingleton + */ + public static GraphSingleton getInstance() { + return Helper.INSTANCE; + + } + + /** + * Gets the count. + * + * @return the count + */ + public AtomicInteger getCount() { + return totalCount; + } + + /** + * Gets the tx graph. + * + * @return the tx graph + */ + public TitanGraph getTxGraph() { + return AAIGraph.getInstance().getGraph(); + } + + public TitanGraph getTxGraph(DBConnectionType connectionType) { + return AAIGraph.getInstance().getGraph(connectionType); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/LegacyDBSerializer.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/LegacyDBSerializer.java new file mode 100644 index 00000000..841b1b74 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/LegacyDBSerializer.java @@ -0,0 +1,35 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; +import org.apache.tinkerpop.gremlin.structure.Graph; + +public class LegacyDBSerializer extends DBSerializer { + + public LegacyDBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException { + super(version, engine, introspectionType, sourceOfTruth); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/MultiplicityRule.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/MultiplicityRule.java new file mode 100644 index 00000000..734a44bc --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/MultiplicityRule.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +public enum MultiplicityRule { + MANY2ONE, + ONE2MANY, + ONE2ONE, + MANY2MANY +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/TitanGraphSingleton.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/TitanGraphSingleton.java new file mode 100644 index 00000000..bca2d70c --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/TitanGraphSingleton.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db; + +/* This is class is just a wrapper of its parent */ +public class TitanGraphSingleton extends GraphSingleton { + + private static class Helper { + private static final TitanGraphSingleton INSTANCE = new TitanGraphSingleton(); + } + + /** + * Gets the single instance of TitanGraphSingleton. + * + * @return single instance of TitanGraphSingleton + */ + public static TitanGraphSingleton getInstance() { + return Helper.INSTANCE; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java new file mode 100644 index 00000000..6647f4d5 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.db.exceptions; + +import org.openecomp.aai.exceptions.AAIException; + +public class NoEdgeRuleFoundException extends AAIException { + + private static final long serialVersionUID = -906843868234976763L; + + public NoEdgeRuleFoundException(String message) { + super("AAI_6129", message); + } + + public NoEdgeRuleFoundException(Throwable cause) { + super("AAI_6129",cause); + } + + public NoEdgeRuleFoundException(String message, Throwable cause) { + super("AAI_6129", cause, message); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/QueryStyle.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/QueryStyle.java new file mode 100644 index 00000000..acec8dff --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/QueryStyle.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.engines; + +public enum QueryStyle { + GREMLIN_TRAVERSAL, GREMLIN_UNIQUE, GREMLINPIPELINE_TRAVERSAL, TRAVERSAL +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TitanDBEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TitanDBEngine.java new file mode 100644 index 00000000..e3e0e857 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TitanDBEngine.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.engines; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; + +import org.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.serialization.db.TitanGraphSingleton; +import com.thinkaurelius.titan.core.TitanVertex; + +public class TitanDBEngine extends TransactionalGraphEngine { + + /** + * Instantiates a new titan DB engine. + * + * @param style the style + * @param loader the loader + */ + public TitanDBEngine(QueryStyle style, DBConnectionType connectionType, Loader loader) { + super(style, loader, connectionType, TitanGraphSingleton.getInstance()); + } + + /** + * Instantiates a new titan DB engine. + * + * @param style the style + * @param loader the loader + * @param connect the connect + */ + public TitanDBEngine(QueryStyle style, Loader loader, boolean connect) { + super(style, loader); + if (connect) { + this.singleton = TitanGraphSingleton.getInstance(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean setListProperty(Vertex v, String name, List<?> objs) { + + //clear out list full replace style + + Iterator<VertexProperty<Object>> iterator = v.properties(name); + while (iterator.hasNext()) { + iterator.next().remove(); + } + if (objs != null) { + for (Object obj : objs) { + v.property(name, obj); + } + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public List<Object> getListProperty(Vertex v, String name) { + + List<Object> result = new ArrayList<Object>(); + + Iterator<VertexProperty<Object>> iterator = v.properties(name); + + while (iterator.hasNext()) { + result.add(iterator.next().value()); + } + + if (result.size() == 0) { + result = null; + } + + return result; + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TransactionalGraphEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TransactionalGraphEngine.java new file mode 100644 index 00000000..7f63c055 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TransactionalGraphEngine.java @@ -0,0 +1,234 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.engines; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.query.builder.GremlinTraversal; +import org.openecomp.aai.query.builder.GremlinUnique; +import org.openecomp.aai.query.builder.QueryBuilder; +import org.openecomp.aai.query.builder.TraversalQuery; +import org.openecomp.aai.serialization.db.GraphSingleton; +import org.openecomp.aai.serialization.engines.query.GraphTraversalQueryEngine; +import org.openecomp.aai.serialization.engines.query.QueryEngine; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanTransaction; +import com.thinkaurelius.titan.core.schema.TitanManagement; + +public abstract class TransactionalGraphEngine { + + protected GraphSingleton singleton = null; + protected QueryEngine queryEngine = null; + protected QueryBuilder queryBuilder = null; + protected QueryStyle style = null; + protected final DBConnectionType connectionType; + protected final Loader loader; + protected TitanTransaction currentTx = null; + protected GraphTraversalSource currentTraversal = null; + protected GraphTraversalSource readOnlyTraversal = null; + private final Admin admin; + /** + * Instantiates a new transactional graph engine. + * + * @param style the style + * @param loader the loader + */ + public TransactionalGraphEngine (QueryStyle style, Loader loader, DBConnectionType connectionType, GraphSingleton singleton) { + this.loader = loader; + this.style = style; + this.singleton = singleton; + this.connectionType = connectionType; + admin = new Admin(); + + } + + public TransactionalGraphEngine (QueryStyle style, Loader loader) { + this.loader = loader; + this.style = style; + this.connectionType = DBConnectionType.REALTIME; + admin = new Admin(); + } + + /** + * Sets the list property. + * + * @param v the v + * @param name the name + * @param obj the obj + * @return true, if successful + */ + public abstract boolean setListProperty(Vertex v, String name, List<?> obj); + + /** + * Gets the list property. + * + * @param v the v + * @param name the name + * @return the list property + */ + public abstract List<Object> getListProperty(Vertex v, String name); + + /** + * Gets the graph. + * + * @return the graph + */ + private TitanGraph getGraph() { + return singleton.getTxGraph(this.connectionType); + } + + /** + * Gets the count. + * + * @return the count + */ + public AtomicInteger getCount() { + return singleton.getCount(); + } + + + /** + * Gets the query engine. + * + * @return the query engine + */ + public QueryEngine getQueryEngine() { + QueryEngine engine = null; + if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) { + //this.queryEngine = new GremlinQueryEngine(this); + } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) { + //this.queryEngine = new GremlinQueryEngine(this); + } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) { + //this.queryEngine = new GremlinPipelineQueryEngine(this); + } else if (style.equals(QueryStyle.TRAVERSAL)) { + + return new GraphTraversalQueryEngine(this.asAdmin().getTraversalSource()); + + } else { + throw new IllegalArgumentException("Query Engine type not recognized"); + } + + return engine; + } + + /** + * Gets the query builder. + * + * @return the query builder + */ + public QueryBuilder getQueryBuilder() { + return getQueryBuilder(this.loader); + } + + public QueryBuilder getQueryBuilder(Loader loader) { + if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) { + return new GremlinTraversal(loader, this.asAdmin().getTraversalSource()); + } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) { + return new GremlinUnique(loader, this.asAdmin().getTraversalSource()); + } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) { + //return new GremlinPipelineTraversal(loader); + } else if (style.equals(QueryStyle.TRAVERSAL)) { + return new TraversalQuery(loader, this.asAdmin().getTraversalSource()); + } else { + throw new IllegalArgumentException("Query Builder type not recognized"); + } + return queryBuilder; + } + /** + * Gets the query builder. + * + * @param start the start + * @return the query builder + */ + public QueryBuilder getQueryBuilder(Vertex start) { + return getQueryBuilder(this.loader, start); + } + + public QueryBuilder getQueryBuilder(Loader loader, Vertex start) { + if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) { + return new GremlinTraversal(loader, this.asAdmin().getTraversalSource(), start); + } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) { + return new GremlinUnique(loader, this.asAdmin().getTraversalSource(), start); + } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) { + //return new GremlinPipelineTraversal(loader,start); + } else if (style.equals(QueryStyle.TRAVERSAL)) { + return new TraversalQuery(loader, this.asAdmin().getTraversalSource(), start); + } else { + throw new IllegalArgumentException("Query Builder type not recognized"); + } + return queryBuilder; + } + + public TitanTransaction startTransaction() { + if (this.tx() == null) { + this.currentTx = this.getGraph().newTransaction(); + this.currentTraversal = this.tx().traversal(); + this.readOnlyTraversal = this.tx().traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance())); + } + return currentTx; + } + + public void rollback() { + if (this.tx() != null) { + this.tx().rollback(); + this.currentTx = null; + this.currentTraversal = null; + this.readOnlyTraversal = null; + } + } + public void commit() { + if (this.tx() != null) { + this.tx().commit(); + this.currentTx = null; + this.currentTraversal = null; + this.readOnlyTraversal = null; + } + } + + public TitanTransaction tx() { + return this.currentTx; + } + + public Admin asAdmin() { + return admin; + } + + public class Admin { + + public GraphTraversalSource getTraversalSource() { + return currentTraversal; + } + public GraphTraversalSource getReadOnlyTraversalSource() { + return readOnlyTraversal; + } + + public TitanManagement getManagementSystem() { + return getGraph().openManagement(); + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GraphTraversalQueryEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GraphTraversalQueryEngine.java new file mode 100644 index 00000000..2f485b10 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GraphTraversalQueryEngine.java @@ -0,0 +1,170 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.engines.query; + +import java.util.List; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.introspection.Loader; + +/* + * This class needs some big explanation despite its compact size. + * This controls all the queries performed by the CRUD API in A&AI. + * findParents, findChildren, and findDeletable require special attention + * These methods use 'repeat'. You cannot use 'emit' with repeat currently + * as it is extremely buggy as of tinkerpop-3.0.1-incubating. The way around + * it (for now) is to sideEffect all the vertices we traverse into an ArrayList. + * + */ +public class GraphTraversalQueryEngine extends QueryEngine { + + /** + * Instantiates a new graph traversal query engine. + * + * @param graphEngine the graph engine + */ + public GraphTraversalQueryEngine(GraphTraversalSource g) { + super(g); + } + + /** + * {@inheritDoc} + */ + @Override + public List<Vertex> findParents(Vertex start) { + + final GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).emit(v -> true).repeat(__.inE().has("isParent", true).outV()); + return pipe.toList(); + } + + /** + * {@inheritDoc} + */ + @Override + public List<Vertex> findAllChildren(Vertex start) { + + GraphTraversal<Vertex, Vertex> pipe = this.g + .V(start).emit(v -> true).repeat(__.outE().has("isParent", true).inV()); + + + return pipe.toList(); + + } + + public List<Vertex> findChildrenOfType(Vertex start, String type) { + GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).union( + __.outE().has("isParent", true).inV(), + __.inE().has("isParent-REV", true).outV() + ).has(AAIProperties.NODE_TYPE, type).dedup(); + + return pipe.toList(); + } + + /** + * {@inheritDoc} + */ + @Override + public List<Vertex> findDeletable(Vertex start) { + GraphTraversal<Vertex, Vertex> pipe = this.g + .V(start).emit(v -> true).repeat(__.outE().or( + __.has("isParent", true), + __.has("hasDelTarget", true)).inV()); + + return pipe.toList(); + } + + /** + * {@inheritDoc} + */ + @Override + public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) { + GraphTraversal<Vertex, Vertex> pipe = this.g.V(start); + switch (direction) { + case OUT: + pipe.out(label); + break; + case IN: + pipe.in(label); + break; + case BOTH: + pipe.both(label); + break; + default: + break; + } + + pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup(); + return pipe.toList(); + } + + @Override + public Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly) { + final GraphTraversal<Vertex, ?> t = this.g.V(start).emit(v -> true).times(iterations).repeat( + __.outE().has("isParent", true).inV()); + + if (!nodeOnly) { + t.union( + __.identity(), + __.bothE().has("isParent", false).dedup().otherV() + ); + } + t.tree(); + if (t.hasNext()) { + return (Tree)t.next(); + } else { + return new Tree(); + } + } + + @Override + public List<Edge> findEdgesForVersion(Vertex start, Loader loader) { + final Set<String> objects = loader.getAllObjects().keySet(); + GraphTraversal<Vertex, Edge> pipeline = this.g.V(start).union( + __.inE().has("isParent", false).has("isParent-REV", false).where(__.outV().has(AAIProperties.NODE_TYPE, P.within(objects))), + __.outE().has("isParent", false).has("isParent-REV", false).where(__.inV().has(AAIProperties.NODE_TYPE, P.within(objects))) + ).dedup(); + + return pipeline.toList(); + } + + + @Override + public List<Vertex> findCousinVertices(Vertex start) { + GraphTraversal<Vertex, Vertex> pipeline = this.g.V(start).union( + __.inE().has("isParent", false).has("isParent-REV", false), + __.outE().has("isParent", false).has("isParent-REV", false)).otherV().dedup(); + + return pipeline.toList(); + } + +} + diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GremlinPipelineQueryEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GremlinPipelineQueryEngine.java new file mode 100644 index 00000000..adf5d405 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GremlinPipelineQueryEngine.java @@ -0,0 +1,185 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +/* +package org.openecomp.aai.serialization.engines.query; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.query.builder.QueryBuilder; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; +import com.tinkerpop.blueprints.Direction; +import com.tinkerpop.blueprints.TransactionalGraph; +import com.tinkerpop.blueprints.Vertex; +import com.tinkerpop.gremlin.java.GremlinPipeline; +import com.tinkerpop.pipes.IdentityPipe; +import com.tinkerpop.pipes.PipeFunction; +import com.tinkerpop.pipes.branch.LoopPipe; + +public class GremlinPipelineQueryEngine extends QueryEngine { + + public GremlinPipelineQueryEngine(TransactionalGraphEngine graphEngine) { + super(graphEngine); + } + + @Override + public List<Vertex> executeQuery(TransactionalGraph g, QueryBuilder query) { + List<Vertex> results = null; + Vertex start = query.getStart(); + if (start != null) { + results = ((GremlinPipeline)query.getQuery()).cast(Vertex.class).toList(); + } else { + GremlinPipeline pipe = new GremlinPipeline(g); + results = process(pipe, (GremlinPipeline)query.getQuery()); + + } + return results; + } + + @Override + public List<Vertex> executeParentQuery(TransactionalGraph g, QueryBuilder query) { + List<Vertex> results = null; + Vertex start = query.getStart(); + if (start != null) { + results = ((GremlinPipeline)query.getParentQuery()).cast(Vertex.class).toList(); + } else { + GremlinPipeline pipe = new GremlinPipeline(g); + results = process(pipe, (GremlinPipeline)query.getParentQuery()); + + } + return results; + } + + @Override + public List<Vertex> findParents(Vertex start) { + GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline(start).as("x").inE() + .has("isParent", true).outV().loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() { + + @Override + public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) { + GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject()); + return pipe.inE().has("isParent", true).count() == 1 || argument.getLoops() < 100; + } + + }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() { + + @Override + public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) { + return true; + } + + }); + + List<Vertex> results = pipe.toList(); + results.add(0, start); + return results; + } + + @Override + public List<Vertex> findChildren(Vertex start) { + Set<Vertex> seen = new HashSet<>(); + seen.add(start); + GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline(start).as("x").outE().has("isParent", true).inV() + .except(seen).store(seen).loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() { + + @Override + public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) { + GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject()); + return pipe.outE().has("isParent", true).count() >= 1 || argument.getLoops() < 100; + } + + }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() { + + @Override + public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) { + return true; + } + + }); + + List<Vertex> results = pipe.toList(); + results.add(0, start); + return results; + } + + @Override + public List<Vertex> findDeletable(Vertex start) { + Set<Vertex> seen = new HashSet<>(); + seen.add(start); + GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>(start).as("x").outE().or( + new GremlinPipeline(new IdentityPipe()).has("isParent", true), + new GremlinPipeline(new IdentityPipe()).has("hasDelTarget", true)).inV() + .except(seen).store(seen).loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() { + + @Override + public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) { + GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject()); + return pipe.outE().or( + new GremlinPipeline(new IdentityPipe()).has("isParent", true), + new GremlinPipeline(new IdentityPipe()).has("hasDelTarget", true)).count() >= 1 || argument.getLoops() < 100; + } + + }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() { + + @Override + public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) { + return true; + } + + }); + List<Vertex> results = pipe.toList(); + results.add(0, start); + + return results; + } + + private List<Vertex> process(GremlinPipeline start, GremlinPipeline pipe) { + + + return start.add(pipe).cast(Vertex.class).toList(); + } + + @Override + public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) { + GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>(start); + switch (direction) { + case OUT: + pipe.out(label); + break; + case IN: + pipe.in(label); + break; + case BOTH: + pipe.both(label); + break; + default: + break; + } + + pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup(); + List<Vertex> result = pipe.toList(); + return result; + } + +} +*/ diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/QueryEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/QueryEngine.java new file mode 100644 index 00000000..bff6f082 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/QueryEngine.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.engines.query; + +import java.util.List; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.introspection.Loader; + +public abstract class QueryEngine { + + final protected GraphTraversalSource g; + + /** + * Instantiates a new query engine. + * + * @param graphEngine the graph engine + */ + public QueryEngine (GraphTraversalSource g) { + this.g = g; + } + + /** + * Find parents. + * + * @param start the start + * @return the list + */ + public abstract List<Vertex> findParents(Vertex start); + + /** + * Find children. + * + * @param start the start + * @return the list + */ + public abstract List<Vertex> findAllChildren(Vertex start); + + public abstract List<Vertex> findChildrenOfType(Vertex start, String type); + /** + * Find deletable. + * + * @param start the start + * @return the list + */ + public abstract List<Vertex> findDeletable(Vertex start); + + public Tree<Element> findSubGraph(Vertex start) { + return findSubGraph(start, AAIProperties.MAXIMUM_DEPTH, false); + } + public abstract Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly); + /** + * Find related vertices. + * + * @param start the start + * @param direction the direction + * @param label the label + * @param nodeType the node type + * @return the list + */ + public abstract List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType); + + public abstract List<Edge> findEdgesForVersion(Vertex start, Loader loader); + + public abstract List<Vertex> findCousinVertices(Vertex start); + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Console.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Console.java new file mode 100644 index 00000000..7aaf02c8 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Console.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import com.google.gson.JsonObject; + +public class Console implements FormatMapper { + + @Override + public JsonObject formatObject(Object v) throws AAIFormatVertexException { + + JsonObject json = new JsonObject(); + json.addProperty("result", v.toString()); + + return json; + } + + @Override + public int parallelThreshold() { + return 100; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Format.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Format.java new file mode 100644 index 00000000..e3618917 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Format.java @@ -0,0 +1,29 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +public enum Format { + graphson, + pathed, id, resource, + simple, + resource_and_url, + console +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatFactory.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatFactory.java new file mode 100644 index 00000000..d00b5cda --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatFactory.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder; + +public class FormatFactory { + + private final Loader loader; + private final DBSerializer serializer; + private final UrlBuilder urlBuilder; + public FormatFactory (Loader loader, DBSerializer serializer) throws AAIException { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = new UrlBuilder(loader.getVersion(), serializer); + } + + public Formatter get(Format format) throws AAIException { + + Formatter formattter = null; + + switch (format) { + case graphson : + formattter = new Formatter(new GraphSON()); + break; + case pathed : + formattter = new Formatter(new PathedURL(loader, urlBuilder)); + break; + case id : + formattter = new Formatter(new IdURL(loader, urlBuilder)); + break; + case resource : + formattter = new Formatter(new Resource.Builder(loader, serializer, urlBuilder).build()); + break; + case resource_and_url : + formattter = new Formatter(new Resource.Builder(loader, serializer, urlBuilder).includeUrl().build()); + break; + case simple : + formattter = new Formatter(new SimpleFormat(urlBuilder)); + break; + case console : + formattter = new Formatter(new Console()); + break; + default : + break; + } + + return formattter; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatMapper.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatMapper.java new file mode 100644 index 00000000..def68e0f --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatMapper.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import com.google.gson.JsonObject; + +public interface FormatMapper { + + public JsonObject formatObject(Object v) throws AAIFormatVertexException; + + public int parallelThreshold(); +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Formatter.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Formatter.java new file mode 100644 index 00000000..f2bafe24 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Formatter.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +public class Formatter { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Formatter.class); + + protected JsonParser parser = new JsonParser(); + protected final FormatMapper format; + public Formatter(FormatMapper format) { + this.format = format; + } + + public JsonObject output(List<Object> vertices) { + Stream<Object> stream = null; + JsonObject result = new JsonObject(); + JsonArray body = new JsonArray(); + if (vertices.size() >= format.parallelThreshold()) { + stream = vertices.parallelStream(); + } else { + stream = vertices.stream(); + } + + stream.map(v -> { + try { + return Optional.<JsonObject>of(format.formatObject(v)); + } catch (AAIFormatVertexException e) { + LOGGER.warn("Failed to format vertex, returning a partial list", e); + } + + return Optional.<JsonObject>empty(); + }).forEach(obj -> { + if (obj.isPresent()) { + synchronized (body) { + body.add(obj.get()); + } + } + }); + + result.add("results", body); + + return result.getAsJsonObject(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/GraphSON.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/GraphSON.java new file mode 100644 index 00000000..69bd1b24 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/GraphSON.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper; +import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.thinkaurelius.titan.graphdb.tinkerpop.TitanIoRegistry; + +public class GraphSON implements FormatMapper { + + private final GraphSONMapper mapper = GraphSONMapper.build().addRegistry(TitanIoRegistry.INSTANCE).create(); + private final GraphSONWriter writer = GraphSONWriter.build().mapper(mapper).create(); + protected JsonParser parser = new JsonParser(); + + @Override + public JsonObject formatObject(Object v) { + OutputStream os = new ByteArrayOutputStream(); + String result = ""; + try { + writer.writeVertex(os, (Vertex)v, Direction.BOTH); + + result = os.toString(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return parser.parse(result).getAsJsonObject(); + + } + + @Override + public int parallelThreshold() { + return 50; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/IdURL.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/IdURL.java new file mode 100644 index 00000000..a7d641dd --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/IdURL.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class IdURL implements FormatMapper { + + private final UrlBuilder urlBuilder; + private final JsonParser parser; + private final Loader loader; + + public IdURL (Loader loader, UrlBuilder urlBuilder) throws AAIException { + this.urlBuilder = urlBuilder; + this.parser = new JsonParser(); + this.loader = loader; + } + + @Override + public int parallelThreshold() { + return 2500; + } + + @Override + public JsonObject formatObject(Object input) throws AAIFormatVertexException { + Vertex v = (Vertex)input; + try { + final Introspector searchResult = this.loader.introspectorFromName("result-data"); + + searchResult.setValue("resource-type", v.value(AAIProperties.NODE_TYPE)); + searchResult.setValue("resource-link", this.urlBuilder.id(v)); + + final String json = searchResult.marshal(false); + + return parser.parse(json).getAsJsonObject(); + + } catch (AAIUnknownObjectException e) { + throw new RuntimeException("Fatal error - result-data object does not exist!"); + } + + + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/PathedURL.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/PathedURL.java new file mode 100644 index 00000000..dda9f4af --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/PathedURL.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public final class PathedURL implements FormatMapper { + + private final UrlBuilder urlBuilder; + private final JsonParser parser; + private final Loader loader; + + public PathedURL (Loader loader, UrlBuilder urlBuilder) throws AAIException { + this.urlBuilder = urlBuilder; + this.parser = new JsonParser(); + this.loader = loader; + } + + @Override + public int parallelThreshold() { + return 20; + } + + @Override + public JsonObject formatObject(Object input) throws AAIFormatVertexException { + Vertex v = (Vertex)input; + try { + final Introspector searchResult = this.loader.introspectorFromName("result-data"); + + searchResult.setValue("resource-type", v.value(AAIProperties.NODE_TYPE)); + + searchResult.setValue("resource-link", this.urlBuilder.pathed(v)); + final String json = searchResult.marshal(false); + return this.parser.parse(json).getAsJsonObject(); + + } catch (AAIUnknownObjectException e) { + throw new RuntimeException("Fatal error - result-data does not exist!", e); + } + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Resource.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Resource.java new file mode 100644 index 00000000..7859719e --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Resource.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class Resource implements FormatMapper { + + private final Loader loader; + private final DBSerializer serializer; + private final JsonParser parser; + private final UrlBuilder urlBuilder; + private final boolean includeUrl; + + private Resource (Builder builder) { + this.parser = new JsonParser(); + this.loader = builder.getLoader(); + this.serializer = builder.getSerializer(); + this.urlBuilder = builder.getUrlBuilder(); + this.includeUrl = builder.isIncludeUrl(); + } + + @Override + public JsonObject formatObject(Object input) throws AAIFormatVertexException { + Vertex v = (Vertex)input; + JsonObject json = new JsonObject(); + + if (this.includeUrl) { + json.addProperty("url", this.urlBuilder.pathed(v)); + } + json.add(v.<String>property(AAIProperties.NODE_TYPE) + .orElse(null), this.vertexToJsonObject(v)); + + return json; + } + + protected JsonObject vertexToJsonObject(Vertex v) throws AAIFormatVertexException { + try { + final Introspector obj = getLoader().introspectorFromName( + v.<String>property(AAIProperties.NODE_TYPE) + .orElse(null) + ); + + final List<Vertex> wrapper = new ArrayList<>(); + + wrapper.add(v); + + try { + getSerializer().dbToObject(wrapper, obj, 1, false, "false"); + } catch (AAIException | UnsupportedEncodingException e) { + throw new AAIFormatVertexException("Failed to format vertex - error while serializing: " + e.getMessage(), e); + } + + final String json = obj.marshal(false); + + return getParser().parse(json).getAsJsonObject(); + } catch (AAIUnknownObjectException e) { + throw new AAIFormatVertexException("Failed to format vertex - unknown object", e); + } + } + + @Override + public int parallelThreshold() { + return 20; + } + + private Loader getLoader() { return loader; } + private DBSerializer getSerializer() { return serializer; } + private JsonParser getParser() { return parser; } + + public static class Builder { + + private final Loader loader; + private final DBSerializer serializer; + private final UrlBuilder urlBuilder; + private boolean includeUrl = false; + + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + } + + protected Loader getLoader() { + return this.loader; + } + + protected DBSerializer getSerializer() { + return this.serializer; + } + + protected UrlBuilder getUrlBuilder() { + return this.urlBuilder; + } + + public Builder includeUrl() { + this.includeUrl = true; + return this; + } + + protected boolean isIncludeUrl() { + return this.includeUrl; + } + + public Resource build() { + return new Resource(this); + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SimpleFormat.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SimpleFormat.java new file mode 100644 index 00000000..222b0922 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SimpleFormat.java @@ -0,0 +1,114 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +public class SimpleFormat implements FormatMapper { + + private final UrlBuilder urlBuilder; + private final Set<String> blacklist; + private final Collection<String> props = Arrays.asList(AAIProperties.AAI_URI, AAIProperties.NODE_TYPE); + public SimpleFormat(UrlBuilder urlBuilder) { + this.urlBuilder = urlBuilder; + this.blacklist = new HashSet<>(); + blacklist.addAll(props); + } + + @Override + public JsonObject formatObject(Object input) throws AAIFormatVertexException { + Vertex v = (Vertex)input; + JsonObject json = new JsonObject(); + json.addProperty("id", v.id().toString()); + json.addProperty("node-type", v.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(v)); + json.add("properties", this.createPropertiesObject(v)); + json.add("related-to", this.createRelationshipObject(v)); + + return json; + } + + @Override + public int parallelThreshold() { + return 100; + } + + private JsonObject createPropertiesObject(Vertex v) { + JsonObject json = new JsonObject(); + Iterator<VertexProperty<Object>> iter = v.properties(); + + while (iter.hasNext()) { + VertexProperty<Object> prop = iter.next(); + if (!blacklist.contains(prop.key())) { + if (prop.value() instanceof String) { + json.addProperty(prop.key(), (String)prop.value()); + } else if (prop.value() instanceof Boolean) { + json.addProperty(prop.key(), (Boolean)prop.value()); + } else if (prop.value() instanceof Number) { + json.addProperty(prop.key(), (Number)prop.value()); + } else if (prop.value() instanceof List) { + Gson gson = new Gson(); + String list = gson.toJson(prop.value()); + + json.addProperty(prop.key(), list); + } else { + //throw exception? + return null; + } + } + } + + return json; + } + + private JsonArray createRelationshipObject(Vertex v) throws AAIFormatVertexException { + JsonArray jarray = new JsonArray(); + Iterator<Vertex> iter = v.vertices(Direction.BOTH); + + while (iter.hasNext()) { + Vertex related = iter.next(); + + JsonObject json = new JsonObject(); + json.addProperty("id", related.id().toString()); + json.addProperty("node-type", related.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(related)); + jarray.add(json); + } + + return jarray; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SubGraphStyle.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SubGraphStyle.java new file mode 100644 index 00000000..7fa30431 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SubGraphStyle.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats; + +public enum SubGraphStyle { + star, + prune, + no_op +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java new file mode 100644 index 00000000..692f4f65 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats.exceptions; + +public class AAIFormatVertexException extends Exception { + + private static final long serialVersionUID = -5814240841844624097L; + + public AAIFormatVertexException() {} + + public AAIFormatVertexException(String message) { + super(message); + } + + public AAIFormatVertexException(Throwable cause) { + super(cause); + } + + public AAIFormatVertexException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/utils/UrlBuilder.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/utils/UrlBuilder.java new file mode 100644 index 00000000..1c79d24b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/utils/UrlBuilder.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.queryformats.utils; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.openecomp.aai.util.AAIApiServerURLBase; +import org.openecomp.aai.workarounds.LegacyURITransformer; + +public class UrlBuilder { + + private final DBSerializer serializer; + private final Version version; + private final String serverBase; + + public UrlBuilder (Version version, DBSerializer serializer) throws AAIException { + this.serializer = serializer; + this.version = version; + this.serverBase = AAIApiServerURLBase.get(AAIProperties.LATEST); + } + + public String pathed(Vertex v) throws AAIFormatVertexException { + + try { + final StringBuilder result = new StringBuilder(); + final URI uri = this.serializer.getURIForVertex(v); + + result.append(this.serverBase); + result.append(this.version); + result.append(uri.getRawPath()); + + return result.toString(); + } catch (UnsupportedEncodingException | IllegalArgumentException | SecurityException e) { + throw new AAIFormatVertexException(e); + } + } + + public String id(Vertex v) { + final StringBuilder result = new StringBuilder(); + + result.append("/resources/id/" + v.id()); + result.insert(0, this.version); + result.insert(0, this.serverBase); + + return result.toString(); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedEdge.java b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedEdge.java new file mode 100644 index 00000000..36fb6a87 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedEdge.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.tinkerpop; + +import java.util.Iterator; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge; +import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; + + +/** + * Represents a {@link Edge} that is disconnected from a {@link Graph} however, + * traversals are supported as they are backed by a Tree with saturated {@link Vertex} and {@link Edge} objects. + * These objects are not mutable and can only be used to read information out. + * + */ +public class TreeBackedEdge extends DetachedEdge implements Edge { + + private static final long serialVersionUID = 5419650145562077538L; + private TreeBackedVertex inVertex; + private TreeBackedVertex outVertex; + public TreeBackedEdge(Edge edge, TreeBackedVertex inVertex, TreeBackedVertex outVertex) { + super(edge, true); + this.inVertex = inVertex; + this.outVertex = outVertex; + } + + @Override + public Vertex inVertex() { + return this.inVertex; + } + + @Override + public Vertex outVertex() { + return this.outVertex; + } + + @Override + public Iterator<Vertex> bothVertices() { + return this.vertices(Direction.BOTH); + } + + @Override + public Iterator<Vertex> vertices(Direction direction) { + switch (direction) { + case OUT: + return IteratorUtils.of(this.outVertex); + case IN: + return IteratorUtils.of(this.inVertex); + default: + return IteratorUtils.of(this.outVertex, this.inVertex); + } + } + + + + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedVertex.java b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedVertex.java new file mode 100644 index 00000000..92655803 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedVertex.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.serialization.tinkerpop; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex; + +/** + * Represents a {@link Vertex} that is disconnected from a {@link Graph} however, + * traversals are supported as they are backed by a Tree with saturated {@link Vertex} and {@link Edge} objects. + * These objects are not mutable and can only be used to read information out. + * + */ + +public class TreeBackedVertex extends DetachedVertex implements Vertex { + + private static final long serialVersionUID = -976854460992756953L; + private final Tree<Element> tree; + private final Vertex self; + public TreeBackedVertex (Vertex v, Tree<Element> tree) { + super(v, true); + this.self = v; + this.tree = tree; + } + + @Override + public Iterator<Edge> edges(final Direction direction, final String... edgeLabels) { + final List<Element> edges = tree.getObjectsAtDepth(2); + final List<Tree<Element>> trees = tree.getTreesAtDepth(2); + final List<Tree<Element>> vTrees = tree.getTreesAtDepth(3); + return edges.stream().map( ele -> (Edge)ele).filter(e -> { + if (Direction.IN.equals(direction)) { + return e.inVertex().equals(self); + } else if (Direction.OUT.equals(direction)) { + return e.outVertex().equals(self); + } else { + return true; + } + }).filter(e -> { + boolean result = false; + if (edgeLabels.length == 0) { + return true; + } + for (String label : edgeLabels) { + if (label.equals(e.label())) { + result = true; + break; + } + } + return result; + }).map(e -> { + Tree<Element> eTree = new Tree<>(); + for (Tree<Element> tree : trees) { + if (tree.keySet().contains(e)) { + eTree = tree; + break; + } + } + TreeBackedVertex in = null; + TreeBackedVertex out = null; + if (e.inVertex().equals(self)) { + in = this; + out = this.createForVertex(e.outVertex(), vTrees); + } else if (e.outVertex().equals(self)) { + out = this; + in = this.createForVertex(e.inVertex(), vTrees); + } + return (Edge)new TreeBackedEdge(e, in, out); + }).iterator(); + + } + + private TreeBackedVertex createForVertex(Vertex v, List<Tree<Element>> trees) { + Tree<Element> vTree = new Tree<>(); + for (Tree<Element> tree : trees) { + if (tree.keySet().contains(v)) { + vTree = tree; + break; + } + } + + return new TreeBackedVertex((Vertex)vTree.keySet().iterator().next(), vTree); + } + @Override + public Iterator<Vertex> vertices(final Direction direction, final String... labels) { + final List<Tree<Element>> vertexElements = tree.getTreesAtDepth(3); + final List<Element> edgeElements = tree.getObjectsAtDepth(2); + return edgeElements.stream().map( ele -> (Edge)ele).filter(e -> { + boolean result = false; + if (labels.length == 0) { + return true; + } + for (String label : labels) { + if (label.equals(e.label())) { + result = true; + break; + } + } + return result; + }).filter(e -> { + if (Direction.IN.equals(direction) && e.inVertex().equals(self)) { + return true; + } else if (Direction.OUT.equals(direction) && e.outVertex().equals(self)) { + return true; + } else if (Direction.BOTH.equals(direction)){ + return true; + } else { + return false; + } + }).map(e -> { + final List<Vertex> list; + if (Direction.IN.equals(direction)) { + list = Collections.singletonList(e.outVertex()); + } else if (Direction.OUT.equals(direction)){ + list = Collections.singletonList(e.inVertex()); + } else { + list = new ArrayList<>(); + Iterator<Vertex> itr = e.bothVertices(); + while (itr.hasNext()) { + list.add(itr.next()); + } + } + return list; + + }).flatMap(list -> list.stream()).map(v -> { + Tree<Element> vTree = new Tree<Element>(); + for (Tree<Element> tree : vertexElements) { + if (tree.keySet().contains(v)) { + vTree = tree; + break; + } + } + + return (Vertex)new TreeBackedVertex(v, vTree); + }).iterator(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/tasks/ScheduledTasks.java b/aai-core/src/main/java/org/openecomp/aai/tasks/ScheduledTasks.java new file mode 100644 index 00000000..7cb17cf8 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/tasks/ScheduledTasks.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.tasks; + +import java.io.File; +import java.util.Arrays; +import java.util.Date; +import java.util.UUID; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.comparator.LastModifiedFileComparator; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import org.openecomp.aai.logging.LoggingContext; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +@Component +public class ScheduledTasks { + + private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(ScheduledTasks.class); + + private static final String COMPONENT = "Scheduler"; + private static final String FROM_APP_ID = "CronApp"; + private static final long PROPERTY_READ_INTERVAL = 60000; // every minute + + private String GlobalPropFileName = AAIConstants.AAI_CONFIG_FILENAME; + + // for read and possibly reloading aaiconfig.properties and other + /** + * Load AAI properties. + */ + // configuration properties files + @Scheduled(fixedRate = PROPERTY_READ_INTERVAL) + public void loadAAIProperties() { + final UUID transId = UUID.randomUUID(); + + LoggingContext.requestId(transId); + LoggingContext.partnerName(FROM_APP_ID); + LoggingContext.component(COMPONENT); + + String dir = FilenameUtils.getFullPathNoEndSeparator(GlobalPropFileName); + if (dir == null || dir.length() < 3) { + dir = "/opt/aai/etc"; + } + + File pdir = new File(dir); + File[] files = pdir.listFiles(); + Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE); + String fn; + + // leave this loop here since we may want to check other configurable + // property files in the SAME directory + for (File file : files) { + fn = file.getName(); + if (fn.equals("aaiconfig.properties")) { + Date lastMod = new Date(file.lastModified()); + long lastModTm = lastMod.getTime(); + Date curTS = new Date(); + long curTSTm = curTS.getTime(); + if (curTSTm - lastModTm < PROPERTY_READ_INTERVAL + 1000) { + AAIConfig.reloadConfig(); + LOGGER.info("reloaded from aaiconfig.properties"); + } + break; + } + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIApiServerURLBase.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiServerURLBase.java new file mode 100644 index 00000000..da3bb11e --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiServerURLBase.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.util.List; +import java.util.Map; + +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.PhaseInterceptorChain; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Version; + +public class AAIApiServerURLBase { + + /** + * Gets the. + * + * @return the string + * @throws AAIException the AAI exception + */ + public static String get() throws AAIException { + + String hostName = null; + try { + Message message = PhaseInterceptorChain.getCurrentMessage(); + Map<String, List<String>> headers = CastUtils.cast((Map) message.get(Message.PROTOCOL_HEADERS)); + List sa = null; + if (headers != null) { + sa = headers.get("host"); + } + + if (sa != null && sa.size() == 1) { + hostName = "https://"+ sa.get(0).toString() + "/aai/"; + } + } catch (Exception e) { + // TODO: we may want to log an error here + } + // TODO: should this check the value a little closer and look for a pattern? + if (hostName == null) { + hostName = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE); + //AAIConstants.AAI_SERVER_URL_BASE; + } + return hostName; + } + + /** + * Gets the. + * + * @param v the v + * @return the string + * @throws AAIException the AAI exception + */ + public static String get(Version v) throws AAIException { + String hostName = null; + hostName = AAIApiServerURLBase.get(); + + return hostName; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIApiVersion.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiVersion.java new file mode 100644 index 00000000..56687244 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiVersion.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.PhaseInterceptorChain; + +import org.openecomp.aai.exceptions.AAIException; + +public class AAIApiVersion { + + private static final Pattern versionPattern = Pattern.compile("(^|\\/)(v\\d+)\\/"); + + private static final Pattern latestVersionPattern = Pattern.compile("(^|\\/)(latest)\\/"); + + /** + * Gets the. + * + * @return the string + * @throws AAIException the AAI exception + */ + public static String get() throws AAIException { + + String apiVersion = null; + try { + Message message = PhaseInterceptorChain.getCurrentMessage(); + String requestURI = (String) message.get(Message.REQUEST_URI); + + if (requestURI != null) { + Matcher matcher = versionPattern.matcher(requestURI); + if (matcher.find() && matcher.groupCount() >= 2) { + apiVersion = matcher.group(2); + } + if (apiVersion == null) { + Matcher latestMatcher = latestVersionPattern.matcher(requestURI); + if (latestMatcher.find() && latestMatcher.groupCount() >= 2) { + apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP, AAIConstants.AAI_DEFAULT_API_VERSION); + } + } + + } + + } catch (Exception e) { + // TODO: we may want to log an error here + } + // TODO: should this check the value a little closer and look for a pattern? + if (apiVersion == null || !apiVersion.startsWith("v")) { + apiVersion = AAIConfig.get (AAIConstants.AAI_DEFAULT_API_VERSION_PROP, AAIConstants.AAI_DEFAULT_API_VERSION); + //apiVersion = AAIConstants.AAI_DEFAULT_API_VERSION; + } + return apiVersion; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAICSVWriter.java b/aai-core/src/main/java/org/openecomp/aai/util/AAICSVWriter.java new file mode 100644 index 00000000..63383194 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAICSVWriter.java @@ -0,0 +1,167 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +/** + * + */ +package org.openecomp.aai.util; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; + +import com.opencsv.CSVWriter; + +/** + * had to overwrite the separate character to separate string + * Based on the public - A very simple CSV writer released under a commercial-friendly license. + * + + */ +public class AAICSVWriter extends CSVWriter { + + private String separatorStr; + private char overridequotechar; + private String overridelineEnd; + private Writer rawWriter; + private PrintWriter pw; + + /** + * Instantiates a new AAICSV writer. + * + * @param writer the writer + */ + public AAICSVWriter(Writer writer) { + super(writer); + // TODO Auto-generated constructor stub + } + + /** + * Constructs AAICSVWriter with supplied separator string and quote char. + * + * @param writer the writer to an underlying CSV source. + * @param overrideseparator the overrideseparator + * @param quotechar the character to use for quoted elements + * @param lineEnd the line feed terminator to use + */ + public AAICSVWriter(Writer writer, String overrideseparator, char quotechar, String lineEnd) { + super(writer, CSVWriter.DEFAULT_SEPARATOR, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd); + separatorStr = overrideseparator; + overridequotechar = quotechar; + overridelineEnd = lineEnd; + this.rawWriter = writer; + this.pw = new PrintWriter(writer); + } + + /** + * String contains special characters. + * + * @param line the line + * @return true, if successful + */ + private boolean stringContainsSpecialCharacters(String line) { + return line.indexOf(overridequotechar) != -1 || line.indexOf(DEFAULT_ESCAPE_CHARACTER) != -1 || line.indexOf(separatorStr) != -1 || line.contains("\n") || line.contains("\r"); + } + + /** + * Close the underlying stream writer flushing any buffered content. + * + * @throws IOException if bad things happen + */ + public void close() throws IOException { + flush(); + pw.close(); + rawWriter.close(); + } + + /** + * Writes the next line to the file. + * + * @param nextLine a string array with each comma-separated element as a separate + * entry. + * @param applyQuotesToAll true if all values are to be quoted. false applies quotes only + * to values which contain the separator, escape, quote or new line characters. + */ + public void writeNext(String[] nextLine, boolean applyQuotesToAll) { + + if (nextLine == null) + return; + + StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE); + for (int i = 0; i < nextLine.length; i++) { + + if (i != 0) { + sb.append(separatorStr); + } + + String nextElement = nextLine[i]; + + if (nextElement == null) + continue; + + Boolean stringContainsSpecialCharacters = stringContainsSpecialCharacters(nextElement); + + if ((applyQuotesToAll || stringContainsSpecialCharacters) && overridequotechar != NO_QUOTE_CHARACTER) + sb.append(overridequotechar); + + if (stringContainsSpecialCharacters) { + sb.append(processLine(nextElement)); + } else { + sb.append(nextElement); + } + + if ((applyQuotesToAll || stringContainsSpecialCharacters) && overridequotechar != NO_QUOTE_CHARACTER) + sb.append(overridequotechar); + } + + sb.append(overridelineEnd); + pw.write(sb.toString()); + } + + + /** + * Writes the next line to the file ignoring all exceptions. + * + * @param nextLine a string array with each comma-separated element as a separate + * entry. + */ + public void writeColumn(String[] nextLine) { + + if (nextLine == null) + return; + + StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE); + for (int i = 0; i < nextLine.length; i++) { + + + String nextElement = nextLine[i]; + + if (nextElement == null) + continue; + + sb.append(nextElement); + + + } + + sb.append(overridelineEnd); + pw.write(sb.toString()); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIConfig.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfig.java new file mode 100644 index 00000000..eaea46e3 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfig.java @@ -0,0 +1,265 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.eclipse.jetty.util.security.Password; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Properties; +import java.util.Timer; + + +public class AAIConfig { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIConfig.class); + private static final String GLOBAL_PROP_FILE_NAME = AAIConstants.AAI_CONFIG_FILENAME; + private static Properties serverProps; + private static boolean propsInitialized = false; + + // this (probably) won't change between releases, put it in the config if it gets annoying... + private static HashMap<String,ArrayList<String>> defaultBools = new HashMap<String,ArrayList<String>>(); + private static Timer timer = new Timer(); + + /** + * Instantiates a new AAI config. + */ + // Don't instantiate + private AAIConfig() {} + + /** + * Inits the. + * + * @throws AAIException the AAI exception + */ + public synchronized static void init() throws AAIException { + LOGGER.info("Initializing AAIConfig"); + + ArrayList<String> genericVnfBools = new ArrayList<String>(); + ArrayList<String> l3NetworkBools = new ArrayList<String>(); + ArrayList<String> pserverBools = new ArrayList<String>(); + ArrayList<String> subnetBools = new ArrayList<String>(); + ArrayList<String> vserverBools = new ArrayList<String>(); + ArrayList<String> vnfcBools = new ArrayList<String>(); + + genericVnfBools.add("in-maint"); + genericVnfBools.add("is-closed-loop-disabled"); + l3NetworkBools.add("is-bound-to-vpn"); + pserverBools.add("in-maint"); + subnetBools.add("dhcp-enabled"); + vserverBools.add("in-maint"); + vserverBools.add("is-closed-loop-disabled"); + vnfcBools.add("in-maint"); + vnfcBools.add("is-closed-loop-disabled"); + + defaultBools.put("generic-vnf", genericVnfBools); + defaultBools.put("l3-network", l3NetworkBools); + defaultBools.put("pserver", pserverBools); + defaultBools.put("subnet", subnetBools); + defaultBools.put("vserver", vserverBools); + defaultBools.put("vnfc", vnfcBools); + + AAIConfig.getConfigFile(); + AAIConfig.reloadConfig(); + + if (AAIConstants.AAI_NODENAME == null || AAIConstants.AAI_NODENAME == "") { + ErrorLogHelper.logError("AAI_4005", " AAI_NODENAME is not defined"); + } else { + LOGGER.info("A&AI Server Node Name = " + AAIConstants.AAI_NODENAME); + } + } + + /** + * Gets the default bools. + * + * @return the default bools + */ + public static HashMap<String,ArrayList<String>> getDefaultBools() { + return defaultBools; + } + + /** + * Cleanup. + */ + public static void cleanup() { + timer.cancel(); + } + + /** + * Gets the config file. + * + * @return the config file + */ + public static String getConfigFile() { +// if (GlobalPropFileName == null) { +// String nc = System.getProperty("aaiconfig"); +// if (nc == null) nc = "/home/aaiadmin/etc/aaiconfig.props"; +// logger.info( "aaiconfig = " + nc==null?"null":nc); +// GlobalPropFileName = nc; +// } + return GLOBAL_PROP_FILE_NAME; + } + + /** + * Reload config. + */ + public synchronized static void reloadConfig() { + + String propFileName = GLOBAL_PROP_FILE_NAME; + Properties newServerProps = null; + + LOGGER.info("Reloading config from " + propFileName); + + try { + InputStream is = new FileInputStream(propFileName); + newServerProps = new Properties(); + newServerProps.load(is); + propsInitialized = true; + + serverProps = newServerProps; + newServerProps = null; + + } catch (FileNotFoundException fnfe) { + ErrorLogHelper.logError("AAI_4001", " " + propFileName + ". Exception: "+fnfe.getMessage()); + } catch (IOException e) { + ErrorLogHelper.logError("AAI_4002", " " + propFileName + ". IOException: "+e.getMessage()); + } + } + + /** + * Gets the. + * + * @param key the key + * @param defaultValue the default value + * @return the string + */ + public static String get(String key, String defaultValue) { + String result = defaultValue; + try { + result = get (key); + } + catch ( AAIException a ) { + + } + return ( result ); + } + + /** + * Gets the. + * + * @param key the key + * @return the string + * @throws AAIException the AAI exception + */ + public static String get(String key) throws AAIException { + String response = null; + + if (key.equals(AAIConstants.AAI_NODENAME)) { + // Get this from InetAddress rather than the properties file + String nodeName = getNodeName(); + if (nodeName != null) { + return nodeName; + } + // else get from property file + } + + if (!propsInitialized || (serverProps == null)) { + reloadConfig(); + } + + if ((key.endsWith("password") || key.endsWith("passwd") || key.endsWith("apisecret")) && serverProps.containsKey(key+".x")) { + String valx = serverProps.getProperty(key+".x"); + return Password.deobfuscate(valx); + } + + if (!serverProps.containsKey(key)) { + throw new AAIException("AAI_4005", "Property key "+key+" cannot be found"); + } else { + response = serverProps.getProperty(key); + if (response == null || response.isEmpty()) { + throw new AAIException("AAI_4005", "Property key "+key+" is null or empty"); + } + } + return response; + } + + /** + * Gets the int. + * + * @param key the key + * @return the int + * @throws AAIException the AAI exception + */ + public static int getInt(String key) throws AAIException { + return Integer.valueOf(AAIConfig.get(key)); + } + + /** + * Gets the server props. + * + * @return the server props + */ + public static Properties getServerProps() { + return serverProps; + } + + /** + * Gets the node name. + * + * @return the node name + */ + public static String getNodeName() { + try { + InetAddress ip = InetAddress.getLocalHost(); + if (ip != null) { + String hostname = ip.getHostName(); + if (hostname != null) { + return hostname; + } + } + } catch (Exception e) { + return null; + } + return null; + } + + + /** + * Check if a null or an Empty string is passed in. + * + * @param s the s + * @return boolean + */ + public static boolean isEmpty(String s) + { + return (s == null || s.length() == 0); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIConfigCommandLinePropGetter.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfigCommandLinePropGetter.java new file mode 100644 index 00000000..8844e824 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfigCommandLinePropGetter.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import org.openecomp.aai.exceptions.AAIException; + +/* + * The script deobfuscatePW.sh needs to retrieve pws from the AAIConfig file. + * As AAIConfig has no main to be callable on the command line, this class helps + * by providing one for accessing AAIConfig that way. + * (AAIConfig deobfuscates pws itself, so we just need to call its .get() on the desired pw.) + * + * This could be used to get any property from AAIConfig via the command line, + * not just the pws, even though it was made for pw-related needs. + */ +public class AAIConfigCommandLinePropGetter { + + /** + * The main method. + * + * @param args the arguments + */ + /* + * usage: + * AAIConfigCommandLinePropGetter propertyname + */ + public static void main(String[] args) { + if (args.length != 1) { + System.out.println("only one property may be requested at a time"); + System.out.println("usage: AAIConfigCommandLinePropGetter propertyname"); + } + try { + AAIConfig.init(); + String value = AAIConfig.get(args[0]); + if (value != null) { + System.out.println(value); //bc this utility used by a shell script so it needs the result sent to stdout + } else { + System.out.println("requested property could not be found"); + } + } catch(AAIException e) { + System.out.println("exception:" + e.toString()); //TODO is this reasonable? + } finally { + System.exit(0); + } + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIConstants.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIConstants.java new file mode 100644 index 00000000..825a5eba --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIConstants.java @@ -0,0 +1,153 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +public final class AAIConstants { + + // + // + /** Default to unix file separator if system property file.separator is null */ + public static final String AAI_FILESEP = (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator"); + // + /** Default to opt aai if system property aai.home is null, using file.separator */ + public static final String AAI_HOME = (System.getProperty("AJSC_HOME") == null) ? AAI_FILESEP + "opt" + AAI_FILESEP + "app" + AAI_FILESEP +"aai" : System.getProperty("AJSC_HOME"); + public static final String AAI_BUNDLECONFIG_NAME = (System.getProperty("BUNDLECONFIG_DIR") == null) ? "bundleconfig" : System.getProperty("BUNDLECONFIG_DIR"); + public static final String AAI_HOME_BUNDLECONFIG = (System.getProperty("AJSC_HOME") == null) ? AAI_FILESEP + "opt" + AAI_FILESEP + "app" + AAI_FILESEP + "aai" + AAI_FILESEP + AAI_BUNDLECONFIG_NAME : System.getProperty("AJSC_HOME")+ AAI_FILESEP + AAI_BUNDLECONFIG_NAME; + + /** etc directory, relative to AAI_HOME */ + public static final String AAI_HOME_ETC = AAI_HOME_BUNDLECONFIG + AAI_FILESEP + "etc" + AAI_FILESEP; + public static final String AAI_HOME_ETC_APP_PROPERTIES = AAI_HOME_ETC + "appprops" + AAI_FILESEP; + public static final String AAI_V2_OUTPUT_TRANSFORMS = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + AAIConstants.AAI_FILESEP + "output" + AAIConstants.AAI_FILESEP; + public static final String AAI_HOME_ETC_AUTH = AAI_HOME_ETC + "auth" + AAI_FILESEP; + public static final String AAI_CONFIG_FILENAME = AAI_HOME_ETC_APP_PROPERTIES + "aaiconfig.properties"; + public static final String AAI_AUTH_CONFIG_FILENAME = AAI_HOME_ETC_AUTH + "aai_policy.json"; + public static final String AAI_MECHID_CONFIG_FILENAME = AAI_HOME_ETC_APP_PROPERTIES + "mechIds.json"; + public static final String AAI_HOME_ETC_QUERY = AAI_HOME_ETC + "query" + AAI_FILESEP + "stored-queries.properties"; + public static final String REALTIME_DB_CONFIG = AAI_HOME_ETC_APP_PROPERTIES + "titan-realtime.properties"; + public static final String CACHED_DB_CONFIG = AAI_HOME_ETC_APP_PROPERTIES + "titan-cached.properties"; + public static final String AAI_HOME_ETC_OXM = AAI_HOME_ETC + "oxm" + AAI_FILESEP; + public static final String AAI_EVENT_DMAAP_PROPS = AAI_HOME_ETC_APP_PROPERTIES + "aaiEventDMaaPPublisher.properties"; + + public static final String AAI_PROV_LOGBACK_PROPS = "prov-logback.xml"; + public static final String AAI_GETRES_LOGBACK_PROPS = "getres-logback.xml"; + public static final String AAI_DELTOOL_LOGBACK_PROPS = "deltool-logback.xml"; + public static final String AAI_UPDTOOL_LOGBACK_PROPS = "updtool-logback.xml"; + public static final String AAI_PUTTOOL_LOGBACK_PROPS = "puttool-logback.xml"; + public static final String AAI_POSTTOOL_LOGBACK_PROPS = "posttool-logback.xml"; + public static final String AAI_NOTIFYSDNCTOOL_LOGBACK_PROPS = "notifysdnctool-logback.xml"; + public static final String AAI_RSHIPTOOL_LOGBACK_PROPS = "rshiptool-logback.xml"; + public static final String AAI_LOGBACK_PROPS = "logback.xml"; + + + public static final String AAI_CREATE_DB_SCHEMA_LOGBACK_PROPS = "createDBSchema-logback.xml"; + public static final String AAI_PULL_INV_DATA_LOGBACK_PROPS = "pullInvData-logback.xml"; + public static final String AAI_DATA_GROOMING_LOGBACK_PROPS = "dataGrooming-logback.xml"; + public static final String AAI_DATA_SNAPSHOT_LOGBACK_PROPS = "dataSnapshot-logback.xml"; + public static final String AAI_SCHEMA_MOD_LOGBACK_PROPS = "schemaMod-logback.xml"; + public static final String AAI_FORCE_DELETE_LOGBACK_PROPS = "forceDelete-logback.xml"; + + public static final String AAI_LOAD_DATA_DHV_LOGBACK_PROPS = "loadDataForDHV-logback.xml"; + + public static final String AVPN_INTERIM_LAG_INTERFACE = "aai.avpn.interim.laginterface"; + + public static final String AAI_TRUSTSTORE_FILENAME = "aai.truststore.filename"; + public static final String AAI_TRUSTSTORE_PASSWD = "aai.truststore.passwd"; + public static final String AAI_KEYSTORE_FILENAME = "aai.keystore.filename"; + public static final String AAI_KEYSTORE_PASSWD = "aai.keystore.passwd"; + + public static final String AAI_OLDSERVER_URL_BASE = "aai.oldserver.url.base"; + public static final String AAI_SERVER_URL_BASE = "aai.server.url.base"; + public static final String AAI_SERVER_URL = "aai.server.url"; + public static final String AAI_OLDSERVER_URL = "aai.oldserver.url"; + public static final String AAI_GLOBAL_CALLBACK_URL = "aai.global.callback.url"; + + public static final String AAI_DEFAULT_API_VERSION = "v7"; + public static final String AAI_DEFAULT_API_VERSION_PROP = "aai.default.api.version"; + public static final String AAI_NOTIFICATION_CURRENT_VERSION = "aai.notification.current.version"; + + public static final String AAI_NODENAME = "aai.config.nodename"; + + public static final String AAI_LOGGING_HBASE_INTERCEPTOR = "aai.logging.hbase.interceptor"; + public static final String AAI_LOGGING_HBASE_ENABLED = "aai.logging.hbase.enabled"; + public static final String AAI_LOGGING_HBASE_LOGREQUEST = "aai.logging.hbase.logrequest"; + public static final String AAI_LOGGING_HBASE_LOGRESPONSE = "aai.logging.hbase.logresponse"; + + public static final String AAI_LOGGING_TRACE_ENABLED = "aai.logging.trace.enabled"; + public static final String AAI_LOGGING_TRACE_LOGREQUEST = "aai.logging.trace.logrequest"; + public static final String AAI_LOGGING_TRACE_LOGRESPONSE = "aai.logging.trace.logresponse"; + + public static final String AAI_CONFIG_CHECKINGTIME = "aai.config.checktime"; + public static final String AAI_DBMODEL_FILENAME = "aai.dbmodel.filename"; + public static final String AAI_RESVERSION_ENABLEFLAG = "aai.resourceversion.enableflag"; + + public static final String ECM_OPENSTACK_TENANTID = "ecm.openstack.tenantid"; + + public static final String HBASE_TABLE_NAME = "hbase.table.name"; + public static final String HBASE_NOTIFICATION_TABLE_NAME = "hbase.notificationTable.name"; + public static final String HBASE_TABLE_TIMESTAMP_FORMAT = "hbase.table.timestamp.format"; + public static final String HBASE_CONFIGURATION_ZOOKEEPER_QUORUM = "hbase.zookeeper.quorum"; + public static final String HBASE_CONFIGURATION_ZOOKEEPER_CLIENTPORT = "hbase.zookeeper.property.clientPort"; + public static final String HBASE_ZOOKEEPER_ZNODE_PARENT = "hbase.zookeeper.znode.parent"; + public static final String ZOOKEEPER_ZNODE_PARENT = "zookeeper.znode.parent"; + + public static final int AAI_MAX_TRANS_RETRIES = 5; + public static final long AAI_TRANS_RETRY_SLEEP_MSEC = 500; + + public static final int AAI_GROOMING_DEFAULT_MAX_FIX = 150; + public static final int AAI_GROOMING_DEFAULT_SLEEP_MINUTES = 7; + + public static final int AAI_DUPETOOL_DEFAULT_MAX_FIX = 25; + public static final int AAI_DUPETOOL_DEFAULT_SLEEP_MINUTES = 7; + + public static final String LOGGING_MAX_STACK_TRACE_ENTRIES = "aai.logging.maxStackTraceEntries"; + + /** Default to skipping real-time grooming unless system property aai.skiprealtime.grooming is set to "false" */ + public static final String AAI_SKIPREALTIME_GROOMING = (System.getProperty("aai.skiprealtime.grooming") == null) ? "true" : System.getProperty("aai.skiprealtime.grooming"); + + + /*** UEB ***/ + public static final String UEB_PUB_PARTITION_AAI = "AAI"; + public static final String UEB_PUB_AAI_VCE_INTERFACE_DATA_TOPIC = "ueb.pub.aai.vce.interface.data.topic"; + + + /** Service description for Hosted Communications */ + public static final String AAI_SERVICEDESCRIPTION_HOSTEDCOMM = "aai.servicedescription.hostedcomm"; + + /** Service description for Mobility */ + public static final String AAI_SERVICEDESCRIPTION_MOBILITY = "aai.servicedescription.mobility"; + + /** Service description for Mobility */ + public static final String AAI_SERVICEDESCRIPTION_VUSP = "aai.servicedescription.vusp"; + + /** Service description for Vvig */ + public static final String AAI_SERVICEDESCRIPTION_VVIG = "aai.servicedescription.vvig"; + + /** Service description for LRSI */ + public static final String AAI_SERVICEDESCRIPTION_LRSI = "aai.servicedescription.lrsi"; + + /** + * Instantiates a new AAI constants. + */ + private AAIConstants() { + // prevent instantiation + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIMechIdConfig.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIMechIdConfig.java new file mode 100644 index 00000000..1d0cd74a --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIMechIdConfig.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +import org.openecomp.aai.logging.ErrorLogHelper; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +public class AAIMechIdConfig { + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIMechIdConfig.class); + private static final String mechIdConfigFileName = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "mechid-config.json"; + + public static final String SYSTEM_GFP_IP = "GFP"; + public static final String SYSTEM_GCP = "GCP"; + public static final String SYSTEM_DCAE = "DCAE"; + public static final String SYSTEM_RUBY = "RUBY"; + public static final String SYSTEM_ACTION = "ACTION"; + public static final String SYSTEM_INSTAR = "INSTAR-LPP-AMS"; + public static final String FILE_CLASS_GFP_IP = "GFP-IP"; + public static final String FILE_CLASS_INSTAR = "INSTAR-LPP-AMS"; + + public static HashMap<String, String> mechIdtoSystem = new HashMap<String, String>(); + public static HashMap<String, ArrayList<String>> fileClassToMechId = new HashMap<String, ArrayList<String>>(); + + /** + * Inits the. + * + * @param tId the t id + * @param appId the app id + * @param logger the logger + */ + public static void init() { + LOGGER.debug("Initializing AAIMechIdConfig"); + Boolean enable; + String systemMechId = ""; + JSONParser parser = new JSONParser(); + + try { + Object obj = parser.parse(new FileReader(mechIdConfigFileName)); + JSONObject jsonObject = (JSONObject) obj; + JSONObject mechIds = (JSONObject) jsonObject.get("mech-ids"); + + @SuppressWarnings("unchecked") + Set<String> systemSet = mechIds.keySet(); + for (String system : systemSet) { + JSONObject systemJsonObj = (JSONObject) mechIds.get(system); + systemMechId = (String) systemJsonObj.get("mechid"); + enable = (Boolean) systemJsonObj.get("enable"); + if (systemMechId != null && !systemMechId.isEmpty() && enable != null && enable == true) { + mechIdtoSystem.put(systemMechId, system); + JSONArray fileClasses = (JSONArray) systemJsonObj.get("file-classes"); + if (fileClasses != null ) { + String fileClass = ""; + for (Object fileClassObj : fileClasses) { + fileClass = (String) fileClassObj; + + if (!fileClassToMechId.containsKey(fileClass)) { + fileClassToMechId.put(fileClass, new ArrayList<String>()); + fileClassToMechId.get(fileClass).add(systemMechId); + } else { + if(!fileClassToMechId.get(fileClass).contains(systemMechId)){ + fileClassToMechId.get(fileClass).add(systemMechId); + + } + } + } + } + } + } + + } catch (FileNotFoundException fnfe) { + ErrorLogHelper.logError("AAI_4001", + " " + mechIdConfigFileName + ". Exception: " + fnfe.getMessage()); + } catch (Exception e) { + ErrorLogHelper.logError("AAI_4004", + " " + mechIdConfigFileName + ". Exception: " + e.getMessage()); + } + } + + + /** + * Transform mech id to pickup dir. + * + * @param systemMechId the system mech id + * @return the string + */ + public static String transformMechIdToPickupDir(String systemMechId) { + String pickupDir = ""; + if (systemMechId != null && !systemMechId.isEmpty()) { + pickupDir = "/opt/aaihome/" + systemMechId + "/pickup"; + + if (pickupDir != null && !pickupDir.isEmpty() && new File(pickupDir).isDirectory()) { + return pickupDir; + } + + } + return null; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIRSyncUtility.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIRSyncUtility.java new file mode 100644 index 00000000..b32e8882 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIRSyncUtility.java @@ -0,0 +1,197 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +/** + * + */ +package org.openecomp.aai.util; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import org.openecomp.aai.exceptions.AAIException; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + + +public class AAIRSyncUtility { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIRSyncUtility.class); + private final String DEFAULT_CHECK = new String("aai.primary.filetransfer."); + + /** + * Instantiates a new AAIR sync utility. + */ + public AAIRSyncUtility() { + + } + + /** + * Do command. + * + * @param command the command + * @return the int + * @throws Exception the exception + */ + public int doCommand(List<String> command) + throws Exception + { + String s = null; + + ProcessBuilder pb = new ProcessBuilder(command); + Process process = pb.start(); + + BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); + BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); + + LOGGER.debug("Here is the standard output of the command:\n"); + while ((s = stdInput.readLine()) != null) + { + LOGGER.debug(s); + } + + LOGGER.debug("Here is the standard error of the command (if any):\n"); + while ((s = stdError.readLine()) != null) + { + LOGGER.debug(s); + } + return process.waitFor(); + } + + + /** + * Method sendRsyncCommand. + * + * @param transId the trans id + * @param fileName the file name + */ + public void sendRsyncCommand(String transId, String fileName) + { + String aaiServerList = null; + String rsyncOptionsList = null; + + try { + aaiServerList = AAIConfig.get(DEFAULT_CHECK + "serverlist"); + rsyncOptionsList = AAIConfig.get("aai.rsync.options.list"); + String enableRsync = AAIConfig.get("aai.rsync.enabled"); + + if (!AAIConfig.isEmpty(enableRsync) && "n".equalsIgnoreCase(enableRsync)){ + LOGGER.info("rsync not invoked for " + fileName + ": rsync is not enabled in aaiconfig.properties"); + return; + } + } catch ( Exception e ) { + LOGGER.warn( "rsync not invoked: missing aaiconfig.properties entries for rsync" ); + } + + LOGGER.info("rsync to copy files started...."); + + ArrayList<String> remoteHostList = new ArrayList<String>(); + StringTokenizer serverList = new StringTokenizer( aaiServerList, "|" ); + String host = null; + try { + host = getHost(); + String remoteConnString = null; + + remoteHostList = getRemoteHostList(serverList, host); + LOGGER.debug("This host:" + host); + String pickUpDirectory = AAIConfig.get("instar.pickup.dir"); + String user = AAIConfig.get("aai.rsync.remote.user"); + String rsyncCmd = AAIConfig.get("aai.rsync.command"); + + //Push: rsync [OPTION...] SRC... [USER@]HOST:DEST + + java.util.Iterator<String> remoteHostItr = remoteHostList.iterator(); + while (!remoteHostList.isEmpty() && remoteHostItr.hasNext()) { + String remoteHost = remoteHostItr.next(); + remoteConnString =user+"@"+remoteHost+":"+pickUpDirectory; + + List<String> commands = new ArrayList<String>(); + commands.add(rsyncCmd); + StringTokenizer optionTks = new StringTokenizer( rsyncOptionsList, "|" ); + while (optionTks.hasMoreTokens()){ + commands.add(optionTks.nextToken()); + } + commands.add(fileName); // src directory/fileName + commands.add(remoteConnString); // target username/host/path + LOGGER.debug("Commands: " + commands.toString()); + int rsyncResult = doCommand(commands); + if ( rsyncResult == 0 ) { + LOGGER.info("rsync completed for "+remoteHost); + }else { + LOGGER.error("rsync failed for "+ remoteHost+ " with response code "+rsyncResult ); + } + } + } catch ( Exception e) { + LOGGER.error("no server found processing serverList for host " + host + ": " + e.getMessage() + " (AAI_4000)"); + } + } + + /** + * Gets the remote host list. + * + * @param serverList the server list + * @param host the host + * @return the remote host list + */ + private ArrayList<String> getRemoteHostList(StringTokenizer serverList, String host) { + ArrayList<String> remoteHostList = new ArrayList<String>(); + String remoteHost = null; + while ( serverList.hasMoreTokens() ) { + remoteHost = serverList.nextToken(); + if (!host.equalsIgnoreCase(remoteHost)){ + remoteHostList.add(remoteHost); + } + } + return remoteHostList; + } + + /** + * Gets the host. + * + * @return the host + * @throws AAIException the AAI exception + */ + private String getHost() throws AAIException { + String aaiServerList = AAIConfig.get(DEFAULT_CHECK + "serverlist"); + String hostname = null; + try { + InetAddress ip = InetAddress.getLocalHost(); + if ( ip != null ) { + hostname = ip.getHostName(); + if ( hostname != null ) { + if ( !( aaiServerList.contains(hostname) ) ) + LOGGER.warn("Host name not found in server list " + hostname); + } else + LOGGER.warn("InetAddress returned null hostname"); + } + + } catch (UnknownHostException e) { + LOGGER.warn("InetAddress getLocalHost exception " + e.getMessage()); + } + + return hostname; + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAITxnLog.java b/aai-core/src/main/java/org/openecomp/aai/util/AAITxnLog.java new file mode 100644 index 00000000..98a78478 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAITxnLog.java @@ -0,0 +1,501 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.client.*; +import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; +import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.filter.FilterList; +import org.apache.hadoop.hbase.filter.RegexStringComparator; +import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; +import org.apache.hadoop.hbase.util.Bytes; +import org.openecomp.aai.domain.notificationEvent.NotificationEvent; +import org.openecomp.aai.domain.translog.TransactionLogEntries; +import org.openecomp.aai.domain.translog.TransactionLogEntry; +import org.openecomp.aai.exceptions.AAIException; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class AAITxnLog { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAITxnLog.class); + + private final org.apache.hadoop.conf.Configuration config; + private HTable table = null; + private String tm = null; + + /** + * Instantiates a new AAI txn log. + * + * @param transId the trans id + * @param fromAppId the from app id + */ + public AAITxnLog(String transId, String fromAppId) { + /* When you create a HBaseConfiguration, it reads in whatever you've set + into your hbase-site.xml and in hbase-default.xml, as long as these can + be found on the CLASSPATH */ + + config = HBaseConfiguration.create(); + + try { + config.set(AAIConstants.ZOOKEEPER_ZNODE_PARENT, AAIConfig.get(AAIConstants.HBASE_ZOOKEEPER_ZNODE_PARENT)); + config.set(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_QUORUM, AAIConfig.get(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_QUORUM)); + config.set(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_CLIENTPORT, AAIConfig.get(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_CLIENTPORT)); + + Date date = new Date(); + DateFormat formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT)); + tm = formatter.format(date); + } catch (AAIException e) { + LOGGER.warn("Missing configuration in AAIConfig: " + e.getMessage()); + } + } + + /** + * Put. + * + * @param status the status + * @param srcId the src id + * @param rsrcId the rsrc id + * @param rsrcType the rsrc type + * @param rqstBuf the rqst buf + * @param respBuf the resp buf + * @return the string + */ + public String put( + String status, + String srcId, + String rsrcId, + String rsrcType, + String rqstBuf, + String respBuf + ) { + return put ("",status,"","",srcId,rsrcId,rsrcType,rqstBuf,respBuf,false,new NotificationEvent()); + + } + + /** + * Put. + * + * @param tid the tid + * @param status the status + * @param srcId the src id + * @param rsrcId the rsrc id + * @param rsrcType the rsrc type + * @param rqstBuf the rqst buf + * @param respBuf the resp buf + * @return the string + */ + public String put( + String tid, + String status, + String srcId, + String rsrcId, + String rsrcType, + String rqstBuf, + String respBuf + ) { + return put (tid,status,"","",srcId,rsrcId,rsrcType,rqstBuf,respBuf,false,new NotificationEvent()); + } + + /** + * Put. + * + * @param tid the tid + * @param status the status + * @param rqstTm the rqst tm + * @param respTm the resp tm + * @param srcId the src id + * @param rsrcId the rsrc id + * @param rsrcType the rsrc type + * @param rqstBuf the rqst buf + * @param respBuf the resp buf + * @return the string + */ + public String put( + String tid, + String status, + String rqstTm, + String respTm, + String srcId, + String rsrcId, + String rsrcType, + String rqstBuf, + String respBuf + ) { + return put (tid,status,"","",srcId,rsrcId,rsrcType,rqstBuf,respBuf,false,new NotificationEvent()); + } + + /** + * Put. + * + * @param tid the tid + * @param status the status + * @param rqstTm the rqst tm + * @param respTm the resp tm + * @param srcId the src id + * @param rsrcId the rsrc id + * @param rsrcType the rsrc type + * @param rqstBuf the rqst buf + * @param respBuf the resp buf + * @param hasNotificationEvent the has notification event + * @param ne the ne + * @return the string + */ + public String put( + String tid, + String status, + String rqstTm, + String respTm, + String srcId, + String rsrcId, + String rsrcType, + String rqstBuf, + String respBuf, + boolean hasNotificationEvent, + NotificationEvent ne + ) { + + if (tid == null || "".equals(tid)) { + Date date = new Date(); + DateFormat formatter = null; + try { + formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT)); + } catch (Exception e) { + formatter = new SimpleDateFormat("YYYYMMdd-HH:mm:ss:SSS"); + } + tm = formatter.format(date); + tid = tm + "-"; + } + String htid = tid; + + //need to add a prefix for better hbase logging server balancing + htid = HbaseSaltPrefixer.getInstance().prependSalt(htid); + + if (rqstTm == null || "".equals(rqstTm)) { + rqstTm = tm; + } + + if (respTm == null || "".equals(respTm)) { + respTm = tm; + } + + try { + table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME)); + + Put p = new Put(Bytes.toBytes(htid)); + + p.add(Bytes.toBytes("transaction"),Bytes.toBytes("tid"),Bytes.toBytes(tid)); + p.add(Bytes.toBytes("transaction"),Bytes.toBytes("status"),Bytes.toBytes(status)); + p.add(Bytes.toBytes("transaction"),Bytes.toBytes("rqstDate"),Bytes.toBytes(rqstTm)); + p.add(Bytes.toBytes("transaction"),Bytes.toBytes("respDate"),Bytes.toBytes(respTm)); + p.add(Bytes.toBytes("transaction"),Bytes.toBytes("sourceId"),Bytes.toBytes(srcId)); + + p.add(Bytes.toBytes("resource"),Bytes.toBytes("resourceId"),Bytes.toBytes(rsrcId)); + p.add(Bytes.toBytes("resource"),Bytes.toBytes("resourceType"),Bytes.toBytes(rsrcType)); + + p.add(Bytes.toBytes("payload"),Bytes.toBytes("rqstBuf"),Bytes.toBytes(rqstBuf)); + p.add(Bytes.toBytes("payload"),Bytes.toBytes("respBuf"),Bytes.toBytes(respBuf)); + + if (hasNotificationEvent == true) { + String eventType = ne.getEventHeader().getEventType(); + String eventStatus = ne.getEventHeader().getStatus(); + + if (eventStatus == null) { + eventStatus = AAIConfig.get("aai.notificationEvent.default.status", "UNPROCESSED"); + } + if (eventType == null) { + eventType = AAIConfig.get("aai.notificationEvent.default.eventType", "AAI-EVENT"); + } + + if (ne.getEntity() != null) { + PojoUtils pu = new PojoUtils(); + p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationPayload"),Bytes.toBytes(pu.getJsonFromObject(ne))); + } + if (ne.getEventHeader().getId() != null) { + p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationId"),Bytes.toBytes(ne.getEventHeader().getId())); + } + + p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationStatus"),Bytes.toBytes(eventStatus)); + p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationTopic"),Bytes.toBytes(eventType)); + + if (ne.getEventHeader().getEntityLink() != null) { + p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationEntityLink"),Bytes.toBytes(ne.getEventHeader().getEntityLink())); + } + if (ne.getEventHeader().getAction() != null) { + p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationAction"),Bytes.toBytes(ne.getEventHeader().getAction()) ); + } + } + /* Once you've adorned your Put instance with all the updates you want to + make, to commit it do the following */ + table.put(p); + table.flushCommits(); + table.close(); + return htid; + } catch (Exception e) { + LOGGER.warn("AAITxnLog: put: Exception", e); + return htid; + } + } + + /** + * Gets the. + * + * @param htid the htid + * @return the transaction log entry + * @throws AAIException the AAI exception + */ + public TransactionLogEntry get(String htid) throws AAIException { + + LOGGER.debug("In get: searching hbase config file..."); + String tidStr = ""; + TransactionLogEntry txObj = new TransactionLogEntry(); + + try { + table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME)); + + Get g = new Get(Bytes.toBytes(htid)); + + Result r = table.get(g); + byte [] tid = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("tid")); + byte [] status = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("status")); + byte [] rqstDate = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("rqstDate")); + byte [] respDate = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("respDate")); + byte [] sourceId = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("sourceId")); + + byte [] resourceId = r.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceId")); + byte [] resourceType = r.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceType")); + + byte [] rqstBuf = r.getValue(Bytes.toBytes("payload"),Bytes.toBytes("rqstBuf")); + byte [] respBuf = r.getValue(Bytes.toBytes("payload"),Bytes.toBytes("respBuf")); + + byte [] notificationPayload = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationPayload")); + byte [] notificationStatus = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationStatus")); + byte [] notificationId = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationId")); + byte [] notificationTopic = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationTopic")); + byte [] notificationEntityLink = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationEntityLink")); + byte [] notificationAction = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationAction")); + + table.close(); + + tidStr = Bytes.toString(tid); + txObj.setTransactionLogEntryId(tidStr); + txObj.setStatus(Bytes.toString(status)); + txObj.setRqstDate(Bytes.toString(rqstDate)); + txObj.setRespDate(Bytes.toString(respDate)); + txObj.setSourceId(Bytes.toString(sourceId)); + txObj.setResourceId(Bytes.toString(resourceId)); + txObj.setResourceType(Bytes.toString(resourceType)); + txObj.setRqstBuf(Bytes.toString(rqstBuf)); + txObj.setrespBuf(Bytes.toString(respBuf)); + txObj.setNotificationPayload(Bytes.toString(notificationPayload)); + txObj.setNotificationStatus(Bytes.toString(notificationStatus)); + txObj.setNotificationId(Bytes.toString(notificationId)); + txObj.setNotificationTopic(Bytes.toString(notificationTopic)); + txObj.setNotificationEntityLink(Bytes.toString(notificationEntityLink)); + txObj.setNotificationAction(Bytes.toString(notificationAction)); + } catch (IOException e) { + LOGGER.error("IOException on hbase call", e); + throw new AAIException("AAI_4000"); + } + + return txObj; + } + + + /** + * Scan filtered. + * + * @param startMillis the start millis + * @param endMillis the end millis + * @param methodList the method list + * @param putFilter the put filter + * @param getFilter the get filter + * @param resourceFilter the resource filter + * @param fromAppIdFilter the from app id filter + * @return the transaction log entries + */ + public TransactionLogEntries scanFiltered(long startMillis, long endMillis, List<String> methodList, + String putFilter, String getFilter, String resourceFilter, String fromAppIdFilter) { + + LOGGER.debug("Starting scanFiltered()"); + + // we should have the config ready from the constructor + + TransactionLogEntries txs = new TransactionLogEntries(); + + if (config == null) { + LOGGER.debug("in scan: can't create HBase configuration"); + return txs; + } + + try { + table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME)); + Scan s = new Scan(); + FilterList flMaster = new FilterList(FilterList.Operator.MUST_PASS_ALL); + FilterList methodflMaster = new FilterList(FilterList.Operator.MUST_PASS_ONE); + if (methodList != null) { + for (String method : methodList) { + Filter filt = new SingleColumnValueFilter(Bytes.toBytes("resource"), + Bytes.toBytes("resourceType"), CompareOp.EQUAL, Bytes.toBytes(method)); + methodflMaster.addFilter(filt); + } + flMaster.addFilter(methodflMaster); + } + + if (getFilter != null) { + Filter filt = new SingleColumnValueFilter(Bytes.toBytes("payload"), + Bytes.toBytes("respBuf"), CompareOp.EQUAL, new RegexStringComparator(getFilter)); + flMaster.addFilter(filt); + } + if (putFilter != null) { + Filter filt = new SingleColumnValueFilter(Bytes.toBytes("payload"), + Bytes.toBytes("rqstBuf"), CompareOp.EQUAL, new RegexStringComparator(putFilter)); + flMaster.addFilter(filt); + } + if (resourceFilter != null) { + Filter filt = new SingleColumnValueFilter(Bytes.toBytes("resource"), + Bytes.toBytes("resourceId"), CompareOp.EQUAL, new RegexStringComparator(resourceFilter)); + flMaster.addFilter(filt); + } + if (fromAppIdFilter != null) { + Filter filt = new SingleColumnValueFilter(Bytes.toBytes("transaction"), + Bytes.toBytes("sourceId"), CompareOp.EQUAL, new RegexStringComparator("^" + fromAppIdFilter)); + flMaster.addFilter(filt); + } + + if (flMaster.hasFilterRow()) { + s.setFilter(flMaster); + } + + s.setTimeRange(startMillis, endMillis); + ResultScanner scanner = table.getScanner(s); + + try { + for (Result rr = scanner.next(); rr != null; rr = scanner.next()) { + + byte [] tid = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("tid")); + byte [] status = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("status")); + byte [] rqstDate = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("rqstDate")); + byte [] respDate = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("respDate")); + byte [] sourceId = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("sourceId")); + + byte [] resourceId = rr.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceId")); + byte [] resourceType = rr.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceType")); + + byte [] rqstBuf = rr.getValue(Bytes.toBytes("payload"),Bytes.toBytes("rqstBuf")); + byte [] respBuf = rr.getValue(Bytes.toBytes("payload"),Bytes.toBytes("respBuf")); + + byte [] notificationPayload = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationPayload")); + byte [] notificationStatus = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationStatus")); + byte [] notificationId = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationId")); + byte [] notificationTopic = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationTopic")); + byte [] notificationEntityLink = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationEntityLink")); + byte [] notificationAction = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationAction")); + TransactionLogEntry txObj = new TransactionLogEntry(); + String tidStr = Bytes.toString(tid); + txObj.setTransactionLogEntryId(tidStr); + txObj.setStatus(Bytes.toString(status)); + txObj.setRqstDate(Bytes.toString(rqstDate)); + txObj.setRespDate(Bytes.toString(respDate)); + txObj.setSourceId(Bytes.toString(sourceId)); + txObj.setResourceId(Bytes.toString(resourceId)); + txObj.setResourceType(Bytes.toString(resourceType)); + txObj.setRqstBuf(Bytes.toString(rqstBuf)); + txObj.setrespBuf(Bytes.toString(respBuf)); + txObj.setNotificationPayload(Bytes.toString(notificationPayload)); + txObj.setNotificationStatus(Bytes.toString(notificationStatus)); + txObj.setNotificationId(Bytes.toString(notificationId)); + txObj.setNotificationTopic(Bytes.toString(notificationTopic)); + txObj.setNotificationEntityLink(Bytes.toString(notificationEntityLink)); + txObj.setNotificationAction(Bytes.toString(notificationAction)); + txs.getTransactionLogEntries().add(txObj); + } + } finally { + // Make sure you close your scanners when you are done! + scanner.close(); + } + table.close(); + } catch (Exception e) { + LOGGER.warn("AAITxnLog: scan: Exception=" + e.toString()); + } + + return txs; + } + + /** + * Scan. + * + * @param htid the htid + * @return the list + */ + public List<String> scan(String htid) { + + List<String> list = new ArrayList<String>(); + LOGGER.debug("In scan: searching hbase config file..."); + // we should have the config ready from the constructor + if (config == null) { + LOGGER.debug("in scan: can't create HBase configuration"); + return list; + } + + try { + table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME)); + Scan s = new Scan(Bytes.toBytes(htid)); + ResultScanner scanner = table.getScanner(s); + + try { + for (Result rr = scanner.next(); rr != null; rr = scanner.next()) { + list.add(rr.toString()); + LOGGER.debug("in scan: Found row : " + rr); + + } + } finally { + // Make sure you close your scanners when you are done! + scanner.close(); + } + table.close(); + } catch (Exception e) { + + LOGGER.debug("AAITxnLog: scan: Exception=" + e.toString()); + } + return list; + } + +} + +/* +Need to implement HBase Connection Pooling in the future. +This is to reduce the 1 second delay during the first open of HConnection, and HTable instantiation. +Hbase provides the Hconnection class and the HConnectionManager class. +Both provifde the functionaltity similar to jdbc connection pooling +to share pre-existing opened connections. +Here we should be able to use the getTable() method to get a +reference to an HTable instance. + + */ diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIUtils.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIUtils.java new file mode 100644 index 00000000..1ea39b0b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIUtils.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.TimeZone; + +public class AAIUtils { + + /** + * Null check. + * + * @param <T> the generic type + * @param iterable the iterable + * @return the iterable + */ + public static <T> Iterable<T> nullCheck(Iterable<T> iterable) { + return iterable == null ? Collections.<T>emptyList() : iterable; + } + + /** + * Gen date. + * + * @return the string + */ + public static String genDate() { + Date date = new Date(); + DateFormat formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS"); + formatter.setTimeZone(TimeZone.getTimeZone("GMT")); + return formatter.format(date); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/Entity.java b/aai-core/src/main/java/org/openecomp/aai/util/Entity.java new file mode 100644 index 00000000..865fe8b6 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/Entity.java @@ -0,0 +1,196 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "equipment-role", + "action", + "key-value-list", + "self-link" +}) +public class Entity { + + @JsonProperty("equipment-role") + private String equipmentRole; + @JsonProperty("action") + private String action; + @JsonProperty("key-value-list") + private List<KeyValueList> keyValueList = new ArrayList<KeyValueList>(); + @JsonProperty("self-link") + private String selfLink; + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * + * @return + * The equipmentRole + */ + @JsonProperty("equipment-role") + public String getEquipmentRole() { + return equipmentRole; + } + + /** + * + * @param equipmentRole + * The equipment-role + */ + @JsonProperty("equipment-role") + public void setEquipmentRole(String equipmentRole) { + this.equipmentRole = equipmentRole; + } + + public Entity withEquipmentRole(String equipmentRole) { + this.equipmentRole = equipmentRole; + return this; + } + + /** + * + * @return + * The action + */ + @JsonProperty("action") + public String getAction() { + return action; + } + + /** + * + * @param action + * The action + */ + @JsonProperty("action") + public void setAction(String action) { + this.action = action; + } + + public Entity withAction(String action) { + this.action = action; + return this; + } + + /** + * + * @return + * The keyValueList + */ + @JsonProperty("key-value-list") + public List<KeyValueList> getKeyValueList() { + return keyValueList; + } + + /** + * + * @param keyValueList + * The key-value-list + */ + @JsonProperty("key-value-list") + public void setKeyValueList(List<KeyValueList> keyValueList) { + this.keyValueList = keyValueList; + } + + public Entity withKeyValueList(List<KeyValueList> keyValueList) { + this.keyValueList = keyValueList; + return this; + } + + /** + * + * @return + * The selfLink + */ + @JsonProperty("self-link") + public String getSelfLink() { + return selfLink; + } + + /** + * + * @param selfLink + * The self-link + */ + @JsonProperty("self-link") + public void setSelfLink(String selfLink) { + this.selfLink = selfLink; + } + + public Entity withSelfLink(String selfLink) { + this.selfLink = selfLink; + return this; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + public Entity withAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + return this; + } + + @Override + public int hashCode() { + return new HashCodeBuilder().append(equipmentRole).append(action).append(keyValueList).append(selfLink).append(additionalProperties).toHashCode(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if ((other instanceof Entity) == false) { + return false; + } + Entity rhs = ((Entity) other); + return new EqualsBuilder().append(equipmentRole, rhs.equipmentRole).append(action, rhs.action).append(keyValueList, rhs.keyValueList).append(selfLink, rhs.selfLink).append(additionalProperties, rhs.additionalProperties).isEquals(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/EntityList.java b/aai-core/src/main/java/org/openecomp/aai/util/EntityList.java new file mode 100644 index 00000000..db685dbc --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/EntityList.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "entity" +}) +public class EntityList { + + @JsonProperty("entity") + private List<Entity> entity = new ArrayList<Entity>(); + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * + * @return + * The entity + */ + @JsonProperty("entity") + public List<Entity> getEntity() { + return entity; + } + + /** + * + * @param entity + * The entity + */ + @JsonProperty("entity") + public void setEntity(List<Entity> entity) { + this.entity = entity; + } + + public EntityList withEntity(List<Entity> entity) { + this.entity = entity; + return this; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + public EntityList withAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + return this; + } + + @Override + public int hashCode() { + return new HashCodeBuilder().append(entity).append(additionalProperties).toHashCode(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if ((other instanceof EntityList) == false) { + return false; + } + EntityList rhs = ((EntityList) other); + return new EqualsBuilder().append(entity, rhs.entity).append(additionalProperties, rhs.additionalProperties).isEquals(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/FileWatcher.java b/aai-core/src/main/java/org/openecomp/aai/util/FileWatcher.java new file mode 100644 index 00000000..6db89ebe --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/FileWatcher.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.util.*; +import java.io.*; + +public abstract class FileWatcher extends TimerTask { + private long timeStamp; + private File file; + + /** + * Instantiates a new file watcher. + * + * @param file the file + */ + public FileWatcher( File file ) { + this.file = file; + this.timeStamp = file.lastModified(); + } + + /** + * runs a timer task + * @see java.util.TimerTask.run + */ + public final void run() { + long timeStamp = file.lastModified(); + + if( (timeStamp - this.timeStamp) > 500 ) { + this.timeStamp = timeStamp; + onChange(file); + } + } + + /** + * On change. + * + * @param file the file + */ + protected abstract void onChange( File file ); +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/GenerateXsd.java b/aai-core/src/main/java/org/openecomp/aai/util/GenerateXsd.java new file mode 100644 index 00000000..a1668886 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/GenerateXsd.java @@ -0,0 +1,1672 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.SchemaOutputResolver; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Result; +import javax.xml.transform.stream.StreamResult; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.NodeList; + +import org.openecomp.aai.dbmodel.DbEdgeRules; +import com.google.common.base.Joiner; +import com.google.common.collect.Multimap; + + +public class GenerateXsd { + static String apiVersion = null; + static String apiVersionFmt = null; + static String responsesUrl = null; + static String responsesLabel = null; + static Map<String, String> generatedJavaType = new HashMap<String, String>(); + static Map<String, String> appliedPaths = new HashMap<String, String>(); + static NodeList javaTypeNodes; + static Class<?> versionedClass; + + + public static final int VALUE_NONE = 0; + public static final int VALUE_DESCRIPTION = 1; + public static final int VALUE_INDEXED_PROPS = 2; + + private static XPath xpath = XPathFactory.newInstance().newXPath(); + + + private enum LineageType { + PARENT, CHILD, UNRELATED; + } + private class EdgeDescription { + + private String ruleKey; + private LineageType type = LineageType.UNRELATED; + private String direction; + private String multiplicity; + private boolean hasDelTarget = false; + + public String getRuleKey() { + return ruleKey; + } + public String getMultiplicity() { + return multiplicity; + } + public String getDirection() { + return direction; + } + public void setRuleKey(String val) { + this.ruleKey=val; + } + public void setType(LineageType val) { + this.type=val; + } + public void setDirection(String val) { + this.direction = val; + } + public void setMultiplicity(String val) { + this.multiplicity=val; + } + public void setHasDelTarget(String val) { + hasDelTarget = Boolean.parseBoolean(val); + } + + public String getRelationshipDescription(String fromTo, String otherNodeName) { + + String result = ""; + + if ("FROM".equals(fromTo)) { + if ("OUT".equals(direction)) { + if (LineageType.PARENT == type) { + result = " (is composed of "+otherNodeName; + } + } + else { + if (LineageType.CHILD == type) { + result = " (comprises "+otherNodeName; + } + else if (LineageType.PARENT == type) { + result = " (comprises "+otherNodeName; + } + } + } else { + if ("OUT".equals(direction)) { + if (LineageType.PARENT == type) { + result = " (comprises "+otherNodeName; + } + } else { + if (LineageType.PARENT == type) { + result = " (is composed of "+otherNodeName; + } + } + } + +// if (type != null) { +// if (LineageType.PARENT.equals(type) && "FROM".equals(fromTo)) { +// if ("OUT".equals(direction)) { +// result = " (is composed of "+otherNodeName; +// } else { +// result = " (comprises "+otherNodeName; +// } +// } else { +// result = " (comprises " + otherNodeName; +// // if (!(multiplicity.startsWith("One"))) { +// // System.err.println("Surprised to find multiplicity "+multiplicity+" with comprises for "+ruleKey); +// // } +// } +// } + if ("TO".equals(fromTo)) { + if (result.length() == 0) result = result + " ("; + else result = result + ", "; + + result = result + mapMultiplicity(fromTo); + if (hasDelTarget) result = result + ", will delete target node"; + } + + if (result.length() > 0) result = result + ")"; + + return result; + } + + private String mapMultiplicity(String fromTo) { + String result = multiplicity; +// Below logic works if an IN switches multiplicity, which it doesn't today. +// if ("TO".equals(fromTo)) { +// if (direction.equals("OUT")) { +// result = multiplicity; +// } else { +// result = switchMultiplicity(multiplicity); +// } +// } else { +// if (direction.equals("OUT")) { +// result = multiplicity; +// } else { +// result = switchMultiplicity(multiplicity); +// } +// } + return result; + } + +// private String switchMultiplicity(String val) throws IllegalArgumentException +// { +// String result = null; +// switch (val) { +// case "Many2Many": +// case "One2One": +// result = val; +// break; +// case "Many2One": +// result = "One2Many"; +// break; +// case "One2Many": +// result = "Many2One"; +// break; +// default: +// throw new IllegalArgumentException("Multiplicity cannot be "+val); +// } +// System.out.println("Switched Multiplicity from "+val+" to "+result); +// return result; +// } + } + + public static void main(String[] args) throws IOException { + + if (args.length > 0) { + if (args[0] != null) { + apiVersion = args[0]; + } + } + boolean genDoc = false; + if ( args.length > 1 ) { + genDoc = true; + int index = args[1].indexOf("|"); + if ( index > 0 ) { + responsesUrl = args[1].substring(0, index); + responsesLabel = args[1].substring(index+1); + //System.out.println( "response URL " + responsesUrl); + //System.out.println( "response label " + responsesLabel); + responsesUrl = "description: "+ responsesLabel + "(" + + responsesUrl + ").\n"; + //System.out.println( "operation described with " + responsesUrl); + } else { // default + responsesUrl = ""; + } + } + String oxmPath = null; + if ( apiVersion == null ) { + // to run from eclipse, set these env, e.g. v7, \sources\aai\aaimastergit\bundleconfig-local\etc\oxm\ + String envRev= System.getenv("OXM_REV"); + if ( envRev != null ) + apiVersion = envRev; + + } + oxmPath = System.getenv("OXM_PATH"); + String outfileName; + if ( genDoc ) { + outfileName = "c:\\temp\\aai.yaml"; + } else + outfileName = "c:\\temp\\aai_schema.xsd"; + if ( apiVersion != null ) { // generate from oxm + apiVersionFmt = "." + apiVersion + "."; + if ( oxmPath == null ) { + oxmPath = AAIConstants.AAI_HOME_ETC_OXM + AAIConstants.AAI_FILESEP; + //oxmPath = "\\sources\\aai\\aaimastergit\\bundleconfig-local\\etc\\oxm\\"; + } + + File oxm_file = new File(oxmPath + "aai_oxm_" + apiVersion + ".xml"); + String xsd; + File outfile; + if ( genDoc ) { + xsd = generateSwaggerFromOxmFile( oxm_file); + outfile =new File(outfileName); + } else { + xsd = processOxmFile( oxm_file); + outfile =new File(outfileName); + } + + + try { + outfile.createNewFile(); + } catch (IOException e) { + System.out.println( "Exception creating output file " + outfileName); + e.printStackTrace(); + } + try { + FileWriter fw = new FileWriter(outfile.getAbsoluteFile()); + BufferedWriter bw = new BufferedWriter(fw); + bw.write(xsd); + bw.close(); + + } catch ( IOException e) { + System.out.println( "Exception writing output file " + outfileName); + e.printStackTrace(); + } + System.out.println( "GeneratedXSD successful, saved in " + outfileName); + return; + } + + JAXBContext jaxbContext = null; + try { + jaxbContext = JAXBContext.newInstance(org.openecomp.aai.domain.yang.Vce.class); + } catch (JAXBException e) { + + e.printStackTrace(); + } + SchemaOutputResolver sor = new MySchemaOutputResolver(); + jaxbContext.generateSchema(sor); + + } + + public static class MySchemaOutputResolver extends SchemaOutputResolver { + + public Result createOutput(String namespaceURI, String suggestedFileName) throws IOException { + File file = new File("c:\\temp\\aai_schema.xsd"); + StreamResult result = new StreamResult(file); + result.setSystemId(file.toURI().toURL().toString()); + return result; + } + + } + + public static String processJavaTypeElement( String javaTypeName, Element javaTypeElement) { + + String xmlRootElementName = null; + + NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes"); + StringBuffer sb = new StringBuffer(); + if ( parentNodes.getLength() == 0 ) { + System.out.println( "no java-attributes for java-type " + javaTypeName); + return ""; + + } + + NamedNodeMap attributes; + + NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element"); + Element valElement = (Element) valNodes.item(0); + attributes = valElement.getAttributes(); + for ( int i = 0; i < attributes.getLength(); ++i ) { + Attr attr = (Attr) attributes.item(i); + String attrName = attr.getNodeName(); + + String attrValue = attr.getNodeValue(); + //System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue); + if ( attrName.equals("name")) + xmlRootElementName = attrValue; + } + /* + if ( javaTypeName.equals("RelationshipList")) { + System.out.println( "Skipping " + javaTypeName); + generatedJavaType.put(javaTypeName, null); + return ""; + } + */ + + Element parentElement = (Element)parentNodes.item(0); + NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element"); + NodeList childNodes; + Element childElement; + String xmlElementWrapper; + + Element xmlElementElement; + String addType; + String elementName, elementType, elementIsKey, elementIsRequired, elementContainerType; + StringBuffer sb1 = new StringBuffer(); + if ( xmlElementNodes.getLength() > 0 ) { + sb1.append(" <xs:element name=\"" + xmlRootElementName + "\">\n"); + sb1.append(" <xs:complexType>\n"); + NodeList properties = GenerateXsd.locateXmlProperties(javaTypeElement); + if (properties != null) { + System.out.println("properties found for: " + xmlRootElementName); + sb1.append(" <xs:annotation>\r\n"); + insertAnnotation(properties, false, "class", sb1, " "); + + sb1.append(" </xs:annotation>\r\n"); + } else { + System.out.println("no properties found for: " + xmlRootElementName); + } + sb1.append(" <xs:sequence>\n"); + for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) { + + xmlElementElement = (Element)xmlElementNodes.item(i); + childNodes = xmlElementElement.getElementsByTagName("xml-element-wrapper"); + + xmlElementWrapper = null; + if ( childNodes.getLength() > 0 ) { + childElement = (Element)childNodes.item(0); + // get name + attributes = childElement.getAttributes(); + for ( int k = 0; k < attributes.getLength(); ++k ) { + Attr attr = (Attr) attributes.item(k); + String attrName = attr.getNodeName(); + String attrValue = attr.getNodeValue(); + if ( attrName.equals("name")) { + xmlElementWrapper = attrValue; + //System.out.println("found xml-element-wrapper " + xmlElementWrapper); + } + } + + } + attributes = xmlElementElement.getAttributes(); + addType = null; + + + elementName = elementType = elementIsKey = elementIsRequired = elementContainerType = null; + for ( int j = 0; j < attributes.getLength(); ++j ) { + Attr attr = (Attr) attributes.item(j); + String attrName = attr.getNodeName(); + + String attrValue = attr.getNodeValue(); + //System.out.println("For " + xmlRootElementName + " Found xml-element attribute: " + attrName + " with value: " + attrValue); + if ( attrName.equals("name")) { + elementName = attrValue; + } + if ( attrName.equals("type")) { + elementType = attrValue; + if ( attrValue.contains(apiVersionFmt) ) { + addType = attrValue.substring(attrValue.lastIndexOf('.')+1); + if ( !generatedJavaType.containsKey(addType) ) { + generatedJavaType.put(addType, attrValue); + sb.append(processJavaTypeElement( addType, getJavaTypeElement(addType) )); + } + } + + } + + if ( attrName.equals("xml-key")) { + elementIsKey = attrValue; + } + if ( attrName.equals("required")) { + elementIsRequired = attrValue; + } + if ( attrName.equals("container-type")) { + elementContainerType = attrValue; + } + } + + if ( xmlElementWrapper != null ) { + sb1.append(" <xs:element name=\"" + xmlElementWrapper +"\""); + if ( elementIsRequired == null || !elementIsRequired.equals("true")||addType != null) { + sb1.append(" minOccurs=\"0\""); + } + sb1.append(">\n"); + sb1.append(" <xs:complexType>\n"); + properties = GenerateXsd.locateXmlProperties(javaTypeElement); + if (properties != null) { + sb1.append(" <xs:annotation>\r\n"); + insertAnnotation(properties, false, "class", sb1, " "); + sb1.append(" </xs:annotation>\r\n"); + } else { + System.out.println("no properties found for: " + xmlElementWrapper); + } + sb1.append(" <xs:sequence>\n"); + sb1.append(" "); + } + if ("Nodes".equals(addType)) { + System.out.println ("Skipping nodes, temporary testing"); + continue; + } + if ( addType != null ) { + //sb1.append(" <xs:element ref=\"tns:" + elementName +"\""); + sb1.append(" <xs:element ref=\"tns:" + getXmlRootElementName(addType) +"\""); + } else { + sb1.append(" <xs:element name=\"" + elementName +"\""); + } + if ( elementType.equals("java.lang.String")) + sb1.append(" type=\"xs:string\""); + //if ( elementType.equals("java.lang.String")) + //sb1.append(" type=\"xs:string\""); + if ( elementType.equals("java.lang.Long")) + sb1.append(" type=\"xs:unsignedInt\""); + if ( elementType.equals("java.lang.Integer")) + sb1.append(" type=\"xs:int\""); + if ( elementType.equals("java.lang.Boolean")) + sb1.append(" type=\"xs:boolean\""); + //if ( elementIsRequired != null && elementIsRequired.equals("true")||addType != null) { + if ( elementIsRequired == null || !elementIsRequired.equals("true")||addType != null) { + sb1.append(" minOccurs=\"0\""); + } + if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) { + sb1.append(" maxOccurs=\"unbounded\""); + } + properties = GenerateXsd.locateXmlProperties(xmlElementElement); + if (properties != null || elementIsKey != null) { + sb1.append(">\n"); + sb1.append(" <xs:annotation>\r\n"); + insertAnnotation(properties, elementIsKey != null, "field", sb1, " "); + sb1.append(" </xs:annotation>\r\n"); + + if (xmlElementWrapper== null) { + sb1.append(" </xs:element>\n"); + } + } else { + sb1.append("/>\n"); + } + if ( xmlElementWrapper != null ) { + sb1.append(" </xs:sequence>\n"); + sb1.append(" </xs:complexType>\n"); + sb1.append(" </xs:element>\n"); + } + } + /* + if ( xmlRootElementName.equals("notify") || + xmlRootElementName.equals("relationship") || + xmlRootElementName.equals("relationship-data") || + xmlRootElementName.equals("related-to-property") ) + + sb1.append(" <xs:any namespace=\"##other\" processContents=\"lax\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n"); + */ + sb1.append(" </xs:sequence>\n"); + sb1.append(" </xs:complexType>\n"); + sb1.append(" </xs:element>\n"); + } + /* + NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element"); + Element valElement = (Element) valNodes.item(0); + attributes = valElement.getAttributes(); + for ( int i = 0; i < attributes.getLength(); ++i ) { + Attr attr = (Attr) attributes.item(i); + String attrName = attr.getNodeName(); + + String attrValue = attr.getNodeValue(); + System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue); + if ( attrValue.equals("name")) + xmlRootElementName = attrValue; + } + */ + + if ( xmlElementNodes.getLength() < 1 ) { + sb.append(" <xs:element name=\"" + xmlRootElementName + "\">\n"); + sb.append(" <xs:complexType>\n"); + sb.append(" <xs:sequence/>\n"); + sb.append(" </xs:complexType>\n"); + sb.append(" </xs:element>\n"); + generatedJavaType.put(javaTypeName, null); + return sb.toString(); + } + + sb.append( sb1 ); + + return sb.toString(); + } + + private static void insertAnnotation(NodeList items, boolean isKey, String target, StringBuffer sb1, String indentation) { + if (items != null || isKey) { + List<String> metadata = new ArrayList<>(); + + String name = ""; + String value = ""; + Element item = null; + if (isKey) { + metadata.add("isKey=true"); + } + if (items != null) { + for (int i = 0; i < items.getLength(); i++) { + item = (Element)items.item(i); + name = item.getAttribute("name"); + value = item.getAttribute("value"); + if (name.equals("abstract")) { + name = "isAbstract"; + } else if (name.equals("extends")) { + name = "extendsFrom"; + } + metadata.add(name + "=\"" + value.replaceAll("&", "&") + "\""); + System.out.println("property name: " + name); + + } + } + sb1.append( + indentation + " <xs:appinfo>\r\n" + + indentation + " <annox:annotate target=\""+target+"\">@org.openecomp.aai.annotations.Metadata(" + Joiner.on(",").join(metadata) + ")</annox:annotate>\r\n" + + indentation + " </xs:appinfo>\r\n"); + } + + } + + private static Element getJavaTypeElement( String javaTypeName ) + { + + String attrName, attrValue; + Attr attr; + Element javaTypeElement; + for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { + javaTypeElement = (Element) javaTypeNodes.item(i); + NamedNodeMap attributes = javaTypeElement.getAttributes(); + for ( int j = 0; j < attributes.getLength(); ++j ) { + attr = (Attr) attributes.item(j); + attrName = attr.getNodeName(); + attrValue = attr.getNodeValue(); + if ( attrName.equals("name") && attrValue.equals(javaTypeName)) + return javaTypeElement; + } + } + System.out.println( "oxm file format error, missing java-type " + javaTypeName); + return (Element) null; + } + + private static Element getJavaTypeElementSwagger( String javaTypeName ) + { + + String attrName, attrValue; + Attr attr; + Element javaTypeElement; + for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { + javaTypeElement = (Element) javaTypeNodes.item(i); + NamedNodeMap attributes = javaTypeElement.getAttributes(); + for ( int j = 0; j < attributes.getLength(); ++j ) { + attr = (Attr) attributes.item(j); + attrName = attr.getNodeName(); + attrValue = attr.getNodeValue(); + if ( attrName.equals("name") && attrValue.equals(javaTypeName)) + return javaTypeElement; + } + } + System.out.println( "oxm file format error, missing java-type " + javaTypeName); + return (Element) null; + } + private static String getXmlRootElementName( String javaTypeName ) + { + + String attrName, attrValue; + Attr attr; + Element javaTypeElement; + for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { + javaTypeElement = (Element) javaTypeNodes.item(i); + NamedNodeMap attributes = javaTypeElement.getAttributes(); + for ( int j = 0; j < attributes.getLength(); ++j ) { + attr = (Attr) attributes.item(j); + attrName = attr.getNodeName(); + attrValue = attr.getNodeValue(); + if ( attrName.equals("name") && attrValue.equals(javaTypeName)) { + NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element"); + Element valElement = (Element) valNodes.item(0); + attributes = valElement.getAttributes(); + for ( int k = 0; k < attributes.getLength(); ++k ) { + attr = (Attr) attributes.item(k); + attrName = attr.getNodeName(); + + attrValue = attr.getNodeValue(); + //System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue); + if ( attrName.equals("name")) + return (attrValue); + } + } + } + } + System.out.println( "oxm file format error, missing java-type " + javaTypeName); + return null; + } + + + public static String processOxmFile( File oxmFile ) + { + StringBuffer sb = new StringBuffer(); + sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"); + String namespace = "org.openecomp"; + sb.append("<xs:schema elementFormDefault=\"qualified\" version=\"1.0\" targetNamespace=\"http://" + namespace + ".aai.inventory/" + + apiVersion + "\" xmlns:tns=\"http://" + namespace + ".aai.inventory/" + apiVersion + "\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"" + + "\n" + + "xmlns:jaxb=\"http://java.sun.com/xml/ns/jaxb\"\r\n" + + " jaxb:version=\"2.1\" \r\n" + + " xmlns:annox=\"http://annox.dev.java.net\" \r\n" + + " jaxb:extensionBindingPrefixes=\"annox\">\n\n"); + + try { + + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(oxmFile); + + NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings"); + Element bindingElement; + NodeList javaTypesNodes; + Element javaTypesElement; + + Element javaTypeElement; + + + if ( bindingsNodes == null || bindingsNodes.getLength() == 0 ) { + System.out.println( "missing <binding-nodes> in " + oxmFile ); + return null; + } + + bindingElement = (Element) bindingsNodes.item(0); + javaTypesNodes = bindingElement.getElementsByTagName("java-types"); + if ( javaTypesNodes.getLength() < 1 ) { + System.out.println( "missing <binding-nodes><java-types> in " + oxmFile ); + return null; + } + javaTypesElement = (Element) javaTypesNodes.item(0); + javaTypeNodes = javaTypesElement.getElementsByTagName("java-type"); + if ( javaTypeNodes.getLength() < 1 ) { + System.out.println( "missing <binding-nodes><java-types><java-type> in " + oxmFile ); + return null; + } + + String javaTypeName; + String attrName, attrValue; + Attr attr; + for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { + javaTypeElement = (Element) javaTypeNodes.item(i); + NamedNodeMap attributes = javaTypeElement.getAttributes(); + javaTypeName = null; + for ( int j = 0; j < attributes.getLength(); ++j ) { + attr = (Attr) attributes.item(j); + attrName = attr.getNodeName(); + attrValue = attr.getNodeValue(); + if ( attrName.equals("name")) + javaTypeName = attrValue; + } + if ( javaTypeName == null ) { + System.out.println( "<java-type> has no name attribute in " + oxmFile ); + return null; + } + if ("Nodes".equals(javaTypeName)) { + System.out.println("skipping Nodes entry (temporary feature)"); + continue; + } + if ( !generatedJavaType.containsKey(javaTypeName) ) { + generatedJavaType.put(javaTypeName, null); + sb.append(processJavaTypeElement( javaTypeName, javaTypeElement )); + } + } + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + sb.append("</xs:schema>\n"); + return sb.toString(); + } + + private static boolean isStandardType( String elementType ) + { + switch ( elementType ) { + case "java.lang.String": + case "java.lang.Long": + case "java.lang.Integer": + case"java.lang.Boolean": + return true; + } + return false; + } + + private static Vector<String> getIndexedProps( String attrValue ) + { + if ( attrValue == null ) + return null; + StringTokenizer st = new StringTokenizer( attrValue, ","); + if ( st.countTokens() == 0 ) + return null; + Vector<String> result = new Vector<String>(); + while ( st.hasMoreTokens()) { + result.add(st.nextToken()); + } + return result; + } + + private static Class<?> getEdgeRulesClass() throws ClassNotFoundException { + Class<?> result = null; + + // If a class matching the apiVersion exists, we are generating documentation for a prior release + // Otherwise, we're generated documentation for the current release. + try { + result = Class.forName("org.openecomp.aai.dbmodel." + apiVersion +".gen.DbEdgeRules"); + } catch (ClassNotFoundException ex) { + result = Class.forName("org.openecomp.aai.dbmodel.DbEdgeRules"); + } + return result; + } + + /** + * Guaranteed to at least return non null but empty collection of edge descriptions + * @param nodeName name of the vertex whose edge relationships to return + * @return collection of node neighbors based on DbEdgeRules + */ + private static Collection<EdgeDescription> getEdgeRules( String nodeName ) + { + + ArrayList<EdgeDescription> result = new ArrayList<>(); + Iterator<String> edgeRulesIterator; + + try { + + Field mapfield = versionedClass.getField("EdgeRules"); + Object map = mapfield.get(null); + if (map instanceof Multimap<?,?>) { + edgeRulesIterator = ((Multimap<String,String>) map).keySet().iterator(); + } else { + throw new NoSuchFieldException ("Didn't get back the multimap field expected"); + } + GenerateXsd x = new GenerateXsd(); + + while( edgeRulesIterator.hasNext() ){ + String ruleKey = edgeRulesIterator.next(); + if ( ruleKey.startsWith(nodeName + "|" ) || + ruleKey.endsWith("|" + nodeName)) { + Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(ruleKey); + Iterator <String> ruleItr = edRuleColl.iterator(); + while( ruleItr.hasNext() ){ + EdgeDescription edgeDes = x.new EdgeDescription(); + edgeDes.setRuleKey(ruleKey); + String fullRuleString = ruleItr.next(); + String[] toks = fullRuleString.split(","); + if (toks != null) { + if (toks.length > 1) { + edgeDes.setDirection(toks[1]); + } + if (toks.length > 2) { + edgeDes.setMultiplicity(toks[2]); + } + if (toks.length > 3) { + if (toks[3].equals("true")) + edgeDes.setType(LineageType.PARENT); + else if (toks[3].equals("parent")) + edgeDes.setType(LineageType.PARENT); + else if (toks[3].equals("child")) + edgeDes.setType(LineageType.CHILD); + else + edgeDes.setType(LineageType.UNRELATED); + } + if (toks.length > 5) { + edgeDes.setHasDelTarget(toks[5]);; + } + } + + //System.out.println( "nodeName " + nodeName + " ruleKey " + ruleKey + " ruleString " + fullRuleString); + //result.add(ruleKey + "-" + fullRuleString); + result.add(edgeDes); + } + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return result; + } + + /** + * Finds the default delete scope from DBEdgeRules + * @param nodeName name of vertex whose delete scope to return + * @return default delete scope of the input nodeName, null if none. + */ + private static String getDeleteRules( String nodeName ) + { + String result = null; + Iterator<String> delRulesIterator; + + try { + + Field mapfield = versionedClass.getField("DefaultDeleteScope"); + Object map = mapfield.get(null); + if (map instanceof Multimap<?,?>) { + delRulesIterator = ((Multimap<String,String>) map).keySet().iterator(); + } else { + throw new NoSuchFieldException ("Didn't get back the multimap field expected"); + } + + while( delRulesIterator.hasNext() ){ + String ruleKey = delRulesIterator.next(); + if ( ruleKey.equals(nodeName)) { + Collection <String> deRuleColl = DbEdgeRules.DefaultDeleteScope.get(ruleKey); + Iterator <String> ruleItr = deRuleColl.iterator(); + if( ruleItr.hasNext() ){ + result = ruleItr.next(); + } + } + } + + } catch (Exception ex) { + ex.printStackTrace(); + } + return result; + } + + public static String processJavaTypeElementSwagger( String javaTypeName, Element javaTypeElement, + StringBuffer pathSb, StringBuffer definitionsSb, String path, String tag, String opId, + String getItemName, StringBuffer pathParams, String queryParams, String validEdges) { + + String xmlRootElementName = null; + + //Map<String, String> addJavaType = new HashMap<String, String>(); + String useTag = null; + String useOpId = null; + + if ( tag != null ) { + switch ( tag ) { + case "Network": + case "ServiceDesignAndCreation": + case "Business": + case "CloudInfrastructure": + break; + default: + return null; + } + } + + if ( !javaTypeName.equals("Inventory") ) { + if ( javaTypeName.equals("AaiInternal")) + return null; + if ( opId == null ) + useOpId = javaTypeName; + else + useOpId = opId + javaTypeName; + if ( tag == null ) + useTag = javaTypeName; + } + + NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes"); + + if ( parentNodes.getLength() == 0 ) { + System.out.println( "no java-attributes for java-type " + javaTypeName); + return ""; + + } + + NamedNodeMap attributes; + + NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element"); + Element valElement = (Element) valNodes.item(0); + attributes = valElement.getAttributes(); + for ( int i = 0; i < attributes.getLength(); ++i ) { + Attr attr = (Attr) attributes.item(i); + String attrName = attr.getNodeName(); + + String attrValue = attr.getNodeValue(); + //System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue); + if ( attrName.equals("name")) + xmlRootElementName = attrValue; + } + /* + if ( xmlRootElementName.equals("oam-networks")) + System.out.println( "xmlRootElement oam-networks with getItemData [" + getItemName + "]"); + */ + //already processed + /* + if ( generatedJavaType.containsKey(xmlRootElementName) ) { + return null; + } + */ + NodeList childNodes; + Element childElement; + NodeList xmlPropNodes = javaTypeElement.getElementsByTagName("xml-properties"); + Element xmlPropElement; + String pathDescriptionProperty = null; + + + Vector<String> indexedProps = null; + + /*System.out.println( "javaTypeName " + javaTypeName + " has xml-properties length " + xmlPropNodes.getLength()); + if ( path != null && path.equals("/network/generic-vnfs")) + System.out.println("path is " + "/network/generic-vnfs with getItemName " + getItemName); + */ + if ( xmlPropNodes.getLength() > 0 ) { + + for ( int i = 0; i < xmlPropNodes.getLength(); ++i ) { + xmlPropElement = (Element)xmlPropNodes.item(i); + if ( !xmlPropElement.getParentNode().isSameNode(javaTypeElement)) + continue; + childNodes = xmlPropElement.getElementsByTagName("xml-property"); + + if ( childNodes.getLength() > 0 ) { + for ( int j = 0; j < childNodes.getLength(); ++j ) { + childElement = (Element)childNodes.item(j); + // get name + int useValue = VALUE_NONE; + attributes = childElement.getAttributes(); + for ( int k = 0; k < attributes.getLength(); ++k ) { + Attr attr = (Attr) attributes.item(k); + String attrName = attr.getNodeName(); + String attrValue = attr.getNodeValue(); + if ( attrName == null || attrValue == null ) + continue; + if ( attrName.equals("name") && attrValue.equals("description")) { + useValue = VALUE_DESCRIPTION; + } + if ( useValue == VALUE_DESCRIPTION && attrName.equals("value")) { + pathDescriptionProperty = attrValue; + //break; + //System.out.println("found xml-element-wrapper " + xmlElementWrapper); + } + if ( attrValue.equals("indexedProps")) { + useValue = VALUE_INDEXED_PROPS; + } + if ( useValue == VALUE_INDEXED_PROPS && attrName.equals("value")) { + indexedProps = getIndexedProps( attrValue ); + } + } + } + } + } + } + //System.out.println("javaTypeName " + javaTypeName + " description " + pathDescriptionProperty); + + /* + if ( javaTypeName.equals("RelationshipList")) { + System.out.println( "Skipping " + javaTypeName); + generatedJavaType.put(javaTypeName, null); + return ""; + } + */ + + Element parentElement = (Element)parentNodes.item(0); + NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element"); + + + String attrDescription = null; + + Element xmlElementElement; + String addType = null; + String elementType = null, elementIsKey = null, elementIsRequired, elementContainerType = null; + String elementName = null; + StringBuffer sbParameters = new StringBuffer(); + + StringBuffer sbRequired = new StringBuffer(); + int requiredCnt = 0; + int propertyCnt = 0; + StringBuffer sbProperties = new StringBuffer(); + StringBuffer sbIndexedParams = new StringBuffer(); + + + StringTokenizer st; + if ( xmlRootElementName.equals("inventory")) + path = ""; + else if ( path == null ) + //path = "/aai/" + apiVersion; + path = "/" + xmlRootElementName; + else + path += "/" + xmlRootElementName; + st = new StringTokenizer(path, "/"); + /* + if ( path.equals("/business/customers/customer/{global-customer-id}/service-subscriptions/service-subscription")) + System.out.println("processing path /business/customers/customer/{global-customer-id}/service-subscriptions with tag " + tag); + */ + boolean genPath = false; + /* + if ( path != null && path.equals("/network/generic-vnfs/generic-vnf")) + System.out.println("path is " + "/network/generic-vnfs/generic-vnf"); + */ + if ( st.countTokens() > 1 && getItemName == null ) { + if ( appliedPaths.containsKey(path)) + return null; + appliedPaths.put(path, null); + genPath = true; + if ( path.contains("/relationship/") ) { // filter paths with relationship-list + genPath = false; + } + if ( path.endsWith("/relationship-list")) { + genPath = false; + } + + } + + Vector<String> addTypeV = null; + if ( xmlElementNodes.getLength() > 0 ) { + + for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) { + xmlElementElement = (Element)xmlElementNodes.item(i); + if ( !xmlElementElement.getParentNode().isSameNode(parentElement)) + continue; + /*childNodes = xmlElementElement.getElementsByTagName("xml-element-wrapper"); + if ( childNodes.getLength() > 0 ) { + childElement = (Element)childNodes.item(0); + // get name + attributes = childElement.getAttributes(); + for ( int k = 0; k < attributes.getLength(); ++k ) { + Attr attr = (Attr) attributes.item(k); + String attrName = attr.getNodeName(); + String attrValue = attr.getNodeValue(); + if ( attrName.equals("name")) { + xmlElementWrapper = attrValue; + //System.out.println("found xml-element-wrapper " + xmlElementWrapper); + } + } + + } + */ + valNodes = xmlElementElement.getElementsByTagName("xml-properties"); + attrDescription = null; + if ( valNodes.getLength() > 0 ) { + for ( int j = 0; j < valNodes.getLength(); ++j ) { + valElement = (Element)valNodes.item(j); + if ( !valElement.getParentNode().isSameNode(xmlElementElement)) + continue; + childNodes = valElement.getElementsByTagName("xml-property"); + if ( childNodes.getLength() > 0 ) { + childElement = (Element)childNodes.item(0); + // get name + attributes = childElement.getAttributes(); + attrDescription = null; + boolean useValue = false; + for ( int k = 0; k < attributes.getLength(); ++k ) { + Attr attr = (Attr) attributes.item(k); + String attrName = attr.getNodeName(); + String attrValue = attr.getNodeValue(); + if ( attrName.equals("name") && attrValue.equals("description")) { + useValue = true; + } + if ( useValue && attrName.equals("value")) { + attrDescription = attrValue; + //System.out.println("found xml-element-wrapper " + xmlElementWrapper); + } + } + + } + } + } + + attributes = xmlElementElement.getAttributes(); + addTypeV = null; // vector of 1 + addType = null; + + elementName = elementType = elementIsKey = elementIsRequired = elementContainerType = null; + for ( int j = 0; j < attributes.getLength(); ++j ) { + Attr attr = (Attr) attributes.item(j); + String attrName = attr.getNodeName(); + + String attrValue = attr.getNodeValue(); + //System.out.println("For " + xmlRootElementName + " Found xml-element attribute: " + attrName + " with value: " + attrValue); + if ( attrName.equals("name")) { + elementName = attrValue; + + } + if ( attrName.equals("type") && getItemName == null ) { + elementType = attrValue; + if ( attrValue.contains(apiVersionFmt) ) { + addType = attrValue.substring(attrValue.lastIndexOf('.')+1); + if ( addTypeV == null ) + addTypeV = new Vector<String>(); + addTypeV.add(addType); + } + + } + if ( attrName.equals("xml-key")) { + elementIsKey = attrValue; + path += "/{" + elementName + "}"; + } + if ( attrName.equals("required")) { + elementIsRequired = attrValue; + } + if ( attrName.equals("container-type")) { + elementContainerType = attrValue; + } + } + if ( getItemName != null ) { + if ( getItemName.equals("array") ) { + if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) { + //System.out.println( " returning array " + elementName ); + return elementName; + } + + } else { // not an array check + if ( elementContainerType == null || !elementContainerType.equals("java.util.ArrayList")) { + //System.out.println( " returning object " + elementName ); + return elementName; + } + + } + //System.out.println( " returning null" ); + return null; + } + if ( elementIsRequired != null ) { + if ( requiredCnt == 0 ) + sbRequired.append(" required:\n"); + ++requiredCnt; + if ( addTypeV != null ) { + for ( int k = 0; k < addTypeV.size(); ++i ) { + sbRequired.append(" - " + getXmlRootElementName(addTypeV.elementAt(k)) + ":\n"); + } + } else + sbRequired.append(" - " + elementName + "\n"); + + } + + if ( elementIsKey != null ) { + sbParameters.append((" - name: " + elementName + "\n")); + sbParameters.append((" in: path\n")); + if ( attrDescription != null && attrDescription.length() > 0 ) + sbParameters.append((" description: " + attrDescription + "\n")); + sbParameters.append((" required: true\n")); + if ( elementType.equals("java.lang.String")) + sbParameters.append(" type: string\n"); + if ( elementType.equals("java.lang.Long")) { + sbParameters.append(" type: integer\n"); + sbParameters.append(" format: int64\n"); + } + if ( elementType.equals("java.lang.Integer")) { + sbParameters.append(" type: integer\n"); + sbParameters.append(" format: int32\n"); + } + if ( elementType.equals("java.lang.Boolean")) + sbParameters.append(" type: boolean\n"); + + + } else if ( indexedProps != null + && indexedProps.contains(elementName ) ) { + sbIndexedParams.append((" - name: " + elementName + "\n")); + sbIndexedParams.append((" in: query\n")); + if ( attrDescription != null && attrDescription.length() > 0 ) + sbIndexedParams.append((" description: " + attrDescription + "\n")); + sbIndexedParams.append((" required: false\n")); + if ( elementType.equals("java.lang.String")) + sbIndexedParams.append(" type: string\n"); + if ( elementType.equals("java.lang.Long")) { + sbIndexedParams.append(" type: integer\n"); + sbIndexedParams.append(" format: int64\n"); + } + if ( elementType.equals("java.lang.Integer")) { + sbIndexedParams.append(" type: integer\n"); + sbIndexedParams.append(" format: int32\n"); + } + if ( elementType.equals("java.lang.Boolean")) + sbIndexedParams.append(" type: boolean\n"); + } + + /* + if ( elementName != null && elementName.equals("inventory-item")) + System.out.println( "processing inventory-item elementName"); + */ + + if ( isStandardType(elementType)) { + sbProperties.append(" " + elementName + ":\n"); + ++propertyCnt; + sbProperties.append(" type: "); + + if ( elementType.equals("java.lang.String")) + sbProperties.append("string\n"); + else if ( elementType.equals("java.lang.Long")) { + sbProperties.append("integer\n"); + sbProperties.append(" format: int64\n"); + } + else if ( elementType.equals("java.lang.Integer")){ + sbProperties.append("integer\n"); + sbProperties.append(" format: int32\n"); + } + else if ( elementType.equals("java.lang.Boolean")) + sbProperties.append("boolean\n"); + if ( attrDescription != null && attrDescription.length() > 0 ) + sbProperties.append(" description: " + attrDescription + "\n"); + } + + //if ( addType != null && elementContainerType != null && elementContainerType.equals("java.util.ArrayList") ) { + + if ( addTypeV != null ) { + StringBuffer newPathParams = null; + if ( pathParams != null ) { + newPathParams = new StringBuffer(); + newPathParams.append(pathParams); + } + if ( sbParameters.toString().length() > 0 ) { + if ( newPathParams == null ) + newPathParams = new StringBuffer(); + newPathParams.append(sbParameters); + } + String newQueryParams = null; + if ( sbIndexedParams.toString().length() > 0 ) { + if ( queryParams == null ) + newQueryParams = sbIndexedParams.toString(); + else + newQueryParams = queryParams + sbIndexedParams.toString(); + } else { + newQueryParams = queryParams; + } + for ( int k = 0; k < addTypeV.size(); ++k ) { + addType = addTypeV.elementAt(k); + + if ( opId == null || !opId.contains(addType)) { + processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), + pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, null, + newPathParams, newQueryParams, validEdges); + } + // need item name of array + String itemName = processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), + pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, + "array", null, null, null ); + + if ( itemName != null ) { + if ( addType.equals("AaiInternal") ) { + //System.out.println( "addType AaiInternal, skip properties"); + + } else if ( getItemName == null) { + ++propertyCnt; + sbProperties.append(" " + getXmlRootElementName(addType) + ":\n"); + sbProperties.append(" type: array\n items:\n"); + sbProperties.append(" $ref: \"#/definitions/" + itemName + "\"\n"); + if ( attrDescription != null && attrDescription.length() > 0 ) + sbProperties.append(" description: " + attrDescription + "\n"); + } + } else { + /*itemName = processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), + pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, "other" ); + if ( itemName != null ) { + */ + if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) { + // need properties for getXmlRootElementName(addType) + newPathParams = null; + if ( pathParams != null ) { + newPathParams = new StringBuffer(); + newPathParams.append(pathParams); + } + if ( sbParameters.toString().length() > 0 ) { + if ( newPathParams == null ) + newPathParams = new StringBuffer(); + newPathParams.append(sbParameters); + } + newQueryParams = null; + if ( sbIndexedParams.toString().length() > 0 ) { + if ( queryParams == null ) + newQueryParams = sbIndexedParams.toString(); + else + newQueryParams = queryParams + sbIndexedParams.toString(); + } else { + newQueryParams = queryParams; + } + processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), + pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, + null, newPathParams, newQueryParams, validEdges ); + sbProperties.append(" " + getXmlRootElementName(addType) + ":\n"); + sbProperties.append(" type: array\n items: \n"); + sbProperties.append(" $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n"); + } else { + sbProperties.append(" " + getXmlRootElementName(addType) + ":\n"); + sbProperties.append(" type: object\n"); + sbProperties.append(" $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n"); + } + if ( attrDescription != null && attrDescription.length() > 0 ) + sbProperties.append(" description: " + attrDescription + "\n"); + ++propertyCnt; + /*} + else { + System.out.println(" unable to define swagger object for " + addType); + } + */ + } + //if ( getItemName == null) looking for missing properties + //generatedJavaType.put(addType, null); + } + } + } + } + if ( genPath ) { + /* + if ( useOpId.equals("CloudInfrastructureComplexesComplexCtagPools")) + System.out.println( "adding path CloudInfrastructureComplexesComplexCtagPools"); + */ + + if ( !path.endsWith("/relationship") ) { + pathSb.append(" " + path + ":\n" ); + pathSb.append(" get:\n"); + pathSb.append(" tags:\n"); + pathSb.append(" - " + tag + "\n"); + pathSb.append(" summary: returns " + xmlRootElementName + "\n"); + + pathSb.append(" description: returns " + xmlRootElementName + "\n"); + pathSb.append(" operationId: get" + useOpId + "\n"); + pathSb.append(" produces:\n"); + pathSb.append(" - application/json\n"); + pathSb.append(" - application/xml\n"); + + pathSb.append(" responses:\n"); + pathSb.append(" \"200\":\n"); + pathSb.append(" description: successful operation\n"); + pathSb.append(" schema:\n"); + pathSb.append(" $ref: \"#/definitions/" + xmlRootElementName + "\"\n"); + pathSb.append(" \"default\":\n"); + pathSb.append(" " + responsesUrl); + /* + pathSb.append(" \"200\":\n"); + pathSb.append(" description: successful operation\n"); + pathSb.append(" schema:\n"); + pathSb.append(" $ref: \"#/definitions/" + xmlRootElementName + "\"\n"); + pathSb.append(" \"404\":\n"); + pathSb.append(" description: resource was not found\n"); + pathSb.append(" \"400\":\n"); + pathSb.append(" description: bad request\n"); + */ + if ( path.indexOf('{') > 0 ) { + + if ( sbParameters.toString().length() > 0 ) { + if ( pathParams == null ) + pathParams = new StringBuffer(); + pathParams.append(sbParameters); + } + if ( pathParams != null) { + pathSb.append(" parameters:\n"); + pathSb.append(pathParams); + } else + System.out.println( "null pathParams for " + useOpId); + if ( sbIndexedParams.toString().length() > 0 ) { + if ( queryParams == null ) + queryParams = sbIndexedParams.toString(); + else + queryParams = queryParams + sbIndexedParams.toString(); + } + if ( queryParams != null ) { + if ( pathParams == null ) { + pathSb.append(" parameters:\n"); + } + pathSb.append(queryParams); + } + } + } + boolean skipPutDelete = false; // no put or delete for "all" + if ( !path.endsWith("/relationship") ) { + if ( !path.endsWith("}") ){ + skipPutDelete = true; + } + + } + if ( path.indexOf('{') > 0 && !opId.startsWith("Search") &&!skipPutDelete) { + // add PUT + if ( path.endsWith("/relationship") ) { + pathSb.append(" " + path + ":\n" ); + } + pathSb.append(" put:\n"); + pathSb.append(" tags:\n"); + pathSb.append(" - " + tag + "\n"); + + if ( path.endsWith("/relationship") ) { + pathSb.append(" summary: see node definition for valid relationships\n"); + } else { + pathSb.append(" summary: create or update an existing " + xmlRootElementName + "\n"); + pathSb.append(" description: create or update an existing " + xmlRootElementName + "\n"); + } + pathSb.append(" operationId: createOrUpdate" + useOpId + "\n"); + pathSb.append(" consumes:\n"); + pathSb.append(" - application/json\n"); + pathSb.append(" - application/xml\n"); + pathSb.append(" produces:\n"); + pathSb.append(" - application/json\n"); + pathSb.append(" - application/xml\n"); + pathSb.append(" responses:\n"); + pathSb.append(" \"default\":\n"); + pathSb.append(" " + responsesUrl); + /* + pathSb.append(" responses:\n"); + pathSb.append(" \"200\":\n"); + pathSb.append(" description: existing resource has been modified and there is a response buffer\n"); + pathSb.append(" \"201\":\n"); + pathSb.append(" description: new resource is created\n"); + pathSb.append(" \"202\":\n"); + pathSb.append(" description: action requested but may have taken other actions as well, which are returned in the response payload\n"); + pathSb.append(" \"204\":\n"); + pathSb.append(" description: existing resource has been modified and there is no response buffer\n"); + pathSb.append(" \"400\":\n"); + pathSb.append(" description: Bad Request will be returned if headers are missing\n"); + pathSb.append(" \"404\":\n"); + pathSb.append(" description: Not Found will be returned if an unknown URL is used\n"); + */ + pathSb.append(" parameters:\n"); + //pathSb.append(" - in: path\n"); + pathSb.append(pathParams); // for nesting + pathSb.append(" - name: body\n"); + pathSb.append(" in: body\n"); + pathSb.append(" description: " + xmlRootElementName + " object that needs to be created or updated\n"); + pathSb.append(" required: true\n"); + pathSb.append(" schema:\n"); + pathSb.append(" $ref: \"#/definitions/" + xmlRootElementName + "\"\n"); + /* + if ( queryParams != null ) { + pathSb.append(queryParams); + } + */ + // add DELETE + pathSb.append(" delete:\n"); + pathSb.append(" tags:\n"); + pathSb.append(" - " + tag + "\n"); + pathSb.append(" summary: delete an existing " + xmlRootElementName + "\n"); + + pathSb.append(" description: delete an existing " + xmlRootElementName + "\n"); + + pathSb.append(" operationId: delete" + useOpId + "\n"); + pathSb.append(" consumes:\n"); + pathSb.append(" - application/json\n"); + pathSb.append(" - application/xml\n"); + pathSb.append(" produces:\n"); + pathSb.append(" - application/json\n"); + pathSb.append(" - application/xml\n"); + pathSb.append(" responses:\n"); + pathSb.append(" \"default\":\n"); + pathSb.append(" " + responsesUrl); + /* + pathSb.append(" responses:\n"); + pathSb.append(" \"200\":\n"); + pathSb.append(" description: successful, the response includes an entity describing the status\n"); + pathSb.append(" \"204\":\n"); + pathSb.append(" description: successful, action has been enacted but the response does not include an entity\n"); + pathSb.append(" \"400\":\n"); + pathSb.append(" description: Bad Request will be returned if headers are missing\n"); + pathSb.append(" \"404\":\n"); + pathSb.append(" description: Not Found will be returned if an unknown URL is used\n"); + */ + pathSb.append(" parameters:\n"); + //pathSb.append(" - in: path\n"); + pathSb.append(pathParams); // for nesting + if ( !path.endsWith("/relationship") ) { + pathSb.append(" - name: resource-version\n"); + + pathSb.append(" in: query\n"); + pathSb.append(" description: resource-version for concurrency\n"); + pathSb.append(" required: true\n"); + pathSb.append(" type: string\n"); + } + /* + if ( queryParams != null ) { + pathSb.append(queryParams); + } + */ + } + + } + if ( generatedJavaType.containsKey(xmlRootElementName) ) { + return null; + } + + definitionsSb.append(" " + xmlRootElementName + ":\n"); + Collection<EdgeDescription> edges = getEdgeRules(xmlRootElementName ); + if ( edges.size() > 0 ) { + StringBuffer sbEdge = new StringBuffer(); + sbEdge.append(" ###### Related Nodes\n"); + for (EdgeDescription ed : edges) { + if ( ed.getRuleKey().startsWith(xmlRootElementName)) { + sbEdge.append(" - TO ").append(ed.getRuleKey().substring(ed.getRuleKey().indexOf("|")+1)); + sbEdge.append(ed.getRelationshipDescription("TO", xmlRootElementName)); + sbEdge.append("\n"); + } + } + for (EdgeDescription ed : edges) { + if ( ed.getRuleKey().endsWith(xmlRootElementName)) { + sbEdge.append(" - FROM ").append(ed.getRuleKey().substring(0, ed.getRuleKey().indexOf("|"))); + sbEdge.append(ed.getRelationshipDescription("FROM", xmlRootElementName)); + sbEdge.append("\n"); + } + } + validEdges = sbEdge.toString(); + } + + String deleteRule = getDeleteRules(xmlRootElementName); + // Handle description property. Might have a description OR valid edges OR both OR neither. + // Only put a description: tag if there is at least one. + if (pathDescriptionProperty != null || deleteRule != null || validEdges != null) { + definitionsSb.append(" description: |\n"); + + if ( pathDescriptionProperty != null ) + definitionsSb.append(" " + pathDescriptionProperty + "\n" ); + if (deleteRule != null) + definitionsSb.append(" ###### Default Delete Scope\n ").append(deleteRule).append("\n"); + if (validEdges != null) + definitionsSb.append(validEdges); + } + + if ( requiredCnt > 0 ) + definitionsSb.append(sbRequired); + if ( propertyCnt > 0 ) { + definitionsSb.append(" properties:\n"); + definitionsSb.append(sbProperties); + } + generatedJavaType.put(xmlRootElementName, null); + return null; + } + + public static String generateSwaggerFromOxmFile( File oxmFile ) + { + + StringBuffer sb = new StringBuffer(); + sb.append("swagger: \"2.0\"\ninfo:\n description:\n A&AI REST API\n version: \"" + apiVersion +"\"\n"); + sb.append(" title: Active and Available Inventory REST API\n"); + sb.append(" license:\n name: Apache 2.0\n url: http://www.apache.org/licenses/LICENSE-2.0.html\n"); + sb.append("schemes:\n - https\npaths:\n"); + /* + sb.append("responses:\n"); + sb.append(" \"200\":\n"); + sb.append(" description: successful operation\n"); + sb.append(" \"404\":\n"); + sb.append(" description: resource was not found\n"); + sb.append(" \"400\":\n"); + sb.append(" description: bad request\n"); + */ + try { + + versionedClass = getEdgeRulesClass(); + + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(oxmFile); + + NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings"); + Element bindingElement; + NodeList javaTypesNodes; + Element javaTypesElement; + + Element javaTypeElement; + + + if ( bindingsNodes == null || bindingsNodes.getLength() == 0 ) { + System.out.println( "missing <binding-nodes> in " + oxmFile ); + return null; + } + + bindingElement = (Element) bindingsNodes.item(0); + javaTypesNodes = bindingElement.getElementsByTagName("java-types"); + if ( javaTypesNodes.getLength() < 1 ) { + System.out.println( "missing <binding-nodes><java-types> in " + oxmFile ); + return null; + } + javaTypesElement = (Element) javaTypesNodes.item(0); + + javaTypeNodes = javaTypesElement.getElementsByTagName("java-type"); + if ( javaTypeNodes.getLength() < 1 ) { + System.out.println( "missing <binding-nodes><java-types><java-type> in " + oxmFile ); + return null; + } + + String javaTypeName; + String attrName, attrValue; + Attr attr; + StringBuffer pathSb = new StringBuffer(); + + StringBuffer definitionsSb = new StringBuffer("definitions:\n"); + + for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { + javaTypeElement = (Element) javaTypeNodes.item(i); + NamedNodeMap attributes = javaTypeElement.getAttributes(); + javaTypeName = null; + for ( int j = 0; j < attributes.getLength(); ++j ) { + attr = (Attr) attributes.item(j); + attrName = attr.getNodeName(); + attrValue = attr.getNodeValue(); + if ( attrName.equals("name")) + javaTypeName = attrValue; + } + if ( javaTypeName == null ) { + System.out.println( "<java-type> has no name attribute in " + oxmFile ); + return null; + } + if ( !generatedJavaType.containsKey(getXmlRootElementName(javaTypeName)) ) { + + //generatedJavaType.put(javaTypeName, null); + //if ( javaTypeName.equals("search")||javaTypeName.equals("actions")) + + processJavaTypeElementSwagger( javaTypeName, javaTypeElement, pathSb, + definitionsSb, null, null, null, null, null, null, null); + } + } + sb.append(pathSb); + //System.out.println( "definitions block\n" + definitionsSb.toString()); + sb.append(definitionsSb.toString()); + //sb.append(definitionsSb); + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + //System.out.println("generated " + sb.toString()); + return sb.toString(); + } + + private static NodeList locateXmlProperties(Element element) { + XPathExpression expr; + NodeList result = null; + try { + expr = xpath.compile("xml-properties"); + if (expr != null) { + Object nodeset = expr.evaluate(element, XPathConstants.NODESET); + if (nodeset != null) { + NodeList nodes = (NodeList) nodeset; + if (nodes != null && nodes.getLength() > 0) { + Element xmlProperty = (Element)nodes.item(0); + result = xmlProperty.getElementsByTagName("xml-property"); + } + } + } + } catch (XPathExpressionException e) { + e.printStackTrace(); + } + return result; + + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/HbaseSaltPrefixer.java b/aai-core/src/main/java/org/openecomp/aai/util/HbaseSaltPrefixer.java new file mode 100644 index 00000000..29373858 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/HbaseSaltPrefixer.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +/* + * logging to hbase encountered hotspotting issues, so per + * http://archive.cloudera.com/cdh5/cdh/5/hbase-0.98.6-cdh5.3.8/book/rowkey.design.html + * we decided to salt the rowkeys + * as these keys are generated in a couple places, I made a class to contain that logic + */ +public class HbaseSaltPrefixer { + private int NUM_REGION_BUCKETS = 3; //the number of hbase region servers per cluster + + private static class SingletonHolder{ + private static final HbaseSaltPrefixer INSTANCE = new HbaseSaltPrefixer(); + } + + /** + * Instantiates a new hbase salt prefixer. + */ + private HbaseSaltPrefixer(){} + + /** + * Gets the single instance of HbaseSaltPrefixer. + * + * @return single instance of HbaseSaltPrefixer + */ + public static HbaseSaltPrefixer getInstance() { + return SingletonHolder.INSTANCE; + } + + /** + * Prepend salt. + * + * @param key the key + * @return the string + */ + public String prependSalt(String key) { + int salt = Math.abs(key.hashCode()) % NUM_REGION_BUCKETS; + return salt + "-" + key; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/KeyValueList.java b/aai-core/src/main/java/org/openecomp/aai/util/KeyValueList.java new file mode 100644 index 00000000..95f09d58 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/KeyValueList.java @@ -0,0 +1,138 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "key", + "value" +}) +public class KeyValueList { + + @JsonProperty("key") + private String key; + @JsonProperty("value") + private String value; + @JsonIgnore + private Map<String, Object> additionalProperties = new HashMap<String, Object>(); + + /** + * + * @return + * The key + */ + @JsonProperty("key") + public String getKey() { + return key; + } + + /** + * + * @param key + * The key + */ + @JsonProperty("key") + public void setKey(String key) { + this.key = key; + } + + public KeyValueList withKey(String key) { + this.key = key; + return this; + } + + /** + * + * @return + * The value + */ + @JsonProperty("value") + public String getValue() { + return value; + } + + /** + * + * @param value + * The value + */ + @JsonProperty("value") + public void setValue(String value) { + this.value = value; + } + + public KeyValueList withValue(String value) { + this.value = value; + return this; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + @JsonAnyGetter + public Map<String, Object> getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + public KeyValueList withAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + return this; + } + + @Override + public int hashCode() { + return new HashCodeBuilder().append(key).append(value).append(additionalProperties).toHashCode(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if ((other instanceof KeyValueList) == false) { + return false; + } + KeyValueList rhs = ((KeyValueList) other); + return new EqualsBuilder().append(key, rhs.key).append(value, rhs.value).append(additionalProperties, rhs.additionalProperties).isEquals(); + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/MapperUtil.java b/aai-core/src/main/java/org/openecomp/aai/util/MapperUtil.java new file mode 100644 index 00000000..54f239b6 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/MapperUtil.java @@ -0,0 +1,115 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import org.openecomp.aai.exceptions.AAIException; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; + +public class MapperUtil { + + + /** + * Read as object of. + * + * @param <T> the generic type + * @param clazz the clazz + * @param value the value + * @return the t + * @throws AAIException the AAI exception + */ + public static <T> T readAsObjectOf(Class<T> clazz, String value) throws AAIException { + com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper(); + try { + return MAPPER.readValue(value, clazz); + } catch (Exception e) { + throw new AAIException("AAI_4007", e); + } + } + + /** + * Read with dashes as object of. + * + * @param <T> the generic type + * @param clazz the clazz + * @param value the value + * @return the t + * @throws AAIException the AAI exception + */ + public static <T> T readWithDashesAsObjectOf(Class<T> clazz, String value) throws AAIException { + com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper(); + try { + MAPPER.registerModule(new JaxbAnnotationModule()); + MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false); + + return MAPPER.readValue(value, clazz); + } catch (Exception e) { + throw new AAIException("AAI_4007", e); + } + } + + /** + * Write as JSON string. + * + * @param obj the obj + * @return the string + * @throws AAIException the AAI exception + */ + public static String writeAsJSONString(Object obj) throws AAIException { + com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper(); + try { + String s = MAPPER.writeValueAsString(obj); + return s; + //readValue(value, clazz); + } catch (Exception e) { + throw new AAIException("AAI_4008", e); + } + } + + /** + * Write as JSON string with dashes. + * + * @param obj the obj + * @return the string + * @throws AAIException the AAI exception + */ + public static String writeAsJSONStringWithDashes(Object obj) throws AAIException { + com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper(); + try { + MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + MAPPER.configure(SerializationFeature.INDENT_OUTPUT, false); + MAPPER.configure(SerializationFeature.WRAP_ROOT_VALUE, false); + + MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false); + + MAPPER.registerModule(new JaxbAnnotationModule()); + String s = MAPPER.writeValueAsString(obj); + return s; + } catch (Exception e) { + throw new AAIException("AAI_4008", e); + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/PojoUtils.java b/aai-core/src/main/java/org/openecomp/aai/util/PojoUtils.java new file mode 100644 index 00000000..cd4d771f --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/PojoUtils.java @@ -0,0 +1,738 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; +import com.google.common.base.CaseFormat; +import com.google.common.collect.Multimap; +import com.thinkaurelius.titan.core.TitanVertex; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.eclipse.persistence.dynamic.DynamicEntity; +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.openecomp.aai.domain.model.AAIResource; +import org.openecomp.aai.exceptions.AAIException; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.Map.Entry; + +public class PojoUtils { + + /** + * Gets the key value list. + * + * @param <T> the generic type + * @param e the e + * @param clazz the clazz + * @return the key value list + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + */ + public <T> List<KeyValueList> getKeyValueList(Entity e, T clazz) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + List<KeyValueList> kvList = e.getKeyValueList(); + Object value = null; + Method[] methods = clazz.getClass().getDeclaredMethods(); + String propertyName = ""; + + for (Method method : methods) { + if (method.getName().startsWith("get")) { + propertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + if (!(method.getReturnType().getName().contains("aai")) || method.getReturnType().getName().contains("java.util.List")) { + value = method.invoke(clazz); + KeyValueList kv = new KeyValueList(); + kv.setKey(propertyName); + if (value != null) { + kv.setValue(value.toString()); + } else { + kv.setValue(""); + } + kvList.add(kv); + } + } + } + return kvList; + } + + /** + * Gets the json from object. + * + * @param <T> the generic type + * @param clazz the clazz + * @return the json from object + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + */ + public <T> String getJsonFromObject(T clazz) throws JsonGenerationException, JsonMappingException, IOException { + return getJsonFromObject(clazz, false, true); + } + + /** + * Gets the json from object. + * + * @param <T> the generic type + * @param clazz the clazz + * @param wrapRoot the wrap root + * @param indent the indent + * @return the json from object + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + */ + public <T> String getJsonFromObject(T clazz, boolean wrapRoot, boolean indent) throws JsonGenerationException, JsonMappingException, IOException { + ObjectMapper mapper = new ObjectMapper(); + + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.configure(SerializationFeature.INDENT_OUTPUT, indent); + mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, wrapRoot); + + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, wrapRoot); + + mapper.registerModule(new JaxbAnnotationModule()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + mapper.writeValue(baos, clazz); + + return baos.toString(); + } + + /** + * Gets the json from dynamic object. + * + * @param ent the ent + * @param jaxbContext the jaxb context + * @param includeRoot the include root + * @return the json from dynamic object + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + * @throws JAXBException the JAXB exception + */ + public String getJsonFromDynamicObject(DynamicEntity ent, org.eclipse.persistence.jaxb.JAXBContext jaxbContext, boolean includeRoot) throws JsonGenerationException, JsonMappingException, IOException, JAXBException { + org.eclipse.persistence.jaxb.JAXBMarshaller marshaller = jaxbContext.createMarshaller(); + + marshaller.setProperty(org.eclipse.persistence.jaxb.JAXBMarshaller.JAXB_FORMATTED_OUTPUT, false); + marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ; + marshaller.setProperty("eclipselink.json.include-root", includeRoot); + marshaller.setProperty("eclipselink.media-type", "application/json"); + StringWriter writer = new StringWriter(); + marshaller.marshal(ent, writer); + + return writer.toString(); + } + + /** + * Gets the xml from object. + * + * @param <T> the generic type + * @param clazz the clazz + * @return the xml from object + * @throws JAXBException the JAXB exception + */ + public <T> String getXmlFromObject(T clazz) throws JAXBException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + JAXBContext jc = JAXBContext.newInstance(clazz.getClass().getPackage().getName()); + + Marshaller marshaller = jc.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.marshal(clazz, baos); + + return baos.toString(); + } + + /** + * Gets the lookup key. + * + * @param baseKey the base key + * @param lookupHash the lookup hash + * @param keyProps the key props + * @return the lookup key + */ + public String getLookupKey (String baseKey, HashMap<String,Object> lookupHash, Collection<String> keyProps) { + int baseKeyLen = baseKey.length(); + StringBuffer newKey = new StringBuffer(); + if (baseKeyLen > 0) { + newKey.append(baseKey); + } + + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + String keyProp = keyPropI.next(); + if (baseKeyLen > 0) { + newKey.append("&"); + } + newKey.append(keyProp + "=" + lookupHash.get(keyProp)); + } + return newKey.toString(); + } + + /** + * Gets the lookup keys. + * + * @param lookupHashes the lookup hashes + * @param _dbRulesNodeKeyProps the db rules node key props + * @return the lookup keys + */ + public String getLookupKeys (LinkedHashMap<String,HashMap<String,Object>> lookupHashes, Multimap<String, String> _dbRulesNodeKeyProps) { + Iterator<String> it = lookupHashes.keySet().iterator(); + String lookupKeys = ""; + while (it.hasNext()) { + String objectType = (String)it.next(); + HashMap<String,Object> lookupHash = lookupHashes.get(objectType); + + Collection<String> keyProps = _dbRulesNodeKeyProps.get(objectType); + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + lookupKeys += lookupHash.get(keyPropI.next()); + } + } + return lookupKeys; + } + + /** + * Gets the example object. + * + * @param <T> the generic type + * @param clazz the clazz + * @param singleton the singleton + * @return the example object + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + */ + public <T> void getExampleObject(T clazz, boolean singleton) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException { + Method[] methods = clazz.getClass().getDeclaredMethods(); + String dnHypPropertyName = ""; + String upCamPropertyName = ""; + Random rand = new Random(); + int randInt = rand.nextInt(10000000); + + for (Method method : methods) { + boolean go = false; + if (method.getName().startsWith("get")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3)); + go = true; + } else if (method.getName().startsWith("is")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2)); + go = true; + } + // don't return resource-version on a singleton + if (singleton && dnHypPropertyName.equals("resource-version")) { + go = false; + } + if (go) { + String retType = method.getReturnType().getName(); + if (!retType.contains("aai") && !retType.contains("java.util.List")) { + // get the setter + Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + + if (retType.contains("String")) { + String val = "example-" + dnHypPropertyName + "-val-" + randInt; + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("long")) { + Integer foo = rand.nextInt(100000); + meth.invoke(clazz, foo.longValue()); + } else if (retType.toLowerCase().contains("int")) { + meth.invoke(clazz, rand.nextInt(100000)); + } else if (retType.toLowerCase().contains("short")) { + Integer randShort = rand.nextInt(10000); + meth.invoke(clazz, randShort.shortValue()); + } else if (retType.toLowerCase().contains("boolean")) { + meth.invoke(clazz, true); + } + } + } + } + } + + + /** + * Gets the aai object from vertex. + * + * @param <T> the generic type + * @param clazz the clazz + * @param vert the vert + * @param _propertyDataTypeMap the property data type map + * @return the aai object from vertex + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + */ + public <T> void getAaiObjectFromVertex(T clazz, TitanVertex vert, Map<String, String> _propertyDataTypeMap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException { + Method[] methods = clazz.getClass().getDeclaredMethods(); + String dnHypPropertyName = ""; + String upCamPropertyName = ""; + for (Method method : methods) { + boolean go = false; + if (method.getName().startsWith("get")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3)); + go = true; + } else if (method.getName().startsWith("is")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2)); + go = true; + } + if (go) { + String retType = method.getReturnType().getName(); + if (!retType.contains("aai") && !retType.contains("java.util.List")) { + // get the setter + Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + + if (retType.contains("String")) { + String val = (String)vert.<String>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("long")) { + String titanType = _propertyDataTypeMap.get(dnHypPropertyName); + + Long val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null); + if (intVal != null) { + val = intVal.longValue(); + } + } else { + val = (Long)vert.<Long>property(dnHypPropertyName).orElse(null); + } + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("int")) { + Integer val = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("short")) { + Short val = (Short)vert.<Short>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("boolean")) { + Boolean val = (Boolean)vert.<Boolean>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } + } + } + } + } + + /** + * Gets the topology object. + * + * @param <T> the generic type + * @param clazz the clazz + * @param _dbRulesNodeNameProps the db rules node name props + * @param _dbRulesNodeKeyProps the db rules node key props + * @param vert the vert + * @return the topology object + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + */ + public <T> void getTopologyObject(T clazz, Multimap<String, String> _dbRulesNodeNameProps, Multimap<String, String> _dbRulesNodeKeyProps, TitanVertex vert) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException { + Method[] methods = clazz.getClass().getDeclaredMethods(); + String dnHypPropertyName = ""; +// Object value = null; + List<String> includeProps = new ArrayList<String>(); + + if ("false".equals(AAIConfig.get("aai.notification.topology.allAttrs", "false"))) { + for (Method method : methods) { + if (method.getName().startsWith("is")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2)); + String upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2)); + String retType = method.getReturnType().getName(); + if (retType.equals("java.lang.Boolean")) { + // get the setter + Method setterMeth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + setterMeth.invoke(clazz, (Boolean)null); + } + } + } + String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,clazz.getClass().getSimpleName()); + Collection<String> keepProps = _dbRulesNodeNameProps.get(dnHypClassName); + Iterator <String> keepPropI = keepProps.iterator(); + while( keepPropI.hasNext() ){ + includeProps.add(keepPropI.next()); + } + Collection<String> keepProps2 = _dbRulesNodeKeyProps.get(dnHypClassName); + Iterator <String> keepPropI2 = keepProps2.iterator(); + while( keepPropI2.hasNext() ){ + includeProps.add(keepPropI2.next()); + } + } + + for (Method method : methods) { + if (method.getName().startsWith("get")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + if (includeProps.size() > 0) { + if (!includeProps.contains(dnHypPropertyName)) { + continue; + } + } + String upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3)); + String retType = method.getReturnType().getName(); + if (!retType.contains("aai") && !retType.contains("java.util.List")) { + // get the setter + Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + + if (retType.contains("String")) { + String val = (String)vert.<String>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("long")) { + Long val = (Long)vert.<Long>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("int")) { + Integer val = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("short")) { + Short val = (Short)vert.<Short>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } + } + } + } + } + + /** + * Gets the dynamic topology object. + * + * @param aaiRes the aai res + * @param meObjectType the me object type + * @param _dbRulesNodeNameProps the db rules node name props + * @param _dbRulesNodeKeyProps the db rules node key props + * @param _propertyDataTypeMap the property data type map + * @param vert the vert + * @return the dynamic topology object + * @throws AAIException the AAI exception + */ + public DynamicEntity getDynamicTopologyObject(AAIResource aaiRes, DynamicType meObjectType, Multimap<String, String> _dbRulesNodeNameProps, + Multimap<String, String> _dbRulesNodeKeyProps, Map<String, String> _propertyDataTypeMap, TitanVertex vert) throws AAIException { + + DynamicEntity meObject = meObjectType.newDynamicEntity(); + + List<String> includeProps = new ArrayList<String>(); + + if ("false".equals(AAIConfig.get("aai.notification.topology.allAttrs", "false"))) { + String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,meObjectType.getJavaClass().getSimpleName()); + Collection<String> keepProps = _dbRulesNodeNameProps.get(dnHypClassName); + Iterator <String> keepPropI = keepProps.iterator(); + while( keepPropI.hasNext() ){ + includeProps.add(keepPropI.next()); + } + Collection<String> keepProps2 = _dbRulesNodeKeyProps.get(dnHypClassName); + Iterator <String> keepPropI2 = keepProps2.iterator(); + while( keepPropI2.hasNext() ) { + includeProps.add(keepPropI2.next()); + } + } + + + + for (String attrName : aaiRes.getStringFields()) { + if (includeProps.contains(attrName)) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<String>property(attrName).orElse(null)); + } + } + // the attrName might need to be converted to camel case!!! + for (String attrName : aaiRes.getLongFields()) { + if (includeProps.contains(attrName)) { + String titanType = _propertyDataTypeMap.get(attrName); + + Long val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null); + if (intVal != null) { + val = intVal.longValue(); + } + } else { + val = (Long)vert.<Long>property(attrName).orElse(null); + } + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + + for (String attrName : aaiRes.getIntFields()) { + if (includeProps.contains(attrName)) { + Integer val = (Integer)vert.<Integer>property(attrName).orElse(null); + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + + for (String attrName : aaiRes.getShortFields()) { + if (includeProps.contains(attrName)) { + String titanType = _propertyDataTypeMap.get(attrName); + + Short val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null); + if (intVal != null) { + val = intVal.shortValue(); + } + } else { + val = (Short)vert.<Short>property(attrName).orElse(null); + } + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + + for (String attrName : aaiRes.getBooleanFields()) { + if (includeProps.contains(attrName)) { + Boolean val = (Boolean)vert.<Boolean>property(attrName).orElse(null); + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + return meObject; + } + + /** + * Gets the aai dynamic object from vertex. + * + * @param aaiRes the aai res + * @param meObject the me object + * @param vert the vert + * @param _propertyDataTypeMap the property data type map + * @return the aai dynamic object from vertex + */ + public void getAaiDynamicObjectFromVertex(AAIResource aaiRes, DynamicEntity meObject, TitanVertex vert, + Map<String, String> _propertyDataTypeMap) { + getAaiDynamicObjectFromVertex(aaiRes, meObject, vert, _propertyDataTypeMap, null); + } + + /** + * Gets the aai dynamic object from vertex. + * + * @param aaiRes the aai res + * @param meObject the me object + * @param vert the vert + * @param _propertyDataTypeMap the property data type map + * @param propertyOverRideHash the property over ride hash + * @return the aai dynamic object from vertex + */ + @SuppressWarnings("unchecked") + public void getAaiDynamicObjectFromVertex(AAIResource aaiRes, DynamicEntity meObject, TitanVertex vert, + Map<String, String> _propertyDataTypeMap, HashMap<String, Object> propertyOverRideHash) { + + for (String attrName : aaiRes.getStringFields()) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<String>property(dbAliasWorkaround(attrName)).orElse(null)); + } + } + + for (String attrName : aaiRes.getStringListFields()) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<ArrayList<String>>property(attrName).orElse(null)); + } + } + + // the attrName might need to be converted to camel case!!! + for (String attrName : aaiRes.getLongFields()) { + String titanType = _propertyDataTypeMap.get(attrName); + Long val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Object vertexVal = vert.property(attrName).orElse(null); + if (vertexVal != null) { + if (vertexVal instanceof Integer) { + val = ((Integer)vertexVal).longValue(); + + } else { + val = (Long)vert.<Long>property(attrName).orElse(null); + } + } + } else { + val = (Long)vert.<Long>property(attrName).orElse(null); + } + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + for (String attrName : aaiRes.getIntFields()) { + Integer val = (Integer)vert.<Integer>property(attrName).orElse(null); + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + for (String attrName : aaiRes.getShortFields()) { + String titanType = _propertyDataTypeMap.get(attrName); + Short val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null); + if (intVal != null) { + val = intVal.shortValue(); + } + } else { + val = (Short)vert.<Short>property(attrName).orElse(null); + } + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + for (String attrName : aaiRes.getBooleanFields()) { + Boolean val = (Boolean)vert.<Boolean>property(attrName).orElse(null); + // This is not ideal, but moxy isn't marshalling these attributes. + // TODO: Figure out how to see the default-value from the OXM at startup (or at runtime). + String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,aaiRes.getSimpleName()); + if (val == null && AAIConfig.getDefaultBools().containsKey(dnHypClassName)) { + if (AAIConfig.getDefaultBools().get(dnHypClassName).contains(attrName)) { + val = false; + } + } + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + } + + private String dbAliasWorkaround(String propName) { + final String modelInvariantIdLocal = "model-invariant-id-local"; + final String modelVersionIdLocal = "model-version-id-local"; + final String modelInvariantId = "model-invariant-id"; + final String modelVersionId = "model-version-id"; + + if (propName.equals(modelInvariantId)) { + return modelInvariantIdLocal; + } + if (propName.equals(modelVersionId)) { + return modelVersionIdLocal; + } + + return propName; + + } + + /** + * Gets the dynamic example object. + * + * @param childObject the child object + * @param aaiRes the aai res + * @param singleton the singleton + * @return the dynamic example object + */ + public void getDynamicExampleObject(DynamicEntity childObject, AAIResource aaiRes, boolean singleton) { + // TODO Auto-generated method stub + + Random rand = new Random(); + Integer randInt = rand.nextInt(100000); + long range = 100000000L; + long randLong = (long)(rand.nextDouble()*range); + Integer randShrt = rand.nextInt(20000); + short randShort = randShrt.shortValue(); + + for (String dnHypAttrName : aaiRes.getStringFields()) { + + if (singleton && ("resource-version").equals(dnHypAttrName)) { + continue; + } + + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, "example-" + dnHypAttrName + "-val-" + randInt); + + } + + for (String dnHypAttrName : aaiRes.getStringListFields()) { + ArrayList<String> exampleList = new ArrayList<String>(); + exampleList.add("example-" + dnHypAttrName + "-val-" + randInt + "-" + 1); + exampleList.add("example-" + dnHypAttrName + "-val-" + randInt + "-" + 2); + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, exampleList); + } + + // the attrName might need to be converted to camel case!!! + for (String dnHypAttrName : aaiRes.getLongFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, randLong); + } + + for (String dnHypAttrName : aaiRes.getIntFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, randInt); + } + + for (String dnHypAttrName : aaiRes.getShortFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, randShort); + } + + for (String dnHypAttrName : aaiRes.getBooleanFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, Boolean.TRUE); + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/Request.java b/aai-core/src/main/java/org/openecomp/aai/util/Request.java new file mode 100644 index 00000000..cc812f0d --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/Request.java @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import javax.ws.rs.core.UriBuilder; + +import org.openecomp.aai.exceptions.AAIException; + +public class Request<T> { + + public static final String V2 = "v2"; + public static final String V3 = "v3"; + public static final String V4 = "v4"; + public static final String V5 = "v5"; + public final String fromAppId; + public final String transactionId; + public final String path; + public final RestObject<T> restObj; + public final boolean oldServer; + public final String apiVersion; + + + /** + * Instantiates a new request. + * + * @param builder the builder + */ + public Request(RequestBuilder<T> builder) { + + fromAppId = builder.fromAppId; + transactionId = builder.transactionId; + restObj = builder.restObj; + oldServer = builder.oldServer; + apiVersion = builder.apiVersion; + + if (!oldServer) { + path = apiVersion + "/" + builder.path; + } else { + path = builder.path; + } + + + } + + public static class RequestBuilder<T> { + private String fromAppId; + private String transactionId; + private String path; + private RestObject<T> restObj; + private boolean oldServer; + private String apiVersion = Request.V4; + + + /** + * Sets the from app id. + * + * @param fromAppId the from app id + * @return the request builder + */ + public RequestBuilder<T> setFromAppId(String fromAppId) { + this.fromAppId = fromAppId; + return this; + } + + /** + * Sets the transaction id. + * + * @param transactionId the transaction id + * @return the request builder + */ + public RequestBuilder<T> setTransactionId(String transactionId) { + this.transactionId = transactionId; + return this; + + } + + /** + * Sets the path. + * + * @param path the path + * @return the request builder + */ + public RequestBuilder<T> setPath(String path) { + + this.path = path; + return this; + + } + + /** + * Sets the restcore obj. + * + * @param restObj the restcore obj + * @return the request builder + */ + public RequestBuilder<T> setRestObj(RestObject<T> restObj) { + this.restObj = restObj; + return this; + + } + + /** + * Sets the old server. + * + * @param oldServer the old server + * @return the request builder + */ + public RequestBuilder<T> setOldServer(boolean oldServer) { + this.oldServer = oldServer; + return this; + + } + + /** + * Sets the api version. + * + * @param apiVersion the api version + * @return the request builder + */ + public RequestBuilder<T> setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + return this; + } + + /** + * Builds the. + * + * @return the request + */ + public Request<T> build() { + return new Request<T>(this); + } + + } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/RestObject.java b/aai-core/src/main/java/org/openecomp/aai/util/RestObject.java new file mode 100644 index 00000000..c8b78d41 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/RestObject.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +public class RestObject<T> { + + /** + * Generic version of the RestObject class. + * @param <T> the type of the value being called for the Rest object interface + */ + // T stands for "Type" + private T t; + + /** + * Sets the. + * + * @param t the t + */ + public void set(T t) { this.t = t; } + + /** + * Gets the. + * + * @return the t + */ + public T get() { return t; } + +} diff --git a/aai-core/src/main/java/org/openecomp/aai/util/RestURLEncoder.java b/aai-core/src/main/java/org/openecomp/aai/util/RestURLEncoder.java new file mode 100644 index 00000000..d75fe27b --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/RestURLEncoder.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.io.UnsupportedEncodingException; +import org.springframework.web.util.UriUtils; + + +public class RestURLEncoder { + + + /** + * Encode URL. + * + * @param nodeKey the node key + * @return the string + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public static final String encodeURL (String nodeKey) throws UnsupportedEncodingException { + return UriUtils.encode(nodeKey, "UTF-8").replaceAll("\\+", "%20"); + } +} + diff --git a/aai-core/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java b/aai-core/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java new file mode 100644 index 00000000..58eb41a4 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java @@ -0,0 +1,264 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.slf4j.MDC; + +import org.openecomp.aai.exceptions.AAIException; +import com.att.eelf.configuration.Configuration; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.thinkaurelius.titan.core.TitanEdge; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanTransaction; +import com.thinkaurelius.titan.core.TitanVertex; + + + +public class UniquePropertyCheck { + + + private static final String FROMAPPID = "AAI-UTILS"; + private static final String TRANSID = UUID.randomUUID().toString(); + private static final String COMPONENT = "UniquePropertyCheck"; + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + + + Properties props = System.getProperties(); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, "uniquePropertyCheck-logback.xml"); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES); + EELFLogger logger = EELFManager.getInstance().getLogger(UniquePropertyCheck.class.getSimpleName()); + MDC.put("logFilenameAppender", UniquePropertyCheck.class.getSimpleName()); + + if( args == null || args.length != 1 ){ + String msg = "usage: UniquePropertyCheck propertyName \n"; + System.out.println(msg); + logAndPrint(logger, msg ); + System.exit(1); + } + String propertyName = args[0]; + TitanTransaction graph = null; + + try { + AAIConfig.init(); + System.out.println(" ---- NOTE --- about to open graph (takes a little while)--------\n"); + TitanGraph tGraph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG); + + if( tGraph == null ) { + logAndPrint(logger, " Error: Could not get TitanGraph "); + System.exit(1); + } + + graph = tGraph.newTransaction(); + if( graph == null ){ + logAndPrint(logger, "could not get graph object in UniquePropertyCheck() \n"); + System.exit(0); + } + } + catch (AAIException e1) { + String msg = "Threw Exception: [" + e1.toString() + "]"; + logAndPrint(logger, msg); + System.exit(0); + } + catch (Exception e2) { + String msg = "Threw Exception: [" + e2.toString() + "]"; + logAndPrint(logger, msg); + System.exit(0); + } + + runTheCheckForUniqueness( TRANSID, FROMAPPID, graph, propertyName, logger ); + System.exit(0); + + }// End main() + + + /** + * Run the check for uniqueness. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param propertyName the property name + * @param logger the logger + * @return the boolean + */ + public static Boolean runTheCheckForUniqueness( String transId, String fromAppId, TitanTransaction graph, + String propertyName, EELFLogger logger ){ + + // Note - property can be found in more than one nodetype + // our uniqueness constraints are always across the entire db - so this + // tool looks across all nodeTypes that the property is found in. + Boolean foundDupesFlag = false; + + HashMap <String,String> valuesAndVidHash = new HashMap <String, String> (); + HashMap <String,String> dupeHash = new HashMap <String, String> (); + + int propCount = 0; + int dupeCount = 0; + Iterable <?> vertItr = graph.query().has(propertyName).vertices(); + Iterator <?> vertItor = vertItr.iterator(); + while( vertItor.hasNext() ){ + propCount++; + TitanVertex v = (TitanVertex)vertItor.next(); + String thisVid = v.id().toString(); + Object val = (v.<Object>property(propertyName)).orElse(null); + if( valuesAndVidHash.containsKey(val) ){ + // We've seen this one before- track it in our dupe hash + dupeCount++; + if( dupeHash.containsKey(val) ){ + // This is not the first one being added to the dupe hash for this value + String updatedDupeList = dupeHash.get(val) + "|" + thisVid; + dupeHash.put(val.toString(), updatedDupeList); + } + else { + // This is the first time we see this value repeating + String firstTwoVids = valuesAndVidHash.get(val) + "|" + thisVid; + dupeHash.put(val.toString(), firstTwoVids); + } + } + else { + valuesAndVidHash.put(val.toString(), thisVid); + } + } + + + String info = "\n Found this property [" + propertyName + "] " + propCount + " times in our db."; + logAndPrint(logger, info); + info = " Found " + dupeCount + " cases of duplicate values for this property.\n\n"; + logAndPrint(logger, info); + + try { + if( ! dupeHash.isEmpty() ){ + Iterator <?> dupeItr = dupeHash.entrySet().iterator(); + while( dupeItr.hasNext() ){ + Map.Entry pair = (Map.Entry) dupeItr.next(); + String dupeValue = pair.getKey().toString();; + String vidsStr = pair.getValue().toString(); + String[] vidArr = vidsStr.split("\\|"); + logAndPrint(logger, "\n\n -------------- Found " + vidArr.length + + " nodes with " + propertyName + " of this value: [" + dupeValue + "]. Node details: "); + + for( int i = 0; i < vidArr.length; i++ ){ + String vidString = vidArr[i]; + Long idLong = Long.valueOf(vidString); + TitanVertex tvx = (TitanVertex)graph.getVertex(idLong); + showPropertiesAndEdges( TRANSID, FROMAPPID, tvx, logger ); + } + } + } + } + catch( Exception e2 ){ + logAndPrint(logger, "Threw Exception: [" + e2.toString() + "]"); + } + finally { + if( graph != null ){ + graph.rollback(); + } + } + + return foundDupesFlag; + + }// end of runTheCheckForUniqueness() + + + /** + * Show properties and edges. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param tVert the t vert + * @param logger the logger + */ + private static void showPropertiesAndEdges( String transId, String fromAppId, TitanVertex tVert, + EELFLogger logger ){ + + if( tVert == null ){ + logAndPrint(logger, "Null node passed to showPropertiesAndEdges."); + } + else { + String nodeType = ""; + Object ob = tVert.<String>property("aai-node-type").orElse(null); + if( ob == null ){ + nodeType = "null"; + } + else{ + nodeType = ob.toString(); + } + + logAndPrint(logger, " AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]"); + logAndPrint(logger, " Property Detail: "); + Iterator<VertexProperty<Object>> pI = tVert.properties(); + while( pI.hasNext() ){ + VertexProperty<Object> tp = pI.next(); + Object val = tp.value(); + logAndPrint(logger, "Prop: [" + tp.key() + "], val = [" + val + "] "); + } + + Iterator <Edge> eI = tVert.edges(Direction.BOTH); + if( ! eI.hasNext() ){ + logAndPrint(logger, "No edges were found for this vertex. "); + } + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + String lab = ed.label(); + TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert); + if( vtx == null ){ + logAndPrint(logger, " >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< "); + } + else { + String nType = vtx.<String>property("aai-node-type").orElse(null); + String vid = vtx.id().toString(); + logAndPrint(logger, "Found an edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid); + } + } + } + } // End of showPropertiesAndEdges() + + + /** + * Log and print. + * + * @param logger the logger + * @param msg the msg + */ + protected static void logAndPrint(EELFLogger logger, String msg) { + System.out.println(msg); + logger.info(msg); + } + +} + + diff --git a/aai-core/src/main/java/org/openecomp/aai/workarounds/LegacyURITransformer.java b/aai-core/src/main/java/org/openecomp/aai/workarounds/LegacyURITransformer.java new file mode 100644 index 00000000..896243cc --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/workarounds/LegacyURITransformer.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.workarounds; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class LegacyURITransformer { + + private final Pattern legacyUriPattern = Pattern.compile("/aai/servers/(?<version>v[23])/(?<tenantKey>.*?)/vservers/(?<vserverKey>[^/]*?$)"); + private final Pattern currentUriPattern = Pattern.compile("/aai/(?<version>v\\d+)/cloud-infrastructure/tenants/tenant/(?<tenantKey>.*?)/vservers/vserver/(?<vserverKey>[^/]*?$)"); + /** + * Instantiates a new legacy URL transformer. + */ + private LegacyURITransformer() { + + } + + private static class Helper { + private static final LegacyURITransformer INSTANCE = new LegacyURITransformer(); + } + + /** + * Gets the single instance of LegacyURLTransformer. + * + * @return single instance of LegacyURLTransformer + */ + public static LegacyURITransformer getInstance() { + return Helper.INSTANCE; + } + + /** + * Gets the legacy URL. + * + * @param url the url + * @return the legacy URL + * @throws URISyntaxException + * @throws MalformedURLException the malformed URL exception + */ + public URI getLegacyURI(URI url) throws URISyntaxException { + String replacement = "/aai/servers/${version}/${tenantKey}/vservers/${vserverKey}"; + String result = url.toString(); + Matcher m = currentUriPattern.matcher(result); + if (m.find()) { + result = m.replaceFirst(replacement); + + } + + return new URI(result); + + } + + /** + * Gets the current URL. + * + * @param url the url + * @return the current URL + * @throws URISyntaxException + * @throws MalformedURLException the malformed URL exception + */ + public URI getCurrentURI(URI url) throws URISyntaxException { + String replacement = "/aai/${version}/cloud-infrastructure/tenants/tenant/${tenantKey}/vservers/vserver/${vserverKey}"; + String result = url.toString(); + Matcher m = legacyUriPattern.matcher(result); + if (m.find()) { + result = m.replaceFirst(replacement); + + } + + return new URI(result); + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/workarounds/NamingExceptions.java b/aai-core/src/main/java/org/openecomp/aai/workarounds/NamingExceptions.java new file mode 100644 index 00000000..ac1d2cc7 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/workarounds/NamingExceptions.java @@ -0,0 +1,79 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.workarounds; + +public class NamingExceptions { + + /** + * Instantiates a new naming exceptions. + */ + private NamingExceptions() { + + } + + private static class Helper { + private static final NamingExceptions INSTANCE = new NamingExceptions(); + } + + /** + * Gets the single instance of NamingExceptions. + * + * @return single instance of NamingExceptions + */ + public static NamingExceptions getInstance() { + return Helper.INSTANCE; + } + + /** + * Gets the object name. + * + * @param name the name + * @return the object name + */ + public String getObjectName(String name) { + + String result = name; + + if (name.equals("cvlan-tag")) { + result = "cvlan-tag-entry"; + } + + return result; + } + + /** + * Gets the DB name. + * + * @param name the name + * @return the DB name + */ + public String getDBName(String name) { + + String result = name; + + if (name.equals("cvlan-tag-entry")) { + result = "cvlan-tag"; + } + + return result; + + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/workarounds/RemoveDME2QueryParams.java b/aai-core/src/main/java/org/openecomp/aai/workarounds/RemoveDME2QueryParams.java new file mode 100644 index 00000000..8713de63 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/workarounds/RemoveDME2QueryParams.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.workarounds; + +import javax.ws.rs.core.MultivaluedMap; + +public class RemoveDME2QueryParams { + + private final String[] blacklist = {"version", "envContext", "routeOffer"}; + + + /** + * Should remove query params. + * + * @param params the params + * @return true, if successful + */ + public boolean shouldRemoveQueryParams(MultivaluedMap<String, String> params) { + boolean remove = true; + + for (String param : blacklist) { + if (!params.containsKey(param)) { + remove = false; + break; + } + } + + return remove; + + } + + /** + * Removes the query params. + * + * @param params the params + */ + public void removeQueryParams(MultivaluedMap<String, String> params) { + + + for (String param : blacklist) { + params.remove(param); + } + + + } + +} |