aa5084b988d58fcde6052dbc00950c98843dab5f
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / dbgen / DataGrooming.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
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
10
11      http://www.apache.org/licenses/LICENSE-2.0
12
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=========================================================
19  */
20
21 package org.openecomp.aai.dbgen;
22
23 import java.io.BufferedReader;
24 import java.io.BufferedWriter;
25 import java.io.File;
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;
37 import java.util.Map;
38 import java.util.Properties;
39 import java.util.Set;
40 import java.util.TimeZone;
41 import java.util.UUID;
42
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;
50
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;
66
67
68 public class DataGrooming {
69
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;
74         
75         /**
76          * The main method.
77          *
78          * @param args the arguments
79          */
80         public static void main(String[] args) {
81                 
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);
86                                 
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;
97                 
98                 int maxRecordsToFix = AAIConstants.AAI_GROOMING_DEFAULT_MAX_FIX;
99                 int sleepMinutes = AAIConstants.AAI_GROOMING_DEFAULT_SLEEP_MINUTES;
100                 try {
101                         String maxFixStr = AAIConfig.get("aai.grooming.default.max.fix");
102                         if( maxFixStr != null &&  !maxFixStr.equals("") ){
103                                 maxRecordsToFix = Integer.parseInt(maxFixStr);
104                         }
105                         String sleepStr = AAIConfig.get("aai.grooming.default.sleep.minutes");
106                         if( sleepStr != null &&  !sleepStr.equals("") ){
107                                 sleepMinutes = Integer.parseInt(sleepStr);
108                         }
109                 }
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. ");
113                 }
114                 
115                 String prevFileName = "";
116                 dupeGrpsDeleted = 0;
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";
121
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")) {
129                                         doAutoFix = true;
130                                 } else if (thisArg.equals("-dontFixOrphans")) {
131                                         dontFixOrphansFlag = true;
132                                 } else if (thisArg.equals("-singleCommits")) {
133                                         singleCommits = true;
134                                 } else if (thisArg.equals("-dupeCheckOff")) {
135                                         dupeCheckOff = true;
136                                 } else if (thisArg.equals("-dupeFixOn")) {
137                                         dupeFixOn = true;
138                                 } else if (thisArg.equals("-ghost2CheckOff")) {
139                                         ghost2CheckOff = true;
140                                 } else if (thisArg.equals("-neverUseCache")) {
141                                         neverUseCache = true;
142                                 } else if (thisArg.equals("-ghost2FixOn")) {
143                                         ghost2FixOn = true;
144                                 } else if (thisArg.equals("-maxFix")) {
145                                         i++;
146                                         if (i >= args.length) {
147                                                 LOGGER.error(" No value passed with -maxFix option.  ");
148                                                 System.exit(0);
149                                         }
150                                         String nextArg = args[i];
151                                         try {
152                                                 maxRecordsToFix = Integer.parseInt(nextArg);
153                                         } catch (Exception e) {
154                                                 LOGGER.error("Bad value passed with -maxFix option: ["
155                                                                                 + nextArg + "]");
156                                                 System.exit(0);
157                                         }
158                                 } else if (thisArg.equals("-sleepMinutes")) {
159                                         i++;
160                                         if (i >= args.length) {
161                                                 LOGGER.error("No value passed with -sleepMinutes option.");
162                                                 System.exit(0);
163                                         }
164                                         String nextArg = args[i];
165                                         try {
166                                                 sleepMinutes = Integer.parseInt(nextArg);
167                                         } catch (Exception e) {
168                                                 LOGGER.error("Bad value passed with -sleepMinutes option: ["
169                                                                                 + nextArg + "]");
170                                                 System.exit(0);
171                                         }
172                                 } else if (thisArg.equals("-f")) {
173                                         i++;
174                                         if (i >= args.length) {
175                                                 LOGGER.error(" No value passed with -f option. ");
176                                                 System.exit(0);
177                                         }
178                                         prevFileName = args[i];
179                                 } else {
180                                         LOGGER.error(" Unrecognized argument passed to DataGrooming: ["
181                                                                         + thisArg + "]. ");
182                                         LOGGER.error(" Valid values are: -f -autoFix -maxFix -edgesOnly -dupeFixOn -donFixOrphans -sleepMinutes -neverUseCache");
183                                         System.exit(0);
184                                 }
185                         }
186                 }
187                 
188
189                 IngestModelMoxyOxm moxyMod = new IngestModelMoxyOxm();
190                 try {
191                         ArrayList <String> defaultVerLst = new ArrayList <> ();
192                         defaultVerLst.add( AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP) );
193                         moxyMod.init( defaultVerLst, false);
194                 }
195                 catch (Exception ex){
196                         LOGGER.error("ERROR - Could not do the moxyMod.init()", ex);
197                         System.exit(1);
198                 }
199
200                 try {
201                         if (!prevFileName.equals("")) {
202                                 // They are trying to fix some data based on a data in a
203                                 // previous file.
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
218                                 // two runs.
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. ");
229                                 } else {
230                                         // We'll sleep a little and then run a fix-pass based on the
231                                         // first-run's output file.
232                                         try {
233                                                 LOGGER.info("About to sleep for " + sleepMinutes
234                                                                 + " minutes.");
235                                                 int sleepMsec = sleepMinutes * 60 * 1000;
236                                                 Thread.sleep(sleepMsec);
237                                         } catch (InterruptedException ie) {
238                                                 LOGGER.info("\n >>> Sleep Thread has been Interrupted <<< ");
239                                                 System.exit(0);
240                                         }
241
242                                         d = new SimpleDateFormat("yyyyMMddHHmm");
243                                         d.setTimeZone(TimeZone.getTimeZone("GMT"));
244                                         dteStr = d.format(new Date()).toString();
245                                         String secondGroomOutFileName = "dataGrooming." + dteStr
246                                                         + ".out";
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);
257                                 }
258                         } else {
259                                 // Do the grooming - plain vanilla (no fix-it-file, no
260                                 // auto-fixing)
261                                 Boolean finalShutdownFlag = true;
262                                 LOGGER.info(" Call doTheGrooming() ");
263                                 Boolean cacheDbOkFlag = true;
264                                 if( neverUseCache ){
265                                         // They have forbidden us from using a cached db connection.
266                                         cacheDbOkFlag = false;
267                                 }
268                                 doTheGrooming("", edgesOnlyFlag, dontFixOrphansFlag,
269                                                 maxRecordsToFix, groomOutFileName, ver, singleCommits,
270                                                 dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn, 
271                                                 finalShutdownFlag, cacheDbOkFlag);
272                         }
273                 } catch (Exception ex) {
274                         LOGGER.error("Exception while grooming data", ex);
275                 }
276
277                 LOGGER.info(" Done! ");
278                 System.exit(0);
279
280         }// End of main()
281
282         /**
283          * Do the grooming.
284          *
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
298          * @return the int
299          */
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) {
307
308                 LOGGER.debug(" Entering doTheGrooming \n");
309
310                 int cleanupCandidateCount = 0;
311                 BufferedWriter bw = null;
312                 TitanGraph graph = null;
313                 TitanGraph graph2 = null;
314                 int deleteCount = 0;
315                 boolean executeFinalCommit = false;
316                 Set<String> deleteCandidateList = new LinkedHashSet<>();
317                 Set<String> processedVertices = new LinkedHashSet<>();
318                 TitanTransaction g = null;
319                 TitanTransaction g2 = null;
320                 try {
321                         AAIConfig.init();
322                         String targetDir = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP
323                                         + "logs" + AAIConstants.AAI_FILESEP + "data"
324                                         + AAIConstants.AAI_FILESEP + "dataGrooming";
325
326                         // Make sure the target directory exists
327                         new File(targetDir).mkdirs();
328
329                         if (!fileNameForFixing.equals("")) {
330                                 deleteCandidateList = getDeleteList(targetDir,
331                                                 fileNameForFixing, edgesOnlyFlag, dontFixOrphansFlag,
332                                                 dupeFixOn);
333                         }
334
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: "
339                                                 + maxRecordsToFix
340                                                 + ".  No candidates will be deleted. ");
341                                 // Clear out the list so it won't be processed below.
342                                 deleteCandidateList = new LinkedHashSet<>();
343                         }
344
345                         SimpleDateFormat d = new SimpleDateFormat("yyyyMMddHHmm");
346                         d.setTimeZone(TimeZone.getTimeZone("GMT"));
347
348                         String fullOutputFileName = targetDir + AAIConstants.AAI_FILESEP
349                                         + groomOutFileName;
350                         File groomOutFile = new File(fullOutputFileName);
351                         try {
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);
357                         }
358
359                         LOGGER.info(" Will write to " + fullOutputFileName );
360                         FileWriter fw = new FileWriter(groomOutFile.getAbsoluteFile());
361                         bw = new BufferedWriter(fw);
362                         ErrorLogHelper.loadProperties();
363                         
364                         LOGGER.info("    ---- NOTE --- about to open graph (takes a little while)--------\n");
365
366                         if( cacheDbOkFlag ){
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);
370                         }
371                         else {
372                                 graph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG);
373                         }
374                         if (graph == null) {
375                                 String emsg = "null graph object in DataGrooming\n";
376                                 throw new AAIException("AAI_6101", emsg);
377                         }
378                 
379                         LOGGER.debug(" Got the graph object. ");
380                         
381                         g = graph.newTransaction();
382                         if (g == null) {
383                                 String emsg = "null graphTransaction object in DataGrooming\n";
384                                 throw new AAIException("AAI_6101", emsg);
385                         }
386
387                         
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<>();
397
398
399                         DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
400                         
401                         Iterator<String> nodeMapKPropsIterator = dbMaps.NodeKeyProps.keySet().iterator();
402                         String ntList = "";
403
404                         LOGGER.info("  Starting DataGrooming Processing ");
405
406                         if (edgesOnlyFlag) {
407                                 LOGGER.info(" NOTE >> Skipping Node processing as requested.  Will only process Edges. << ");
408                         } 
409                         else {
410                                 while (nodeMapKPropsIterator.hasNext()) {
411                                         String nType = nodeMapKPropsIterator.next();
412                                         int thisNtCount = 0;
413                                         int thisNtDeleteCount = 0;
414                                         LOGGER.debug(" >  Look at : [" + nType + "] ...");
415                                         ntList = ntList + "," + nType;
416
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);
422                                         }
423                                         else {
424                                                 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")"); 
425                                         }
426                                         
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);
431                                         }
432                                         
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());
441                                         }
442                                         
443                                         Iterator <?> iter = tmpList.iterator();
444                                         while (iter.hasNext()) {
445                                                 try {
446                                                         thisNtCount++;
447                                                         if( thisNtCount == lastShownForNt + 250 ){
448                                                                 lastShownForNt = thisNtCount;
449                                                                 LOGGER.debug("count for " + nType + " so far = " + thisNtCount );
450                                                         }
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);
455                                                                 continue;
456                                                         }
457                                                         totalNodeCount++;
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                                                         // -----------------------------------------------------------------------
464                                                         
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();
470                                                                 String propVal = "";
471                                                                 //delete an already deleted vertex
472                                                                 Object obj = thisVtx.<Object>property(propName).orElse(null);
473                                                                 if (obj != null) {
474                                                                         propVal = obj.toString();
475                                                                 }
476                                                                 propHashWithKeys.put(propName, propVal);
477                                                         }
478                                                         try {
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 );
488                                                                 } 
489                                                                 else {
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;
496                                                                         int pCount = 0;
497                                                                         while( vertI2 != null && vertI2.hasNext() ){
498                                                                                 parentVtx = (TitanVertex) vertI2.next();
499                                                                                 pCount++;
500                                                                         }
501                                                                         if( pCount <= 0 ){
502                                                                         
503                                                                         
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()){
506                                                                                         
507                                                                                 // It's Missing it's dependent/parent node 
508                                                                                 depNodeOk = false;
509                                                                                 boolean zeroEdges = false;
510                                                                                 try {
511                                                                                         Iterator<Edge> tmpEdgeIter = thisVtx.edges(Direction.BOTH);
512                                                                                         int edgeCount = 0;
513                                                                                         while( tmpEdgeIter.hasNext() ){
514                                                                                                 edgeCount++;
515                                                                                                 tmpEdgeIter.next();
516                                                                                         }
517                                                                                         if( edgeCount == 0 ){  
518                                                                                                 zeroEdges = true;
519                                                                                         }
520                                                                                 } catch (Exception ex) {
521                                                                                         LOGGER.warn("WARNING from inside the for-each-vid-loop orphan-edges-check ", ex);
522                                                                                 }
523                                                                                 
524                                                                                 if (deleteCandidateList.contains(thisVid)) {
525                                                                                         boolean okFlag = true;
526                                                                                         try {
527                                                                                                 processedVertices.add(thisVtx.id().toString());
528                                                                                                 thisVtx.remove();
529                                                                                                 deleteCount++;
530                                                                                                 thisNtDeleteCount++;
531                                                                                         } catch (Exception e) {
532                                                                                                 okFlag = false;
533                                                                                                 LOGGER.error("ERROR trying to delete missing-dep-node VID = " + thisVid, e);
534                                                                                         }
535                                                                                         if (okFlag) {
536                                                                                                 LOGGER.info(" DELETED missing-dep-node VID = " + thisVid);
537                                                                                         }
538                                                                                 } else {
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".
543                                                                                         if( zeroEdges ){
544                                                                                                 missingDepNodeHash.put(thisVid, thisVtx);
545                                                                                         }
546                                                                                         else {
547                                                                                                 orphanNodeHash.put(thisVid, thisVtx);
548                                                                                         }
549                                                                                 }
550                                                                         }
551                                                                         else if ( pCount > 1 ){
552                                                                                 // Not sure how this could happen?  Should we do something here?
553                                                                                 depNodeOk = false;
554                                                                         }
555                                                                         else {
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);
566                                                                                         }
567                                                                                 }
568                                                                         }
569                                                                 }
570                                                                 
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;
576                                                                                 try {
577                                                                                         thisVtx.remove();
578                                                                                         deleteCount++;
579                                                                                         thisNtDeleteCount++;
580                                                                                 } catch (Exception e) {
581                                                                                         okFlag = false;
582                                                                                         LOGGER.error("ERROR trying to delete phantom VID = " + thisVid, e);
583                                                                                 }
584                                                                                 if (okFlag) {
585                                                                                         LOGGER.info(" DELETED VID = " + thisVid);
586                                                                                 }
587                                                                         } else {
588                                                                                 ghostNodeHash.put(thisVid, thisVtx);
589                                                                         }
590                                                                 }
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);
604                                                                         }
605                                                                 }
606                                                         } 
607                                                         catch (AAIException e1) {
608                                                                 LOGGER.warn(" For nodeType = " + nType + " Caught exception", e1);
609                                                                 errArr.add(e1.getErrorObject().toString());
610                                                         }
611                                                         catch (Exception e2) {
612                                                                 LOGGER.warn(" For nodeType = " + nType
613                                                                                 + " Caught exception", e2);
614                                                                 errArr.add(e2.getMessage());
615                                                         }
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);
619                                                 }
620                                                 
621                                         } // while loop for each record of a nodeType
622                                         
623                                         if ( (thisNtDeleteCount > 0) && singleCommits ) {
624                                                 // NOTE - the singleCommits option is not used in normal processing
625                                                 g.commit();
626                                                 g = AAIGraph.getInstance().getGraph().newTransaction();
627                                                 
628                                         }
629                                         thisNtDeleteCount = 0;
630                                         LOGGER.info( " Processed " + thisNtCount + " records for [" + nType + "], " + totalNodeCount + " total overall. " );
631                                         
632                                 }// While-loop for each node type
633                         }// end of check to make sure we weren't only supposed to do edges
634
635                 
636                         // --------------------------------------------------------------------------------------
637                         // Now, we're going to look for one-armed-edges. Ie. an edge that
638                         // should have
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
642                         // empty.
643                         // --------------------------------------------------------------------------------------
644
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);
653                         } else {
654                                 LOGGER.debug("Got the graph2 object... \n");
655                         }
656                         g2 = graph2.newTransaction();
657                         if (g2 == null) {
658                                 String emsg = "null graphTransaction2 object in DataGrooming\n";
659                                 throw new AAIException("AAI_6101", emsg);
660                         }
661                         
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
666                         // through these
667                         while (vItor3.hasNext()) {
668                                 Vertex v = vItor3.next();
669                                 vertList.add(v);
670                         }
671                         int counter = 0;
672                         int lastShown = 0;
673                         Iterator<Vertex> vItor2 = vertList.iterator();
674                         LOGGER.info(" Checking for bad edges  --- ");
675
676                         while (vItor2.hasNext()) {
677                                 Vertex v = null;
678                                 try {
679                                         try {
680                                                 v = vItor2.next();
681                                         } catch (Exception vex) {
682                                                 LOGGER.warn(">>> WARNING trying to get next vertex on the vItor2 ");
683                                                 continue;
684                                         }
685
686                                         counter++;
687                                         String thisVertId = "";
688                                         try {
689                                                 thisVertId = v.id().toString();
690                                         } catch (Exception ev) {
691                                                 LOGGER.warn("WARNING when doing getId() on a vertex from our vertex list.  ");
692                                                 continue;
693                                         }
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 = "
697                                                                                 + thisVertId
698                                                                                 + ", since that guy is a Phantom Node");
699                                                 continue;
700                                         }
701                                         if (counter == lastShown + 250) {
702                                                 lastShown = counter;
703                                                 LOGGER.info("... Checking edges for vertex # "
704                                                                 + counter);
705                                         }
706                                         Iterator<Edge> eItor = v.edges(Direction.BOTH);
707                                         while (eItor.hasNext()) {
708                                                 Edge e = null;
709                                                 Vertex vIn = null;
710                                                 Vertex vOut = null;
711                                                 try {
712                                                         e = eItor.next();
713                                                 } catch (Exception iex) {
714                                                         LOGGER.warn(">>> WARNING trying to get next edge on the eItor ", iex);
715                                                         continue;
716                                                 }
717
718                                                 try {
719                                                         vIn = e.inVertex();
720                                                 } catch (Exception err) {
721                                                         LOGGER.warn(">>> WARNING trying to get edge's In-vertex ", err);
722                                                 }
723                                                 String vNtI = "";
724                                                 String vIdI = "";
725                                                 TitanVertex ghost2 = null;
726                                                 
727                                                 Boolean keysMissing = true;
728                                                 Boolean cantGetUsingVid = false;
729                                                 if (vIn != null) {
730                                                         try {
731                                                                 Object ob = vIn.<Object>property("aai-node-type").orElse(null);
732                                                                 if (ob != null) {
733                                                                         vNtI = ob.toString();
734                                                                         keysMissing = anyKeyFieldsMissing(vNtI, vIn, dbMaps);
735                                                                 }
736                                                                 ob = vIn.id();
737                                                                 long vIdLong = 0L;
738                                                                 if (ob != null) {
739                                                                         vIdI = ob.toString();
740                                                                         vIdLong = Long.parseLong(vIdI);
741                                                                 }
742                                                                 
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;
748                                                                                 
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 
751                                                                                 // object.  
752                                                                                 try {
753                                                                                          ghost2 = g.getVertex(vIdLong);
754                                                                                 }
755                                                                                 catch( Exception ex){
756                                                                                         LOGGER.warn( "GHOST2 --  Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex);
757                                                                                 }
758                                                                                 if( ghost2 != null ){
759                                                                                         ghostNodeHash.put(vIdI, ghost2);
760                                                                                 }
761                                                                         }
762                                                                 }// end of the ghost2 checking
763                                                         } 
764                                                         catch (Exception err) {
765                                                                 LOGGER.warn(">>> WARNING trying to get edge's In-vertex props ", err);
766                                                         }
767                                                 }
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
777                                                                         try {
778                                                                                 if( (ghost2 != null) && ghost2FixOn ){
779                                                                                         ghost2.remove();
780                                                                                 }
781                                                                                 else {
782                                                                                         vIn.remove();
783                                                                                 }
784                                                                                 if (singleCommits) {
785                                                                                         // NOTE - the singleCommits option is not used in normal processing
786                                                                                         g.commit();
787                                                                                         g = AAIGraph.getInstance().getGraph().newTransaction();
788                                                                                 }
789                                                                                 deleteCount++;
790                                                                         } catch (Exception e1) {
791                                                                                 okFlag = false;
792                                                                                 LOGGER.warn("WARNING when trying to delete bad-edge-connected VERTEX VID = "
793                                                                                                 + vIdI, e1);
794                                                                         }
795                                                                         if (okFlag) {
796                                                                                 LOGGER.info(" DELETED vertex from bad edge = "
797                                                                                                                 + vIdI);
798                                                                         }
799                                                                 } else {
800                                                                         // remove the edge if we couldn't get the
801                                                                         // vertex
802                                                                         try {
803                                                                                 e.remove();
804                                                                                 if (singleCommits) {
805                                                                                         // NOTE - the singleCommits option is not used in normal processing
806                                                                                         g.commit();
807                                                                                         g = AAIGraph.getInstance().getGraph().newTransaction();
808                                                                                 }
809                                                                                 deleteCount++;
810                                                                         } catch (Exception ex) {
811                                                                                 // NOTE - often, the exception is just
812                                                                                 // that this edge has already been
813                                                                                 // removed
814                                                                                 okFlag = false;
815                                                                                 LOGGER.warn("WARNING when trying to delete edge = "
816                                                                                                 + thisEid);
817                                                                         }
818                                                                         if (okFlag) {
819                                                                                 LOGGER.info(" DELETED edge = " + thisEid);
820                                                                         }
821                                                                 }
822                                                         } else {
823                                                                 oneArmedEdgeHash.put(thisEid, e);
824                                                                 if ((vIn != null) && (vIn.id() != null)) {
825                                                                         emptyVertexHash.put(thisEid, vIn.id()
826                                                                                         .toString());
827                                                                 }
828                                                         }
829                                                 }
830
831                                                 try {
832                                                         vOut = e.outVertex();
833                                                 } catch (Exception err) {
834                                                         LOGGER.warn(">>> WARNING trying to get edge's Out-vertex ");
835                                                 }
836                                                 String vNtO = "";
837                                                 String vIdO = "";
838                                                 ghost2 = null;
839                                                 keysMissing = true;
840                                                 cantGetUsingVid = false;
841                                                 if (vOut != null) {
842                                                         try {
843                                                                 Object ob = vOut.<Object>property("aai-node-type").orElse(null);
844                                                                 if (ob != null) {
845                                                                         vNtO = ob.toString();
846                                                                         keysMissing = anyKeyFieldsMissing(vNtO,
847                                                                                         vOut, dbMaps);
848                                                                 }
849                                                                 ob = vOut.id();
850                                                                 long vIdLong = 0L;
851                                                                 if (ob != null) {
852                                                                         vIdO = ob.toString();
853                                                                         vIdLong = Long.parseLong(vIdO);
854                                                                 }
855                                                                 
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
862                                                                                 try {
863                                                                                          ghost2 = g.getVertex(vIdLong);
864                                                                                 }
865                                                                                 catch( Exception ex){
866                                                                                         LOGGER.warn( "GHOST2 -- Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex);
867                                                                                 }
868                                                                                 if( ghost2 != null ){
869                                                                                         ghostNodeHash.put(vIdO, ghost2);
870                                                                                 }
871                                                                         }
872                                                                 }
873                                                         } catch (Exception err) {
874                                                                 LOGGER.warn(">>> WARNING trying to get edge's Out-vertex props ", err);
875                                                         }
876                                                 }
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
886                                                                         try {
887                                                                                 if( (ghost2 != null) && ghost2FixOn ){
888                                                                                         ghost2.remove();
889                                                                                 }
890                                                                                 else {
891                                                                                         vOut.remove();
892                                                                                 }
893                                                                                 if (singleCommits) {
894                                                                                         // NOTE - the singleCommits option is not used in normal processing
895                                                                                         g.commit();
896                                                                                         g = AAIGraph.getInstance().getGraph().newTransaction();
897                                                                                 }
898                                                                                 deleteCount++;
899                                                                         } catch (Exception e1) {
900                                                                                 okFlag = false;
901                                                                                 LOGGER.warn("WARNING when trying to delete bad-edge-connected VID = "
902                                                                                                 + vIdO, e1);
903                                                                         }
904                                                                         if (okFlag) {
905                                                                                 LOGGER.info(" DELETED vertex from bad edge = "
906                                                                                                                 + vIdO);
907                                                                         }
908                                                                 } else {
909                                                                         // remove the edge if we couldn't get the
910                                                                         // vertex
911                                                                         try {
912                                                                                 e.remove();
913                                                                                 if (singleCommits) {
914                                                                                         // NOTE - the singleCommits option is not used in normal processing
915                                                                                         g.commit();
916                                                                                         g = AAIGraph.getInstance().getGraph().newTransaction();
917                                                                                 }
918                                                                                 deleteCount++;
919                                                                         } catch (Exception ex) {
920                                                                                 // NOTE - often, the exception is just
921                                                                                 // that this edge has already been
922                                                                                 // removed
923                                                                                 okFlag = false;
924                                                                                 LOGGER.warn("WARNING when trying to delete edge = "
925                                                                                                 + thisEid, ex);
926                                                                         }
927                                                                         if (okFlag) {
928                                                                                 LOGGER.info(" DELETED edge = " + thisEid);
929                                                                         }
930                                                                 }
931                                                         } else {
932                                                                 oneArmedEdgeHash.put(thisEid, e);
933                                                                 if ((vOut != null) && (vOut.id() != null)) {
934                                                                         emptyVertexHash.put(thisEid, vOut.id()
935                                                                                         .toString());
936                                                                 }
937                                                         }
938                                                 }
939                                         }// End of while-edges-loop
940                                 } catch (Exception exx) {
941                                         LOGGER.warn("WARNING from in the while-verts-loop ", exx);
942                                 }
943                         }// End of while-vertices-loop
944
945                         deleteCount = deleteCount + dupeGrpsDeleted;
946                         if (!singleCommits && deleteCount > 0) {
947                                 try {
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);
954                                         deleteCount = 0;
955                                 }
956                         }
957
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();
963
964                         deleteCount = deleteCount + dupeGrpsDeleted;
965
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");
972                         }
973                         bw.write("Deleted this many delete candidates =  " + deleteCount
974                                         + "\n");
975                         bw.write("Total number of nodes looked at =  " + totalNodeCount
976                                         + "\n");
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");
985
986                         bw.write("\n ------------- Delete Candidates ---------\n");
987                         for (Map.Entry<String, TitanVertex> entry : ghostNodeHash
988                                         .entrySet()) {
989                                 String vid = entry.getKey();
990                                 bw.write("DeleteCandidate: Phantom Vid = [" + vid + "]\n");
991                                 cleanupCandidateCount++;
992                         }
993                         for (Map.Entry<String, TitanVertex> entry : orphanNodeHash
994                                         .entrySet()) {
995                                 String vid = entry.getKey();
996                                 bw.write("DeleteCandidate: OrphanDepNode Vid = [" + vid + "]\n");
997                                 if (!dontFixOrphansFlag) {
998                                         cleanupCandidateCount++;
999                                 }
1000                         }
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++;
1005                         }
1006                         for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash
1007                                         .entrySet()) {
1008                                 String vid = entry.getKey();
1009                                 bw.write("DeleteCandidate: (maybe) missingDepNode Vid = ["
1010                                                 + vid + "]\n");
1011                                 cleanupCandidateCount++;
1012                         }
1013                         bw.write("\n-- NOTE - To see DeleteCandidates for Duplicates, you need to look in the Duplicates Detail section below.\n");
1014
1015                         bw.write("\n ------------- GHOST NODES - detail ");
1016                         for (Map.Entry<String, TitanVertex> entry : ghostNodeHash
1017                                         .entrySet()) {
1018                                 try {
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");
1025                                         }
1026         
1027                                         retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
1028                                                         entry.getValue());
1029                                         for (String info : retArr) {
1030                                                 bw.write(info + "\n");
1031                                         }
1032                                 } catch (Exception dex) {
1033                                         LOGGER.error("error trying to print detail info for a ghost-node:  ", dex);
1034                                 }
1035                         }
1036
1037                         bw.write("\n ------------- Missing Dependent Edge ORPHAN NODES - detail: ");
1038                         for (Map.Entry<String, TitanVertex> entry : orphanNodeHash
1039                                         .entrySet()) {
1040                                 try {
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");
1047                                         }
1048         
1049                                         retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
1050                                                         entry.getValue());
1051                                         for (String info : retArr) {
1052                                                 bw.write(info + "\n");
1053                                         }
1054                                 } catch (Exception dex) {
1055                                         LOGGER.error("error trying to print detail info for a Orphan Node /missing dependent edge", dex);
1056                                 }
1057                         }
1058
1059                         bw.write("\n ------------- Missing Dependent Edge (but not orphan) NODES: ");
1060                         for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash
1061                                         .entrySet()) {
1062                                 try {
1063                                         String vid = entry.getKey();
1064                                         bw.write("\n>  Missing edge to Dependent Node (but has edges) Vid = "
1065                                                         + vid + "\n");
1066                                         ArrayList<String> retArr = showPropertiesForNode(
1067                                                         TRANSID, FROMAPPID, entry.getValue());
1068                                         for (String info : retArr) {
1069                                                 bw.write(info + "\n");
1070                                         }
1071         
1072                                         retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
1073                                                         entry.getValue());
1074                                         for (String info : retArr) {
1075                                                 bw.write(info + "\n");
1076                                         }
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);
1079                                 }
1080                         }
1081
1082                         bw.write("\n ------------- EDGES pointing to empty/bad vertices: ");
1083                         for (Map.Entry<String, Edge> entry : oneArmedEdgeHash.entrySet()) {
1084                                 try {
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");
1096                                         }
1097                                 } catch (Exception pex) {
1098                                         LOGGER.error("error trying to print empty/bad vertex data: ", pex);
1099                                 }
1100                         }
1101
1102                         bw.write("\n ------------- Duplicates: ");
1103                         Iterator<String> dupeIter = dupeGroups.iterator();
1104                         int dupeSetCounter = 0;
1105                         while (dupeIter.hasNext()) {
1106                                 dupeSetCounter++;
1107                                 String dset = (String) dupeIter.next();
1108
1109                                 bw.write("\n --- Duplicate Group # " + dupeSetCounter
1110                                                 + " Detail -----------\n");
1111                                 try {
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
1123                                                                         + " ----\n");
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();
1131                                                         }
1132                                                         ArrayList<String> retArr = showPropertiesForNode(TRANSID, FROMAPPID, vtx);
1133                                                         for (String info : retArr) {
1134                                                                 bw.write(info + "\n");
1135                                                         }
1136
1137                                                         retArr = showAllEdgesForNode(TRANSID,
1138                                                                         FROMAPPID, vtx);
1139                                                         for (String info : retArr) {
1140                                                                 bw.write(info + "\n");
1141                                                         }
1142                                                 } else {
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");
1149                                                         } else {
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");
1156                                                                 } else {
1157                                                                         String keepVidStr = prefArr[1];
1158                                                                         if (idArr.contains(keepVidStr)) {
1159                                                                                 bw.write("\n The vertex we want to KEEP has vertexId = "
1160                                                                                                 + keepVidStr);
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");
1167                                                                                 }
1168                                                                         } else {
1169                                                                                 throw new Exception("ERROR - Vertex Id to keep not found in list of dupes.  dset = ["
1170                                                                                                 + dset + "]");
1171                                                                         }
1172                                                                 }
1173                                                         }// else we know which one to keep
1174                                                 }// else last entry
1175                                         }// for each vertex in a group
1176                                 } catch (Exception dex) {
1177                                         LOGGER.error("error trying to print duplicate vertex data", dex);
1178                                 }
1179
1180                         }// while - work on each group of dupes
1181
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");
1186                         }
1187
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");
1193                         }
1194
1195                         bw.close();
1196
1197                         LOGGER.info("\n ------------- Done doing all the checks ------------ ");
1198                         LOGGER.info("Output will be written to " + fullOutputFileName);
1199
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. ");
1206                         }
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");
1213                 } finally {
1214
1215                         if (bw != null) {
1216                                 try {
1217                                         bw.close();
1218                                 } catch (IOException iox) {
1219                                         LOGGER.warn("Got an IOException trying to close bufferedWriter() \n", iox);
1220                                 }
1221                         }
1222                         
1223                         if (g != null && !g.isClosed()) {
1224                                 // Any changes that worked correctly should have already done
1225                                 // their commits.
1226                                 try {
1227                                         if (executeFinalCommit) {
1228                                                 g.commit();
1229                                         }
1230                                         g.rollback();
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);
1234                                 }
1235                         }
1236                         
1237                         if (g2 != null && !g2.isClosed()) {
1238                                 // Any changes that worked correctly should have already done
1239                                 // their commits.
1240                                 try {
1241                                         g2.rollback();
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);
1245                                 }
1246                         }
1247                                 
1248                         if( finalShutdownFlag ){
1249                                 try {
1250                                         if( graph != null && graph.isOpen() ){
1251                                                 graph.tx().close();
1252                                                 graph.close();
1253                                         }
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);
1257                                 }
1258                                 
1259                                 try {
1260                                         if( graph2 != null && graph2.isOpen() ){
1261                                                 graph2.tx().close();
1262                                                 graph2.close();
1263                                         }
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);
1267                                 }
1268                         }
1269                                 
1270                 }
1271
1272                 return cleanupCandidateCount;
1273
1274         }// end of doTheGrooming()
1275         
1276         
1277         /**
1278          * Vertex has these keys.
1279          *
1280          * @param tmpV the tmp V
1281          * @param propHashWithKeys the prop hash with keys
1282          * @return the boolean
1283          */
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();
1293                         }
1294                         Object propValObj = propEntry.getValue();
1295                         if( propValObj != null ){
1296                                 propVal = propValObj.toString();
1297                         }
1298                         Object checkValObj = tmpV.<Object>property(propName).orElse(null);
1299                         if( checkValObj == null ) {
1300                                 return false;
1301                         }
1302                         else if( !propVal.equals(checkValObj.toString()) ){
1303                                 return false;
1304                         }
1305                 }
1306                 return true;
1307         }       
1308         
1309         
1310         /**
1311          * Any key fields missing.
1312          *
1313          * @param nType the n type
1314          * @param v the v
1315          * @return the boolean
1316          */
1317         private static Boolean anyKeyFieldsMissing(String nType, Vertex v, DbMaps dbMaps) {
1318
1319                 try {
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);
1324                         }
1325                         else {
1326                                 throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")"); 
1327                         }
1328                         
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
1335                                         return true;
1336                                 }
1337                         }
1338                 } catch (AAIException e) {
1339                         // Something was wrong
1340                         return true;
1341                 }
1342                 return false;
1343         }
1344         
1345
1346         /**
1347          * Gets the delete list.
1348          *
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
1356          */
1357         private static Set<String> getDeleteList(String targetDir,
1358                         String fileName, Boolean edgesOnlyFlag, Boolean dontFixOrphans,
1359                         Boolean dupeFixOn) throws AAIException {
1360
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;
1366                 
1367                 try {
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
1378                                         } else {
1379                                                 int begIndex = line.indexOf("id = ");
1380                                                 int endIndex = line.indexOf("]");
1381                                                 String vidVal = line.substring(begIndex + 6, endIndex);
1382                                                 delList.add(vidVal);
1383                                         }
1384                                 }
1385                                 line = br.readLine();
1386                         }
1387                         br.close();
1388                 } catch (IOException e) {
1389                         throw new AAIException("AAI_6124", e, "Could not open input-file [" + fullFileName
1390                                         + "], exception= " + e.getMessage());
1391                 }
1392
1393                 return delList;
1394
1395         }// end of getDeleteList
1396
1397         /**
1398          * Gets the preferred dupe.
1399          *
1400          * @param transId the trans id
1401          * @param fromAppId the from app id
1402          * @param g the g
1403          * @param dupeVertexList the dupe vertex list
1404          * @param ver the ver
1405          * @return TitanVertex
1406          * @throws AAIException the AAI exception
1407          */
1408         public static TitanVertex getPreferredDupe(String transId,
1409                         String fromAppId, TitanTransaction g,
1410                         ArrayList<TitanVertex> dupeVertexList, String ver, DbMaps dbMaps)
1411                         throws AAIException {
1412
1413                 // This method assumes that it is being passed a List of vertex objects
1414                 // which
1415                 // violate our uniqueness constraints.
1416
1417                 TitanVertex nullVtx = null;
1418
1419                 if (dupeVertexList == null) {
1420                         return nullVtx;
1421                 }
1422                 int listSize = dupeVertexList.size();
1423                 if (listSize == 0) {
1424                         return nullVtx;
1425                 }
1426                 if (listSize == 1) {
1427                         return ((TitanVertex) dupeVertexList.get(0));
1428                 }
1429
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
1438                                 return nullVtx;
1439                         } else {
1440                                 currentFaveVtx = vtxPreferred;
1441                         }
1442                 }
1443
1444                 return (currentFaveVtx);
1445
1446         } // end of getPreferredDupe()
1447
1448         /**
1449          * Pick one of two dupes.
1450          *
1451          * @param transId the trans id
1452          * @param fromAppId the from app id
1453          * @param g the g
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
1459          */
1460         public static TitanVertex pickOneOfTwoDupes(String transId,
1461                         String fromAppId, TitanTransaction g, TitanVertex vtxA,
1462                         TitanVertex vtxB, String ver, DbMaps dbMaps) throws AAIException {
1463
1464                 TitanVertex nullVtx = null;
1465                 TitanVertex preferredVtx = null;
1466
1467                 Long vidA = new Long(vtxA.id().toString());
1468                 Long vidB = new Long(vtxB.id().toString());
1469
1470                 String vtxANodeType = "";
1471                 String vtxBNodeType = "";
1472                 Object obj = vtxA.<Object>property("aai-node-type").orElse(null);
1473                 if (obj != null) {
1474                         vtxANodeType = obj.toString();
1475                 }
1476                 obj = vtxB.<Object>property("aai-node-type").orElse(null);
1477                 if (obj != null) {
1478                         vtxBNodeType = obj.toString();
1479                 }
1480
1481                 if (vtxANodeType.equals("") || (!vtxANodeType.equals(vtxBNodeType))) {
1482                         // Either they're not really dupes or there's some bad data - so
1483                         // don't pick one
1484                         return nullVtx;
1485                 }
1486
1487                 // Check that node A and B both have the same key values (or else they
1488                 // are not dupes)
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);
1494                 }
1495                 else {
1496                         throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + vtxANodeType + ")"); 
1497                 }
1498                 
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);
1504                         if (obj != null) {
1505                                 vtxAKeyPropVal = obj.toString();
1506                         }
1507                         String vtxBKeyPropVal = "";
1508                         obj = vtxB.<Object>property(propName).orElse(null);
1509                         if (obj != null) {
1510                                 vtxBKeyPropVal = obj.toString();
1511                         }
1512
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
1517                                 return nullVtx;
1518                         }
1519                 }
1520
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<>();
1527
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();
1534                                 String nt = "";
1535                                 obj = tvCon.<Object>property("aai-node-type").orElse(null);
1536                                 if (obj != null) {
1537                                         nt = obj.toString();
1538                                 }
1539                                 nodeTypesConn2A.put(nt, conVid);
1540                                 vtxIdsConn2A.add(conVid);
1541                         }
1542                 }
1543
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();
1550                                 String nt = "";
1551                                 obj = tvCon.<Object>property("aai-node-type").orElse(null);
1552                                 if (obj != null) {
1553                                         nt = obj.toString();
1554                                 }
1555                                 nodeTypesConn2B.put(nt, conVid);
1556                                 vtxIdsConn2B.add(conVid);
1557                         }
1558                 }
1559
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
1563                 // duplicates)
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
1568                 // connected to.
1569                 Collection <String> depNodeTypes = new ArrayList <>();
1570                 if( dbMaps.NodeDependencies.containsKey(vtxANodeType) ){
1571                         depNodeTypes = dbMaps.NodeDependencies.get(vtxANodeType);
1572                 }
1573                                 
1574                 if (depNodeTypes.isEmpty()) {
1575                         // This kind of node is not dependent on any other. That is ok.
1576                 } else {
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);
1585                                 }
1586                                 if (nodeTypesConn2B.containsKey(depNodeType)) {
1587                                         // This is the dependent node type that vertex B is using
1588                                         depNodeVtxId4B = nodeTypesConn2B.get(depNodeType);
1589                                 }
1590                         }
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
1595                                 return nullVtx;
1596                         }
1597                 }
1598
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)) {
1607                                         allTheSame = false;
1608                                         break;
1609                                 }
1610                         }
1611
1612                         if (allTheSame) {
1613                                 if (vidA < vidB) {
1614                                         preferredVtx = vtxA;
1615                                 } else {
1616                                         preferredVtx = vtxB;
1617                                 }
1618                         }
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)) {
1627                                         missingOne = true;
1628                                         break;
1629                                 }
1630                         }
1631                         if (!missingOne) {
1632                                 preferredVtx = vtxA;
1633                         }
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)) {
1642                                         missingOne = true;
1643                                         break;
1644                                 }
1645                         }
1646                         if (!missingOne) {
1647                                 preferredVtx = vtxB;
1648                         }
1649                 } else {
1650                         preferredVtx = nullVtx;
1651                 }
1652
1653                 return (preferredVtx);
1654
1655         } // end of pickOneOfTwoDupes()
1656
1657         /**
1658          * Check and process dupes.
1659          *
1660          * @param transId the trans id
1661          * @param fromAppId the from app id
1662          * @param g the g
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
1672          */
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 ) {
1678                 
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;
1693                         }
1694                 }
1695
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
1708                 // found.
1709                 //
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)
1715
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.
1719
1720                 try {
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);
1728                                 }
1729                         }
1730
1731                         if (checkVertList.size() < 2) {
1732                                 // Nothing new to check.
1733                                 return returnList;
1734                         }
1735
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++) {
1743                                         dupesStr = dupesStr
1744                                                         + ((TitanVertex) (checkVertList.get(i))).id()
1745                                                                         .toString() + "|";
1746                                 }
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);
1754                                         } else {
1755                                                 dupesStr = dupesStr + "KeepVid=" + prefV.id();
1756                                                 Boolean didRemove = false;
1757                                                 if (dupeFixOn) {
1758                                                         didRemove = deleteNonKeepersIfAppropriate(g,
1759                                                                         dupesStr, prefV.id().toString(),
1760                                                                         deleteCandidateList, singleCommits);
1761                                                 }
1762                                                 if (didRemove) {
1763                                                         dupeGrpsDeleted++;
1764                                                 } else {
1765                                                         // keep them on our list
1766                                                         returnList.add(dupesStr);
1767                                                 }
1768                                         }
1769                                 }
1770                         } else {
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
1779                                 // duplicates.
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
1784                                                 .entrySet()) {
1785                                         ArrayList<TitanVertex> thisParentsVertList = entry
1786                                                         .getValue();
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++) {
1792                                                         dupesStr = dupesStr
1793                                                                         + ((TitanVertex) (thisParentsVertList
1794                                                                                         .get(i))).id() + "|";
1795                                                 }
1796                                                 if (dupesStr != "") {
1797                                                         TitanVertex prefV = getPreferredDupe(transId,
1798                                                                         fromAppId, g, thisParentsVertList,
1799                                                                         version, dbMaps);
1800
1801                                                         if (prefV == null) {
1802                                                                 // We could not determine which duplicate to
1803                                                                 // keep
1804                                                                 dupesStr = dupesStr + "KeepVid=UNDETERMINED";
1805                                                                 returnList.add(dupesStr);
1806                                                         } else {
1807                                                                 Boolean didRemove = false;
1808                                                                 dupesStr = dupesStr + "KeepVid="
1809                                                                                 + prefV.id().toString();
1810                                                                 if (dupeFixOn) {
1811                                                                         didRemove = deleteNonKeepersIfAppropriate(
1812                                                                                         g, dupesStr, prefV.id()
1813                                                                                                         .toString(),
1814                                                                                         deleteCandidateList, singleCommits);
1815                                                                 }
1816                                                                 if (didRemove) {
1817                                                                         dupeGrpsDeleted++;
1818                                                                 } else {
1819                                                                         // keep them on our list
1820                                                                         returnList.add(dupesStr);
1821                                                                 }
1822                                                         }
1823                                                 }
1824                                         }
1825                                 }
1826                         }
1827                 } catch (Exception e) {
1828                         LOGGER.warn(" >>> Threw an error in checkAndProcessDupes - just absorb this error and move on. ", e);
1829                 }
1830
1831                 return returnList;
1832
1833         }// End of checkAndProcessDupes()
1834
1835         /**
1836          * Group verts by dep nodes.
1837          *
1838          * @param transId the trans id
1839          * @param fromAppId the from app id
1840          * @param g the g
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
1847          */
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.
1859
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
1863                         // kind of node
1864                         // that depends on a parent for uniqueness, so just return the empty
1865                         // hash.
1866                         return retHash;
1867                 }
1868
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());
1875                 }
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();
1886                                         String conNt = "";
1887                                         Object obj = tvCon.<Object>property("aai-node-type").orElse(null);
1888                                         if (obj != null) {
1889                                                 conNt = obj.toString();
1890                                         }
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);
1897                                                 } else {
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);
1902                                                 }
1903                                         }
1904                                 }
1905                         }
1906                 }
1907
1908                 return retHash;
1909
1910         }// end of groupVertsByDepNodes()
1911
1912         /**
1913          * Delete non keepers if appropriate.
1914          *
1915          * @param g the g
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
1921          */
1922         private static Boolean deleteNonKeepersIfAppropriate(TitanTransaction g,
1923                         String dupeInfoString, String vidToKeep,
1924                         Set<String> deleteCandidateList, Boolean singleCommits) {
1925
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
1932                         // this run
1933                         return false;
1934                 }
1935
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);
1944                         } else {
1945                                 // This is the last entry which should tell us if we have a
1946                                 // preferred keeper
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
1951                                         return false;
1952                                 } else {
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");
1958                                                 return false;
1959                                         } else {
1960                                                 String keepVidStr = prefArr[1];
1961                                                 if (idArr.contains(keepVidStr)) {
1962                                                         idArr.remove(keepVidStr);
1963
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.
1972                                                                         try {
1973                                                                                 long longVertId = Long
1974                                                                                                 .parseLong(thisVid);
1975                                                                                 TitanVertex vtx = g
1976                                                                                                 .getVertex(longVertId);
1977                                                                                 vtx.remove();
1978                                                                                 if (singleCommits) {
1979                                                                                         // NOTE - the singleCommits option is not used in normal processing
1980                                                                                         g.commit();
1981                                                                                         g = AAIGraph.getInstance().getGraph().newTransaction();
1982                                                                                 }
1983                                                                         } catch (Exception e) {
1984                                                                                 okFlag = false;
1985                                                                                 LOGGER.error("ERROR trying to delete VID = " + thisVid, e);
1986                                                                         }
1987                                                                         if (okFlag) {
1988                                                                                 LOGGER.info(" DELETED VID = " + thisVid);
1989                                                                                 deletedSomething = true;
1990                                                                         }
1991                                                                 }
1992                                                         }
1993                                                 } else {
1994                                                         LOGGER.error("ERROR - Vertex Id to keep not found in list of dupes.  dupeInfoString = ["
1995                                                                         + dupeInfoString + "]");
1996                                                         return false;
1997                                                 }
1998                                         }
1999                                 }// else we know which one to keep
2000                         }// else last entry
2001                 }// for each vertex in a group
2002
2003                 return deletedSomething;
2004
2005         }// end of deleteNonKeepersIfAppropriate()
2006
2007         
2008         /**
2009          * Gets the node just using key params.
2010          *
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
2019          */
2020         public static List <TitanVertex> getNodeJustUsingKeyParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
2021                         HashMap<String,Object> keyPropsHash, String apiVersion )         throws AAIException{
2022                 
2023                 List <TitanVertex> retVertList = new ArrayList <> ();
2024                 
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 + "]. "); 
2032                 }
2033                 
2034                 int i = -1;
2035                 for( Map.Entry<String, Object> entry : keyPropsHash.entrySet() ){
2036                         i++;
2037                         kName.add(i, entry.getKey());
2038                         kVal.add(i, entry.getValue());
2039                 }
2040                 int topPropIndex = i;
2041                 TitanVertex tiV = null;
2042                 String propsAndValuesForMsg = "";
2043                 Iterable <?> verts = null;
2044
2045                 try { 
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();    
2049                         }       
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();    
2054                         }                       
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();                        
2060                         }       
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();                  
2067                         }                       
2068                         else {
2069                                 throw new AAIException("AAI_6114", " We only support 4 keys per nodeType for now \n"); 
2070                         }
2071                 }
2072                 catch( Exception ex ){
2073                         LOGGER.error( " ERROR trying to get node for: [" + propsAndValuesForMsg + "]", ex);
2074                 }
2075
2076                 if( verts != null ){
2077                         Iterator <?> vertI = verts.iterator();
2078                         while( vertI.hasNext() ){
2079                                 tiV = (TitanVertex) vertI.next();
2080                                 retVertList.add(tiV);
2081                         }
2082                 }
2083                 
2084                 if( retVertList.size() == 0 ){
2085                         LOGGER.debug("DEBUG No node found for nodeType = [" + nodeType +
2086                                         "], propsAndVal = " + propsAndValuesForMsg );
2087                 }
2088                 
2089                 return retVertList;
2090                 
2091         }// End of getNodeJustUsingKeyParams() 
2092         
2093         /**
2094          * Show all edges for node.
2095          *
2096          * @param transId the trans id
2097          * @param fromAppId the from app id
2098          * @param tVert the t vert
2099          * @return the array list
2100          */
2101         private static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){ 
2102
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. ");
2107                 }
2108                 while( eI.hasNext() ){
2109                         TitanEdge ed = (TitanEdge) eI.next();
2110                         String lab = ed.label();
2111                         TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
2112                         if( vtx == null ){
2113                                 retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
2114                         }
2115                         else {
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 );
2119                                 
2120                         }
2121                 }
2122                 
2123                 eI = tVert.edges(Direction.OUT);
2124                 if( ! eI.hasNext() ){
2125                         retArr.add("No OUT edges were found for this vertex. ");
2126                 }
2127                 while( eI.hasNext() ){
2128                         TitanEdge ed = (TitanEdge) eI.next();
2129                         String lab = ed.label();
2130                         TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
2131                         if( vtx == null ){
2132                                 retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
2133                         }
2134                         else {
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 );
2138                         }
2139                 }
2140                 return retArr;
2141         }
2142
2143         
2144         /**
2145          * Show properties for node.
2146          *
2147          * @param transId the trans id
2148          * @param fromAppId the from app id
2149          * @param tVert the t vert
2150          * @return the array list
2151          */
2152         private static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){ 
2153
2154                 ArrayList <String> retArr = new ArrayList <> ();
2155                 if( tVert == null ){
2156                         retArr.add("null Node object passed to showPropertiesForNode()\n");
2157                 }
2158                 else {
2159                         String nodeType = "";
2160                         Object ob = tVert.<Object>property("aai-node-type").orElse(null);
2161                         if( ob == null ){
2162                                 nodeType = "null";
2163                         }
2164                         else{
2165                                 nodeType = ob.toString();
2166                         }
2167                         
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 + "] ");
2175                         }
2176                 }
2177                 return retArr;
2178         }
2179
2180         
2181         private static ArrayList <TitanVertex> getConnectedNodes(TitanTransaction g, TitanVertex startVtx ) 
2182                         throws AAIException {
2183         
2184                 ArrayList <TitanVertex> retArr = new ArrayList <> ();
2185                 if( startVtx == null ){
2186                         return retArr;
2187                 }
2188                 else {
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);
2195                                 }
2196                         }
2197                 }
2198                 return retArr;
2199                 
2200         }// End of getConnectedNodes()
2201         
2202
2203         private static ArrayList <TitanVertex> getConnectedChildren( TitanTransaction graph, 
2204                         TitanVertex startVtx ) throws AAIException{
2205                 
2206                 ArrayList <TitanVertex> childList = new ArrayList <> ();
2207                 
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);
2214                 }
2215                 
2216                 return childList;               
2217
2218         }// End of getConnectedChildren()
2219
2220         
2221         
2222         
2223 }