/*- * ============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 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 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 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 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 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 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 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 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 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.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.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 nodeAltKey1PropsHash = new HashMap(); Collection altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion); if( altKey1Props != null ){ Iterator 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 nodeKeyPropsHash = new HashMap(); Collection keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion); Iterator 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.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.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.property("aai-created-ts").orElse(null); if( tmpOb != null ){ existingCreateTs = (long) tmpOb; } String msg = "UPDATE vertex of type = [" + nodeType + "] "; if( useDepNode ){ String depNType = depNodeVal.property("aai-node-type").orElse(null); HashMap 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 propCol = dbMaps.NodeProps.get(nodeType); Iterator 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 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 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 currentData = new ArrayList (); if( patchOnly ){ // When patching - gotta know what's already in the db Iterator> 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.property("aai-node-type").orElse(null); HashMap 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 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 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 currentData = new ArrayList (); 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 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 keyProps = new ArrayList (); 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 nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); Iterator 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 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 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 altKey1Props = new ArrayList (); 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 nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); Iterator 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 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 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.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.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 kName = new ArrayList(); ArrayList kVal = new ArrayList(); Collection keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion); Iterator 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 altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion); Iterator 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 onlyKeysHash = new HashMap(); Collection onlyKeyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion); Iterator onlyKeyPropsI = onlyKeyProps.iterator(); while( onlyKeyPropsI.hasNext() ){ String keyName = onlyKeyPropsI.next(); onlyKeysHash.put(keyName, keyPropsHash.get(keyName)); } propsAndValuesForMsg = onlyKeysHash.toString() + " combined with a Dependent [" + depNodeVal.property("aai-node-type").orElse(null) + "] node."; ArrayList 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.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 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 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 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 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 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 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 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 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 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 getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType, HashMap 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 returnHash = new HashMap (); Iterator >it = passedHash.entrySet().iterator(); while( it.hasNext() ){ Map.Entry pairs = (Map.Entry)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 getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType, HashMap 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 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 depNodeTypeL = new ArrayList (); if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){ // This is a good-ole nodeType Collection depNTColl = dbMaps.NodeDependencies.get(nodeType); Iterator ntItr = depNTColl.iterator(); while( ntItr.hasNext() ){ depNodeTypeL.add(ntItr.next()); } } else { // The passed-in nodeType must really be a nodeTypeCategory Collection nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); Iterator 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 depNTColl = dbMaps.NodeDependencies.get(nodeType); Iterator 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 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 scopeList = DbEdgeRules.DefaultDeleteScope.get(nodeType); if( scopeList.isEmpty() ){ throw new AAIException("AAI_6121", "No default deleteScope found for nodeType = [" + nodeType + "] "); } else { Iterator 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 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 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 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 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 >it = requestParamHash.entrySet().iterator(); while( it.hasNext() ){ Map.Entry pairs = (Map.Entry)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 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 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 conNodeList = getConnectedNodes( transId, fromAppId, graph, nodeType, propFilterHash, startNodeVal, apiVersion, false ); Iterator conVIter = conNodeList.iterator(); while( conVIter.hasNext() ){ TitanVertex connectedVert = conVIter.next(); boolean isFirstOne = true; Iterator 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.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 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 * @throws AAIException the AAI exception */ @Deprecated public static ArrayList getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, HashMap 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 * @throws AAIException the AAI exception */ @Deprecated public static ArrayList getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, HashMap 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 returnVertList = new ArrayList(); 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 kName = new ArrayList(); ArrayList kVal = new ArrayList(); int i = -1; Collection 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 getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, HashMap 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 * @throws AAIException the AAI exception */ public static ArrayList 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 childList = new ArrayList (); Boolean doNodeTypeCheck = false; if( limitToThisNodeType != null && ! limitToThisNodeType.equals("") ){ doNodeTypeCheck = true; } List 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.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 * @throws AAIException the AAI exception */ public static ArrayList getConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType, HashMap 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.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 excludeVidList = new 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.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 returnVertList = new ArrayList(); Iterable qResult = null; Iterator 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.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.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 getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType, HashMap 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 getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType, HashMap 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 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 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 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.property("aai-node-type").orElse(null); String inV_NType = inV.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 nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, outV); ArrayList resultList = new ArrayList(); 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 nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, inV); ArrayList resultList = new ArrayList(); 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 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.property("aai-node-type").orElse(null); String targetNodeType = toVtx.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 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.property("aai-node-type").orElse(null); String targetNodeType = targetVert.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 edRuleColl = DbEdgeRules.EdgeRules.get(fwdRuleKey); Iterator 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 edRuleColl = DbEdgeRules.EdgeRules.get(revRuleKey); Iterator 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 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 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 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 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 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 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.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 nodeKeyPropsHash = new HashMap(); Collection keyProps = dbMaps.NodeKeyProps.get(nType); Iterator keyPropI = keyProps.iterator(); while( keyPropI.hasNext() ){ String propName = keyPropI.next(); Object value = (Object) vtx.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 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.property("aai-node-type").orElse(null); HashMap nodeNamePropsHash = new HashMap(); Collection keyProps = DbMeth.getNodeNameProps(transId, fromAppId, nType, apiVersion); Iterator keyPropI = keyProps.iterator(); while( keyPropI.hasNext() ){ String propName = keyPropI.next(); Object value = (Object) vtx.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 ); } /** *
	 *  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!
	 *  
. * * @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.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.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 eI = thisVtx.edges(Direction.IN); boolean onlyHasParent = false; Edge temp = null; if( eI != null && eI.hasNext() ){ temp = eI.next(); Boolean isParent = temp.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 eI = thisVtx.edges(Direction.BOTH); while( eI.hasNext() ){ TitanEdge ed = (TitanEdge) eI.next(); TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx); String nodeTypeA = otherVtx.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 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 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.property("isParent").orElse(null); if( otherVtxAChild == null ){ otherVtxAChild = false; } Boolean otherVtxADeleteTarget = ed.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.property("aai-node-type").orElse(null); String resVers = otherVtx.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 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 edges = graph.edges(Direction.BOTH); graph.tx().commit(); Edge edge = null; while (edges.hasNext()) { edge = edges.next(); edges.remove(); } graph.tx().commit(); Iterator 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 showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){ ArrayList retArr = new ArrayList (); Iterator 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.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.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 showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){ ArrayList retArr = new ArrayList (); if( tVert == null ){ retArr.add("null Node object passed to showPropertiesForNode()\n"); } else { String nodeType = ""; //String datType = ""; Object ob = tVert.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> pI = tVert.properties(); while( pI.hasNext() ){ VertexProperty 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 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 nameProps = new ArrayList (); 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 nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType); Iterator 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 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 retEdgePropPutMap = new HashMap (); 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 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 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 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.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.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.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 propHashWithKeys = new HashMap(); Collection 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 keyPropI = keyProps.iterator(); while( keyPropI.hasNext() ){ String propName = keyPropI.next(); String propVal = ""; Object ob = v.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 vertList2 = getNodes( transId, fromAppId, graph, nType, propHashWithKeys, false, version, true ); Iterator 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; } }