2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.aai.dbgen;
23 import java.net.Inet4Address;
24 import java.net.Inet6Address;
25 import java.net.InetAddress;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
34 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
35 import org.apache.tinkerpop.gremlin.structure.Direction;
36 import org.apache.tinkerpop.gremlin.structure.Edge;
37 import org.apache.tinkerpop.gremlin.structure.Vertex;
38 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
40 import org.openecomp.aai.dbmodel.DbEdgeRules;
41 import org.openecomp.aai.exceptions.AAIException;
42 import org.openecomp.aai.ingestModel.DbMaps;
43 import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
44 import org.openecomp.aai.serialization.db.EdgeRule;
45 import org.openecomp.aai.serialization.db.EdgeRules;
46 import org.openecomp.aai.util.AAIConfig;
47 import org.openecomp.aai.util.AAIConstants;
48 import com.att.eelf.configuration.EELFLogger;
49 import com.att.eelf.configuration.EELFManager;
50 import com.google.common.net.InetAddresses;
51 import com.thinkaurelius.titan.core.TitanEdge;
52 import com.thinkaurelius.titan.core.TitanGraph;
53 import com.thinkaurelius.titan.core.TitanTransaction;
54 import com.thinkaurelius.titan.core.TitanVertex;
58 * General Database-level Utility class. These methods deal with the database one dataNode / Edge at a time.
59 * Transactions are managed at a higher level by the calling classes by passing in a TitanTransaction object.
63 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DbMeth.class);
68 * @param transId the trans id
69 * @param fromAppId the from app id
70 * @param graph the graph
71 * @param nodeType the node type
72 * @param propHash the prop hash
73 * @param depNodeVal the dep node val
74 * @param apiVersion the api version
76 * @throws AAIException the AAI exception
78 public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
79 HashMap <String,Object> propHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{
80 // If they're calling patchAaiNode, then we only want to add/update the properties that they
81 // pass us in the propHash. If there are others already in the DB, we leave them alone.
83 // Note: to be really official, we'd throw an error if the node wasn't already in the db.
84 boolean[] objectExists = new boolean[1];
85 objectExists[0] = true;
86 Boolean patchOnly = true;
87 TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists);
90 } // end of patchAaiNode()
95 * @param transId the trans id
96 * @param fromAppId the from app id
97 * @param graph the graph
98 * @param nodeType the node type
99 * @param propHash the prop hash
100 * @param depNodeVal the dep node val
101 * @return the titan vertex
102 * @throws AAIException the AAI exception
105 public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
106 HashMap <String,Object> propHash, TitanVertex depNodeVal) throws AAIException{
107 return patchAaiNode( transId, fromAppId, graph, nodeType,
108 propHash, depNodeVal, null );
114 * @param transId the trans id
115 * @param fromAppId the from app id
116 * @param graph the graph
117 * @param nodeType the node type
118 * @param propHash the prop hash
119 * @param depNodeVal the dep node val
120 * @param patchOnly the patch only
121 * @param apiVersion the api version
122 * @return the titan vertex
123 * @throws AAIException the AAI exception
125 public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
126 HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly, String apiVersion) throws AAIException{
127 boolean[] objectExists = new boolean[1];
128 objectExists[0] = false;
129 return persistAaiNodeBASE( transId, fromAppId, graph, nodeType,
130 propHash, depNodeVal, patchOnly, apiVersion, objectExists);
136 * @param transId the trans id
137 * @param fromAppId the from app id
138 * @param graph the graph
139 * @param nodeType the node type
140 * @param propHash the prop hash
141 * @param addIfNotFound the add if not found
142 * @param depNodeVal the dep node val
143 * @param apiVersion the api version
144 * @return the titan vertex
145 * @throws AAIException the AAI exception
148 public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
149 HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion) throws AAIException{
150 // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
151 // there is already a record in the DB, but they do not pass some of the existing properties, they should
152 // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
153 Boolean patchOnly = false;
154 boolean[] objectExists = new boolean[1];
155 objectExists[0] = false;
156 TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists);
163 * @param transId the trans id
164 * @param fromAppId the from app id
165 * @param graph the graph
166 * @param nodeType the node type
167 * @param propHash the prop hash
168 * @param addIfNotFound the add if not found
169 * @param depNodeVal the dep node val
170 * @return the titan vertex
171 * @throws AAIException the AAI exception
174 public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
175 HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal) throws AAIException{
176 // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
177 // there is already a record in the DB, but they do not pass some of the existing properties, they should
178 // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
179 Boolean patchOnly = false;
180 boolean[] objectExists = new boolean[1];
181 objectExists[0] = false;
182 TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, null, objectExists);
184 } // end of persistAaiNode()
189 * @param transId the trans id
190 * @param fromAppId the from app id
191 * @param graph the graph
192 * @param nodeType the node type
193 * @param propHash the prop hash
194 * @param addIfNotFound the add if not found
195 * @param depNodeVal the dep node val
196 * @param apiVersion the api version
197 * @param objectExists the object exists
198 * @return TitanVertex
199 * @throws AAIException the AAI exception
201 public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
202 HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists) throws AAIException{
203 Boolean patchOnly = false;
204 // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
205 // there is already a record in the DB, but they do not pass some of the existing properties, they should
206 // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
207 TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null);
214 * @param transId the trans id
215 * @param fromAppId the from app id
216 * @param graph the graph
217 * @param nodeType the node type
218 * @param propHash the prop hash
219 * @param addIfNotFound the add if not found
220 * @param depNodeVal the dep node val
221 * @param apiVersion the api version
222 * @param objectExists the object exists
223 * @param thisNodeVertex the this node vertex
224 * @return the titan vertex
225 * @throws AAIException the AAI exception
227 public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
228 HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{
229 Boolean patchOnly = false;
230 // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
231 // there is already a record in the DB, but they do not pass some of the existing properties, they should
232 // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
233 TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, thisNodeVertex);
238 * Persist aai node BASE.
240 * @param transId the trans id
241 * @param fromAppId the from app id
242 * @param graph the graph
243 * @param nodeType the node type
244 * @param propHash the prop hash
245 * @param depNodeVal the dep node val
246 * @param patchOnly the patch only
247 * @param apiVersion the api version
248 * @param objectExists the object exists
249 * @return the titan vertex
250 * @throws AAIException the AAI exception
252 public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType,
253 HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly,
254 String apiVersion, boolean[] objectExists) throws AAIException{
255 return persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null);
259 * Persist aai node BASE.
261 * @param transId the trans id
262 * @param fromAppId the from app id
263 * @param graph the graph
264 * @param nodeType the node type
265 * @param propHash the prop hash
266 * @param depNodeVal the dep node val
267 * @param patchOnly the patch only
268 * @param apiVersion the api version
269 * @param objectExists the object exists
270 * @param thisNodeVertex the this node vertex
271 * @return the titan vertex
272 * @throws AAIException the AAI exception
274 public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType,
275 HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly,
276 String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{
279 throw new AAIException("AAI_6101", "null graph object passed to persistAaiNodeBASE()");
282 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
284 boolean useDepNode = false;
285 String resourceVersion = null;
286 if( propHash.containsKey("resource-version") ){
287 resourceVersion = (String)(propHash.get("resource-version"));
289 String aaiUniqueKeyVal = null;
290 if( propHash.containsKey("aai-unique-key") ){
291 // Note -- we are assuming that nobody is monkeying with this. The 16-07 first-pass theory
292 // is that the REST layer is always gonna generate this or pass it through.
293 aaiUniqueKeyVal = (String)(propHash.get("aai-unique-key"));
294 propHash.remove("aai-unique-key");
297 if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){
298 // This kind of node needs a dependent node (for uniqueness)
299 if( depNodeVal == null ){
300 // They should have passed in the node that this one depends on
301 throw new AAIException("AAI_6109", "null dependentNode object passed to persistAaiNodeBASE() but " + nodeType + " requires one.");
303 else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){
304 // They should have passed in the right type of node as the dependent node
305 throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to persistAaiNodeBASE() for nodeType" + nodeType + ".");
313 // Note: as of 1607, we no longer validate property names since that's covered by the REST layer.
314 // Same goes for required fields (as of 1602)
316 // Special ip-address validation for ipAddr nodes only... This will go away when we go to YANG and
317 // do validations like this up at that layer.
318 if( nodeType.equals("ipaddress") ){
319 // Note - this will throw an exception if the ipAddress is using a bad format
320 ipAddressFormatOK( transId, fromAppId, (String)propHash.get("addr"), (String)propHash.get("version") );
323 // Use the key-fields/dependentNode to check if this is an add or an update
324 // We assume that all NodeTypes at least one key-property defined. A dependentNode is optional.
325 if( ! dbMaps.NodeKeyProps.containsKey(nodeType) ){
326 // Problem if no key Properties defined for this nodeType
327 String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
328 throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nodeType + " (ver=" + defVer + ")");
331 Boolean hasAltKey1 = false;
332 HashMap <String,Object>nodeAltKey1PropsHash = new HashMap<String,Object>();
333 Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion);
334 if( altKey1Props != null ){
335 Iterator <String> altKey1PropI = altKey1Props.iterator();
336 while( altKey1PropI.hasNext() ){
337 String propName = altKey1PropI.next();
338 // NOTE: alt-keys are not always required fields. If it is null or blank, we won't
339 // do alt-key checks on it.
340 Object value = propHash.get(propName);
341 if( value != null && !value.toString().equals("") ){
343 nodeAltKey1PropsHash.put(propName, value);
347 HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>();
348 Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
349 Iterator <String> keyPropI = keyProps.iterator();
350 while( keyPropI.hasNext() ){
351 String propName = keyPropI.next();
353 Object value = propHash.get(propName);
354 nodeKeyPropsHash.put(propName, value);
357 // Check if this node is already in the database based on the Primary Key Info
358 TitanVertex existingVert = thisNodeVertex;
359 boolean foundTheNodeInDb = true;
361 if (existingVert == null) {
363 existingVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeKeyPropsHash, depNodeVal, apiVersion );
365 catch (AAIException e) {
366 if (e.getErrorObject().getErrorCode().equals("6114")) {
367 foundTheNodeInDb = false;
375 // this is so the notification knows whether or not the operation was an UPDATE or a CREATe
376 objectExists[0] = foundTheNodeInDb;
377 if( foundTheNodeInDb ){
378 // A record was found in the DB using the PK.
379 if( needToDoResourceVerCheck(apiVersion, patchOnly) ){
380 // Need to check that they knew what they were updating
381 String existingResVer = existingVert.<String>property("resource-version").orElse(null);
382 if( resourceVersion == null || resourceVersion.equals("") ){
383 throw new AAIException("AAI_6130", "Resource-version not passed for update of = " + nodeType + ", " + nodeKeyPropsHash.toString());
385 else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){
386 throw new AAIException("AAI_6131", "Resource-version " + resourceVersion + " MISMATCH WITH EXISTING " + existingResVer + " for update of = " + nodeType + ", " + nodeKeyPropsHash.toString());
390 // Need to ensure that the Alternate key isn't changing to a value that points to a different existing node.
391 // It is ok if it points to nothing -- that would just be an update for this node. It's also ok if
392 // it points to this (existing) node - that just means that it wasn't being updated.
395 TitanVertex chkVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion );
396 if( ! chkVert.id().toString().equals(existingVert.id().toString()) ){
397 throw new AAIException("AAI_6117", "In-Use AlternateKey value passed for update of nodeType = " + nodeType);
400 catch (AAIException e) {
401 if(! e.getErrorObject().getErrorCode().equals("6114") ){
408 // Note not in the DB -- This will be an ADD of a new node
409 // a) make sure they didn't say they were just doing "patchOnly" which cannot be an ADD.
410 // b) if there is an alternate key, we need to make sure the AK isn't already in use by somebody else.
414 depMsg = " plus dependent node. ";
416 throw new AAIException("AAI_6114", "Patch Request, but no Node of type " + nodeType + " found for properties: [" + propHash + "] " + depMsg);
419 if( needToDoResourceVerCheck(apiVersion, patchOnly) && (resourceVersion != null) && !resourceVersion.equals("") ){
420 throw new AAIException("AAI_6131", "Resource-version was passed in, but this is an ADD of a " + nodeType + ", with these params: " + nodeKeyPropsHash.toString());
424 getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion );
425 // Since the Primary Key for this nodeType wasn't found in the DB yet, the fact that
426 // we are able to find a record (no "6114" exception thrown) using the Alternate-Key is an error.
427 // We can't create a new node that uses an AK that's already in use.
428 throw new AAIException("AAI_6117", "Conflicting Key and Alternate-Key values passed for add of nodeType = " + nodeType);
430 catch (AAIException e) {
431 if(! e.getErrorObject().getErrorCode().equals("6114") ){
438 // ------------- Done with checking. Do the add or update to the dB -----------------------
440 if( foundTheNodeInDb ){
441 long unixTimeNow = System.currentTimeMillis() / 1000L;
442 // ----- This is an UPDATE ------
445 String existingSourceOfTruth = fromAppId; // default value if we can't get the old one
446 Object tmpOb = existingVert.<Object>property("source-of-truth").orElse(null);
448 existingSourceOfTruth = tmpOb.toString();
450 long existingCreateTs = unixTimeNow; // default value if we can't get the old one
451 tmpOb = existingVert.<Object>property("aai-created-ts").orElse(null);
453 existingCreateTs = (long) tmpOb;
456 String msg = "UPDATE vertex of type = [" + nodeType + "] ";
458 String depNType = depNodeVal.<String>property("aai-node-type").orElse(null);
459 HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal);
460 LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash +
461 "] which rides on dependent node: type = " + depNType + ", with key(s) = [" + depNodePropKeysHash + "].");
464 LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash + "] (no dep. node).");
466 String removeList = "";
468 // They are updating an existing record, and they want us to "process all defined properties" (not just patch)
469 // So we will see if the node has any properties that were not passed-in. Those need to be removed.
470 Collection <String> propCol = dbMaps.NodeProps.get(nodeType);
471 Iterator <String> propIter = propCol.iterator();
472 while( propIter.hasNext() ){
473 String propName = propIter.next();
474 if( ! propHash.containsKey(propName) && !DbEdgeRules.ReservedPropNames.containsKey(propName)){
475 if( thisPropertyWasPutByNewerVersionOfCode(apiVersion, nodeType, propName) ){
476 // we must be using an older version of code here - but the property that
477 // has not been passed in this persist call is one that this older version of
478 // the database did not know about. So leave it alone.
481 removeList = removeList + "," + propName;
482 existingVert.property(propName).remove();
487 if( !removeList.equals("") ){
488 LOGGER.info("Removed these props on update: [" + removeList + "]");
490 for( Map.Entry<String, Object> entry : propHash.entrySet() ){
491 // update the parameters that have been passed in (except the key-properties)
492 // taking away the key-property check. We will now allow this since
493 // the keys were used to identify this node, so they should be good and
494 // there are times when Titan resolves conflicts by only using the
495 // data set in an update - and was losing our key info...
496 // Similar to the change noted below.
497 //if( ! nodeKeyPropsHash.containsKey(entry.getKey()) ){
498 // existingVert.setProperty( entry.getKey(), entry.getValue() );
500 if( ! entry.getKey().equals("resource-version") ){
501 boolean nonSingleCardinality = false;
502 boolean setSoNoDupes = false;
503 if( checkPropCardinality(entry.getKey(), "Set") ){
504 nonSingleCardinality = true;
507 else if( checkPropCardinality(entry.getKey(), "List") ){
508 nonSingleCardinality = true;
511 Iterator <Object> valIter = null;
512 if( nonSingleCardinality ){
513 String className = entry.getValue().getClass().getSimpleName();
514 if( className.equals("ArrayList") ){
515 valIter = ((ArrayList)(entry.getValue())).iterator();
517 else if( className.equals("List") ){
518 valIter = ((List)(entry.getValue())).iterator();
520 else if( className.equals("Set") ){
521 valIter = ((Set)(entry.getValue())).iterator();
525 if( nonSingleCardinality ){
526 // This property has Cardinality of List or Set - which need to be handled carefully
527 // Note -- for Lists or Sets, we assume they are of dataType String - that is all
528 // the Rest layer supports at the moment (16-02)
529 ArrayList <String> currentData = new ArrayList <String> ();
531 // When patching - gotta know what's already in the db
532 Iterator<VertexProperty<Object>> existingPropsIter = (existingVert.properties(entry.getKey()));
533 if( existingPropsIter != null ){
534 while( existingPropsIter.hasNext() ){
535 String existingVal = existingPropsIter.next().value().toString();
536 currentData.add( existingVal );
541 // Since this is not a patch-update, we first have to clear out what is currently in the db.
542 existingVert.property(entry.getKey()).remove();
545 if( valIter != null ){
546 while( valIter.hasNext() ){
547 Object thisVal = valIter.next();
549 // For Sets, we need to check that the data isn't already in the db or wasn't passed
550 // in to us twice in the propHash. Otherwise Titan throws an exception (instead of just ignoring it...)
551 if( !currentData.contains(thisVal) ){
552 // We don't have this data yet, so add it to the Set
553 existingVert.property( entry.getKey(), thisVal );
554 currentData.add( thisVal.toString() );
558 // For List data types, it's ok to have duplicate values in the db (why would we want this?)
559 existingVert.property( entry.getKey(), thisVal );
565 // This is a normal, "Cardinality = SINGLE" kind of property
566 // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below.
567 //Object cleanVal = convertTypeIfNeeded( entry.getKey(), entry.getValue() );
568 //existingVert.setProperty( entry.getKey(), cleanVal );
569 // ********************************
570 existingVert.property( entry.getKey(), entry.getValue() );
575 // DEBUG - trying to deal with the case where simultaneous PUTs
576 // cause our db to wind up with a vertex that does not have these three properties filled in.
577 existingVert.property( "aai-node-type", nodeType );
578 existingVert.property( "aai-created-ts", existingCreateTs );
579 existingVert.property( "source-of-truth", existingSourceOfTruth );
581 if( aaiUniqueKeyVal != null ){
582 existingVert.property( "aai-unique-key", aaiUniqueKeyVal );
585 existingVert.property( "aai-last-mod-ts", unixTimeNow );
586 String resVers = "" + unixTimeNow;
587 existingVert.property( "resource-version", resVers );
588 existingVert.property( "last-mod-source-of-truth", fromAppId );
590 LOGGER.info(msg + ", [aai-last-mod-ts]/[" + unixTimeNow + "]");
592 return( existingVert );
595 // ----- Not found in the DB, This must be an ADD ------
596 if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
597 throw new AAIException("AAI_6120", "nodeTypeCategory " + nodeType + " cannot be used to ADD a node. Need to pass a valid nodeType");
600 TitanVertex tiVnew = graph.addVertex( nodeType );
602 String msg = "ADD vertex of type = [" + nodeType + "] ";
603 if( depNodeVal != null ){
604 String depNType = depNodeVal.<String>property("aai-node-type").orElse(null);
605 HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal);
606 msg = msg + " onto dependent node: type = " + depNType + ", which has key(s) = [" + depNodePropKeysHash +
607 "]. New Node Prop/values = ";
610 msg = msg + " Note: no dependent node. New Node Prop/values = ";
612 boolean first = true;
613 for( Map.Entry<String, Object> entry : propHash.entrySet() ){
614 if( ! entry.getKey().equals("resource-version") ){
616 msg = msg + " [" + entry.getKey() + "]/[" + entry.getValue() + "]";
620 msg = msg + ", [" + entry.getKey() + "]/[" + entry.getValue() + "]";
623 boolean nonSingleCardinality = false;
624 boolean setSoNoDupes = false;
625 if( checkPropCardinality(entry.getKey(), "Set") ){
626 nonSingleCardinality = true;
629 else if( checkPropCardinality(entry.getKey(), "List") ){
630 nonSingleCardinality = true;
633 Iterator <Object> valIter = null;
634 if( nonSingleCardinality ){
635 String className = entry.getValue().getClass().getSimpleName();
636 if( className.equals("ArrayList") ){
637 valIter = ((ArrayList)(entry.getValue())).iterator();
639 else if( className.equals("List") ){
640 valIter = ((List)(entry.getValue())).iterator();
642 else if( className.equals("Set") ){
643 valIter = ((Set)(entry.getValue())).iterator();
647 if( nonSingleCardinality ){
648 // This property has Cardinality of List or Set - which need to be handled carefully
649 ArrayList <String> currentData = new ArrayList <String> ();
650 if( valIter != null ){
651 while( valIter.hasNext() ){
652 Object thisVal = valIter.next();
654 // For Sets, we need to check that they're not passing us duplicate data in propHash.
655 // Otherwise Titan throws an exception (instead of just ignoring it...)
656 if( !currentData.contains(thisVal) ){
657 // We don't have this data yet, so add it to the Set
658 tiVnew.property( entry.getKey(), thisVal );
659 currentData.add( thisVal.toString() );
663 // For List data types, it's ok to have duplicate values in the db (why would we want this?)
664 tiVnew.property( entry.getKey(), thisVal );
670 // This is a normal, "Cardinality = SINGLE" kind of property
671 // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below.
672 tiVnew.property( entry.getKey(), entry.getValue() );
677 tiVnew.property( "aai-node-type", nodeType );
678 //long unixTime = System.currentTimeMillis() / 1000L;
679 long unixTime = System.currentTimeMillis();
680 tiVnew.property( "aai-created-ts", unixTime );
681 tiVnew.property( "aai-last-mod-ts", unixTime );
682 String resVers = "" + unixTime;
683 tiVnew.property( "resource-version", resVers );
684 tiVnew.property( "source-of-truth", fromAppId );
685 tiVnew.property( "last-mod-source-of-truth", fromAppId );
686 if( aaiUniqueKeyVal != null ){
687 tiVnew.property( "aai-unique-key", aaiUniqueKeyVal );
690 LOGGER.info(msg + ", [aai-created-ts]/[" + unixTime + "]");
694 } // end of persistAaiNodeBASE()
698 * Need to do resource ver check.
700 * @param apiVersion the api version
701 * @param patchOnlyFlag the patch only flag
702 * @return the boolean
703 * @throws AAIException the AAI exception
705 public static Boolean needToDoResourceVerCheck(String apiVersion, Boolean patchOnlyFlag)
709 // we do not do resource checking for patch requests.
713 String resourceCheckOnFlag = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
715 int apiVerInt = cleanUpApiVersion(apiVersion);
717 if( (resourceCheckOnFlag != null) && resourceCheckOnFlag.equals("true") ){
718 // Only do the check if the resource enable flag is set to "true"
720 // We're only doing the resource version checks for v5 and later
726 }// End needToDoResourceVerCheck()
730 * Clean up api version.
732 * @param apiVersionString the api version string
734 * @throws AAIException the AAI exception
736 private static int cleanUpApiVersion( String apiVersionString ) throws AAIException {
737 // Note: we expect an apiVersion to start with the letter "v", followed by an integer.
740 String verStr = apiVersionString;
741 if( (apiVersionString == null) || (apiVersionString.length() < 2) ){
742 // Passed in version doesn't look right
743 verStr = org.openecomp.aai.util.AAIApiVersion.get();
745 versionInt = getVerNumFromVerString( verStr );
751 * Gets the ver num from ver string.
753 * @param versionString the version string
754 * @return the ver num from ver string
755 * @throws AAIException the AAI exception
757 private static int getVerNumFromVerString( String versionString )throws AAIException {
759 if( versionString == null || versionString.length() < 2 ){
760 throw new AAIException("AAI_6121", " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "].");
763 int strLen = versionString.length();
764 // We assume that a version looks like "v" followed by an integer
765 if( ! versionString.substring(0,1).equals("v") ){
766 String detail = " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "].";
767 throw new AAIException("AAI_6121", detail);
770 String intPart = versionString.substring(1,strLen);
772 versionInt = Integer.parseInt( intPart );
774 catch( Exception e ){
775 String detail = " Bad Version passed to getVerNumFromVerString: [" + versionString + "].";
776 throw new AAIException("AAI_6121", detail);
784 * Gets the node key prop names.
786 * @param transId the trans id
787 * @param fromAppId the from app id
788 * @param nodeType the node type
789 * @param apiVersion the api version
790 * @return HashMap of keyProperties
791 * @throws AAIException the AAI exception
793 public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
795 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
797 Collection <String> keyProps = new ArrayList <String>();
798 if( dbMaps.NodeKeyProps.containsKey(nodeType) ){
799 keyProps = dbMaps.NodeKeyProps.get(nodeType);
801 else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
802 // The passed-in nodeType was really a nodeCategory, so we need to look up the key params
803 Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
804 Iterator <String> catItr = nTypeCatCol.iterator();
806 if( catItr.hasNext() ){
807 // For now, we only look for one.
808 catInfo = catItr.next();
811 String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
812 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")");
815 String [] flds = catInfo.split(",");
816 if( flds.length != 4 ){
817 throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data for nodeType = [" + nodeType + "].");
820 String keyPropsString = flds[0];
821 String [] propNames = keyPropsString.split("\\|");
822 for( int i = 0; i < propNames.length; i++ ){
823 keyProps.add(propNames[i]);
827 String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
828 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")");
833 }// end of getNodeKeyPropNames
836 * Gets the node key prop names.
838 * @param transId the trans id
839 * @param fromAppId the from app id
840 * @param nodeType the node type
841 * @return the node key prop names
842 * @throws AAIException the AAI exception
845 public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType ) throws AAIException{
846 return getNodeKeyPropNames( transId, fromAppId, nodeType, null);
850 * Gets the node alt key 1 prop names.
852 * @param transId the trans id
853 * @param fromAppId the from app id
854 * @param nodeType the node type
855 * @param apiVersion the api version
856 * @return HashMap of keyProperties
857 * @throws AAIException the AAI exception
859 public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
861 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
863 Collection <String> altKey1Props = new ArrayList <String>();
864 if( dbMaps.NodeAltKey1Props.containsKey(nodeType) ){
865 altKey1Props = dbMaps.NodeAltKey1Props.get(nodeType);
867 else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
868 // The passed-in nodeType was really a nodeCategory, so we need to look up the key params
869 Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
870 Iterator <String> catItr = nTypeCatCol.iterator();
872 if( catItr.hasNext() ){
873 catInfo = catItr.next();
874 String [] flds = catInfo.split(",");
875 if( flds.length != 4 ){
876 throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
879 String altKeyPropsString = flds[1];
880 String [] propNames = altKeyPropsString.split("\\|");
881 for( int i = 0; i < propNames.length; i++ ){
882 altKey1Props.add(propNames[i]);
889 }// end of getNodeAltKey1PropNames
892 * Gets the node alt key 1 prop names.
894 * @param transId the trans id
895 * @param fromAppId the from app id
896 * @param nodeType the node type
897 * @return the node alt key 1 prop names
898 * @throws AAIException the AAI exception
901 public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType ) throws AAIException{
902 return getNodeAltKey1PropNames( transId, fromAppId, nodeType, null);
907 * Gets the unique node.
909 * @param transId the trans id
910 * @param fromAppId the from app id
911 * @param graph the graph
912 * @param nodeType the node type
913 * @param keyPropsHash the key props hash
914 * @param depNodeVal the dep node val
915 * @param apiVersion the api version
916 * @return TitanVertex
917 * @throws AAIException the AAI exception
920 public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType,
921 HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{
923 // NOTE - this is really for use by the PersistNode method -- it is looking to see if
924 // a node exists in the database given either Primary or Alternate Key data and dependent
925 // node data (if required for uniqueness).
927 // Note - the passed in nodeType could really be a nodeTypeCategory ---
928 Boolean nodeTypeIsCategory = DbEdgeRules.NodeTypeCategory.containsKey(nodeType);
930 Boolean useDepNode = false;
931 if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){
932 // This kind of node depends on another node for uniqueness
933 if( depNodeVal == null ){
934 // They should have passed in the node that this one depends on
935 throw new AAIException("AAI_6109", "null dependentNode object passed to getUniqueNode() but " + nodeType + " requires one.");
937 else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){
938 // They should have passed in the right type of node as the dependent node
939 throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to getUniqueNode() for nodeType" + nodeType + ".\n");
947 // We assume that all NodeTypes have at least one key-property defined. A dependentNode is optional.
948 // Note - instead of key-properties (the primary key properties), a user could pass
949 // alternate-key values if they are defined for the nodeType.
950 ArrayList<String> kName = new ArrayList<String>();
951 ArrayList<Object> kVal = new ArrayList<Object>();
953 Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
954 Iterator <String> keyPropI = keyProps.iterator();
955 Boolean haveSomePrimKeyProps = false;
956 Boolean primaryKeyComplete = true;
957 while( keyPropI.hasNext() ){
958 haveSomePrimKeyProps = true;
960 String propName = keyPropI.next();
961 if( ! keyPropsHash.containsKey(propName) ){
962 primaryKeyComplete = false;
965 Object valObj = keyPropsHash.get(propName);
966 if( valObj == null ){
967 primaryKeyComplete = false;
970 String value = valObj.toString();
971 if( value == null || value.equals("") ){
972 // They passed the property name, but no value
973 primaryKeyComplete = false;
980 if( haveSomePrimKeyProps && primaryKeyComplete ){
981 keyPropI = keyProps.iterator();
982 while( keyPropI.hasNext() ){
983 String propName = keyPropI.next();
984 String value = (keyPropsHash.get(propName)).toString();
986 kName.add(i, propName);
987 kVal.add(i, (Object)value);
991 // See if they're using the alternate key
992 Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion);
993 Iterator <String> altKey1PropI = altKey1Props.iterator();
994 Boolean haveSomeAltKey1Props = false;
995 Boolean altKey1Complete = true;
996 while( altKey1PropI.hasNext() ){
997 haveSomeAltKey1Props = true;
998 String propName = altKey1PropI.next();
999 if( ! keyPropsHash.containsKey(propName) ){
1000 altKey1Complete = false;
1003 Object valObj = keyPropsHash.get(propName);
1004 if( valObj == null ){
1005 altKey1Complete = false;
1008 String value = valObj.toString();
1009 if( value == null || value.equals("") ){
1010 // They passed the property name, but no value
1011 altKey1Complete = false;
1016 if( haveSomeAltKey1Props && altKey1Complete ){
1017 altKey1PropI = altKey1Props.iterator();
1018 while( altKey1PropI.hasNext() ){
1019 String propName = altKey1PropI.next();
1020 String value = (keyPropsHash.get(propName)).toString();
1022 kName.add(i, propName);
1023 kVal.add(i, (Object)value);
1028 int topPropIndex = i;
1029 TitanVertex tiV = null;
1030 String propsAndValuesForMsg = "";
1032 // There is no node that this type of node depends on, so we can look for it based
1033 // solely on the Aai-defined key fields.
1034 Iterable <?> verts = null;
1036 if( topPropIndex == -1 ){
1037 // Problem if no key Properties defined for this nodeType
1038 String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
1039 throw new AAIException("AAI_6105", "Bad or Incomplete Key Property params: (" + keyPropsHash.toString() +
1040 ") for nodeType: " + nodeType + " (ver=" + defVer + ")");
1042 else if( topPropIndex == 0 ){
1043 if (nodeTypeIsCategory) // dont know real type
1044 verts= graph.query().has(kName.get(0),kVal.get(0)).vertices();
1045 else // need this to find dvs switch: dvs.switch-name and port-group.switch-name issue
1046 verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
1047 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
1049 else if( topPropIndex == 1 ){
1050 verts = graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).vertices();
1051 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
1052 + kName.get(1) + " = " + kVal.get(1) + ") ";
1054 else if( topPropIndex == 2 ){
1055 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();
1056 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
1057 + kName.get(1) + " = " + kVal.get(1) + ", "
1058 + kName.get(2) + " = " + kVal.get(2) + ") ";
1060 else if( topPropIndex == 3 ){
1061 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();
1062 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
1063 + kName.get(1) + " = " + kVal.get(1) + ", "
1064 + kName.get(2) + " = " + kVal.get(2) + ", "
1065 + kName.get(3) + " = " + kVal.get(3) + ") ";
1068 String emsg = " We only support 4 keys per nodeType for now \n";
1069 throw new AAIException("AAI_6114", emsg);
1072 Iterator <?> vertI = verts.iterator();
1073 if( vertI != null && vertI.hasNext()) {
1074 // We found a vertex that meets the input criteria.
1075 tiV = (TitanVertex) vertI.next();
1077 if( vertI.hasNext() ){
1078 // Since this routine is looking for a unique node for the given input values, if
1079 // more than one is found - it's a problem.
1080 throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg);
1084 // No Vertex was found for this key - throw a not-found exception
1085 throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg);
1089 // Need to use the dependent vertex to look for this one.
1090 // filter this to the actual keys because
1091 HashMap<String,Object> onlyKeysHash = new HashMap<String,Object>();
1093 Collection <String> onlyKeyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
1095 Iterator <String> onlyKeyPropsI = onlyKeyProps.iterator();
1097 while( onlyKeyPropsI.hasNext() ){
1098 String keyName = onlyKeyPropsI.next();
1099 onlyKeysHash.put(keyName, keyPropsHash.get(keyName));
1102 propsAndValuesForMsg = onlyKeysHash.toString() + " combined with a Dependent [" + depNodeVal.<String>property("aai-node-type").orElse(null) + "] node.";
1103 ArrayList<TitanVertex> resultList = DbMeth.getConnectedNodes(transId, fromAppId, graph, nodeType, onlyKeysHash,
1104 depNodeVal, apiVersion, false);
1105 if( resultList.size() > 1 ){
1106 // More than one vertex found when we thought there should only be one.
1107 throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg);
1109 else if( resultList.size() == 1 ){
1110 tiV = resultList.get(0);
1115 // No Vertex was found for this key - throw a not-found exception
1116 throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg);
1119 if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
1120 // The nodeType passed in was a real one, not a nodeTypeCategory, so we will
1121 // use it as part of the query to make sure we find the right type of node.
1122 // This can be an issue if they're using nodeTypes covered by a nodeTypeCategory but
1123 // pass in the wrong nodeType. We don't want them to ask for one thing and get the other.
1124 String foundNodeType = tiV.<String>property("aai-node-type").orElse(null);
1125 if( foundNodeType != null && !foundNodeType.equals(nodeType) ){
1126 throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg + " (did find a " + foundNodeType + " though.)");
1133 }// End of getUniqueNode()
1136 * Gets the unique node.
1138 * @param transId the trans id
1139 * @param fromAppId the from app id
1140 * @param graph the graph
1141 * @param nodeType the node type
1142 * @param keyPropsHash the key props hash
1143 * @param depNodeVal the dep node val
1144 * @return the unique node
1145 * @throws AAIException the AAI exception
1148 public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1149 HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal) throws AAIException {
1150 return getUniqueNode( transId, fromAppId, graph, nodeType,
1151 keyPropsHash, depNodeVal, null );
1153 // End getUniqueNode()
1157 * Gets the unique node with dep params.
1159 * @param transId the trans id
1160 * @param fromAppId the from app id
1161 * @param graph the graph
1162 * @param nodeType the node type
1163 * @param nodePropsHash the node props hash
1164 * @param apiVersion the api version
1165 * @return TitanVertex
1166 * @throws AAIException the AAI exception
1169 public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1170 HashMap<String,Object> nodePropsHash, String apiVersion )
1171 throws AAIException{
1173 * This method uses the nodePropsHash to walk back over dependent nodes until it finds one that
1174 * does not depend on any other for uniqueness. It uses the getUniqueNode() method as it finds
1175 * dependent nodes. NOTE -- it is passed a hash of all the nodeProperties -- for itself and
1176 * for any dependent nodes that it will need to find. There are some types of nodes that can
1177 * depend on more than one node, we assume that there wouldn't be a case where BOTH types of
1178 * dependent nodes are in the trail that we need to traverse. Ie. an ipaddress can depend on
1179 * either a vserver or pserver. NOTE this case can now happen -- nodePropsHash
1180 * should now be sent as a LinkedHashMap in this case so we can search in order.
1183 // NOTE ALSO -- We're currently supporting 6 layers of dependency. We never thought there would be this
1184 // many layers before hitting a node-type that would be uniquely identifiable on it's own. So the
1185 // code is a little ugly with all these nested if-then-else's. Since we're supporting so many
1186 // layers, it should be re-written so we can support "n" layers instead of having to go in hear
1187 // and adding code... But as of 15-07, we really don't NEED more than 5.
1189 // NOTE: The passed in nodeType could really be a nodeTypeCategory --
1190 // The calls to figureDepNodeTypeForRequest() below will deal with it for the dep nodes, the
1191 // call to getUniqueNode() takes care of it for the node itself.
1193 TitanVertex nullVert = null;
1194 String depNodeType = figureDepNodeTypeForRequest( transId, fromAppId, nodeType, nodePropsHash, apiVersion );
1195 if( depNodeType.equals("")){
1196 // This kind of node does not depend on another node for uniqueness, so
1197 // we can just use the "getUniqueNode()" method to get it.
1198 HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
1199 return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, nullVert, apiVersion) );
1202 // Will need to find the second-layer dependent node
1203 String secondLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, depNodeType, nodePropsHash, apiVersion );
1204 if( secondLayerDepNodeType.equals("")){
1205 // This second-layer kind of node does not depend on another node for uniqueness.
1206 // So once we find the second-layer node, we can use it to get the top-layer guy.
1207 HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
1208 TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
1210 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
1211 return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
1214 // Will need to find the third-layer dependent node
1215 /// String thirdLayerDepNodeType = dbMaps.NodeDependencies.get(secondLayerDepNodeType);
1216 String thirdLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion );
1218 if( thirdLayerDepNodeType.equals("")){
1219 // This third-layer kind of node does not depend on another node for uniqueness.
1220 // So we can find it, and then use it to find the second-layer and then use that to find the top guy.
1221 HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
1222 TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
1224 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
1225 TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
1227 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
1229 return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
1232 // Will need to find the third-layer dependent node
1233 String forthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion );
1234 if( forthLayerDepNodeType == null || forthLayerDepNodeType.equals("")){
1235 // This forth-layer kind of node does not depend on another node for uniqueness.
1236 // 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.
1237 HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
1238 TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
1240 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
1241 TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
1243 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
1244 TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
1246 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
1247 return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
1250 // Will need to find the forth-layer dependent node
1251 String fifthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion );
1252 if( fifthLayerDepNodeType == null || fifthLayerDepNodeType.equals("")){
1253 // This fifth-layer kind of node does not depend on another node for uniqueness.
1254 // 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.
1255 HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion);
1256 TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
1258 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
1259 TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion);
1261 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
1262 TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
1264 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
1265 TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
1267 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
1268 return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
1271 // Will need to find the fifth-layer dependent node
1272 String sixthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion );
1273 if( sixthLayerDepNodeType == null || sixthLayerDepNodeType.equals("")){
1274 // This six-layer kind of node does not depend on another node for uniqueness.
1275 // 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.
1276 HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion);
1277 TitanVertex sixthLayerDepVert = getUniqueNode(transId, fromAppId, graph, fifthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
1279 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion);
1280 TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, sixthLayerDepVert, apiVersion);
1282 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
1283 TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion);
1285 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
1286 TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
1288 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
1289 TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
1291 thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
1292 return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
1295 // We don't currently support more layers. We can later if we need to.
1296 // Hopefully, we'll never need to go this deep -- there should be unique keys in there somewhere!
1297 throw new AAIException("AAI_6114", "CODE-LIMITATION - Can't resolve dependant node layers for nodeType = " + nodeType);
1304 } // End getUniqueNodeWithDepParams()
1307 * Gets the unique node with dep params.
1309 * @param transId the trans id
1310 * @param fromAppId the from app id
1311 * @param graph the graph
1312 * @param nodeType the node type
1313 * @param nodePropsHash the node props hash
1314 * @return the unique node with dep params
1315 * @throws AAIException the AAI exception
1318 public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1319 HashMap<String,Object> nodePropsHash ) throws AAIException {
1320 return getUniqueNodeWithDepParams(transId, fromAppId, graph, nodeType, nodePropsHash, null);
1325 * Gets the this node type params.
1327 * @param transId the trans id
1328 * @param fromAppId the from app id
1329 * @param targetNodeType the target node type
1330 * @param passedHash the passed hash
1331 * @param apiVersion the api version
1332 * @return the this node type params
1333 * @throws AAIException the AAI exception
1335 private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType,
1336 HashMap<String,Object> passedHash, String apiVersion )throws AAIException{
1338 * For the passed-in hash, each key is assumed to look like, "nodeType.paramName". We want to
1339 * pick out the entries that match the targetNodeType and return those with the values they go with. The
1340 * returned keys will have the "nodeType." stripped off.
1342 * NOTE - the nodeType passed to this method could actually be a nodeTypeCategory. Just keepin it ugly.
1345 if( passedHash == null ){
1346 throw new AAIException("AAI_6120", "Bad param: null passedHash ");
1349 String targetNodeTypeCat = "";
1350 if( DbEdgeRules.NodeTypeCatMap.containsKey(targetNodeType) ){
1351 targetNodeTypeCat = DbEdgeRules.NodeTypeCatMap.get(targetNodeType);
1354 HashMap <String,Object> returnHash = new HashMap <String,Object> ();
1355 Iterator <Map.Entry<String,Object>>it = passedHash.entrySet().iterator();
1356 while( it.hasNext() ){
1357 Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next();
1358 String k = (pairs.getKey()).toString();
1359 int periodLoc = k.indexOf(".");
1360 if( periodLoc <= 0 ){
1361 throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n");
1364 String nty = k.substring(0,periodLoc);
1365 String paramName = k.substring(periodLoc + 1);
1366 if( nty.equals(targetNodeType) || (!targetNodeTypeCat.equals("") && nty.equals(targetNodeTypeCat)) ){
1367 String newK = paramName;
1368 returnHash.put( newK,pairs.getValue() );
1373 //aaiLogger.debug(logline, " - end ");
1376 }// End of getThisNodeTypeParams()
1379 * Gets the this node type params.
1381 * @param transId the trans id
1382 * @param fromAppId the from app id
1383 * @param targetNodeType the target node type
1384 * @param passedHash the passed hash
1385 * @return the this node type params
1386 * @throws AAIException the AAI exception
1389 private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType,
1390 HashMap<String,Object> passedHash )throws AAIException{
1391 return getThisNodeTypeParams( transId, fromAppId, targetNodeType,
1397 * Gets the dep node types.
1399 * @param transId the trans id
1400 * @param fromAppId the from app id
1401 * @param nodeType the node type
1402 * @param apiVersion the api version
1403 * @return the dep node types
1404 * @throws AAIException the AAI exception
1406 public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
1408 * This returns any nodeTypes that this nodeType can be dependent on. A particular instance of a node will only
1409 * depend on one other node - we don't currently support dependence on multiple nodes.
1412 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
1414 ArrayList <String> depNodeTypeL = new ArrayList <String> ();
1415 if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
1416 // This is a good-ole nodeType
1417 Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType);
1418 Iterator <String> ntItr = depNTColl.iterator();
1419 while( ntItr.hasNext() ){
1420 depNodeTypeL.add(ntItr.next());
1424 // The passed-in nodeType must really be a nodeTypeCategory
1425 Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
1426 Iterator <String> catItr = nTypeCatCol.iterator();
1427 String catInfo = "";
1428 if( catItr.hasNext() ){
1429 // For now, we only look for one.
1430 catInfo = catItr.next();
1433 throw new AAIException("AAI_6121", "Error getting DbEdgeRules.NodeTypeCategory info for nodeTypeCat = " + nodeType);
1436 String [] flds = catInfo.split(",");
1437 if( flds.length != 4 ){
1438 throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
1441 String nodeTypesString = flds[0];
1442 String hasDepNodes = flds[3];
1443 if( hasDepNodes.equals("true") ){
1444 String [] ntNames = nodeTypesString.split("\\|");
1445 for( int i = 0; i < ntNames.length; i++ ){
1446 Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType);
1447 Iterator <String> ntItr = depNTColl.iterator();
1448 while( ntItr.hasNext() ){
1449 String depNode = ntItr.next();
1450 if( !depNodeTypeL.contains(depNode) ){
1451 depNodeTypeL.add(depNode);
1459 return depNodeTypeL;
1461 }// End getDepNodeTypes()
1464 * Gets the dep node types.
1466 * @param transId the trans id
1467 * @param fromAppId the from app id
1468 * @param nodeType the node type
1469 * @return the dep node types
1470 * @throws AAIException the AAI exception
1473 public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType)throws AAIException{
1474 return getDepNodeTypes( transId, fromAppId, nodeType, null);
1478 * Gets the default delete scope.
1480 * @param transId the trans id
1481 * @param fromAppId the from app id
1482 * @param nodeType the node type
1483 * @param apiVersion the api version
1484 * @return the default delete scope
1485 * @throws AAIException the AAI exception
1487 private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
1489 // At some point we may have different delete rules for different services, so this is
1490 // a list for now even thought there's only one scope per nodeType.
1491 Collection <String> scopeList = DbEdgeRules.DefaultDeleteScope.get(nodeType);
1492 if( scopeList.isEmpty() ){
1493 throw new AAIException("AAI_6121", "No default deleteScope found for nodeType = [" + nodeType + "] ");
1496 Iterator <String> ito = scopeList.iterator();
1500 }// End getDefaultDeleteScope()
1503 * Gets the default delete scope.
1505 * @param transId the trans id
1506 * @param fromAppId the from app id
1507 * @param nodeType the node type
1508 * @return the default delete scope
1509 * @throws AAIException the AAI exception
1512 private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType)throws AAIException{
1513 return getDefaultDeleteScope( transId, fromAppId, nodeType, null);
1517 * Needs A dep node 4 uniqueness.
1519 * @param transId the trans id
1520 * @param fromAppId the from app id
1521 * @param nodeType the node type
1522 * @param apiVersion the api version
1523 * @return the boolean
1524 * @throws AAIException the AAI exception
1526 public static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
1527 // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes()
1529 ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion);
1530 if( depList.isEmpty() ){
1537 }// End needsADepNode4Uniqueness()
1540 * Needs A dep node 4 uniqueness.
1542 * @param transId the trans id
1543 * @param fromAppId the from app id
1544 * @param nodeType the node type
1545 * @return the boolean
1546 * @throws AAIException the AAI exception
1549 private static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType)throws AAIException{
1550 return needsADepNode4Uniqueness( transId, fromAppId, nodeType, null);
1554 * Node type A can depend on B.
1556 * @param transId the trans id
1557 * @param fromAppId the from app id
1558 * @param nodeTypeA the node type A
1559 * @param nodeTypeB the node type B
1560 * @param apiVersion the api version
1561 * @return the boolean
1562 * @throws AAIException the AAI exception
1564 public static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB, String apiVersion)
1565 throws AAIException{
1566 // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes()
1568 ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeTypeA, apiVersion);
1569 if( depList.isEmpty() ){
1572 else if( depList.contains(nodeTypeB) ){
1579 }// End nodeTypeACanDependOnB()
1582 * Node type A can depend on B.
1584 * @param transId the trans id
1585 * @param fromAppId the from app id
1586 * @param nodeTypeA the node type A
1587 * @param nodeTypeB the node type B
1588 * @return the boolean
1589 * @throws AAIException the AAI exception
1592 private static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB)
1593 throws AAIException{
1594 return nodeTypeACanDependOnB( transId, fromAppId, nodeTypeA, nodeTypeB, null);
1598 * Figure dep node type for request.
1600 * @param transId the trans id
1601 * @param fromAppId the from app id
1602 * @param nodeType the node type
1603 * @param requestParamHash the request param hash
1604 * @param apiVersion the api version
1605 * @return the string
1606 * @throws AAIException the AAI exception
1608 public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType,
1609 HashMap<String,Object> requestParamHash, String apiVersion )throws AAIException{
1611 * This is ugly. But if the passed-in nodeType is dependent on another nodeType for
1612 * uniqueness, we need to return what that dependent node-type is. The ugly comes in
1613 * because a node can be dependent on more than one type of node. So, to tell which one
1614 * is going to apply, we root through the passed request parameters to see which of
1615 * the possible dependent node types is being used.
1616 * Note -- if there comes a day when there are so many dependencies that the request could
1617 * have more than one that match -- Then we need to think up something new. But for now,
1618 * we have to assume that if there are more than one legal dep-node-types, only one will
1619 * be represented in the requestHash data. >>> NOTE >>> That day has come. For
1620 * the upstreamers will send in a LinkedHashMap instead of just an unordered
1621 * HashMap so we can look in order for the dependent node.
1625 if( requestParamHash == null ){
1626 throw new AAIException("AAI_6120", "Bad param: null requestParamHash ");
1629 ArrayList <String> depNodeTypes = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion);
1630 if( depNodeTypes.isEmpty() ){
1631 // This kind of node is not dependent on any other
1632 //aaiLogger.debug(logline, " (not dependent) - end ");
1635 else if( depNodeTypes.size() == 1 ){
1636 // This kind of node can only depend on one other nodeType - so return that.
1637 //aaiLogger.debug(logline, " (depends on " + depNodeTypes.get(0) + " - end ");
1638 return depNodeTypes.get(0);
1641 // We need to look to find the first of the dep-node types that is represented in the passed-in
1642 // request data. That will be the one we need to use.
1644 // first find out what node-types are represented in the requestHash
1646 Iterator <Map.Entry<String,Object>>it = requestParamHash.entrySet().iterator();
1647 while( it.hasNext() ){
1648 Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next();
1649 String k = (pairs.getKey()).toString();
1650 int periodLoc = k.indexOf(".");
1651 if( periodLoc <= 0 ){
1652 throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n");
1655 String nty = k.substring(0,periodLoc);
1656 if( depNodeTypes.contains(nty) ){
1657 // This is the first possible dep. node type we've found for the passed in data set
1665 // It's not an error if none is found - the caller needs to deal with cases where there
1666 // should be a dep. node identified but isn't.
1667 //aaiLogger.debug(logline, " no dep NT found - end ");
1670 }// End of figureDepNodeTypeForRequest()
1673 * Figure dep node type for request.
1675 * @param transId the trans id
1676 * @param fromAppId the from app id
1677 * @param nodeType the node type
1678 * @param requestParamHash the request param hash
1679 * @return the string
1680 * @throws AAIException the AAI exception
1683 public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType,
1684 HashMap<String,Object> requestParamHash )throws AAIException{
1685 return figureDepNodeTypeForRequest( transId, fromAppId, nodeType, requestParamHash, null);
1689 * Detach connected nodes.
1691 * @param transId the trans id
1692 * @param fromAppId the from app id
1693 * @param graph the graph
1694 * @param nodeType the node type
1695 * @param propFilterHash the prop filter hash
1696 * @param startNodeVal the start node val
1697 * @param autoDeleteOrphans the auto delete orphans
1698 * @param apiVersion the api version
1699 * @return deletedNodeCount
1700 * @throws AAIException the AAI exception
1702 public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1703 HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans, String apiVersion ) throws AAIException{
1705 /* Find nodes that are attached to this node which meet the nodeType/filterParams criteria.
1706 * Remove the edges that go to those nodes.
1707 * If that turns any of the nodes into an orphan, then delete it if the autoDeleteOrphans flag is set.
1708 * Return a count of how many nodes were actually deleted (not just detached).
1711 int deletedCount = 0;
1713 if( startNodeVal == null ){
1714 // They should have passed in the node that this query starts from
1715 throw new AAIException("AAI_6109", "null startNode object passed to detachConnectedNodes().");
1718 // We want to loop through the connected Nodes that we found.
1719 // For each connected Node, we'll get the all edges that start from that node and look for the one
1720 // that connects back to our startNode.
1721 // Only delete the edge that connects back to our startNode.
1722 // then autoDeleteOrphans flag is set, then delete the connectedNode if it's now orphaned.
1725 String startNodeVId = startNodeVal.id().toString();
1726 ArrayList<TitanVertex> conNodeList = getConnectedNodes( transId, fromAppId, graph, nodeType, propFilterHash, startNodeVal, apiVersion, false );
1727 Iterator<TitanVertex> conVIter = conNodeList.iterator();
1728 while( conVIter.hasNext() ){
1729 TitanVertex connectedVert = conVIter.next();
1730 boolean isFirstOne = true;
1731 Iterator<Edge> eI = connectedVert.edges(Direction.BOTH);
1732 while( eI.hasNext() ){
1733 TitanEdge ed = (TitanEdge) eI.next();
1734 TitanVertex otherVtx = (TitanVertex) ed.otherVertex(connectedVert);
1735 String otherSideLookingBackVId = otherVtx.id().toString();
1736 if( startNodeVId.equals(otherSideLookingBackVId) ){
1737 // This is an edge from the connected node back to our starting node
1738 if( isFirstOne && !eI.hasNext() && autoDeleteOrphans ){
1739 // This was the one and only edge for this connectedNode, so
1740 // delete the node and edge since flag was set
1741 String resVers = connectedVert.<String>property("resource-version").orElse(null);
1742 removeAaiNode( transId, fromAppId, graph, connectedVert, "USE_DEFAULT", apiVersion, resVers);
1743 deletedCount = deletedCount + 1;
1746 removeAaiEdge( transId, fromAppId, graph, ed );
1752 return deletedCount;
1754 } // end of detachConnectedNodes()
1759 * Detach connected nodes.
1761 * @param transId the trans id
1762 * @param fromAppId the from app id
1763 * @param graph the graph
1764 * @param nodeType the node type
1765 * @param propFilterHash the prop filter hash
1766 * @param startNodeVal the start node val
1767 * @param autoDeleteOrphans the auto delete orphans
1769 * @throws AAIException the AAI exception
1772 public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1773 HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans ) throws AAIException{
1774 return detachConnectedNodes( transId, fromAppId, graph, nodeType,
1775 propFilterHash, startNodeVal, autoDeleteOrphans, null);
1781 * @param transId the trans id
1782 * @param fromAppId the from app id
1783 * @param graph the graph
1784 * @param nodeType the node type
1785 * @param propFilterHash the prop filter hash
1786 * @param noFilterOnPurpose the no filter on purpose
1787 * @param apiVersion the api version
1788 * @return ArrayList<TitanVertex>
1789 * @throws AAIException the AAI exception
1792 public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1793 HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion ) throws AAIException{
1794 boolean skipGroomingFlag = true;
1795 // we will only do real-time grooming if a system variable is set, telling us not to skip it.
1796 String skipGroomingStr = AAIConstants.AAI_SKIPREALTIME_GROOMING;
1797 if( skipGroomingStr.equals("false") ){
1798 skipGroomingFlag = false;
1800 return( getNodes(transId, fromAppId, graph, nodeType, propFilterHash, noFilterOnPurpose, apiVersion, skipGroomingFlag) );
1806 * @param transId the trans id
1807 * @param fromAppId the from app id
1808 * @param graph the graph
1809 * @param nodeType the node type
1810 * @param propFilterHash the prop filter hash
1811 * @param noFilterOnPurpose the no filter on purpose
1812 * @param apiVersion the api version
1813 * @param skipGroomCheck the skip groom check
1814 * @return ArrayList<TitanVertex>
1815 * @throws AAIException the AAI exception
1818 public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1819 HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion, boolean skipGroomCheck )
1820 throws AAIException{
1821 // Note - the skipGroomCheck flag is set to true when the DataGrooming tool is using this method to collect
1822 // node data. When the grooming tool is collecting data, we don't want any nodes skipped, because we
1823 // want details about what nodes/edges are bad - more detail than the check in this method does
1824 // as it checks if a node is ok to return to a caller.
1826 /* Use the nodeType + filterParams to find nodes.
1828 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
1830 ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>();
1831 if( nodeType == null || nodeType.equals("") ){
1832 // They should have passed in a nodeType
1833 throw new AAIException("AAI_6118", "Required field: nodeType not passed to getNodes().");
1836 if( !noFilterOnPurpose && (propFilterHash == null || propFilterHash.isEmpty()) ){
1837 // They should have passed at least one property to filter on
1838 throw new AAIException("AAI_6118", "Required field: propFilterHash not passed to getNodes().");
1841 ArrayList<String> kName = new ArrayList<String>();
1842 ArrayList<Object> kVal = new ArrayList<Object>();
1844 Collection <String> indexedProps = dbMaps.NodeMapIndexedProps.get(nodeType);
1845 // First loop through to pick up the indexed-properties if there are any being used
1847 if( propFilterHash != null ){
1848 Iterator <?> it = propFilterHash.entrySet().iterator();
1849 while( it.hasNext() ){
1850 Map.Entry<?,?> propEntry = (Map.Entry<?,?>) it.next();
1851 String propName = (propEntry.getKey()).toString();
1852 // Don't allow search on properties that do not have SINGLE cardinality
1853 if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
1854 if( indexedProps.contains(propName) ){
1856 kName.add(i, propName);
1857 kVal.add(i, (Object)propEntry.getValue());
1862 // Now go through again and pick up the non-indexed properties
1863 it = propFilterHash.entrySet().iterator();
1864 while( it.hasNext() ){
1865 Map.Entry <?,?> propEntry = (Map.Entry<?,?>)it.next();
1866 String propName = (propEntry.getKey()).toString();
1867 // Don't allow search on properties that do not have SINGLE cardinality
1868 if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
1869 if( ! indexedProps.contains(propName) ){
1871 kName.add(i, propName);
1872 kVal.add(i, (Object)propEntry.getValue());
1878 Iterable <?> verts = null;
1879 String propsAndValuesForMsg = "";
1880 int topPropIndex = i;
1881 if( topPropIndex == -1 ){
1882 // No Filtering -- just go get them all
1883 verts= graph.query().has("aai-node-type",nodeType).vertices();
1884 propsAndValuesForMsg = " ( no filter props ) ";
1886 else if( topPropIndex == 0 ){
1887 verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
1888 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
1890 else if( topPropIndex == 1 ){
1891 verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has("aai-node-type",nodeType).vertices();
1892 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
1893 + kName.get(1) + " = " + kVal.get(1) + ") ";
1895 else if( topPropIndex == 2 ){
1896 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();
1897 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
1898 + kName.get(1) + " = " + kVal.get(1) + ", "
1899 + kName.get(2) + " = " + kVal.get(2) + ") ";
1901 else if( topPropIndex == 3 ){
1902 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();
1903 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
1904 + kName.get(1) + " = " + kVal.get(1) + ", "
1905 + kName.get(2) + " = " + kVal.get(2) + ", "
1906 + kName.get(3) + " = " + kVal.get(3) + ") ";
1909 String emsg = " -- Sorry -- we only support 4 filter properties in getNodes() for now... \n";
1910 throw new AAIException("AAI_6114", emsg);
1912 if( verts != null ){
1913 // We did find some matching vertices
1914 Iterator <?> it = verts.iterator();
1915 while( it.hasNext() ){
1916 TitanVertex v = (TitanVertex)it.next();
1918 if( skipGroomCheck ){
1919 // Good or bad, just return everything we find
1920 returnVertList.add( v );
1923 // Weed out any bad vertices we find
1924 if( thisVertexNotReachable(transId, fromAppId, graph, v, apiVersion) ){
1925 LOGGER.info("IN-LINE GROOMING - Unreachable Node DETECTED > skipping it. ");
1927 else if( thisVertexHasBadEdges(transId, fromAppId, graph, v, apiVersion) ){
1928 LOGGER.info("IN-LINE GROOMING - BAD EDGE DETECTED > skipping vtxId = [" + v.id() + "] ");
1930 else if( thisVertexIsAPhantom(transId, fromAppId, graph, v, apiVersion) ){
1931 LOGGER.info("IN-LINE GROOMING - BAD NODE DETECTED > skipping vtxId = [" + v.id() + "] ");
1934 returnVertList.add( v );
1940 return returnVertList;
1946 * @param transId the trans id
1947 * @param fromAppId the from app id
1948 * @param graph the graph
1949 * @param nodeType the node type
1950 * @param propFilterHash the prop filter hash
1951 * @param noFilterOnPurpose the no filter on purpose
1953 * @throws AAIException the AAI exception
1956 public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
1957 HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose ) throws AAIException{
1958 return getNodes(transId, fromAppId, graph, nodeType,
1959 propFilterHash, noFilterOnPurpose, null );
1961 // End of getNodes()
1965 * Gets the connected children.
1967 * @param transId the trans id
1968 * @param fromAppId the from app id
1969 * @param graph the graph
1970 * @param startVtx the start vtx
1971 * @param limitToThisNodeType the limit to this node type
1972 * @return ArrayList <TitanVertex>
1973 * @throws AAIException the AAI exception
1975 public static ArrayList<TitanVertex> getConnectedChildren( String transId, String fromAppId, TitanTransaction graph,
1976 TitanVertex startVtx, String limitToThisNodeType ) throws AAIException{
1978 // Just get child nodes (ie. other end of an OUT edge that is tagged as a parent/Child edge)
1980 ArrayList <TitanVertex> childList = new ArrayList <TitanVertex> ();
1981 Boolean doNodeTypeCheck = false;
1982 if( limitToThisNodeType != null && ! limitToThisNodeType.equals("") ){
1983 doNodeTypeCheck = true;
1987 List<Vertex> verts = graph.traversal().V(startVtx).union(__.inE().has("isParent-REV", true).outV(), __.outE().has("isParent", true).inV()).toList();
1988 TitanVertex tmpVtx = null;
1989 int vertsSize = verts.size();
1990 for (int i = 0; i < vertsSize; i++){
1991 tmpVtx = (TitanVertex) verts.get(i);
1992 if( ! doNodeTypeCheck ){
1993 childList.add(tmpVtx);
1996 String tmpNT = tmpVtx.<String>property("aai-node-type").orElse(null);
1997 if( tmpNT != null && tmpNT.equals(limitToThisNodeType) ){
1998 childList.add(tmpVtx);
2005 }// End of getConnectedChildren()
2010 * Gets the connected nodes.
2012 * @param transId the trans id
2013 * @param fromAppId the from app id
2014 * @param graph the graph
2015 * @param nodeType the node type
2016 * @param propFilterHash the prop filter hash
2017 * @param startNodeVal the start node val
2018 * @param apiVersion the api version
2019 * @param excludeRecurComingIn the exclude recur coming in
2020 * @return ArrayList <TitanVertex>
2021 * @throws AAIException the AAI exception
2023 public static ArrayList<TitanVertex> getConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
2024 HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion, Boolean excludeRecurComingIn ) throws AAIException{
2026 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
2027 /* Get (almost) all the nodes that are connected to this vertex.
2028 * Narrow down what is returned using optional filter parameters nodeType and propFilterHash
2029 * NOTE - the default behavior has changed slightly. For start-Nodes that
2030 * can be recursivly connected, this method will only bring back the same kind of
2031 * connected node by following an OUT edge. Ie. if the start node is an "model-element",
2032 * then this method will only follow OUT edges to get to other "model-element" type nodes.
2035 String startNodeNT = "";
2036 if( startNodeVal == null ){
2037 // They should have passed in the node that this query starts from
2038 throw new AAIException("AAI_6109", "null startNode object passed to getConnectedNodes().");
2041 startNodeNT = startNodeVal.<String>property("aai-node-type").orElse(null);
2044 boolean nodeTypeFilter = false;
2045 if( nodeType != null && !nodeType.equals("") ){
2046 // They want to filter using nodeType
2047 if( ! dbMaps.NodeProps.containsKey(nodeType) ){
2048 throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to getConnectedNodes().");
2050 nodeTypeFilter = true;
2053 ArrayList <String> excludeVidList = new <String> ArrayList ();
2054 if( DbEdgeRules.CanBeRecursiveNT.containsKey(startNodeNT) && excludeRecurComingIn ){
2055 // If we're starting on a nodeType that supports recursion, then find any connected
2056 // nodes that are coming from IN edges so we can exclude them later.
2058 Iterable <?> vertsR = startNodeVal.query().direction(Direction.IN).vertices();
2059 Iterator <?> vertIR = vertsR.iterator();
2060 while( vertIR != null && vertIR.hasNext() ){
2061 TitanVertex tmpVertIN = (TitanVertex) vertIR.next();
2062 String tmpNT = tmpVertIN.<String>property("aai-node-type").orElse(null);
2063 if( tmpNT != null && tmpNT.equals(startNodeNT) ){
2064 // We're on a nodetype that supports recursion (like model-element) and we've
2065 // found an connected Node of this same type on an IN edge - put this
2066 // on our excludeList.
2067 excludeVidList.add( tmpVertIN.id().toString() );
2072 boolean propertyFilter = false;
2073 if( propFilterHash != null && !propFilterHash.isEmpty() ){
2074 // They want to filter using some properties
2075 Iterator <?> it = propFilterHash.entrySet().iterator();
2076 while( it.hasNext() ){
2077 Map.Entry<?,?> propEntry = (Map.Entry<?,?>)it.next();
2078 String propName = (propEntry.getKey()).toString();
2079 if( ! dbMaps.NodeProps.containsValue(propName) ){
2080 throw new AAIException("AAI_6116", "Unrecognized property name [" + propName + "] passed to getConnectedNodes().");
2082 // Don't allow search on properties that do not have SINGLE cardinality
2083 if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
2084 propertyFilter = true;
2088 // If filter-properties were passed in, then look for nodes that have those values.
2089 ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>();
2090 Iterable<TitanVertex> qResult = null;
2091 Iterator<TitanVertex> resultI = null;
2093 qResult = startNodeVal.query().vertices();
2094 resultI = qResult.iterator();
2096 catch( NullPointerException npe ){
2097 throw new AAIException("AAI_6125", "Titan null pointer exception trying to get nodes connected to vertexId = " +
2098 startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "].");
2101 while( resultI != null && resultI.hasNext() ){
2102 boolean addThisOne = true;
2103 TitanVertex tmpV = (TitanVertex)resultI.next();
2105 LOGGER.info("Titan gave a null vertex when looking for nodes connected to vertexId = " +
2106 startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "].");
2107 // Note - we will skip this one, but try to return any others that we find.
2112 String tmpVid = tmpV.id().toString();
2113 if( nodeTypeFilter ){
2114 Object nto = tmpV.<Object>property("aai-node-type").orElse(null);
2115 if( nto == null || !nto.toString().equals(nodeType) ){
2116 //LOGGER.info("Found a connected vertex (vertexId = " +
2117 // tmpVid + "), but we will not collect it. It had aai-node-type [" +
2118 // nto + "], we are looking for [" + nodeType + "]. ");
2119 // Note - we will skip this one, but try to return any others that we find.
2124 if( excludeVidList.contains(tmpVid) ){
2125 LOGGER.info("Found a connected vertex (vertexId = " +
2126 tmpVid + "), but will exclude it since it is on an IN edge and this nodeType " +
2127 startNodeNT + " can be recursively attached.");
2128 // Note - we will skip this one, but try to return any others that we find.
2132 if( propertyFilter ){
2133 Iterator <?> it = propFilterHash.entrySet().iterator();
2134 while( it.hasNext() ){
2135 Map.Entry <?,?>propEntry = (Map.Entry<?,?>)it.next();
2136 String propName = (propEntry.getKey()).toString();
2137 if( checkPropCardinality(propName, "Set") || checkPropCardinality(propName, "List") ){
2138 // Don't allow search on properties that do not have SINGLE cardinality
2141 Object propVal = propEntry.getValue();
2142 Object foundVal = tmpV.<Object>property(propName).orElse(null);
2143 if( foundVal != null && propVal != null && !foundVal.toString().equals(propVal.toString()) ){
2147 else if( (foundVal == null && propVal != null) || (foundVal != null && propVal == null) ){
2155 // This node passed the tests -- put it on the return List
2156 returnVertList.add( (TitanVertex)tmpV );
2159 //aaiLogger.debug(logline, " end ");
2160 return returnVertList;
2162 }// End of getConnectedNodes()
2166 * Gets the connected nodes.
2168 * @param transId the trans id
2169 * @param fromAppId the from app id
2170 * @param graph the graph
2171 * @param nodeType the node type
2172 * @param propFilterHash the prop filter hash
2173 * @param startNodeVal the start node val
2174 * @param apiVersion the api version
2175 * @return the connected nodes
2176 * @throws AAIException the AAI exception
2179 public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType,
2180 HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion ) throws AAIException {
2181 return getConnectedNodes( transId, fromAppId, graph, nodeType,
2182 propFilterHash, startNodeVal, apiVersion, true );
2186 * Gets the connected nodes.
2188 * @param transId the trans id
2189 * @param fromAppId the from app id
2190 * @param graph the graph
2191 * @param nodeType the node type
2192 * @param propFilterHash the prop filter hash
2193 * @param startNodeVal the start node val
2194 * @return the connected nodes
2195 * @throws AAIException the AAI exception
2198 public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType,
2199 HashMap<String,Object> propFilterHash, TitanVertex startNodeVal ) throws AAIException {
2200 return getConnectedNodes( transId, fromAppId, graph, nodeType,
2201 propFilterHash, startNodeVal, null, true );
2206 * Ip address format OK.
2208 * @param transId the trans id
2209 * @param fromAppId the from app id
2210 * @param addrVal the addr val
2211 * @param addrVer the addr ver
2212 * @param apiVersion the api version
2214 * @throws AAIException the AAI exception
2216 public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer, String apiVersion) throws AAIException{
2218 /* NOTE -- the google methods we use do not allow leading zeros in ipV4 addresses.
2219 * So it will reject, "22.33.44.001"
2222 if( addrVal == null ){
2223 throw new AAIException("AAI_6120", "Bad data (addrVal = null) passed to ipAddressFormatOK()");
2225 else if( addrVer == null ){
2226 throw new AAIException("AAI_6120", "Bad data (addrType = null) passed to ipAddressFormatOK()");
2229 Boolean retVal = false;
2230 Boolean lookingForV4 = false;
2231 Boolean lookingForV6 = false;
2232 InetAddress inetAddr = null;
2234 if( addrVer.equalsIgnoreCase("v4") || addrVer.equals("ipv4") || addrVer.equals("4")){
2235 lookingForV4 = true;
2237 else if( addrVer.equalsIgnoreCase("v6") || addrVer.equals("ipv6") || addrVer.equals("6")){
2238 lookingForV6 = true;
2241 throw new AAIException("AAI_6120", " Bad data for addressVersion [" + addrVer + "] passed to ipAddressFormatOK()");
2245 inetAddr = InetAddresses.forString(addrVal);
2246 if( inetAddr instanceof Inet4Address ){
2251 throw new AAIException("AAI_6120", "Bad data. Address is a V4, but addressType said it should be V6. ["
2252 + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK()");
2255 else if( inetAddr instanceof Inet6Address ){
2260 throw new AAIException("AAI_6120", "Bad data. Address is a V6, but addressType said it should be V4. ["
2261 + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK().");
2265 catch (IllegalArgumentException e) {
2266 throw new AAIException("AAI_6120", "Badly formed ip-address: [" + addrVal + "] passed to ipAddressFormatOK()");
2271 }//end of ipAddressFormatOk()
2274 * Ip address format OK.
2276 * @param transId the trans id
2277 * @param fromAppId the from app id
2278 * @param addrVal the addr val
2279 * @param addrVer the addr ver
2280 * @return the boolean
2281 * @throws AAIException the AAI exception
2283 public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer) throws AAIException{
2284 return ipAddressFormatOK( transId, fromAppId, addrVal, addrVer, null);
2288 * Save aai edge to db.
2290 * @param transId the trans id
2291 * @param fromAppId the from app id
2292 * @param graph the graph
2293 * @param edgeLabel the edge label
2294 * @param outV the out V
2295 * @param inV the in V
2296 * @param propHash the prop hash
2297 * @param apiVersion the api version
2299 * @throws AAIException the AAI exception
2301 private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel,
2302 TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash, String apiVersion) throws AAIException{
2304 // If this edge doesn't exist yet, then create it.
2306 // NOTE - the Titan javaDoc says that there might not always be an id for a node.
2307 // This is the internal-titan-unique-id, not any of our data.
2308 // Not sure how to know when it might be there and when it might not?!
2309 // So far, it has worked for all my testing, but this might warrant some
2310 // further investigation.
2312 TitanEdge existingEdge = null;
2313 String inVId = inV.id().toString();
2314 Iterator <Edge> eI = outV.edges(Direction.BOTH, edgeLabel);
2315 while( eI.hasNext() ){
2316 TitanEdge ed = (TitanEdge) eI.next();
2317 TitanVertex otherVtx = (TitanVertex) ed.otherVertex(outV);
2318 if( (otherVtx.id().toString()).equals(inVId) ){
2319 // NOTE -?- Not sure -- at some point we might want to check the edgeLabels also since we might
2320 // want to allow two different-type edges between the same two vertexes? (or maybe not.)
2326 if( existingEdge != null ){
2327 // This is just an UPDATE
2328 for( Map.Entry<String, Object> entry : propHash.entrySet() ){
2329 LOGGER.debug("update edge property/val = [" + entry.getKey() + "]/[" + entry.getValue() + "]");
2330 existingEdge.property( entry.getKey(), entry.getValue() );
2333 return( existingEdge );
2338 // Uniqueness double-check. This is just to catch the possibility that at the transaction layer,
2339 // if data came in for two identical nodes that point to the same dependant node (for uniqueness),
2340 // we would only be able to catch the problem at the time the edge to the second node is added.
2341 // For example - if they had a VM and then got a request to add two ipAddress nodes, but some
2342 // bad data was passed and those two ipAddress nodes were identical -- we'd want to catch it.
2343 String outV_NType = outV.<String>property("aai-node-type").orElse(null);
2344 String inV_NType = inV.<String>property("aai-node-type").orElse(null);
2345 if( needsADepNode4Uniqueness(transId, fromAppId, outV_NType, apiVersion)
2346 && nodeTypeACanDependOnB(transId, fromAppId, outV_NType, inV_NType, apiVersion) ){
2347 // The out-Vertex has a uniqueness dependency on the in-vertex
2348 // Make sure we haven't already added an node/edge like this in this transaction
2349 HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, outV);
2350 ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>();
2351 resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, outV_NType, nodeKeyPropsHash, inV, apiVersion, false);
2352 if( resultList.size() > 0 ){
2353 String propInfo = "";
2354 if( nodeKeyPropsHash != null ){
2355 propInfo = nodeKeyPropsHash.toString();
2357 throw new AAIException("AAI_6117", "Failed to add edge. This node (" + inV_NType + ") already has an edge to a " + outV_NType +
2358 " node with kepProps [" + propInfo + "]");
2361 else if( needsADepNode4Uniqueness(transId, fromAppId, inV_NType, apiVersion)
2362 && nodeTypeACanDependOnB(transId, fromAppId, inV_NType, outV_NType, apiVersion) ){
2363 // The in-Vertex has a uniqueness dependency on the out-vertex
2364 // Make sure we haven't already added an node/edge like this in this transaction
2365 HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, inV);
2366 ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>();
2367 resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, inV_NType, nodeKeyPropsHash, outV, apiVersion, false);
2368 if( resultList.size() > 0 ){
2369 String propInfo = "";
2370 if( nodeKeyPropsHash != null ){
2371 propInfo = nodeKeyPropsHash.toString();
2373 throw new AAIException("AAI_6117", "Failed to add edge. This node (" + outV_NType + ") already has an edge to a " + inV_NType +
2374 " node with kepProps [" + propInfo + "]");
2379 // We're good to go to add this edge
2381 TitanEdge tEdge = outV.addEdge( edgeLabel, inV );
2382 // Add the properties to the new Edge
2383 for( Map.Entry<String, Object> entry : propHash.entrySet() ){
2384 tEdge.property( entry.getKey(), entry.getValue() );
2387 // For (resource-id updates) we need to "touch" the vertices on each side of the edge so
2388 // anybody working on one of those vertices will know that something (ADDing this edge) has happened.
2389 touchVertex( transId, fromAppId, inV );
2390 touchVertex( transId, fromAppId, outV );
2395 }// End saveAaiEdgeToDb()
2400 * Derive edge rule key for this edge.
2402 * @param transId the trans id
2403 * @param fromAppId the from app id
2404 * @param graph the graph
2405 * @param tEdge the t edge
2406 * @return String - key to look up edgeRule (fromNodeType|toNodeType)
2407 * @throws AAIException the AAI exception
2409 public static String deriveEdgeRuleKeyForThisEdge( String transId, String fromAppId, TitanTransaction graph,
2410 TitanEdge tEdge ) throws AAIException{
2412 TitanVertex fromVtx = tEdge.outVertex();
2413 TitanVertex toVtx = tEdge.inVertex();
2414 String startNodeType = fromVtx.<String>property("aai-node-type").orElse(null);
2415 String targetNodeType = toVtx.<String>property("aai-node-type").orElse(null);
2416 String key = startNodeType + "|" + targetNodeType;
2417 if( EdgeRules.getInstance().hasEdgeRule(startNodeType, targetNodeType) ){
2418 // We can use the node info in the order they were given
2422 key = targetNodeType + "|" + startNodeType;
2423 if( EdgeRules.getInstance().hasEdgeRule(targetNodeType, startNodeType) ){
2427 // Couldn't find a rule for this edge
2428 throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", "
2432 }// end of deriveEdgeRuleKeyForThisEdge()
2437 * Save aai edge to db.
2439 * @param transId the trans id
2440 * @param fromAppId the from app id
2441 * @param graph the graph
2442 * @param edgeLabel the edge label
2443 * @param outV the out V
2444 * @param inV the in V
2445 * @param propHash the prop hash
2446 * @return the titan edge
2447 * @throws AAIException the AAI exception
2450 private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel,
2451 TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash) throws AAIException{
2452 return saveAaiEdgeToDb( transId, fromAppId, graph, edgeLabel,
2453 outV, inV, propHash, null);
2459 * @param transId the trans id
2460 * @param fromAppId the from app id
2461 * @param graph the graph
2462 * @param startVert the start vert
2463 * @param targetVert the target vert
2464 * @param apiVersion the api version
2465 * @return the titan edge
2466 * @throws AAIException the AAI exception
2468 public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
2469 TitanVertex startVert, TitanVertex targetVert, String apiVersion ) throws AAIException{
2470 TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, "");
2477 * @param transId the trans id
2478 * @param fromAppId the from app id
2479 * @param graph the graph
2480 * @param startVert the start vert
2481 * @param targetVert the target vert
2482 * @param apiVersion the api version
2483 * @param edgeType the edge type
2485 * @throws AAIException the AAI exception
2487 public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
2488 TitanVertex startVert, TitanVertex targetVert, String apiVersion, String edgeType ) throws AAIException{
2490 TitanVertex fromVtx = null;
2491 TitanVertex toVtx = null;
2492 String startNodeType = startVert.<String>property("aai-node-type").orElse(null);
2493 String targetNodeType = targetVert.<String>property("aai-node-type").orElse(null);
2494 String fwdRuleKey = startNodeType + "|" + targetNodeType;
2495 int fwdRuleCount = 0;
2496 String fwdRule = "";
2497 String fwdLabel = "";
2498 String revRuleKey = targetNodeType + "|" + startNodeType;
2499 int revRuleCount = 0;
2500 String revRule = "";
2501 String revLabel = "";
2503 String edLabel = "";
2505 Boolean checkType = false;
2506 if( (edgeType != null) && edgeType != "" ){
2510 // As of 16-07, it is possible to have more than one kind of edge defined between a given
2511 // pair of nodeTypes. So we need to check to see if there is only one possibility, or if
2512 // we need to look at the edgeType to determine which to use.
2513 // NOTE -- we're only supporting having 2 edges between a given pair of nodeTypes and
2514 // one and only one of them would have to be a parent-child edge.
2516 if( DbEdgeRules.EdgeRules.containsKey(fwdRuleKey) ){
2517 Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(fwdRuleKey);
2518 Iterator <String> ruleItr = edRuleColl.iterator();
2519 while( ruleItr.hasNext() ){
2520 String tmpRule = ruleItr.next();
2521 String [] rules = tmpRule.split(",");
2522 String tmpLabel = rules[0];
2523 String tmpParChild = rules[3];
2525 || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild"))
2526 || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){
2527 // Either they didn't want us to check the edgeType or it is a match
2529 if( fwdRuleCount > 1 ){
2530 // We found more than one with the given info
2531 throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + startNodeType + "], ["
2532 + targetNodeType + "], edgeType = [" + edgeType + "].");
2536 fwdLabel = tmpLabel;
2542 // Try it the other way also (unless this is the case of a nodeType recursively pointing to itself
2543 // Ie. the edge rule: "model-element|model-element"
2544 if( !revRuleKey.equals(fwdRuleKey) && DbEdgeRules.EdgeRules.containsKey(revRuleKey) ){
2545 Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(revRuleKey);
2546 Iterator <String> ruleItr = edRuleColl.iterator();
2547 while( ruleItr.hasNext() ){
2548 String tmpRule = ruleItr.next();
2549 String [] rules = tmpRule.split(",");
2550 String tmpLabel = rules[0];
2551 String tmpParChild = rules[3];
2553 || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild"))
2554 || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){
2555 // Either they didn't want us to check the edgeType or it is a match
2557 if( revRuleCount > 1 ){
2558 // We found more than one with the given info
2559 throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + targetNodeType + "], ["
2560 + startNodeType + "], edgeType = [" + edgeType + "].");
2564 revLabel = tmpLabel;
2570 if( (fwdRuleCount == 1) && (revRuleCount == 0) ){
2571 // We can use the node info in the order they were given
2572 fromVtx = startVert;
2577 else if( (fwdRuleCount == 0) && (revRuleCount == 1) ){
2578 // We need to switch the vertex order so the edge-direction is correct
2580 fromVtx = targetVert;
2584 else if( (fwdRuleCount == 0) && (revRuleCount == 0) ){
2585 // No edge rule found for this
2586 throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", " + targetNodeType
2587 + "], checkLabelType = [" + edgeType + "].");
2589 else if( (fwdRuleCount > 0) && (revRuleCount > 0) ){
2590 // We found more than one with the given info
2591 throw new AAIException("AAI_6120", "Multiple EdgeRules (fwd and rev) found for nodeTypes: [" + startNodeType + "], ["
2592 + targetNodeType + "], checkLabelType = [" + edgeType + "].");
2595 // If we got to this point, we now have a single edge label and we know to and from Vtx.
2597 HashMap <String,Object> edgeParamHash = getEdgeTagPropPutHash4Rule(transId, fromAppId, edRule);
2598 // We do "source-of-truth" for all edges
2599 edgeParamHash.put("source-of-truth", fromAppId );
2601 TitanEdge returnEdge = saveAaiEdgeToDb(transId, fromAppId, graph, edLabel, fromVtx, toVtx, edgeParamHash, apiVersion);
2610 * @param transId the trans id
2611 * @param fromAppId the from app id
2612 * @param graph the graph
2613 * @param startVert the start vert
2614 * @param targetVert the target vert
2615 * @return the titan edge
2616 * @throws AAIException the AAI exception
2619 public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
2620 TitanVertex startVert, TitanVertex targetVert ) throws AAIException{
2621 return persistAaiEdge( transId, fromAppId, graph,
2622 startVert, targetVert, null);
2624 // End persistAaiEdge()
2630 * @param transId the trans id
2631 * @param fromAppId the from app id
2632 * @param graph the graph
2633 * @param edgeLabel the edge label
2634 * @param startVert the start vert
2635 * @param targetVert the target vert
2636 * @param propHash the prop hash
2637 * @param addIfNotFound the add if not found
2638 * @return the titan edge
2639 * @throws AAIException the AAI exception
2642 public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
2643 String edgeLabel, TitanVertex startVert, TitanVertex targetVert,
2644 HashMap <String,Object> propHash, Boolean addIfNotFound ) throws AAIException{
2646 /*----- This method is depricated ------
2647 * We will ignore the parameters: edgeLabel, propHash and addIfNotFound
2648 * We will use the remaining params to call the newer version of this method
2650 TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, null);
2654 }// End depricated version of persistAaiEdge()
2658 * Persist aai edge with dep params.
2660 * @param transId the trans id
2661 * @param fromAppId the from app id
2662 * @param graph the graph
2663 * @param startVert the start vert
2664 * @param targetNodeType the target node type
2665 * @param targetNodeParamHash the target node param hash
2666 * @param apiVersion the api version
2668 * @throws AAIException the AAI exception
2670 public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
2671 TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash, String apiVersion) throws AAIException{
2673 TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion );
2674 TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion);
2678 }// End persistAaiEdgeWithDepParams()
2680 // Version that lets you pass in an edgeType ("parentChild" or "cousin" since it sometimes cannot be determined
2682 * Persist aai edge with dep params.
2684 * @param transId the trans id
2685 * @param fromAppId the from app id
2686 * @param graph the graph
2687 * @param startVert the start vert
2688 * @param targetNodeType the target node type
2689 * @param targetNodeParamHash the target node param hash
2690 * @param apiVersion the api version
2691 * @param edgeType the edge type
2692 * @return the titan edge
2693 * @throws AAIException the AAI exception
2695 // from the two nodeTypes anymore (16-07)
2696 public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
2697 TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash,
2698 String apiVersion, String edgeType) throws AAIException{
2699 TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion );
2700 TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, edgeType);
2704 }// End persistAaiEdgeWithDepParams()
2707 * Persist aai edge with dep params.
2709 * @param transId the trans id
2710 * @param fromAppId the from app id
2711 * @param graph the graph
2712 * @param startVert the start vert
2713 * @param targetNodeType the target node type
2714 * @param targetNodeParamHash the target node param hash
2715 * @return the titan edge
2716 * @throws AAIException the AAI exception
2719 public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
2720 TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash) throws AAIException{
2721 return persistAaiEdgeWithDepParams( transId, fromAppId, graph,
2722 startVert, targetNodeType, targetNodeParamHash, null);
2726 * Gets the node key prop hash.
2728 * @param transId the trans id
2729 * @param fromAppId the from app id
2730 * @param graph the graph
2731 * @param vtx the vtx
2732 * @return nodeKeyPropHash
2733 * @throws AAIException the AAI exception
2735 public static HashMap <String, Object> getNodeKeyPropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx) throws AAIException{
2738 throw new AAIException("AAI_6109", "null node object passed to getNodeKeyPropHash().");
2741 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
2743 String nType = vtx.<String>property("aai-node-type").orElse(null);
2744 if( ! dbMaps.NodeKeyProps.containsKey(nType) ){
2745 // Problem if no key Properties defined for this nodeType
2746 String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
2747 throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nType + " (ver=" + defVer + ")");
2750 HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>();
2751 Collection <String> keyProps = dbMaps.NodeKeyProps.get(nType);
2752 Iterator <String> keyPropI = keyProps.iterator();
2753 while( keyPropI.hasNext() ){
2754 String propName = keyPropI.next();
2755 Object value = (Object) vtx.<Object>property(propName).orElse(null);
2756 nodeKeyPropsHash.put(propName, value);
2759 return nodeKeyPropsHash;
2761 }// End of getNodeKeyPropHash()
2764 * Gets the node name prop hash.
2766 * @param transId the trans id
2767 * @param fromAppId the from app id
2768 * @param graph the graph
2769 * @param vtx the vtx
2770 * @param apiVersion the api version
2771 * @return nodeKeyPropHash
2772 * @throws AAIException the AAI exception
2774 public static HashMap <String, Object> getNodeNamePropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx, String apiVersion) throws AAIException{
2777 throw new AAIException("AAI_6109", "null node object passed to getNodeNamePropHash()." );
2780 String nType = vtx.<String>property("aai-node-type").orElse(null);
2781 HashMap <String,Object>nodeNamePropsHash = new HashMap<String,Object>();
2782 Collection <String> keyProps = DbMeth.getNodeNameProps(transId, fromAppId, nType, apiVersion);
2783 Iterator <String> keyPropI = keyProps.iterator();
2784 while( keyPropI.hasNext() ){
2785 String propName = keyPropI.next();
2786 Object value = (Object) vtx.<Object>property(propName).orElse(null);
2787 nodeNamePropsHash.put(propName, value);
2790 return nodeNamePropsHash;
2792 }// End of getNodeNamePropHash()
2796 * Removes the aai edge.
2798 * @param transId the trans id
2799 * @param fromAppId the from app id
2800 * @param graph the graph
2801 * @param tEdge the t edge
2804 public static void removeAaiEdge( String transId, String fromAppId, TitanTransaction graph, TitanEdge tEdge){
2805 // Before removing the edge, touch the vertices on each side so their resource-versions will get updated
2806 TitanVertex tmpVIn = tEdge.inVertex();
2807 touchVertex( transId, fromAppId, tmpVIn );
2809 TitanVertex tmpVOut = tEdge.outVertex();
2810 touchVertex( transId, fromAppId, tmpVOut );
2812 // Remove the passed in edge.
2815 }// end of removeAaiEdge()
2819 * Removes the aai node.
2821 * @param transId the trans id
2822 * @param fromAppId the from app id
2823 * @param graph the graph
2824 * @param thisVtx the this vtx
2825 * @param scopeParam the scope param
2826 * @param apiVersion the api version
2827 * @param resourceVersion the resource version
2828 * @throws AAIException the AAI exception
2830 public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
2831 String apiVersion, String resourceVersion ) throws AAIException{
2832 // Note: the resource Version Override flag is only set to true when called by the Model Delete code which
2833 // has no way to know the resource-versions of nodes at lower-levels of it's model topology.
2834 Boolean resVersionOverrideFlag = false;
2835 removeAaiNode( transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, resourceVersion, resVersionOverrideFlag );
2841 * Possible values for deleteScope can be:
2842 * USE_DEFAULT - Get the scope from ref data for this node
2843 * THIS_NODE_ONLY (but should fail if it there are nodes that depend on it for uniqueness)
2844 * CASCADE_TO_CHILDREN - will look for OUT-Edges that have parentOf/hasDelTarget = true and follow those down
2845 * ERROR_4_IN_EDGES_OR_CASCADE - combo of error-if-any-IN-edges + CascadeToChildren
2846 * ERROR_IF_ANY_IN_EDGES - Fail if this node has any existing IN edges
2847 * ERROR_IF_ANY_EDGES - Fail if this node has any existing edges at all!
2850 * @param transId the trans id
2851 * @param fromAppId the from app id
2852 * @param graph the graph
2853 * @param thisVtx the this vtx
2854 * @param scopeParam the scope param
2855 * @param apiVersion the api version
2856 * @param resourceVersion the resource version
2857 * @param resVerOverride the res ver override
2859 * @throws AAIException the AAI exception
2861 public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
2862 String apiVersion, String resourceVersion, Boolean resVerOverride ) throws AAIException{
2863 String nodeType2Del = thisVtx.<String>property("aai-node-type").orElse(null);
2864 String deleteScope = scopeParam;
2865 if( scopeParam.equals("USE_DEFAULT") ){
2866 deleteScope = getDefaultDeleteScope(transId, fromAppId, nodeType2Del, apiVersion);
2869 if( !resVerOverride && needToDoResourceVerCheck(apiVersion, false) ){
2870 // Need to check that they knew what they were deleting
2871 String existingResVer = thisVtx.<String>property("resource-version").orElse(null);
2872 if( resourceVersion == null || resourceVersion.equals("") ){
2873 throw new AAIException("AAI_6130", "Resource-version not passed for delete of = " + nodeType2Del);
2875 else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){
2876 throw new AAIException("AAI_6131", "Resource-version MISMATCH for delete of = " + nodeType2Del);
2880 if( !deleteScope.equals("THIS_NODE_ONLY")
2881 && !deleteScope.equals("CASCADE_TO_CHILDREN")
2882 && !deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE")
2883 && !deleteScope.equals("ERROR_IF_ANY_EDGES")
2884 && !deleteScope.equals("ERROR_IF_ANY_IN_EDGES") ){
2885 throw new AAIException("AAI_6120", "Unrecognized value in deleteScope: [" + deleteScope + "].");
2888 if( deleteScope.equals("ERROR_IF_ANY_EDGES") ){
2889 if ( thisVtx.edges(Direction.BOTH).hasNext() ) {
2890 throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the ERROR_IF_ANY_EDGES scope was used.");
2893 else if( deleteScope.equals("ERROR_IF_ANY_IN_EDGES") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE") ){
2894 Iterator <Edge> eI = thisVtx.edges(Direction.IN);
2895 boolean onlyHasParent = false;
2897 if( eI != null && eI.hasNext() ){
2899 Boolean isParent = temp.<Boolean>property("isParent").orElse(null);
2900 if (isParent != null && isParent && !eI.hasNext()) {
2901 onlyHasParent = true;
2904 if (!onlyHasParent) {
2905 throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the " + deleteScope + " scope was used.");
2909 else if( deleteScope.equals("THIS_NODE_ONLY")){
2910 // Make sure nobody depends on this node.
2911 Iterator<Edge> eI = thisVtx.edges(Direction.BOTH);
2912 while( eI.hasNext() ){
2913 TitanEdge ed = (TitanEdge) eI.next();
2914 TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx);
2915 String nodeTypeA = otherVtx.<String>property("aai-node-type").orElse(null);
2916 if( nodeTypeACanDependOnB(transId, fromAppId, nodeTypeA, nodeType2Del, apiVersion)){
2917 // We're only supposed to delete this node - but another node is dependant on it,
2918 // so we shouldn't delete this one.
2919 throw new AAIException("AAI_6110", "Node cannot be deleted using scope = " + deleteScope +
2920 " another node (type = " + nodeTypeA + ") depends on it for uniqueness.");
2925 // We've passed our checks - so do some deleting of edges and maybe pass
2926 // the delete request down to children or delete-targets.
2928 // First we deal with the "IN"-Edges which can't have children/delete-targets which
2929 // by definition (of "IN") on the other end
2930 Iterator <Edge> eI_In = thisVtx.edges(Direction.IN);
2931 while( eI_In.hasNext() ){
2932 TitanEdge ed = (TitanEdge) eI_In.next();
2934 //- "touch" vertex on other side of this edge so it gets a fresh resource-version
2935 TitanVertex tmpVOther = ed.otherVertex(thisVtx);
2936 touchVertex( transId, fromAppId, tmpVOther );
2941 // Now look at the "OUT"-edges which might include children or delete-targets
2942 String cascadeMsg = "This nt = " + nodeType2Del + ", Cascading del to: ";
2943 Iterator <Edge> eI_Out = thisVtx.edges(Direction.OUT);
2944 if( !eI_Out.hasNext() ){
2945 cascadeMsg = cascadeMsg + "[no children for this node]";
2947 while( eI_Out.hasNext() ){
2948 TitanEdge ed = (TitanEdge) eI_Out.next();
2950 // "touch" vertex on other side of this edge so it gets a fresh resource-version
2951 TitanVertex tmpVOther = ed.otherVertex(thisVtx);
2952 touchVertex( transId, fromAppId, tmpVOther );
2954 Boolean otherVtxAChild = ed.<Boolean>property("isParent").orElse(null);
2955 if( otherVtxAChild == null ){
2956 otherVtxAChild = false;
2959 Boolean otherVtxADeleteTarget = ed.<Boolean>property("hasDelTarget").orElse(null);
2960 if( otherVtxADeleteTarget == null ){
2961 otherVtxADeleteTarget = false;
2964 if( (otherVtxAChild || otherVtxADeleteTarget) &&
2965 (deleteScope.equals("CASCADE_TO_CHILDREN") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE")) ){
2966 // Delete the edge to the child and Pass the delete down to it.
2968 TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx);
2969 String vid = otherVtx.id().toString();
2970 String nty = otherVtx.<String>property("aai-node-type").orElse(null);
2971 String resVers = otherVtx.<String>property("resource-version").orElse(null);
2972 cascadeMsg = cascadeMsg + "[" + nty + ":" + vid + "]";
2973 removeAaiNode(transId, fromAppId, graph, otherVtx, "CASCADE_TO_CHILDREN", apiVersion, resVers);
2976 // The other node is not a child or deleteTarget. Delete the edge to it if it is not
2977 // dependent (Should never be dependent since it's not a child/delTarget... but
2978 // someone could create a node that was dependent for Uniqueness without
2979 // being a child/target.
2981 // DEBUG -- eventually add the check for dependancy that isn't on a parent-type or delTarget-type edge
2986 LOGGER.info(cascadeMsg);
2988 Iterator<Edge> eI = thisVtx.edges(Direction.BOTH);
2989 if( ! eI.hasNext() ){
2990 // By this point, either there were no edges to deal with, or we have dealt with them.
2994 // Something went wrong and we couldn't delete all the edges for this guy.
2995 throw new AAIException("AAI_6110", "Node could be deleted because it unexpectedly still has Edges.\n");
3001 * Removes the aai node.
3003 * @param transId the trans id
3004 * @param fromAppId the from app id
3005 * @param graph the graph
3006 * @param thisVtx the this vtx
3007 * @param scopeParam the scope param
3009 * @throws AAIException the AAI exception
3012 public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam) throws AAIException{
3013 removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, null, null);
3017 * Removes the aai node.
3019 * @param transId the trans id
3020 * @param fromAppId the from app id
3021 * @param graph the graph
3022 * @param thisVtx the this vtx
3023 * @param scopeParam the scope param
3024 * @param apiVersion the api version
3025 * @throws AAIException the AAI exception
3028 public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
3029 String apiVersion ) throws AAIException{
3030 removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, null);
3032 // end of removeAaiNode()
3036 * Delete all graph data.
3038 * @param transId the trans id
3039 * @param fromAppId the from app id
3040 * @param graph the graph
3043 public static void deleteAllGraphData( String transId, String fromAppId, TitanGraph graph ){
3044 /** ======================================================================
3045 * WARNING -- this removes ALL the data that is currently in the graph.
3046 * ======================================================================
3048 LOGGER.warn("deleteAllGraphData called! Run for the hills!");
3049 Iterator<Edge> edges = graph.edges(Direction.BOTH);
3050 graph.tx().commit();
3052 while (edges.hasNext()) {
3053 edge = edges.next();
3056 graph.tx().commit();
3057 Iterator<Vertex> vertices = graph.vertices();
3058 graph.tx().commit();
3059 Vertex vertex = null;
3060 while (vertices.hasNext()) {
3061 vertex = vertices.next();
3064 graph.tx().commit();
3069 * Show all edges for node.
3071 * @param transId the trans id
3072 * @param fromAppId the from app id
3073 * @param tVert the t vert
3074 * @return the array list
3076 public static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){
3078 ArrayList <String> retArr = new ArrayList <String> ();
3079 Iterator <Edge> eI = tVert.edges(Direction.IN);
3080 if( ! eI.hasNext() ){
3081 retArr.add("No IN edges were found for this vertex. ");
3083 while( eI.hasNext() ){
3084 TitanEdge ed = (TitanEdge) eI.next();
3085 String lab = ed.label();
3086 TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
3088 retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
3091 String nType = vtx.<String>property("aai-node-type").orElse(null);
3092 String vid = vtx.id().toString();
3093 retArr.add("Found an IN edge (" + lab + ") to this vertex from a [" + nType + "] node with VtxId = " + vid );
3095 //showPropertiesForEdge( transId, fromAppId, ed );
3099 eI = tVert.edges(Direction.OUT);
3100 if( ! eI.hasNext() ){
3101 retArr.add("No OUT edges were found for this vertex. ");
3103 while( eI.hasNext() ){
3104 TitanEdge ed = (TitanEdge) eI.next();
3105 String lab = ed.label();
3106 TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
3108 retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
3111 String nType = vtx.<String>property("aai-node-type").orElse(null);
3112 String vid = vtx.id().toString();
3113 retArr.add("Found an OUT edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid );
3115 //showPropertiesForEdge( transId, fromAppId, ed );
3123 * Show properties for node.
3125 * @param transId the trans id
3126 * @param fromAppId the from app id
3127 * @param tVert the t vert
3128 * @return the array list
3130 public static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){
3132 ArrayList <String> retArr = new ArrayList <String> ();
3133 if( tVert == null ){
3134 retArr.add("null Node object passed to showPropertiesForNode()\n");
3137 String nodeType = "";
3138 //String datType = "";
3139 Object ob = tVert.<Object>property("aai-node-type").orElse(null);
3144 nodeType = ob.toString();
3145 //datType = ob.getClass().getSimpleName();
3148 retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]");
3149 retArr.add(" Property Detail: ");
3150 Iterator<VertexProperty<Object>> pI = tVert.properties();
3151 while( pI.hasNext() ){
3152 VertexProperty<Object> tp = pI.next();
3153 Object val = tp.value();
3154 //retArr.add("Prop: [" + tp.getPropertyKey() + "], val = [" + val + "], dataType = " + val.getClass() );
3155 retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] ");
3163 * Gets the node name props.
3165 * @param transId the trans id
3166 * @param fromAppId the from app id
3167 * @param nodeType the node type
3168 * @param apiVersion the api version
3169 * @return HashMap of keyProperties
3170 * @throws AAIException the AAI exception
3172 public static Collection <String> getNodeNameProps( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
3174 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
3176 Collection <String> nameProps = new ArrayList <String>();
3177 if( dbMaps.NodeNameProps.containsKey(nodeType) ){
3178 nameProps = dbMaps.NodeNameProps.get(nodeType);
3180 else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
3181 // The passed-in nodeType was really a nodeCategory, theoretically, all the guys in the same
3182 // category should have the same name property -- so if they just give us the category, we will
3183 // just give the name info from the first nodeType we encounter of that category.
3184 Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
3185 Iterator <String> catItr = nTypeCatCol.iterator();
3186 String catInfo = "";
3187 if( catItr.hasNext() ){
3188 // For now, we only look for one.
3189 catInfo = catItr.next();
3192 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType);
3195 String [] flds = catInfo.split(",");
3196 if( flds.length != 4 ){
3197 throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
3200 String nodeTypesString = flds[0];
3201 String [] nodeTypeNames = nodeTypesString.split("\\|");
3202 if( nodeTypeNames != null && nodeTypeNames.length > 0 ){
3203 // We'll just use the first one
3204 String nt = nodeTypeNames[0];
3205 nameProps = dbMaps.NodeNameProps.get(nt);
3210 // Note - it's ok if there was no defined name property for this nodeType.
3214 }// end of getNodeKeyPropNames
3218 * Gets the edge tag prop put hash 4 rule.
3220 * @param transId the trans id
3221 * @param fromAppId the from app id
3222 * @param edRule the ed rule
3223 * @return the edge tag prop put hash 4 rule
3224 * @throws AAIException the AAI exception
3226 public static HashMap <String,Object> getEdgeTagPropPutHash4Rule( String transId, String fromAppId, String edRule )
3227 throws AAIException{
3228 // For a given edgeRule - already pulled out of DbEdgeRules.EdgeRules -- parse out the "tags" that
3229 // need to be set for this kind of edge.
3230 // These are the Boolean properties like, "isParent", "usesResource" etc.
3231 HashMap <String,Object> retEdgePropPutMap = new HashMap <String,Object>();
3233 if( (edRule == null) || edRule.equals("") ){
3234 // No edge rule found for this
3235 throw new AAIException("AAI_6120", "blank edRule passed to getEdgeTagPropPutHash4Rule()");
3238 int tagCount = DbEdgeRules.EdgeInfoMap.size();
3239 String [] rules = edRule.split(",");
3240 if( rules.length != tagCount ){
3241 throw new AAIException("AAI_6121", "Bad EdgeRule data (itemCount =" + rules.length + ") for rule = [" + edRule + "].");
3244 // In DbEdgeRules.EdgeRules -- What we have as "edRule" is a comma-delimited set of strings.
3245 // The first item is the edgeLabel.
3246 // The second in the list is always "direction" which is always OUT for the way we've implemented it.
3247 // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to
3248 // tags as defined in EdgeInfoMap.
3249 // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it
3250 for( int i = DbEdgeRules.firstTagIndex; i < tagCount; i++ ){
3251 String booleanStr = rules[i];
3252 Integer mapKey = new Integer(i);
3253 String propName = DbEdgeRules.EdgeInfoMap.get(mapKey);
3254 String revPropName = propName + "-REV";
3256 if( booleanStr.equals("true") ){
3257 retEdgePropPutMap.put(propName, true);
3258 retEdgePropPutMap.put(revPropName,false);
3260 else if( booleanStr.equals("false") ){
3261 retEdgePropPutMap.put(propName, false);
3262 retEdgePropPutMap.put(revPropName,false);
3264 else if( booleanStr.equals("reverse") ){
3265 retEdgePropPutMap.put(propName, false);
3266 retEdgePropPutMap.put(revPropName,true);
3269 throw new AAIException("AAI_6121", "Bad EdgeRule data for rule = [" + edRule + "], val = [" + booleanStr + "].");
3274 return retEdgePropPutMap;
3276 } // End of getEdgeTagPropPutHash()
3281 * Gets the edge tag prop put hash.
3283 * @param transId the trans id
3284 * @param fromAppId the from app id
3285 * @param edgeRuleKey the edge rule key
3286 * @return the edge tag prop put hash
3287 * @throws AAIException the AAI exception
3289 public static Map<String, EdgeRule> getEdgeTagPropPutHash( String transId, String fromAppId, String edgeRuleKey )
3290 throws AAIException{
3291 // For a given edgeRuleKey (nodeTypeA|nodeTypeB), look up the rule that goes with it in
3292 // DbEdgeRules.EdgeRules and parse out the "tags" that need to be set on each edge.
3293 // These are the Boolean properties like, "isParent", "usesResource" etc.
3294 // Note - this code is also used by the updateEdgeTags.java code
3296 String[] edgeRuleKeys = edgeRuleKey.split("\\|");
3298 if (edgeRuleKeys.length < 2 || ! EdgeRules.getInstance().hasEdgeRule(edgeRuleKeys[0], edgeRuleKeys[1])) {
3299 throw new AAIException("AAI_6120", "Could not find an DbEdgeRule entry for passed edgeRuleKey (nodeTypeA|nodeTypeB): " + edgeRuleKey + ".");
3302 Map<String, EdgeRule> edgeRules = EdgeRules.getInstance().getEdgeRules(edgeRuleKeys[0], edgeRuleKeys[1]);
3306 } // End of getEdgeTagPropPutHash()
3310 * This property was put by newer version of code.
3312 * @param apiVersionStr the api version str
3313 * @param nodeType the node type
3314 * @param propName the prop name
3315 * @return true, if successful
3316 * @throws AAIException the AAI exception
3318 private static boolean thisPropertyWasPutByNewerVersionOfCode( String apiVersionStr,
3319 String nodeType, String propName) throws AAIException{
3320 // We want to return True if the nodeType + property-name combo was introduced AFTER the apiVersion passed.
3323 int propIntroVerInt = 0;
3325 if( apiVersionStr == null || apiVersionStr.equals("") ){
3326 apiVersionStr = org.openecomp.aai.util.AAIApiVersion.get();
3328 apiVerInt = getVerNumFromVerString(apiVersionStr);
3329 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
3330 String propIntroKey = nodeType + "|" + propName;
3331 if( propName.equals("prov-status") ){
3332 // This is a special case -- The dbMaps from v2 has it in there, but it was introduced half way through. So
3333 // it needs to be catogorized as v3.
3334 propIntroVerInt = 3;
3336 else if( ! dbMaps.PropertyVersionInfoMap.containsKey(propIntroKey) ){
3337 String detail = propIntroKey + " [" + propIntroKey + "] not found in dbMaps.PropertyVersionInfoMap.";
3338 throw new AAIException("AAI_6121", detail);
3341 String propIntroVerString = dbMaps.PropertyVersionInfoMap.get(propIntroKey);
3342 propIntroVerInt = getVerNumFromVerString( propIntroVerString );
3345 if( propIntroVerInt > apiVerInt ){
3352 } // End of thisPropertyWasPutByNewerVersionOfCode()
3358 * @param transId the trans id
3359 * @param fromAppId the from app id
3363 public static void touchVertex( String transId, String fromAppId, TitanVertex v ){
3364 // We want to "touch" the vertex -- Ie. update it's last-mod-date, last-mod- resource-version to the current date/time
3366 long unixTimeNow = System.currentTimeMillis() / 1000L;
3367 String timeNowInSec = "" + unixTimeNow;
3368 v.property( "aai-last-mod-ts", timeNowInSec );
3369 v.property( "resource-version", timeNowInSec );
3370 v.property( "last-mod-source-of-truth", fromAppId );
3372 } // End of touchVertex()
3376 * Check prop cardinality.
3378 * @param propName the prop name
3379 * @param cardinalityType the cardinality type
3381 * @throws AAIException the AAI exception
3383 public static boolean checkPropCardinality( String propName, String cardinalityType ) throws AAIException {
3385 // Return true if the named property is tagged in our dbMaps PropetyDataTypeMap as
3386 // having the passed in cardinality type.
3387 // NOTE: supported cardinality types in dbMaps = "Set" or "List"
3388 // In Titan (and ex5.json), those go in as "SET" and "LIST"
3389 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
3391 if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){
3392 String propDataType = dbMaps.PropertyDataTypeMap.get(propName);
3393 if( propDataType != null && propDataType.startsWith(cardinalityType) ){
3399 } // End of checkPropCardinality()
3402 * Convert type if needed.
3404 * @param propName the prop name
3405 * @param val the val
3406 * @return convertedValue (if it was a String but needed to be a Boolean)
3407 * @throws AAIException the AAI exception
3409 public static Object convertTypeIfNeeded( String propName, Object val )
3410 throws AAIException {
3411 // Make sure the dataType of the passed-in Object matches what the DB expects
3413 // NOTE: since this is a fix very late in our dev cycle, we'll just fix the scenarios that
3414 // we're having trouble with which is Strings getting into the db which should be going in as
3415 // Booleans or Integers.
3416 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
3418 if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){
3419 String dbExpectedDataType = dbMaps.PropertyDataTypeMap.get(propName);
3420 if( dbExpectedDataType != null
3421 && dbExpectedDataType.equals("Boolean")
3423 && !(val instanceof Boolean) ){
3424 String valStr = val.toString().trim();
3425 if( valStr.equals("true") || valStr.equals("True") || valStr.equals("TRUE") ){
3426 return Boolean.valueOf("true");
3428 else if( valStr.equals("false") || valStr.equals("False") || valStr.equals("FALSE") ){
3429 return Boolean.valueOf("false");
3432 String emsg = "Error trying to convert value: [" + valStr + "] to a Boolean for property + " + propName + "\n";
3433 throw new AAIException("AAI_6120", emsg);
3436 else if( dbExpectedDataType != null
3437 && dbExpectedDataType.equals("Integer")
3439 && !(val.toString().trim().equals(""))
3440 && !(val instanceof Integer) ){
3441 String valStr = val.toString().trim();
3444 newInt = Integer.valueOf(valStr);
3447 catch( Exception e ){
3448 String emsg = "Error trying to convert value: [" + valStr + "] to an Integer for property + " + propName + "\n";
3449 throw new AAIException("AAI_6120", emsg);
3454 // If it didn't need to be converted, just return it.
3457 } // End of convertTypeIfNeeded()
3462 * This vertex not reachable.
3464 * @param transId the trans id
3465 * @param fromAppId the from app id
3466 * @param graph the graph
3468 * @param version the version
3471 public static boolean thisVertexNotReachable( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){
3479 catch( Exception ex ){
3480 // Could not get this -- sometimes we're holding a vertex object that has gotten deleted, so
3481 // when we try to get stuff from it, we get an "Element Has Been Removed" error from Titan
3488 } // End of thisVertexNotReachable()
3491 * This vertex has bad edges.
3493 * @param transId the trans id
3494 * @param fromAppId the from app id
3495 * @param graph the graph
3497 * @param version the version
3500 public static boolean thisVertexHasBadEdges( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){
3502 Iterator <Edge> eItor = v.edges(Direction.BOTH);
3503 while( eItor.hasNext() ){
3509 Vertex vIn = e.inVertex();
3510 if( (vIn == null) || (vIn.<String>property("aai-node-type").orElse(null) == null) ){
3511 // this is a bad edge because it points to a vertex that isn't there anymore
3515 Vertex vOut = e.outVertex();
3516 if( (vOut == null) || (vOut.<String>property("aai-node-type").orElse(null) == null) ){
3517 // this is a bad edge because it points to a vertex that isn't there anymore
3522 // If we made it to here, the vertex's edges must be ok.
3525 } // End of thisVertexHasBadEdges()
3529 * This vertex is A phantom.
3531 * @param transId the trans id
3532 * @param fromAppId the from app id
3533 * @param graph the graph
3535 * @param version the version
3537 * @throws AAIException the AAI exception
3539 public static boolean thisVertexIsAPhantom( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version )
3540 throws AAIException {
3543 // The kind of Phantom we're looking for is the kind that we sometimes get when we do a select without
3544 // using key properties. They can be in the database as a vertex, but the indexes that should point to
3545 // them are not working -- so they cannot be used by normal interfaces (like the REST API) which means
3546 // that if we return it, it can mess up a caller who tries to use it.
3550 String thisVid = v.id().toString();
3552 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
3554 Object propOb = v.<Object>property("aai-node-type").orElse(null);
3555 if( propOb == null ){
3556 // This vertex does not have an aai-node-type ---> it is messed up
3559 String nType = propOb.toString();
3560 if( ! dbMaps.NodeKeyProps.containsKey(nType) ){
3561 // This node Type does not have keys defined
3562 // This could just be bad reference data, so we will not flag this guy, but we
3563 // can't really do our test...
3567 HashMap <String,Object> propHashWithKeys = new HashMap<String, Object>();
3568 Collection <String> keyProps = null;
3570 keyProps = getNodeKeyPropNames(transId, fromAppId, nType, version);
3572 catch (AAIException ex) {
3573 // something wrong with getting this guy's key property names - we'll abandon this test...
3577 Iterator <String> keyPropI = keyProps.iterator();
3578 while( keyPropI.hasNext() ){
3579 String propName = keyPropI.next();
3580 String propVal = "";
3581 Object ob = v.<Object>property(propName).orElse(null);
3583 propVal = ob.toString();
3585 propHashWithKeys.put(propName, propVal);
3588 // Note - We can get more than one back since some nodes need a dep. node for uniqueness.
3589 // We don't care about that -- we just want to make sure we can get this vertex back when
3590 // we're searching with it's indexed fields.
3591 // NOTE - we're passing the skipGroomCheck to getNodes so we don't wind up in an infinite loop
3592 ArrayList <TitanVertex> vertList2 = getNodes( transId, fromAppId, graph, nType, propHashWithKeys, false, version, true );
3593 Iterator<TitanVertex> iter2 = vertList2.iterator();
3594 while( iter2.hasNext() ){
3595 TitanVertex tvx2 = iter2.next();
3596 String foundId = tvx2.id().toString();
3597 if( foundId.equals( thisVid ) ){
3598 // We could get back the vertex by looking it up using key properties... That's good.
3603 catch (Exception e2) {
3604 //String msg = " Error encountered for this vertex id: [" + thisVid +
3605 // "]. Caught this exception: " + e2.toString();
3606 // Something messed up - but that doesn't prove that this is a phantom.
3610 // If we dropped down to here, we have looked but could not pull the vertex out of the
3611 // db using it's key fields, so it gets flagged as a Phantom.
3614 } // End of thisVertexIsAPhantom()
3618 * Gets the node by unique key.
3620 * @param transId the trans id
3621 * @param fromAppId the from app id
3622 * @param graph the graph
3623 * @param aaiUniquekey the aai uniquekey
3624 * @return the node by unique key
3626 public TitanVertex getNodeByUniqueKey(String transId, String fromAppId, TitanTransaction graph, String aaiUniquekey) {
3628 TitanVertex vert = null;
3630 Iterator<?> vertI = graph.query().has("aai-unique-key", aaiUniquekey).vertices().iterator();
3632 if( vertI != null && vertI.hasNext()) {
3633 // We found a vertex that meets the input criteria.
3634 vert = (TitanVertex) vertI.next();