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();