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.io.BufferedReader;
24 import java.io.BufferedWriter;
26 import java.io.FileReader;
27 import java.io.FileWriter;
28 import java.io.IOException;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Date;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.LinkedHashSet;
36 import java.util.List;
38 import java.util.Properties;
40 import java.util.TimeZone;
41 import java.util.UUID;
43 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
44 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
45 import org.apache.tinkerpop.gremlin.structure.Direction;
46 import org.apache.tinkerpop.gremlin.structure.Edge;
47 import org.apache.tinkerpop.gremlin.structure.Property;
48 import org.apache.tinkerpop.gremlin.structure.Vertex;
49 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
51 import org.openecomp.aai.dbmap.AAIGraph;
52 import org.openecomp.aai.exceptions.AAIException;
53 import org.openecomp.aai.ingestModel.DbMaps;
54 import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
55 import org.openecomp.aai.logging.ErrorLogHelper;
56 import org.openecomp.aai.util.AAIConfig;
57 import org.openecomp.aai.util.AAIConstants;
58 import com.att.eelf.configuration.Configuration;
59 import com.att.eelf.configuration.EELFLogger;
60 import com.att.eelf.configuration.EELFManager;
61 import com.thinkaurelius.titan.core.TitanEdge;
62 import com.thinkaurelius.titan.core.TitanFactory;
63 import com.thinkaurelius.titan.core.TitanGraph;
64 import com.thinkaurelius.titan.core.TitanTransaction;
65 import com.thinkaurelius.titan.core.TitanVertex;
68 public class DataGrooming {
70 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DataGrooming.class);
71 private static final String FROMAPPID = "AAI-DB";
72 private static final String TRANSID = UUID.randomUUID().toString();
73 private static int dupeGrpsDeleted = 0;
78 * @param args the arguments
80 public static void main(String[] args) {
82 // Set the logging file properties to be used by EELFManager
83 Properties props = System.getProperties();
84 props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, AAIConstants.AAI_DATA_GROOMING_LOGBACK_PROPS);
85 props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
87 String ver = "version"; // Placeholder
88 Boolean doAutoFix = false;
89 Boolean edgesOnlyFlag = false;
90 Boolean dontFixOrphansFlag = false;
91 Boolean singleCommits = false;
92 Boolean dupeCheckOff = false;
93 Boolean dupeFixOn = false;
94 Boolean ghost2CheckOff = false;
95 Boolean ghost2FixOn = false;
96 Boolean neverUseCache = false;
98 int maxRecordsToFix = AAIConstants.AAI_GROOMING_DEFAULT_MAX_FIX;
99 int sleepMinutes = AAIConstants.AAI_GROOMING_DEFAULT_SLEEP_MINUTES;
101 String maxFixStr = AAIConfig.get("aai.grooming.default.max.fix");
102 if( maxFixStr != null && !maxFixStr.equals("") ){
103 maxRecordsToFix = Integer.parseInt(maxFixStr);
105 String sleepStr = AAIConfig.get("aai.grooming.default.sleep.minutes");
106 if( sleepStr != null && !sleepStr.equals("") ){
107 sleepMinutes = Integer.parseInt(sleepStr);
110 catch ( Exception e ){
111 // Don't worry, we'll just use the defaults that we got from AAIConstants
112 LOGGER.warn("WARNING - could not pick up aai.grooming values from aaiconfig.properties file. ");
115 String prevFileName = "";
117 SimpleDateFormat d = new SimpleDateFormat("yyyyMMddHHmm");
118 d.setTimeZone(TimeZone.getTimeZone("GMT"));
119 String dteStr = d.format(new Date()).toString();
120 String groomOutFileName = "dataGrooming." + dteStr + ".out";
122 if (args.length > 0) {
123 // They passed some arguments in that will affect processing
124 for (int i = 0; i < args.length; i++) {
125 String thisArg = args[i];
126 if (thisArg.equals("-edgesOnly")) {
127 edgesOnlyFlag = true;
128 } else if (thisArg.equals("-autoFix")) {
130 } else if (thisArg.equals("-dontFixOrphans")) {
131 dontFixOrphansFlag = true;
132 } else if (thisArg.equals("-singleCommits")) {
133 singleCommits = true;
134 } else if (thisArg.equals("-dupeCheckOff")) {
136 } else if (thisArg.equals("-dupeFixOn")) {
138 } else if (thisArg.equals("-ghost2CheckOff")) {
139 ghost2CheckOff = true;
140 } else if (thisArg.equals("-neverUseCache")) {
141 neverUseCache = true;
142 } else if (thisArg.equals("-ghost2FixOn")) {
144 } else if (thisArg.equals("-maxFix")) {
146 if (i >= args.length) {
147 LOGGER.error(" No value passed with -maxFix option. ");
150 String nextArg = args[i];
152 maxRecordsToFix = Integer.parseInt(nextArg);
153 } catch (Exception e) {
154 LOGGER.error("Bad value passed with -maxFix option: ["
158 } else if (thisArg.equals("-sleepMinutes")) {
160 if (i >= args.length) {
161 LOGGER.error("No value passed with -sleepMinutes option.");
164 String nextArg = args[i];
166 sleepMinutes = Integer.parseInt(nextArg);
167 } catch (Exception e) {
168 LOGGER.error("Bad value passed with -sleepMinutes option: ["
172 } else if (thisArg.equals("-f")) {
174 if (i >= args.length) {
175 LOGGER.error(" No value passed with -f option. ");
178 prevFileName = args[i];
180 LOGGER.error(" Unrecognized argument passed to DataGrooming: ["
182 LOGGER.error(" Valid values are: -f -autoFix -maxFix -edgesOnly -dupeFixOn -donFixOrphans -sleepMinutes -neverUseCache");
189 IngestModelMoxyOxm moxyMod = new IngestModelMoxyOxm();
191 ArrayList <String> defaultVerLst = new ArrayList <> ();
192 defaultVerLst.add( AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP) );
193 moxyMod.init( defaultVerLst, false);
195 catch (Exception ex){
196 LOGGER.error("ERROR - Could not do the moxyMod.init()", ex);
201 if (!prevFileName.equals("")) {
202 // They are trying to fix some data based on a data in a
204 LOGGER.info(" Call doTheGrooming() with a previous fileName ["
205 + prevFileName + "] for cleanup. ");
206 Boolean finalShutdownFlag = true;
207 Boolean cacheDbOkFlag = false;
208 doTheGrooming(prevFileName, edgesOnlyFlag, dontFixOrphansFlag,
209 maxRecordsToFix, groomOutFileName, ver, singleCommits,
210 dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
211 finalShutdownFlag, cacheDbOkFlag);
212 } else if (doAutoFix) {
213 // They want us to run the processing twice -- first to look for
214 // delete candidates, then after
215 // napping for a while, run it again and delete any candidates
216 // that were found by the first run.
217 // Note: we will produce a separate output file for each of the
219 LOGGER.info(" Doing an auto-fix call to Grooming. ");
220 LOGGER.info(" First, Call doTheGrooming() to look at what's out there. ");
221 Boolean finalShutdownFlag = false;
222 Boolean cacheDbOkFlag = true;
223 int fixCandCount = doTheGrooming("", edgesOnlyFlag,
224 dontFixOrphansFlag, maxRecordsToFix, groomOutFileName,
225 ver, singleCommits, dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
226 finalShutdownFlag, cacheDbOkFlag);
227 if (fixCandCount == 0) {
228 LOGGER.info(" No fix-Candidates were found by the first pass, so no second/fix-pass is needed. ");
230 // We'll sleep a little and then run a fix-pass based on the
231 // first-run's output file.
233 LOGGER.info("About to sleep for " + sleepMinutes
235 int sleepMsec = sleepMinutes * 60 * 1000;
236 Thread.sleep(sleepMsec);
237 } catch (InterruptedException ie) {
238 LOGGER.info("\n >>> Sleep Thread has been Interrupted <<< ");
242 d = new SimpleDateFormat("yyyyMMddHHmm");
243 d.setTimeZone(TimeZone.getTimeZone("GMT"));
244 dteStr = d.format(new Date()).toString();
245 String secondGroomOutFileName = "dataGrooming." + dteStr
247 LOGGER.info(" Now, call doTheGrooming() a second time and pass in the name of the file "
248 + "generated by the first pass for fixing: ["
249 + groomOutFileName + "]");
250 finalShutdownFlag = true;
251 cacheDbOkFlag = false;
252 doTheGrooming(groomOutFileName, edgesOnlyFlag,
253 dontFixOrphansFlag, maxRecordsToFix,
254 secondGroomOutFileName, ver, singleCommits,
255 dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
256 finalShutdownFlag, cacheDbOkFlag);
259 // Do the grooming - plain vanilla (no fix-it-file, no
261 Boolean finalShutdownFlag = true;
262 LOGGER.info(" Call doTheGrooming() ");
263 Boolean cacheDbOkFlag = true;
265 // They have forbidden us from using a cached db connection.
266 cacheDbOkFlag = false;
268 doTheGrooming("", edgesOnlyFlag, dontFixOrphansFlag,
269 maxRecordsToFix, groomOutFileName, ver, singleCommits,
270 dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
271 finalShutdownFlag, cacheDbOkFlag);
273 } catch (Exception ex) {
274 LOGGER.error("Exception while grooming data", ex);
277 LOGGER.info(" Done! ");
285 * @param fileNameForFixing the file name for fixing
286 * @param edgesOnlyFlag the edges only flag
287 * @param dontFixOrphansFlag the dont fix orphans flag
288 * @param maxRecordsToFix the max records to fix
289 * @param groomOutFileName the groom out file name
290 * @param version the version
291 * @param singleCommits the single commits
292 * @param dupeCheckOff the dupe check off
293 * @param dupeFixOn the dupe fix on
294 * @param ghost2CheckOff the ghost 2 check off
295 * @param ghost2FixOn the ghost 2 fix on
296 * @param finalShutdownFlag the final shutdown flag
297 * @param cacheDbOkFlag the cacheDbOk flag
300 private static int doTheGrooming(String fileNameForFixing,
301 Boolean edgesOnlyFlag, Boolean dontFixOrphansFlag,
302 int maxRecordsToFix, String groomOutFileName, String version,
303 Boolean singleCommits,
304 Boolean dupeCheckOff, Boolean dupeFixOn,
305 Boolean ghost2CheckOff, Boolean ghost2FixOn,
306 Boolean finalShutdownFlag, Boolean cacheDbOkFlag) {
308 LOGGER.debug(" Entering doTheGrooming \n");
310 int cleanupCandidateCount = 0;
311 BufferedWriter bw = null;
312 TitanGraph graph = null;
313 TitanGraph graph2 = null;
315 boolean executeFinalCommit = false;
316 Set<String> deleteCandidateList = new LinkedHashSet<>();
317 Set<String> processedVertices = new LinkedHashSet<>();
318 TitanTransaction g = null;
319 TitanTransaction g2 = null;
322 String targetDir = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP
323 + "logs" + AAIConstants.AAI_FILESEP + "data"
324 + AAIConstants.AAI_FILESEP + "dataGrooming";
326 // Make sure the target directory exists
327 new File(targetDir).mkdirs();
329 if (!fileNameForFixing.equals("")) {
330 deleteCandidateList = getDeleteList(targetDir,
331 fileNameForFixing, edgesOnlyFlag, dontFixOrphansFlag,
335 if (deleteCandidateList.size() > maxRecordsToFix) {
336 LOGGER.warn(" >> WARNING >> Delete candidate list size ("
337 + deleteCandidateList.size()
338 + ") is too big. The maxFix we are using is: "
340 + ". No candidates will be deleted. ");
341 // Clear out the list so it won't be processed below.
342 deleteCandidateList = new LinkedHashSet<>();
345 SimpleDateFormat d = new SimpleDateFormat("yyyyMMddHHmm");
346 d.setTimeZone(TimeZone.getTimeZone("GMT"));
348 String fullOutputFileName = targetDir + AAIConstants.AAI_FILESEP
350 File groomOutFile = new File(fullOutputFileName);
352 groomOutFile.createNewFile();
353 } catch (IOException e) {
354 String emsg = " Problem creating output file ["
355 + fullOutputFileName + "], exception=" + e.getMessage();
356 throw new AAIException("AAI_6124", emsg);
359 LOGGER.info(" Will write to " + fullOutputFileName );
360 FileWriter fw = new FileWriter(groomOutFile.getAbsoluteFile());
361 bw = new BufferedWriter(fw);
362 ErrorLogHelper.loadProperties();
364 LOGGER.info(" ---- NOTE --- about to open graph (takes a little while)--------\n");
367 // Since we're just reading (not deleting/fixing anything), we can use
368 // a cached connection to the DB
369 graph = TitanFactory.open(AAIConstants.CACHED_DB_CONFIG);
372 graph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG);
375 String emsg = "null graph object in DataGrooming\n";
376 throw new AAIException("AAI_6101", emsg);
379 LOGGER.debug(" Got the graph object. ");
381 g = graph.newTransaction();
383 String emsg = "null graphTransaction object in DataGrooming\n";
384 throw new AAIException("AAI_6101", emsg);
388 ArrayList<String> errArr = new ArrayList<>();
389 int totalNodeCount = 0;
390 HashMap<String, String> misMatchedHash = new HashMap<String, String>();
391 HashMap<String, TitanVertex> orphanNodeHash = new HashMap<String, TitanVertex>();
392 HashMap<String, TitanVertex> missingDepNodeHash = new HashMap<String, TitanVertex>();
393 HashMap<String, Edge> oneArmedEdgeHash = new HashMap<String, Edge>();
394 HashMap<String, String> emptyVertexHash = new HashMap<String, String>();
395 HashMap<String, TitanVertex> ghostNodeHash = new HashMap<String, TitanVertex>();
396 ArrayList<String> dupeGroups = new ArrayList<>();
399 DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
401 Iterator<String> nodeMapKPropsIterator = dbMaps.NodeKeyProps.keySet().iterator();
404 LOGGER.info(" Starting DataGrooming Processing ");
407 LOGGER.info(" NOTE >> Skipping Node processing as requested. Will only process Edges. << ");
410 while (nodeMapKPropsIterator.hasNext()) {
411 String nType = nodeMapKPropsIterator.next();
413 int thisNtDeleteCount = 0;
414 LOGGER.debug(" > Look at : [" + nType + "] ...");
415 ntList = ntList + "," + nType;
417 // Get a collection of the names of the key properties for this nodeType to use later
418 // Determine what the key fields are for this nodeType
419 Collection <String> keyProps = new ArrayList <>();
420 if( dbMaps.NodeKeyProps.containsKey(nType) ){
421 keyProps = dbMaps.NodeKeyProps.get(nType);
424 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")");
427 // Get the types of nodes that this nodetype depends on for uniqueness (if any)
428 Collection <String> depNodeTypes = new ArrayList <>();
429 if( dbMaps.NodeDependencies.containsKey(nType) ){
430 depNodeTypes = dbMaps.NodeDependencies.get(nType);
433 // Loop through all the nodes of this Node type
434 int lastShownForNt = 0;
435 ArrayList <TitanVertex> tmpList = new ArrayList <> ();
436 Iterable <?> verts = g.query().has("aai-node-type",nType).vertices();
437 Iterator<?> iterv = verts.iterator();
438 while (iterv.hasNext()) {
439 // We put the nodes into an ArrayList because the graph.query iterator can time out
440 tmpList.add((TitanVertex)iterv.next());
443 Iterator <?> iter = tmpList.iterator();
444 while (iter.hasNext()) {
447 if( thisNtCount == lastShownForNt + 250 ){
448 lastShownForNt = thisNtCount;
449 LOGGER.debug("count for " + nType + " so far = " + thisNtCount );
451 TitanVertex thisVtx = (TitanVertex) iter.next();
452 String thisVid = thisVtx.id().toString();
453 if (processedVertices.contains(thisVid)) {
454 LOGGER.debug("skipping already processed vertex: " + thisVid);
458 List <TitanVertex> secondGetList = new ArrayList <> ();
459 // -----------------------------------------------------------------------
460 // For each vertex of this nodeType, we want to:
461 // a) make sure that it can be retrieved using it's AAI defined key
462 // b) make sure that it is not a duplicate
463 // -----------------------------------------------------------------------
465 // For this instance of this nodeType, get the key properties
466 HashMap<String, Object> propHashWithKeys = new HashMap<>();
467 Iterator<String> keyPropI = keyProps.iterator();
468 while (keyPropI.hasNext()) {
469 String propName = keyPropI.next();
471 //delete an already deleted vertex
472 Object obj = thisVtx.<Object>property(propName).orElse(null);
474 propVal = obj.toString();
476 propHashWithKeys.put(propName, propVal);
479 // If this node is dependent on another for uniqueness, then do the query from that parent node
480 // Note - all of our nodes that are dependent on others for uniqueness are
481 // "children" of that node.
482 boolean depNodeOk = true;
483 if( depNodeTypes.isEmpty() ){
484 // This kind of node is not dependent on any other.
485 // Make sure we can get it back using it's key properties and that we only get one.
486 secondGetList = getNodeJustUsingKeyParams( TRANSID, FROMAPPID, g, nType,
487 propHashWithKeys, version );
490 // This kind of node is dependent on another for uniqueness.
491 // Start at it's parent (the dependent vertex) and make sure we can get it
492 // back using it's key properties and that we only get one.
493 Iterable <?> verts2 = thisVtx.query().direction(Direction.IN).has("isParent",true).vertices();
494 Iterator <?> vertI2 = verts2.iterator();
495 TitanVertex parentVtx = null;
497 while( vertI2 != null && vertI2.hasNext() ){
498 parentVtx = (TitanVertex) vertI2.next();
504 //List<Vertex> vertI2 = g.traversal().V(thisVtx).union(__.outE().has("isParent-REV",true).outV(),__.inE().has("isParent",true).inV()).toList();
505 //if( vertI2.isEmpty()){
507 // It's Missing it's dependent/parent node
509 boolean zeroEdges = false;
511 Iterator<Edge> tmpEdgeIter = thisVtx.edges(Direction.BOTH);
513 while( tmpEdgeIter.hasNext() ){
517 if( edgeCount == 0 ){
520 } catch (Exception ex) {
521 LOGGER.warn("WARNING from inside the for-each-vid-loop orphan-edges-check ", ex);
524 if (deleteCandidateList.contains(thisVid)) {
525 boolean okFlag = true;
527 processedVertices.add(thisVtx.id().toString());
531 } catch (Exception e) {
533 LOGGER.error("ERROR trying to delete missing-dep-node VID = " + thisVid, e);
536 LOGGER.info(" DELETED missing-dep-node VID = " + thisVid);
539 // We count nodes missing their depNodes two ways - the first if it has
540 // at least some edges, and the second if it has zero edges. Either
541 // way, they are effectively orphaned.
542 // NOTE - Only nodes that have dependent nodes are ever considered "orphaned".
544 missingDepNodeHash.put(thisVid, thisVtx);
547 orphanNodeHash.put(thisVid, thisVtx);
551 else if ( pCount > 1 ){
552 // Not sure how this could happen? Should we do something here?
556 // We found the parent - so use it to do the second-look.
557 // NOTE --- We're just going to do the same check from the other direction - because
558 // there could be duplicates or the pointer going the other way could be broken
559 ArrayList <TitanVertex> tmpListSec = new ArrayList <> ();
560 tmpListSec = getConnectedChildren( g, parentVtx ) ;
561 Iterator<TitanVertex> vIter = tmpListSec.iterator();
562 while (vIter.hasNext()) {
563 TitanVertex tmpV = vIter.next();
564 if( vertexHasTheseKeys(tmpV, propHashWithKeys) ){
565 secondGetList.add(tmpV);
571 if( depNodeOk && (secondGetList == null || secondGetList.size() == 0) ){
572 // We could not get the node back using it's own key info.
573 // So, it's a PHANTOM
574 if (deleteCandidateList.contains(thisVid)) {
575 boolean okFlag = true;
580 } catch (Exception e) {
582 LOGGER.error("ERROR trying to delete phantom VID = " + thisVid, e);
585 LOGGER.info(" DELETED VID = " + thisVid);
588 ghostNodeHash.put(thisVid, thisVtx);
591 else if( (secondGetList.size() > 1) && depNodeOk && !dupeCheckOff ){
592 // Found some DUPLICATES - need to process them
593 LOGGER.info(" - now check Dupes for this guy - ");
594 List<String> tmpDupeGroups = checkAndProcessDupes(
595 TRANSID, FROMAPPID, g, version,
596 nType, secondGetList, dupeFixOn,
597 deleteCandidateList, singleCommits, dupeGroups, dbMaps);
598 Iterator<String> dIter = tmpDupeGroups.iterator();
599 while (dIter.hasNext()) {
600 // Add in any newly found dupes to our running list
601 String tmpGrp = dIter.next();
602 LOGGER.info("Found set of dupes: [" + tmpGrp + "]");
603 dupeGroups.add(tmpGrp);
607 catch (AAIException e1) {
608 LOGGER.warn(" For nodeType = " + nType + " Caught exception", e1);
609 errArr.add(e1.getErrorObject().toString());
611 catch (Exception e2) {
612 LOGGER.warn(" For nodeType = " + nType
613 + " Caught exception", e2);
614 errArr.add(e2.getMessage());
616 }// try block to enclose looping of a single vertex
617 catch (Exception exx) {
618 LOGGER.warn("WARNING from inside the while-verts-loop ", exx);
621 } // while loop for each record of a nodeType
623 if ( (thisNtDeleteCount > 0) && singleCommits ) {
624 // NOTE - the singleCommits option is not used in normal processing
626 g = AAIGraph.getInstance().getGraph().newTransaction();
629 thisNtDeleteCount = 0;
630 LOGGER.info( " Processed " + thisNtCount + " records for [" + nType + "], " + totalNodeCount + " total overall. " );
632 }// While-loop for each node type
633 }// end of check to make sure we weren't only supposed to do edges
636 // --------------------------------------------------------------------------------------
637 // Now, we're going to look for one-armed-edges. Ie. an edge that
639 // been deleted (because a vertex on one side was deleted) but
640 // somehow was not deleted.
641 // So the one end of it points to a vertexId -- but that vertex is
643 // --------------------------------------------------------------------------------------
645 // To do some strange checking - we need a second graph object
646 LOGGER.debug(" ---- DEBUG --- about to open a SECOND graph (takes a little while)--------\n");
647 // Note - graph2 just reads - but we want it to use a fresh connection to
648 // the database, so we are NOT using the CACHED DB CONFIG here.
649 graph2 = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG);
650 if (graph2 == null) {
651 String emsg = "null graph2 object in DataGrooming\n";
652 throw new AAIException("AAI_6101", emsg);
654 LOGGER.debug("Got the graph2 object... \n");
656 g2 = graph2.newTransaction();
658 String emsg = "null graphTransaction2 object in DataGrooming\n";
659 throw new AAIException("AAI_6101", emsg);
662 ArrayList<Vertex> vertList = new ArrayList<>();
663 Iterable<? extends Vertex> vIt3 = g.query().vertices();
664 Iterator<? extends Vertex> vItor3 = vIt3.iterator();
665 // Gotta hold these in a List - or else HBase times out as you cycle
667 while (vItor3.hasNext()) {
668 Vertex v = vItor3.next();
673 Iterator<Vertex> vItor2 = vertList.iterator();
674 LOGGER.info(" Checking for bad edges --- ");
676 while (vItor2.hasNext()) {
681 } catch (Exception vex) {
682 LOGGER.warn(">>> WARNING trying to get next vertex on the vItor2 ");
687 String thisVertId = "";
689 thisVertId = v.id().toString();
690 } catch (Exception ev) {
691 LOGGER.warn("WARNING when doing getId() on a vertex from our vertex list. ");
694 if (ghostNodeHash.containsKey(thisVertId)) {
695 // This is a phantom node, so don't try to use it
696 LOGGER.info(" >> Skipping edge check for edges from vertexId = "
698 + ", since that guy is a Phantom Node");
701 if (counter == lastShown + 250) {
703 LOGGER.info("... Checking edges for vertex # "
706 Iterator<Edge> eItor = v.edges(Direction.BOTH);
707 while (eItor.hasNext()) {
713 } catch (Exception iex) {
714 LOGGER.warn(">>> WARNING trying to get next edge on the eItor ", iex);
720 } catch (Exception err) {
721 LOGGER.warn(">>> WARNING trying to get edge's In-vertex ", err);
725 TitanVertex ghost2 = null;
727 Boolean keysMissing = true;
728 Boolean cantGetUsingVid = false;
731 Object ob = vIn.<Object>property("aai-node-type").orElse(null);
733 vNtI = ob.toString();
734 keysMissing = anyKeyFieldsMissing(vNtI, vIn, dbMaps);
739 vIdI = ob.toString();
740 vIdLong = Long.parseLong(vIdI);
743 if( ! ghost2CheckOff ){
744 TitanVertex connectedVert = g2.getVertex(vIdLong);
745 if( connectedVert == null ) {
746 LOGGER.warn( "GHOST2 -- got NULL when doing getVertex for vid = " + vIdLong);
747 cantGetUsingVid = true;
749 // If we can NOT get this ghost with the SECOND graph-object,
750 // it is still a ghost since even though we can get data about it using the FIRST graph
753 ghost2 = g.getVertex(vIdLong);
755 catch( Exception ex){
756 LOGGER.warn( "GHOST2 -- Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex);
758 if( ghost2 != null ){
759 ghostNodeHash.put(vIdI, ghost2);
762 }// end of the ghost2 checking
764 catch (Exception err) {
765 LOGGER.warn(">>> WARNING trying to get edge's In-vertex props ", err);
768 if (keysMissing || vIn == null || vNtI.equals("")
769 || cantGetUsingVid) {
770 // this is a bad edge because it points to a vertex
771 // that isn't there anymore or is corrupted
772 String thisEid = e.id().toString();
773 if (deleteCandidateList.contains(thisEid) || deleteCandidateList.contains(vIdI)) {
774 boolean okFlag = true;
775 if (!vIdI.equals("")) {
776 // try to get rid of the corrupted vertex
778 if( (ghost2 != null) && ghost2FixOn ){
785 // NOTE - the singleCommits option is not used in normal processing
787 g = AAIGraph.getInstance().getGraph().newTransaction();
790 } catch (Exception e1) {
792 LOGGER.warn("WARNING when trying to delete bad-edge-connected VERTEX VID = "
796 LOGGER.info(" DELETED vertex from bad edge = "
800 // remove the edge if we couldn't get the
805 // NOTE - the singleCommits option is not used in normal processing
807 g = AAIGraph.getInstance().getGraph().newTransaction();
810 } catch (Exception ex) {
811 // NOTE - often, the exception is just
812 // that this edge has already been
815 LOGGER.warn("WARNING when trying to delete edge = "
819 LOGGER.info(" DELETED edge = " + thisEid);
823 oneArmedEdgeHash.put(thisEid, e);
824 if ((vIn != null) && (vIn.id() != null)) {
825 emptyVertexHash.put(thisEid, vIn.id()
832 vOut = e.outVertex();
833 } catch (Exception err) {
834 LOGGER.warn(">>> WARNING trying to get edge's Out-vertex ");
840 cantGetUsingVid = false;
843 Object ob = vOut.<Object>property("aai-node-type").orElse(null);
845 vNtO = ob.toString();
846 keysMissing = anyKeyFieldsMissing(vNtO,
852 vIdO = ob.toString();
853 vIdLong = Long.parseLong(vIdO);
856 if( ! ghost2CheckOff ){
857 TitanVertex connectedVert = g2.getVertex(vIdLong);
858 if( connectedVert == null ) {
859 cantGetUsingVid = true;
860 LOGGER.info( "GHOST2 -- got NULL when doing getVertex for vid = " + vIdLong);
861 // If we can get this ghost with the other graph-object, then get it -- it's still a ghost
863 ghost2 = g.getVertex(vIdLong);
865 catch( Exception ex){
866 LOGGER.warn( "GHOST2 -- Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex);
868 if( ghost2 != null ){
869 ghostNodeHash.put(vIdO, ghost2);
873 } catch (Exception err) {
874 LOGGER.warn(">>> WARNING trying to get edge's Out-vertex props ", err);
877 if (keysMissing || vOut == null || vNtO.equals("")
878 || cantGetUsingVid) {
879 // this is a bad edge because it points to a vertex
880 // that isn't there anymore
881 String thisEid = e.id().toString();
882 if (deleteCandidateList.contains(thisEid) || deleteCandidateList.contains(vIdO)) {
883 boolean okFlag = true;
884 if (!vIdO.equals("")) {
885 // try to get rid of the corrupted vertex
887 if( (ghost2 != null) && ghost2FixOn ){
894 // NOTE - the singleCommits option is not used in normal processing
896 g = AAIGraph.getInstance().getGraph().newTransaction();
899 } catch (Exception e1) {
901 LOGGER.warn("WARNING when trying to delete bad-edge-connected VID = "
905 LOGGER.info(" DELETED vertex from bad edge = "
909 // remove the edge if we couldn't get the
914 // NOTE - the singleCommits option is not used in normal processing
916 g = AAIGraph.getInstance().getGraph().newTransaction();
919 } catch (Exception ex) {
920 // NOTE - often, the exception is just
921 // that this edge has already been
924 LOGGER.warn("WARNING when trying to delete edge = "
928 LOGGER.info(" DELETED edge = " + thisEid);
932 oneArmedEdgeHash.put(thisEid, e);
933 if ((vOut != null) && (vOut.id() != null)) {
934 emptyVertexHash.put(thisEid, vOut.id()
939 }// End of while-edges-loop
940 } catch (Exception exx) {
941 LOGGER.warn("WARNING from in the while-verts-loop ", exx);
943 }// End of while-vertices-loop
945 deleteCount = deleteCount + dupeGrpsDeleted;
946 if (!singleCommits && deleteCount > 0) {
948 LOGGER.info("About to do the commit for "
949 + deleteCount + " removes. ");
950 executeFinalCommit = true;
951 LOGGER.info("Commit was successful ");
952 } catch (Exception excom) {
953 LOGGER.error(" >>>> ERROR <<<< Could not commit changes. ", excom);
958 int ghostNodeCount = ghostNodeHash.size();
959 int orphanNodeCount = orphanNodeHash.size();
960 int missingDepNodeCount = missingDepNodeHash.size();
961 int oneArmedEdgeCount = oneArmedEdgeHash.size();
962 int dupeCount = dupeGroups.size();
964 deleteCount = deleteCount + dupeGrpsDeleted;
966 bw.write("\n\n ============ Summary ==============\n");
967 bw.write("Ran these nodeTypes: " + ntList + "\n\n");
968 bw.write("There were this many delete candidates from previous run = "
969 + deleteCandidateList.size() + "\n");
970 if (dontFixOrphansFlag) {
971 bw.write(" Note - we are not counting orphan nodes since the -dontFixOrphans parameter was used. \n");
973 bw.write("Deleted this many delete candidates = " + deleteCount
975 bw.write("Total number of nodes looked at = " + totalNodeCount
977 bw.write("Ghost Nodes identified = " + ghostNodeCount + "\n");
978 bw.write("Orphan Nodes identified = " + orphanNodeCount + "\n");
979 bw.write("Bad Edges identified = " + oneArmedEdgeCount + "\n");
980 bw.write("Missing Dependent Edge (but not orphaned) node count = "
981 + missingDepNodeCount + "\n");
982 bw.write("Duplicate Groups count = " + dupeCount + "\n");
983 bw.write("MisMatching Label/aai-node-type count = "
984 + misMatchedHash.size() + "\n");
986 bw.write("\n ------------- Delete Candidates ---------\n");
987 for (Map.Entry<String, TitanVertex> entry : ghostNodeHash
989 String vid = entry.getKey();
990 bw.write("DeleteCandidate: Phantom Vid = [" + vid + "]\n");
991 cleanupCandidateCount++;
993 for (Map.Entry<String, TitanVertex> entry : orphanNodeHash
995 String vid = entry.getKey();
996 bw.write("DeleteCandidate: OrphanDepNode Vid = [" + vid + "]\n");
997 if (!dontFixOrphansFlag) {
998 cleanupCandidateCount++;
1001 for (Map.Entry<String, Edge> entry : oneArmedEdgeHash.entrySet()) {
1002 String eid = entry.getKey();
1003 bw.write("DeleteCandidate: Bad EDGE Edge-id = [" + eid + "]\n");
1004 cleanupCandidateCount++;
1006 for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash
1008 String vid = entry.getKey();
1009 bw.write("DeleteCandidate: (maybe) missingDepNode Vid = ["
1011 cleanupCandidateCount++;
1013 bw.write("\n-- NOTE - To see DeleteCandidates for Duplicates, you need to look in the Duplicates Detail section below.\n");
1015 bw.write("\n ------------- GHOST NODES - detail ");
1016 for (Map.Entry<String, TitanVertex> entry : ghostNodeHash
1019 String vid = entry.getKey();
1020 bw.write("\n ==> Phantom Vid = " + vid + "\n");
1021 ArrayList<String> retArr = showPropertiesForNode(
1022 TRANSID, FROMAPPID, entry.getValue());
1023 for (String info : retArr) {
1024 bw.write(info + "\n");
1027 retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
1029 for (String info : retArr) {
1030 bw.write(info + "\n");
1032 } catch (Exception dex) {
1033 LOGGER.error("error trying to print detail info for a ghost-node: ", dex);
1037 bw.write("\n ------------- Missing Dependent Edge ORPHAN NODES - detail: ");
1038 for (Map.Entry<String, TitanVertex> entry : orphanNodeHash
1041 String vid = entry.getKey();
1042 bw.write("\n> Orphan Node Vid = " + vid + "\n");
1043 ArrayList<String> retArr = showPropertiesForNode(
1044 TRANSID, FROMAPPID, entry.getValue());
1045 for (String info : retArr) {
1046 bw.write(info + "\n");
1049 retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
1051 for (String info : retArr) {
1052 bw.write(info + "\n");
1054 } catch (Exception dex) {
1055 LOGGER.error("error trying to print detail info for a Orphan Node /missing dependent edge", dex);
1059 bw.write("\n ------------- Missing Dependent Edge (but not orphan) NODES: ");
1060 for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash
1063 String vid = entry.getKey();
1064 bw.write("\n> Missing edge to Dependent Node (but has edges) Vid = "
1066 ArrayList<String> retArr = showPropertiesForNode(
1067 TRANSID, FROMAPPID, entry.getValue());
1068 for (String info : retArr) {
1069 bw.write(info + "\n");
1072 retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
1074 for (String info : retArr) {
1075 bw.write(info + "\n");
1077 } catch (Exception dex) {
1078 LOGGER.error("error trying to print detail info for a node missing its dependent edge but not an orphan", dex);
1082 bw.write("\n ------------- EDGES pointing to empty/bad vertices: ");
1083 for (Map.Entry<String, Edge> entry : oneArmedEdgeHash.entrySet()) {
1085 String eid = entry.getKey();
1086 Edge thisE = entry.getValue();
1087 String badVid = emptyVertexHash.get(eid);
1088 bw.write("\n> Edge pointing to bad vertex (Vid = "
1089 + badVid + ") EdgeId = " + eid + "\n");
1090 bw.write("Label: [" + thisE.label() + "]\n");
1091 Iterator<Property<Object>> pI = thisE.properties();
1092 while (pI.hasNext()) {
1093 Property<Object> propKey = pI.next();
1094 bw.write("Prop: [" + propKey + "], val = ["
1095 + propKey.value() + "]\n");
1097 } catch (Exception pex) {
1098 LOGGER.error("error trying to print empty/bad vertex data: ", pex);
1102 bw.write("\n ------------- Duplicates: ");
1103 Iterator<String> dupeIter = dupeGroups.iterator();
1104 int dupeSetCounter = 0;
1105 while (dupeIter.hasNext()) {
1107 String dset = (String) dupeIter.next();
1109 bw.write("\n --- Duplicate Group # " + dupeSetCounter
1110 + " Detail -----------\n");
1112 // We expect each line to have at least two vid's, followed
1113 // by the preferred one to KEEP
1114 String[] dupeArr = dset.split("\\|");
1115 ArrayList<String> idArr = new ArrayList<>();
1116 int lastIndex = dupeArr.length - 1;
1117 for (int i = 0; i <= lastIndex; i++) {
1118 if (i < lastIndex) {
1119 // This is not the last entry, it is one of the
1120 // dupes, so we want to show all its info
1121 bw.write(" >> Duplicate Group # "
1122 + dupeSetCounter + " Node # " + i
1124 String vidString = dupeArr[i];
1125 idArr.add(vidString);
1126 long longVertId = Long.parseLong(vidString);
1127 Iterator<Vertex> vtxIterator = g.vertices(longVertId);
1128 TitanVertex vtx = null;
1129 if (vtxIterator.hasNext()) {
1130 vtx = (TitanVertex)vtxIterator.next();
1132 ArrayList<String> retArr = showPropertiesForNode(TRANSID, FROMAPPID, vtx);
1133 for (String info : retArr) {
1134 bw.write(info + "\n");
1137 retArr = showAllEdgesForNode(TRANSID,
1139 for (String info : retArr) {
1140 bw.write(info + "\n");
1143 // This is the last entry which should tell us if we
1144 // have a preferred keeper
1145 String prefString = dupeArr[i];
1146 if (prefString.equals("KeepVid=UNDETERMINED")) {
1147 bw.write("\n For this group of duplicates, could not tell which one to keep.\n");
1148 bw.write(" >>> This group needs to be taken care of with a manual/forced-delete.\n");
1150 // If we know which to keep, then the prefString
1151 // should look like, "KeepVid=12345"
1152 String[] prefArr = prefString.split("=");
1153 if (prefArr.length != 2
1154 || (!prefArr[0].equals("KeepVid"))) {
1155 throw new Exception("Bad format. Expecting KeepVid=999999");
1157 String keepVidStr = prefArr[1];
1158 if (idArr.contains(keepVidStr)) {
1159 bw.write("\n The vertex we want to KEEP has vertexId = "
1161 bw.write("\n The others become delete candidates: \n");
1162 idArr.remove(keepVidStr);
1163 for (int x = 0; x < idArr.size(); x++) {
1164 cleanupCandidateCount++;
1165 bw.write("DeleteCandidate: Duplicate Vid = ["
1166 + idArr.get(x) + "]\n");
1169 throw new Exception("ERROR - Vertex Id to keep not found in list of dupes. dset = ["
1173 }// else we know which one to keep
1175 }// for each vertex in a group
1176 } catch (Exception dex) {
1177 LOGGER.error("error trying to print duplicate vertex data", dex);
1180 }// while - work on each group of dupes
1182 bw.write("\n ------------- Mis-matched Label/aai-node-type Nodes: \n ");
1183 for (Map.Entry<String, String> entry : misMatchedHash.entrySet()) {
1184 String msg = entry.getValue();
1185 bw.write("MixedMsg = " + msg + "\n");
1188 bw.write("\n ------------- Got these errors while processing: \n");
1189 Iterator<String> errIter = errArr.iterator();
1190 while (errIter.hasNext()) {
1191 String line = (String) errIter.next();
1192 bw.write(line + "\n");
1197 LOGGER.info("\n ------------- Done doing all the checks ------------ ");
1198 LOGGER.info("Output will be written to " + fullOutputFileName);
1200 if (cleanupCandidateCount > 0) {
1201 // Technically, this is not an error -- but we're throwing this
1202 // error so that hopefully a
1203 // monitoring system will pick it up and do something with it.
1204 throw new AAIException("AAI_6123", "See file: [" + fullOutputFileName
1205 + "] and investigate delete candidates. ");
1207 } catch (AAIException e) {
1208 LOGGER.error("Caught AAIException while grooming data", e);
1209 ErrorLogHelper.logException(e);
1210 } catch (Exception ex) {
1211 LOGGER.error("Caught exception while grooming data", ex);
1212 ErrorLogHelper.logError("AAI_6128", ex.getMessage() + ", resolve and rerun dataGrooming");
1218 } catch (IOException iox) {
1219 LOGGER.warn("Got an IOException trying to close bufferedWriter() \n", iox);
1223 if (g != null && !g.isClosed()) {
1224 // Any changes that worked correctly should have already done
1227 if (executeFinalCommit) {
1231 } catch (Exception ex) {
1232 // Don't throw anything because Titan sometimes is just saying that the graph is already closed
1233 LOGGER.warn("WARNING from final graphTransaction.rollback()", ex);
1237 if (g2 != null && !g2.isClosed()) {
1238 // Any changes that worked correctly should have already done
1242 } catch (Exception ex) {
1243 // Don't throw anything because Titan sometimes is just saying that the graph is already closed
1244 LOGGER.warn("WARNING from final graphTransaction2.rollback()", ex);
1248 if( finalShutdownFlag ){
1250 if( graph != null && graph.isOpen() ){
1254 } catch (Exception ex) {
1255 // Don't throw anything because Titan sometimes is just saying that the graph is already closed{
1256 LOGGER.warn("WARNING from final graph.shutdown()", ex);
1260 if( graph2 != null && graph2.isOpen() ){
1261 graph2.tx().close();
1264 } catch (Exception ex) {
1265 // Don't throw anything because Titan sometimes is just saying that the graph is already closed{
1266 LOGGER.warn("WARNING from final graph2.shutdown()", ex);
1272 return cleanupCandidateCount;
1274 }// end of doTheGrooming()
1278 * Vertex has these keys.
1280 * @param tmpV the tmp V
1281 * @param propHashWithKeys the prop hash with keys
1282 * @return the boolean
1284 private static Boolean vertexHasTheseKeys( TitanVertex tmpV, HashMap <String, Object> propHashWithKeys) {
1285 Iterator <?> it = propHashWithKeys.entrySet().iterator();
1286 while( it.hasNext() ){
1287 String propName = "";
1288 String propVal = "";
1289 Map.Entry <?,?>propEntry = (Map.Entry<?,?>)it.next();
1290 Object propNameObj = propEntry.getKey();
1291 if( propNameObj != null ){
1292 propName = propNameObj.toString();
1294 Object propValObj = propEntry.getValue();
1295 if( propValObj != null ){
1296 propVal = propValObj.toString();
1298 Object checkValObj = tmpV.<Object>property(propName).orElse(null);
1299 if( checkValObj == null ) {
1302 else if( !propVal.equals(checkValObj.toString()) ){
1311 * Any key fields missing.
1313 * @param nType the n type
1315 * @return the boolean
1317 private static Boolean anyKeyFieldsMissing(String nType, Vertex v, DbMaps dbMaps) {
1320 // Determine what the key fields are for this nodeType
1321 Collection <String> keyPropNamesColl = new ArrayList <>();
1322 if( dbMaps.NodeKeyProps.containsKey(nType) ){
1323 keyPropNamesColl = dbMaps.NodeKeyProps.get(nType);
1326 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")");
1329 Iterator<String> keyPropI = keyPropNamesColl.iterator();
1330 while (keyPropI.hasNext()) {
1331 String propName = keyPropI.next();
1332 Object ob = v.<Object>property(propName).orElse(null);
1333 if (ob == null || ob.toString().equals("")) {
1334 // It is missing a key property
1338 } catch (AAIException e) {
1339 // Something was wrong
1347 * Gets the delete list.
1349 * @param targetDir the target dir
1350 * @param fileName the file name
1351 * @param edgesOnlyFlag the edges only flag
1352 * @param dontFixOrphans the dont fix orphans
1353 * @param dupeFixOn the dupe fix on
1354 * @return the delete list
1355 * @throws AAIException the AAI exception
1357 private static Set<String> getDeleteList(String targetDir,
1358 String fileName, Boolean edgesOnlyFlag, Boolean dontFixOrphans,
1359 Boolean dupeFixOn) throws AAIException {
1361 // Look in the file for lines formated like we expect - pull out any
1362 // Vertex Id's to delete on this run
1363 Set<String> delList = new LinkedHashSet<>();
1364 String fullFileName = targetDir + AAIConstants.AAI_FILESEP + fileName;
1365 BufferedReader br = null;
1368 br = new BufferedReader(new FileReader(fullFileName));
1369 String line = br.readLine();
1370 while (line != null) {
1371 if (!line.equals("") && line.startsWith("DeleteCandidate")) {
1372 if (edgesOnlyFlag && (!line.contains("Bad Edge"))) {
1373 // We're not going to process edge guys
1374 } else if (dontFixOrphans && line.contains("Orphan")) {
1375 // We're not going to process orphans
1376 } else if (!dupeFixOn && line.contains("Duplicate")) {
1377 // We're not going to process Duplicates
1379 int begIndex = line.indexOf("id = ");
1380 int endIndex = line.indexOf("]");
1381 String vidVal = line.substring(begIndex + 6, endIndex);
1382 delList.add(vidVal);
1385 line = br.readLine();
1388 } catch (IOException e) {
1389 throw new AAIException("AAI_6124", e, "Could not open input-file [" + fullFileName
1390 + "], exception= " + e.getMessage());
1395 }// end of getDeleteList
1398 * Gets the preferred dupe.
1400 * @param transId the trans id
1401 * @param fromAppId the from app id
1403 * @param dupeVertexList the dupe vertex list
1404 * @param ver the ver
1405 * @return TitanVertex
1406 * @throws AAIException the AAI exception
1408 public static TitanVertex getPreferredDupe(String transId,
1409 String fromAppId, TitanTransaction g,
1410 ArrayList<TitanVertex> dupeVertexList, String ver, DbMaps dbMaps)
1411 throws AAIException {
1413 // This method assumes that it is being passed a List of vertex objects
1415 // violate our uniqueness constraints.
1417 TitanVertex nullVtx = null;
1419 if (dupeVertexList == null) {
1422 int listSize = dupeVertexList.size();
1423 if (listSize == 0) {
1426 if (listSize == 1) {
1427 return ((TitanVertex) dupeVertexList.get(0));
1430 TitanVertex vtxPreferred = null;
1431 TitanVertex currentFaveVtx = (TitanVertex) dupeVertexList.get(0);
1432 for (int i = 1; i < listSize; i++) {
1433 TitanVertex vtxB = (TitanVertex) dupeVertexList.get(i);
1434 vtxPreferred = pickOneOfTwoDupes(transId, fromAppId, g,
1435 currentFaveVtx, vtxB, ver, dbMaps);
1436 if (vtxPreferred == null) {
1437 // We couldn't choose one
1440 currentFaveVtx = vtxPreferred;
1444 return (currentFaveVtx);
1446 } // end of getPreferredDupe()
1449 * Pick one of two dupes.
1451 * @param transId the trans id
1452 * @param fromAppId the from app id
1454 * @param vtxA the vtx A
1455 * @param vtxB the vtx B
1456 * @param ver the ver
1457 * @return TitanVertex
1458 * @throws AAIException the AAI exception
1460 public static TitanVertex pickOneOfTwoDupes(String transId,
1461 String fromAppId, TitanTransaction g, TitanVertex vtxA,
1462 TitanVertex vtxB, String ver, DbMaps dbMaps) throws AAIException {
1464 TitanVertex nullVtx = null;
1465 TitanVertex preferredVtx = null;
1467 Long vidA = new Long(vtxA.id().toString());
1468 Long vidB = new Long(vtxB.id().toString());
1470 String vtxANodeType = "";
1471 String vtxBNodeType = "";
1472 Object obj = vtxA.<Object>property("aai-node-type").orElse(null);
1474 vtxANodeType = obj.toString();
1476 obj = vtxB.<Object>property("aai-node-type").orElse(null);
1478 vtxBNodeType = obj.toString();
1481 if (vtxANodeType.equals("") || (!vtxANodeType.equals(vtxBNodeType))) {
1482 // Either they're not really dupes or there's some bad data - so
1487 // Check that node A and B both have the same key values (or else they
1489 // (We'll check dep-node later)
1490 // Determine what the key fields are for this nodeType
1491 Collection <String> keyProps = new ArrayList <>();
1492 if( dbMaps.NodeKeyProps.containsKey(vtxANodeType) ){
1493 keyProps = dbMaps.NodeKeyProps.get(vtxANodeType);
1496 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + vtxANodeType + ")");
1499 Iterator<String> keyPropI = keyProps.iterator();
1500 while (keyPropI.hasNext()) {
1501 String propName = keyPropI.next();
1502 String vtxAKeyPropVal = "";
1503 obj = vtxA.<Object>property(propName).orElse(null);
1505 vtxAKeyPropVal = obj.toString();
1507 String vtxBKeyPropVal = "";
1508 obj = vtxB.<Object>property(propName).orElse(null);
1510 vtxBKeyPropVal = obj.toString();
1513 if (vtxAKeyPropVal.equals("")
1514 || (!vtxAKeyPropVal.equals(vtxBKeyPropVal))) {
1515 // Either they're not really dupes or they are missing some key
1516 // data - so don't pick one
1521 // Collect the vid's and aai-node-types of the vertices that each vertex
1522 // (A and B) is connected to.
1523 ArrayList<String> vtxIdsConn2A = new ArrayList<>();
1524 ArrayList<String> vtxIdsConn2B = new ArrayList<>();
1525 HashMap<String, String> nodeTypesConn2A = new HashMap<>();
1526 HashMap<String, String> nodeTypesConn2B = new HashMap<>();
1528 ArrayList<TitanVertex> vertListA = getConnectedNodes( g, vtxA );
1529 if (vertListA != null) {
1530 Iterator<TitanVertex> iter = vertListA.iterator();
1531 while (iter.hasNext()) {
1532 TitanVertex tvCon = iter.next();
1533 String conVid = tvCon.id().toString();
1535 obj = tvCon.<Object>property("aai-node-type").orElse(null);
1537 nt = obj.toString();
1539 nodeTypesConn2A.put(nt, conVid);
1540 vtxIdsConn2A.add(conVid);
1544 ArrayList<TitanVertex> vertListB = getConnectedNodes( g, vtxB );
1545 if (vertListB != null) {
1546 Iterator<TitanVertex> iter = vertListB.iterator();
1547 while (iter.hasNext()) {
1548 TitanVertex tvCon = iter.next();
1549 String conVid = tvCon.id().toString();
1551 obj = tvCon.<Object>property("aai-node-type").orElse(null);
1553 nt = obj.toString();
1555 nodeTypesConn2B.put(nt, conVid);
1556 vtxIdsConn2B.add(conVid);
1560 // 1 - If this kind of node needs a dependent node for uniqueness, then
1561 // verify that they both nodes
1562 // point to the same dependent node (otherwise they're not really
1564 // Note - there are sometimes more than one dependent node type since
1565 // one nodeType can be used in
1566 // different ways. But for a particular node, it will only have one
1567 // dependent node that it's
1569 Collection <String> depNodeTypes = new ArrayList <>();
1570 if( dbMaps.NodeDependencies.containsKey(vtxANodeType) ){
1571 depNodeTypes = dbMaps.NodeDependencies.get(vtxANodeType);
1574 if (depNodeTypes.isEmpty()) {
1575 // This kind of node is not dependent on any other. That is ok.
1577 String depNodeVtxId4A = "";
1578 String depNodeVtxId4B = "";
1579 Iterator<String> iter = depNodeTypes.iterator();
1580 while (iter.hasNext()) {
1581 String depNodeType = iter.next();
1582 if (nodeTypesConn2A.containsKey(depNodeType)) {
1583 // This is the dependent node type that vertex A is using
1584 depNodeVtxId4A = nodeTypesConn2A.get(depNodeType);
1586 if (nodeTypesConn2B.containsKey(depNodeType)) {
1587 // This is the dependent node type that vertex B is using
1588 depNodeVtxId4B = nodeTypesConn2B.get(depNodeType);
1591 if (depNodeVtxId4A.equals("")
1592 || (!depNodeVtxId4A.equals(depNodeVtxId4B))) {
1593 // Either they're not really dupes or there's some bad data - so
1594 // don't pick either one
1599 if (vtxIdsConn2A.size() == vtxIdsConn2B.size()) {
1600 // 2 - If they both have edges to all the same vertices, then return
1601 // the one with the lower vertexId.
1602 boolean allTheSame = true;
1603 Iterator<String> iter = vtxIdsConn2A.iterator();
1604 while (iter.hasNext()) {
1605 String vtxIdConn2A = iter.next();
1606 if (!vtxIdsConn2B.contains(vtxIdConn2A)) {
1614 preferredVtx = vtxA;
1616 preferredVtx = vtxB;
1619 } else if (vtxIdsConn2A.size() > vtxIdsConn2B.size()) {
1620 // 3 - VertexA is connected to more things than vtxB.
1621 // We'll pick VtxA if its edges are a superset of vtxB's edges.
1622 boolean missingOne = false;
1623 Iterator<String> iter = vtxIdsConn2B.iterator();
1624 while (iter.hasNext()) {
1625 String vtxIdConn2B = iter.next();
1626 if (!vtxIdsConn2A.contains(vtxIdConn2B)) {
1632 preferredVtx = vtxA;
1634 } else if (vtxIdsConn2B.size() > vtxIdsConn2A.size()) {
1635 // 4 - VertexB is connected to more things than vtxA.
1636 // We'll pick VtxB if its edges are a superset of vtxA's edges.
1637 boolean missingOne = false;
1638 Iterator<String> iter = vtxIdsConn2A.iterator();
1639 while (iter.hasNext()) {
1640 String vtxIdConn2A = iter.next();
1641 if (!vtxIdsConn2B.contains(vtxIdConn2A)) {
1647 preferredVtx = vtxB;
1650 preferredVtx = nullVtx;
1653 return (preferredVtx);
1655 } // end of pickOneOfTwoDupes()
1658 * Check and process dupes.
1660 * @param transId the trans id
1661 * @param fromAppId the from app id
1663 * @param version the version
1664 * @param nType the n type
1665 * @param passedVertList the passed vert list
1666 * @param dupeFixOn the dupe fix on
1667 * @param deleteCandidateList the delete candidate list
1668 * @param singleCommits the single commits
1669 * @param alreadyFoundDupeGroups the already found dupe groups
1670 * @param dbMaps the db maps
1671 * @return the array list
1673 private static List<String> checkAndProcessDupes(String transId,
1674 String fromAppId, TitanTransaction g, String version, String nType,
1675 List<TitanVertex> passedVertList, Boolean dupeFixOn,
1676 Set<String> deleteCandidateList, Boolean singleCommits,
1677 ArrayList<String> alreadyFoundDupeGroups, DbMaps dbMaps ) {
1679 ArrayList<String> returnList = new ArrayList<>();
1680 ArrayList<TitanVertex> checkVertList = new ArrayList<>();
1681 ArrayList<String> alreadyFoundDupeVidArr = new ArrayList<>();
1682 Boolean noFilterList = true;
1683 Iterator<String> afItr = alreadyFoundDupeGroups.iterator();
1684 while (afItr.hasNext()) {
1685 String dupeGrpStr = afItr.next();
1686 String[] dupeArr = dupeGrpStr.split("\\|");
1687 int lastIndex = dupeArr.length - 1;
1688 for (int i = 0; i < lastIndex; i++) {
1689 // Note: we don't want the last one...
1690 String vidString = dupeArr[i];
1691 alreadyFoundDupeVidArr.add(vidString);
1692 noFilterList = false;
1696 // For a given set of Nodes that were found with a set of KEY
1697 // Parameters, (nodeType + key data) we will
1698 // see if we find any duplicate nodes that need to be cleaned up. Note -
1699 // it's legit to have more than one
1700 // node with the same key data if the nodes depend on a parent for
1701 // uniqueness -- as long as the two nodes
1702 // don't hang off the same Parent.
1703 // If we find duplicates, and we can figure out which of each set of
1704 // duplicates is the one that we
1705 // think should be preserved, we will record that. Whether we can tell
1706 // which one should be
1707 // preserved or not, we will return info about any sets of duplicates
1710 // Each element in the returned arrayList might look like this:
1711 // "1234|5678|keepVid=UNDETERMINED" (if there were 2 dupes, and we
1712 // couldn't figure out which one to keep)
1713 // or, "100017|200027|30037|keepVid=30037" (if there were 3 dupes and we
1714 // thought the third one was the one that should survive)
1716 // Because of the way the calling code loops over stuff, we can get the
1717 // same data multiple times - so we should
1718 // not process any vertices that we've already seen.
1721 Iterator<TitanVertex> pItr = passedVertList.iterator();
1722 while (pItr.hasNext()) {
1723 TitanVertex tvx = (TitanVertex) pItr.next();
1724 String passedId = tvx.id().toString();
1725 if (noFilterList || !alreadyFoundDupeVidArr.contains(passedId)) {
1726 // We haven't seen this one before - so we should check it.
1727 checkVertList.add(tvx);
1731 if (checkVertList.size() < 2) {
1732 // Nothing new to check.
1736 if (!dbMaps.NodeDependencies.containsKey(nType)) {
1737 // If this was a node that does NOT depend on other nodes for
1738 // uniqueness, and we
1739 // found more than one node using its key -- record the found
1740 // vertices as duplicates.
1741 String dupesStr = "";
1742 for (int i = 0; i < checkVertList.size(); i++) {
1744 + ((TitanVertex) (checkVertList.get(i))).id()
1747 if (dupesStr != "") {
1748 TitanVertex prefV = getPreferredDupe(transId, fromAppId,
1749 g, checkVertList, version, dbMaps);
1750 if (prefV == null) {
1751 // We could not determine which duplicate to keep
1752 dupesStr = dupesStr + "KeepVid=UNDETERMINED";
1753 returnList.add(dupesStr);
1755 dupesStr = dupesStr + "KeepVid=" + prefV.id();
1756 Boolean didRemove = false;
1758 didRemove = deleteNonKeepersIfAppropriate(g,
1759 dupesStr, prefV.id().toString(),
1760 deleteCandidateList, singleCommits);
1765 // keep them on our list
1766 returnList.add(dupesStr);
1771 // More than one node have the same key fields since they may
1772 // depend on a parent node for
1773 // uniqueness. Since we're finding more than one, we want to
1774 // check to see if any of the
1775 // vertices that have this set of keys are also pointing at the
1776 // same 'parent' node.
1777 // Note: for a given set of key data, it is possible that there
1778 // could be more than one set of
1780 HashMap<String, ArrayList<TitanVertex>> vertsGroupedByParentHash = groupVertsByDepNodes(
1781 transId, fromAppId, g, version, nType,
1782 checkVertList, dbMaps);
1783 for (Map.Entry<String, ArrayList<TitanVertex>> entry : vertsGroupedByParentHash
1785 ArrayList<TitanVertex> thisParentsVertList = entry
1787 if (thisParentsVertList.size() > 1) {
1788 // More than one vertex found with the same key info
1789 // hanging off the same parent/dependent node
1790 String dupesStr = "";
1791 for (int i = 0; i < thisParentsVertList.size(); i++) {
1793 + ((TitanVertex) (thisParentsVertList
1794 .get(i))).id() + "|";
1796 if (dupesStr != "") {
1797 TitanVertex prefV = getPreferredDupe(transId,
1798 fromAppId, g, thisParentsVertList,
1801 if (prefV == null) {
1802 // We could not determine which duplicate to
1804 dupesStr = dupesStr + "KeepVid=UNDETERMINED";
1805 returnList.add(dupesStr);
1807 Boolean didRemove = false;
1808 dupesStr = dupesStr + "KeepVid="
1809 + prefV.id().toString();
1811 didRemove = deleteNonKeepersIfAppropriate(
1812 g, dupesStr, prefV.id()
1814 deleteCandidateList, singleCommits);
1819 // keep them on our list
1820 returnList.add(dupesStr);
1827 } catch (Exception e) {
1828 LOGGER.warn(" >>> Threw an error in checkAndProcessDupes - just absorb this error and move on. ", e);
1833 }// End of checkAndProcessDupes()
1836 * Group verts by dep nodes.
1838 * @param transId the trans id
1839 * @param fromAppId the from app id
1841 * @param version the version
1842 * @param nType the n type
1843 * @param passedVertList the passed vert list
1844 * @param dbMaps the db maps
1845 * @return the hash map
1846 * @throws AAIException the AAI exception
1848 private static HashMap<String, ArrayList<TitanVertex>> groupVertsByDepNodes(
1849 String transId, String fromAppId, TitanTransaction g, String version,
1850 String nType, ArrayList<TitanVertex> passedVertList, DbMaps dbMaps)
1851 throws AAIException {
1852 // Given a list of Titan Vertices, group them together by dependent
1853 // nodes. Ie. if given a list of
1854 // ip address nodes (assumed to all have the same key info) they might
1855 // sit under several different parent vertices.
1856 // Under Normal conditions, there would only be one per parent -- but
1857 // we're trying to find duplicates - so we
1858 // allow for the case where more than one is under the same parent node.
1860 HashMap<String, ArrayList<TitanVertex>> retHash = new HashMap<String, ArrayList<TitanVertex>>();
1861 if (!dbMaps.NodeDependencies.containsKey(nType)) {
1862 // This method really should not have been called if this is not the
1864 // that depends on a parent for uniqueness, so just return the empty
1869 // Find out what types of nodes the passed in nodes can depend on
1870 ArrayList<String> depNodeTypeL = new ArrayList<>();
1871 Collection<String> depNTColl = dbMaps.NodeDependencies.get(nType);
1872 Iterator<String> ntItr = depNTColl.iterator();
1873 while (ntItr.hasNext()) {
1874 depNodeTypeL.add(ntItr.next());
1876 // For each vertex, we want find its dependent vertex and add it to
1877 // other vertexes that are dependent on that same guy.
1878 if (passedVertList != null) {
1879 Iterator<TitanVertex> iter = passedVertList.iterator();
1880 while (iter.hasNext()) {
1881 TitanVertex thisVert = iter.next();
1882 ArrayList<TitanVertex> connectedVList = getConnectedNodes( g, thisVert );
1883 Iterator<TitanVertex> connIter = connectedVList.iterator();
1884 while (connIter.hasNext()) {
1885 TitanVertex tvCon = connIter.next();
1887 Object obj = tvCon.<Object>property("aai-node-type").orElse(null);
1889 conNt = obj.toString();
1891 if (depNTColl.contains(conNt)) {
1892 // This must be the parent/dependent node
1893 String parentVid = tvCon.id().toString();
1894 if (retHash.containsKey(parentVid)) {
1895 // add this vert to the list for this parent key
1896 retHash.get(parentVid).add(thisVert);
1898 // This is the first one we found on this parent
1899 ArrayList<TitanVertex> vList = new ArrayList<>();
1900 vList.add(thisVert);
1901 retHash.put(parentVid, vList);
1910 }// end of groupVertsByDepNodes()
1913 * Delete non keepers if appropriate.
1916 * @param dupeInfoString the dupe info string
1917 * @param vidToKeep the vid to keep
1918 * @param deleteCandidateList the delete candidate list
1919 * @param singleCommits the single commits
1920 * @return the boolean
1922 private static Boolean deleteNonKeepersIfAppropriate(TitanTransaction g,
1923 String dupeInfoString, String vidToKeep,
1924 Set<String> deleteCandidateList, Boolean singleCommits) {
1926 Boolean deletedSomething = false;
1927 // This assumes that the dupeInfoString is in the format of
1928 // pipe-delimited vid's followed by
1929 // ie. "3456|9880|keepVid=3456"
1930 if (deleteCandidateList == null || deleteCandidateList.size() == 0) {
1931 // No vid's on the candidate list -- so no deleting will happen on
1936 String[] dupeArr = dupeInfoString.split("\\|");
1937 ArrayList<String> idArr = new ArrayList<>();
1938 int lastIndex = dupeArr.length - 1;
1939 for (int i = 0; i <= lastIndex; i++) {
1940 if (i < lastIndex) {
1941 // This is not the last entry, it is one of the dupes,
1942 String vidString = dupeArr[i];
1943 idArr.add(vidString);
1945 // This is the last entry which should tell us if we have a
1947 String prefString = dupeArr[i];
1948 if (prefString.equals("KeepVid=UNDETERMINED")) {
1949 // They sent us a bad string -- nothing should be deleted if
1950 // no dupe could be tagged as preferred
1953 // If we know which to keep, then the prefString should look
1954 // like, "KeepVid=12345"
1955 String[] prefArr = prefString.split("=");
1956 if (prefArr.length != 2 || (!prefArr[0].equals("KeepVid"))) {
1957 LOGGER.error("Bad format. Expecting KeepVid=999999");
1960 String keepVidStr = prefArr[1];
1961 if (idArr.contains(keepVidStr)) {
1962 idArr.remove(keepVidStr);
1964 // So now, the idArr should just contain the vid's
1965 // that we want to remove.
1966 for (int x = 0; x < idArr.size(); x++) {
1967 boolean okFlag = true;
1968 String thisVid = idArr.get(x);
1969 if (deleteCandidateList.contains(thisVid)) {
1970 // This vid is a valid delete candidate from
1971 // a prev. run, so we can remove it.
1973 long longVertId = Long
1974 .parseLong(thisVid);
1976 .getVertex(longVertId);
1978 if (singleCommits) {
1979 // NOTE - the singleCommits option is not used in normal processing
1981 g = AAIGraph.getInstance().getGraph().newTransaction();
1983 } catch (Exception e) {
1985 LOGGER.error("ERROR trying to delete VID = " + thisVid, e);
1988 LOGGER.info(" DELETED VID = " + thisVid);
1989 deletedSomething = true;
1994 LOGGER.error("ERROR - Vertex Id to keep not found in list of dupes. dupeInfoString = ["
1995 + dupeInfoString + "]");
1999 }// else we know which one to keep
2001 }// for each vertex in a group
2003 return deletedSomething;
2005 }// end of deleteNonKeepersIfAppropriate()
2009 * Gets the node just using key params.
2011 * @param transId the trans id
2012 * @param fromAppId the from app id
2013 * @param graph the graph
2014 * @param nodeType the node type
2015 * @param keyPropsHash the key props hash
2016 * @param apiVersion the api version
2017 * @return the node just using key params
2018 * @throws AAIException the AAI exception
2020 public static List <TitanVertex> getNodeJustUsingKeyParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
2021 HashMap<String,Object> keyPropsHash, String apiVersion ) throws AAIException{
2023 List <TitanVertex> retVertList = new ArrayList <> ();
2025 // We assume that all NodeTypes have at least one key-property defined.
2026 // Note - instead of key-properties (the primary key properties), a user could pass
2027 // alternate-key values if they are defined for the nodeType.
2028 List<String> kName = new ArrayList<>();
2029 List<Object> kVal = new ArrayList<>();
2030 if( keyPropsHash == null || keyPropsHash.isEmpty() ) {
2031 throw new AAIException("AAI_6120", " NO key properties passed for this getNodeJustUsingKeyParams() request. NodeType = [" + nodeType + "]. ");
2035 for( Map.Entry<String, Object> entry : keyPropsHash.entrySet() ){
2037 kName.add(i, entry.getKey());
2038 kVal.add(i, entry.getValue());
2040 int topPropIndex = i;
2041 TitanVertex tiV = null;
2042 String propsAndValuesForMsg = "";
2043 Iterable <?> verts = null;
2046 if( topPropIndex == 0 ){
2047 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
2048 verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
2050 else if( topPropIndex == 1 ){
2051 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
2052 + kName.get(1) + " = " + kVal.get(1) + ") ";
2053 verts = graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has("aai-node-type",nodeType).vertices();
2055 else if( topPropIndex == 2 ){
2056 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
2057 + kName.get(1) + " = " + kVal.get(1) + ", "
2058 + kName.get(2) + " = " + kVal.get(2) + ") ";
2059 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();
2061 else if( topPropIndex == 3 ){
2062 propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
2063 + kName.get(1) + " = " + kVal.get(1) + ", "
2064 + kName.get(2) + " = " + kVal.get(2) + ", "
2065 + kName.get(3) + " = " + kVal.get(3) + ") ";
2066 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();
2069 throw new AAIException("AAI_6114", " We only support 4 keys per nodeType for now \n");
2072 catch( Exception ex ){
2073 LOGGER.error( " ERROR trying to get node for: [" + propsAndValuesForMsg + "]", ex);
2076 if( verts != null ){
2077 Iterator <?> vertI = verts.iterator();
2078 while( vertI.hasNext() ){
2079 tiV = (TitanVertex) vertI.next();
2080 retVertList.add(tiV);
2084 if( retVertList.size() == 0 ){
2085 LOGGER.debug("DEBUG No node found for nodeType = [" + nodeType +
2086 "], propsAndVal = " + propsAndValuesForMsg );
2091 }// End of getNodeJustUsingKeyParams()
2094 * Show all edges for node.
2096 * @param transId the trans id
2097 * @param fromAppId the from app id
2098 * @param tVert the t vert
2099 * @return the array list
2101 private static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){
2103 ArrayList <String> retArr = new ArrayList <> ();
2104 Iterator <Edge> eI = tVert.edges(Direction.IN);
2105 if( ! eI.hasNext() ){
2106 retArr.add("No IN edges were found for this vertex. ");
2108 while( eI.hasNext() ){
2109 TitanEdge ed = (TitanEdge) eI.next();
2110 String lab = ed.label();
2111 TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
2113 retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
2116 String nType = vtx.<String>property("aai-node-type").orElse(null);
2117 String vid = vtx.id().toString();
2118 retArr.add("Found an IN edge (" + lab + ") to this vertex from a [" + nType + "] node with VtxId = " + vid );
2123 eI = tVert.edges(Direction.OUT);
2124 if( ! eI.hasNext() ){
2125 retArr.add("No OUT edges were found for this vertex. ");
2127 while( eI.hasNext() ){
2128 TitanEdge ed = (TitanEdge) eI.next();
2129 String lab = ed.label();
2130 TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
2132 retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
2135 String nType = vtx.<String>property("aai-node-type").orElse(null);
2136 String vid = vtx.id().toString();
2137 retArr.add("Found an OUT edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid );
2145 * Show properties for node.
2147 * @param transId the trans id
2148 * @param fromAppId the from app id
2149 * @param tVert the t vert
2150 * @return the array list
2152 private static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){
2154 ArrayList <String> retArr = new ArrayList <> ();
2155 if( tVert == null ){
2156 retArr.add("null Node object passed to showPropertiesForNode()\n");
2159 String nodeType = "";
2160 Object ob = tVert.<Object>property("aai-node-type").orElse(null);
2165 nodeType = ob.toString();
2168 retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]");
2169 retArr.add(" Property Detail: ");
2170 Iterator<VertexProperty<Object>> pI = tVert.properties();
2171 while( pI.hasNext() ){
2172 VertexProperty<Object> tp = pI.next();
2173 Object val = tp.value();
2174 retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] ");
2181 private static ArrayList <TitanVertex> getConnectedNodes(TitanTransaction g, TitanVertex startVtx )
2182 throws AAIException {
2184 ArrayList <TitanVertex> retArr = new ArrayList <> ();
2185 if( startVtx == null ){
2189 GraphTraversal<Vertex, Vertex> modPipe = null;
2190 modPipe = g.traversal().V(startVtx).both();
2191 if( modPipe != null && modPipe.hasNext() ){
2192 while( modPipe.hasNext() ){
2193 TitanVertex conVert = (TitanVertex) modPipe.next();
2194 retArr.add(conVert);
2200 }// End of getConnectedNodes()
2203 private static ArrayList <TitanVertex> getConnectedChildren( TitanTransaction graph,
2204 TitanVertex startVtx ) throws AAIException{
2206 ArrayList <TitanVertex> childList = new ArrayList <> ();
2208 Iterable <?> verts = startVtx.query().direction(Direction.OUT).has("isParent",true).vertices();
2209 Iterator <?> vertI = verts.iterator();
2210 TitanVertex tmpVtx = null;
2211 while( vertI != null && vertI.hasNext() ){
2212 tmpVtx = (TitanVertex) vertI.next();
2213 childList.add(tmpVtx);
2218 }// End of getConnectedChildren()