aboutsummaryrefslogtreecommitdiffstats
path: root/aai-resources/src/main/java/org/onap/aai/dbgen/DupeTool.java
diff options
context:
space:
mode:
Diffstat (limited to 'aai-resources/src/main/java/org/onap/aai/dbgen/DupeTool.java')
-rw-r--r--aai-resources/src/main/java/org/onap/aai/dbgen/DupeTool.java1877
1 files changed, 0 insertions, 1877 deletions
diff --git a/aai-resources/src/main/java/org/onap/aai/dbgen/DupeTool.java b/aai-resources/src/main/java/org/onap/aai/dbgen/DupeTool.java
deleted file mode 100644
index 1e323b0..0000000
--- a/aai-resources/src/main/java/org/onap/aai/dbgen/DupeTool.java
+++ /dev/null
@@ -1,1877 +0,0 @@
-/**
- * ============LICENSE_START=======================================================
- * org.onap.aai
- * ================================================================================
- * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-package org.onap.aai.dbgen;
-import java.io.FileInputStream;
-import java.io.InputStream;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import java.util.Properties;
-import java.util.UUID;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.onap.aai.db.props.AAIProperties;
-import org.onap.aai.dbmap.AAIGraphConfig;
-import org.onap.aai.dbmap.AAIGraph;
-import org.onap.aai.exceptions.AAIException;
-import org.onap.aai.introspection.Introspector;
-import org.onap.aai.introspection.Loader;
-import org.onap.aai.introspection.LoaderFactory;
-import org.onap.aai.introspection.ModelType;
-import org.onap.aai.logging.ErrorLogHelper;
-import org.onap.aai.logging.LogFormatTools;
-import org.onap.aai.logging.LoggingContext;
-import org.onap.aai.logging.LoggingContext.StatusCode;
-import org.onap.aai.util.AAIConfig;
-import org.onap.aai.util.AAIConstants;
-import org.slf4j.MDC;
-
-import com.att.eelf.configuration.Configuration;
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
-import org.janusgraph.core.JanusGraphFactory;
-import org.janusgraph.core.JanusGraph;
-
-
-
-public class DupeTool {
-
- private static final String FROMAPPID = "AAI-DB";
- private static final String TRANSID = UUID.randomUUID().toString();
- private static final String COULD_NOT_FIND_EDGE_ID_ = " >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = ";
- private static final String AAI_NODE_TYPE = "aai-node-type";
- private static final String KEEP_VID = "KeepVid";
- private static final String INMEMORY = "inmemory";
-
- private static String graphType = "realdb";
-
- public static boolean SHOULD_EXIT_VM = true;
-
- public static int EXIT_VM_STATUS_CODE = -1;
-
- public static void exit(int statusCode){
- if(SHOULD_EXIT_VM){
- System.exit(1);
- }
- EXIT_VM_STATUS_CODE = statusCode;
- }
-
-
- /**
- * The main method.
- *
- * @param args the arguments
- */
- public static void main(String[] args) {
- System.setProperty("aai.service.name", DupeTool.class.getSimpleName());
- // Set the logging file properties to be used by EELFManager
- Properties props = System.getProperties();
- props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, "dupeTool-logback.xml");
- props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
- EELFLogger logger = EELFManager.getInstance().getLogger(DupeTool.class.getSimpleName());
- MDC.put("logFilenameAppender", DupeTool.class.getSimpleName());
-
- LoggingContext.init();
- LoggingContext.partnerName(FROMAPPID);
- LoggingContext.serviceName(AAIConstants.AAI_RESOURCES_MS);
- LoggingContext.component("dupeTool");
- LoggingContext.targetEntity(AAIConstants.AAI_RESOURCES_MS);
- LoggingContext.targetServiceName("main");
- LoggingContext.requestId(TRANSID);
- LoggingContext.statusCode(StatusCode.COMPLETE);
- LoggingContext.responseCode(LoggingContext.SUCCESS);
-
- String defVersion = "v9";
- try {
- defVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
- }
- catch ( AAIException ae ){
- String emsg = "Error trying to get default API Version property \n";
- System.out.println(emsg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error(emsg);
- exit(0);
- }
-
- Loader loader= null;
- try {
- loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, AAIProperties.LATEST);
-
- }
- catch (Exception ex){
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.UNKNOWN_ERROR);
- logger.error("ERROR - Could not do the moxyMod.init() " + LogFormatTools.getStackTop(ex));
- exit(1);
- }
- JanusGraph graph1 = null;
- JanusGraph graph2 = null;
- Graph gt1 = null;
- Graph gt2 = null;
-
- boolean specialTenantRule = false;
-
- try {
- AAIConfig.init();
- int maxRecordsToFix = AAIConstants.AAI_DUPETOOL_DEFAULT_MAX_FIX;
- int sleepMinutes = AAIConstants.AAI_DUPETOOL_DEFAULT_SLEEP_MINUTES;
- int timeWindowMinutes = 0; // A value of 0 means that we will not have a time-window -- we will look
- // at all nodes of the passed-in nodeType.
- long windowStartTime = 0; // Translation of the window into a starting timestamp
-
- try {
- String maxFixStr = AAIConfig.get("aai.dupeTool.default.max.fix");
- if( maxFixStr != null && !maxFixStr.isEmpty() ){
- maxRecordsToFix = Integer.parseInt(maxFixStr);
- }
- String sleepStr = AAIConfig.get("aai.dupeTool.default.sleep.minutes");
- if( sleepStr != null && !sleepStr.isEmpty() ){
- sleepMinutes = Integer.parseInt(sleepStr);
- }
- }
- catch ( Exception e ){
- // Don't worry, we'll just use the defaults that we got from AAIConstants
- logger.warn("WARNING - could not pick up aai.dupeTool values from aaiconfig.properties file. Will use defaults. ");
- }
-
- String nodeTypeVal = "";
- String userIdVal = "";
- String filterParams = "";
- Boolean skipHostCheck = false;
- Boolean autoFix = false;
- String argStr4Msg = "";
- Introspector obj = null;
-
- if (args != null && args.length > 0) {
- // They passed some arguments in that will affect processing
- for (int i = 0; i < args.length; i++) {
- String thisArg = args[i];
- argStr4Msg = argStr4Msg + " " + thisArg;
-
- if ("-nodeType".equals(thisArg)) {
- i++;
- if (i >= args.length) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error(" No value passed with -nodeType option. ");
- exit(0);
- }
- nodeTypeVal = args[i];
- argStr4Msg = argStr4Msg + " " + nodeTypeVal;
- }
- else if ("-sleepMinutes".equals(thisArg)) {
- i++;
- if (i >= args.length) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error("No value passed with -sleepMinutes option.");
- exit(0);
- }
- String nextArg = args[i];
- try {
- sleepMinutes = Integer.parseInt(nextArg);
- } catch (Exception e) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error("Bad value passed with -sleepMinutes option: ["
- + nextArg + "]");
- exit(0);
- }
- argStr4Msg = argStr4Msg + " " + sleepMinutes;
- }
- else if ("-maxFix".equals(thisArg)) {
- i++;
- if (i >= args.length) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error("No value passed with -maxFix option.");
- exit(0);
- }
- String nextArg = args[i];
- try {
- maxRecordsToFix = Integer.parseInt(nextArg);
- } catch (Exception e) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error("Bad value passed with -maxFix option: ["
- + nextArg + "]");
- exit(0);
- }
- argStr4Msg = argStr4Msg + " " + maxRecordsToFix;
- }
- else if ("-timeWindowMinutes".equals(thisArg)) {
- i++;
- if (i >= args.length) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error("No value passed with -timeWindowMinutes option.");
- exit(0);
- }
- String nextArg = args[i];
- try {
- timeWindowMinutes = Integer.parseInt(nextArg);
- } catch (Exception e) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error("Bad value passed with -timeWindowMinutes option: ["
- + nextArg + "]");
- exit(0);
- }
- argStr4Msg = argStr4Msg + " " + timeWindowMinutes;
- }
- else if ("-skipHostCheck".equals(thisArg)) {
- skipHostCheck = true;
- }
- else if ("-specialTenantRule".equals(thisArg)) {
- specialTenantRule = true;
- }
- else if ("-autoFix".equals(thisArg)) {
- autoFix = true;
- }
- else if ("-userId".equals(thisArg)) {
- i++;
- if (i >= args.length) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error(" No value passed with -userId option. ");
- exit(0);
- }
- userIdVal = args[i];
- argStr4Msg = argStr4Msg + " " + userIdVal;
- }
- else if ("-params4Collect".equals(thisArg)) {
- i++;
- if (i >= args.length) {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error(" No value passed with -params4Collect option. ");
- exit(0);
- }
- filterParams = args[i];
- argStr4Msg = argStr4Msg + " " + filterParams;
- }
- else {
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error(" Unrecognized argument passed to DupeTool: ["
- + thisArg + "]. ");
- logger.error(" Valid values are: -action -userId -vertexId -edgeId -overRideProtection ");
- exit(0);
- }
- }
- }
-
- userIdVal = userIdVal.trim();
- if( (userIdVal.length() < 6) || "AAIADMIN".equalsIgnoreCase(userIdVal) ){
- String emsg = "userId parameter is required. [" + userIdVal + "] passed to DupeTool(). userId must be not empty and not aaiadmin \n";
- System.out.println(emsg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error(emsg);
- exit(0);
- }
-
- nodeTypeVal = nodeTypeVal.trim();
- if( nodeTypeVal.isEmpty() ){
- String emsg = " nodeType is a required parameter for DupeTool().\n";
- System.out.println(emsg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR);
- logger.error(emsg);
- exit(0);
- }
- obj = loader.introspectorFromName(nodeTypeVal);
-
- if (skipHostCheck) {
- logger.info(" We will skip the HostCheck as requested. ");
- }
-
- if( timeWindowMinutes > 0 ){
- // Translate the window value (ie. 30 minutes) into a unix timestamp like
- // we use in the db - so we can select data created after that time.
- windowStartTime = figureWindowStartTime( timeWindowMinutes );
- }
-
- String msg = "";
- msg = "DupeTool called with these params: [" + argStr4Msg + "]";
- System.out.println(msg);
- logger.info(msg);
-
- // Determine what the key fields are for this nodeType (and we want them ordered)
- ArrayList <String> keyPropNamesArr = new ArrayList<String>(obj.getKeys());
-
- // Determine what kinds of nodes (if any) this nodeType is dependent on for uniqueness
- ArrayList<String> depNodeTypeList = new ArrayList<String>();
- Collection<String> depNTColl = obj.getDependentOn();
- Iterator<String> ntItr = depNTColl.iterator();
- while( ntItr.hasNext() ){
- depNodeTypeList.add(ntItr.next());
- }
-
- // Based on the nodeType, window and filterData, figure out the vertices that we will be checking
- System.out.println(" ---- NOTE --- about to open graph (takes a little while)--------\n");
- graph1 = setupGraph(logger);
- gt1 = getGraphTransaction( graph1, logger );
- ArrayList<Vertex> verts2Check = new ArrayList<Vertex>();
-
- verts2Check = figureOutNodes2Check( TRANSID, FROMAPPID, gt1,
- nodeTypeVal, windowStartTime, filterParams, logger );
-
- if( verts2Check == null || verts2Check.isEmpty() ){
- msg = " No vertices found to check. Used nodeType = [" + nodeTypeVal
- + "], windowMinutes = " + timeWindowMinutes
- + ", filterData = [" + filterParams + "].";
- logger.info( msg );
- System.out.println( msg );
- exit(0);
- }
- else {
- msg = " Found " + verts2Check.size() + " nodes of type " + nodeTypeVal
- + " to check using passed filterParams and windowStartTime. ";
- logger.info( msg );
- System.out.println( msg );
- }
-
- ArrayList<String> firstPassDupeSets = new ArrayList <String>();
- ArrayList <String> secondPassDupeSets = new ArrayList <String>();
- Boolean isDependentOnParent = false;
- if( !obj.getDependentOn().isEmpty() ){
- isDependentOnParent = true;
- }
-
- if( isDependentOnParent ){
- firstPassDupeSets = getDupeSets4DependentNodes( TRANSID, FROMAPPID, gt1,
- defVersion, nodeTypeVal, verts2Check, keyPropNamesArr, loader,
- specialTenantRule, logger );
- }
- else {
- firstPassDupeSets = getDupeSets4NonDepNodes( TRANSID, FROMAPPID, gt1,
- defVersion, nodeTypeVal, verts2Check, keyPropNamesArr,
- specialTenantRule, loader, logger );
- }
-
- msg = " Found " + firstPassDupeSets.size() + " sets of duplicates for this request. ";
- logger.info( msg );
- System.out.println( msg );
- if( !firstPassDupeSets.isEmpty() ){
- msg = " Here is what they look like: ";
- logger.info( msg );
- System.out.println( msg );
- for( int x = 0; x < firstPassDupeSets.size(); x++ ){
- msg = " Set " + x + ": [" + firstPassDupeSets.get(x) +"] ";
- logger.info( msg );
- System.out.println( msg );
- showNodeDetailsForADupeSet(gt1, firstPassDupeSets.get(x), logger);
- }
- }
-
- boolean didSomeDeletesFlag = false;
- ArrayList <String> dupeSetsToFix = new ArrayList <String> ();
- if( autoFix && firstPassDupeSets.isEmpty() ){
- msg = "AutoFix option is on, but no dupes were found on the first pass. Nothing to fix.";
- logger.info( msg );
- System.out.println( msg );
- }
- else if( autoFix ){
- // We will try to fix any dupes that we can - but only after sleeping for a
- // time and re-checking the list of duplicates using a seperate transaction.
- try {
- msg = "\n\n----------- About to sleep for " + sleepMinutes + " minutes."
- + " -----------\n\n";
- logger.info( msg );
- System.out.println( msg );
- int sleepMsec = sleepMinutes * 60 * 1000;
- Thread.sleep(sleepMsec);
- } catch (InterruptedException ie) {
- msg = "\n >>> Sleep Thread has been Interrupted <<< ";
- Thread.currentThread().interrupt();
- logger.info( msg );
- System.out.println( msg );
- exit(0);
- }
-
- graph2 = setupGraph(logger);
- gt2 = getGraphTransaction( graph2, logger );
- if( isDependentOnParent ){
- secondPassDupeSets = getDupeSets4DependentNodes( TRANSID, FROMAPPID, gt2,
- defVersion, nodeTypeVal, verts2Check, keyPropNamesArr, loader,
- specialTenantRule, logger );
- }
- else {
- secondPassDupeSets = getDupeSets4NonDepNodes( TRANSID, FROMAPPID, gt2,
- defVersion, nodeTypeVal, verts2Check, keyPropNamesArr,
- specialTenantRule, loader, logger );
- }
-
- dupeSetsToFix = figureWhichDupesStillNeedFixing( firstPassDupeSets, secondPassDupeSets, logger );
- msg = "\nAfter running a second pass, there were " + dupeSetsToFix.size()
- + " sets of duplicates that we think can be deleted. ";
- logger.info( msg );
- System.out.println( msg );
- if( !dupeSetsToFix.isEmpty()){
- msg = " Here is what the sets look like: ";
- logger.info( msg );
- System.out.println( msg );
- for( int x = 0; x < dupeSetsToFix.size(); x++ ){
- msg = " Set " + x + ": [" + dupeSetsToFix.get(x) +"] ";
- logger.info( msg );
- System.out.println( msg );
- showNodeDetailsForADupeSet(gt2, dupeSetsToFix.get(x), logger);
- }
- }
-
- if( !dupeSetsToFix.isEmpty() ){
- if( dupeSetsToFix.size() > maxRecordsToFix ){
- String infMsg = " >> WARNING >> Dupe list size ("
- + dupeSetsToFix.size()
- + ") is too big. The maxFix we are using is: "
- + maxRecordsToFix
- + ". No nodes will be deleted. (use the"
- + " -maxFix option to override this limit.)";
- System.out.println(infMsg);
- logger.info(infMsg);
- }
- else {
- // Call the routine that fixes known dupes
- didSomeDeletesFlag = deleteNonKeepers( gt2, dupeSetsToFix, logger );
- }
- }
- if( didSomeDeletesFlag ){
- gt2.tx().commit();
- }
- }
-
- } catch (AAIException e) {
- logger.error("Caught AAIException while running the dupeTool: " + LogFormatTools.getStackTop(e));
- ErrorLogHelper.logException(e);
- } catch (Exception ex) {
- logger.error("Caught exception while running the dupeTool: "+ LogFormatTools.getStackTop(ex));
- ErrorLogHelper.logError("AAI_6128", ex.getMessage() + ", resolve and rerun the dupeTool. ");
- } finally {
- if (gt1 != null && gt1.tx().isOpen()) {
- // We don't change any data with gt1 - so just roll it back so it knows we're done.
- try {
- gt1.tx().rollback();
- }
- catch (Exception ex) {
- // Don't throw anything because JanusGraph sometimes is just saying that the graph is already closed
- logger.warn("WARNING from final gt1.rollback() " + LogFormatTools.getStackTop(ex));
- }
- }
-
- if (gt2 != null && gt2.tx().isOpen()) {
- // Any changes that worked correctly should have already done
- // their commits.
- try {
- gt2.tx().rollback();
- } catch (Exception ex) {
- // Don't throw anything because JanusGraph sometimes is just saying that the graph is already closed
- logger.warn("WARNING from final gt2.rollback() " + LogFormatTools.getStackTop(ex));
- }
- }
-
- try {
- if( graph1 != null && graph1.isOpen() ){
- closeGraph(graph1, logger);
- }
- } catch (Exception ex) {
- // Don't throw anything because JanusGraph sometimes is just saying that the graph is already closed{
- logger.warn("WARNING from final graph1.shutdown() " + LogFormatTools.getStackTop(ex));
- }
-
- try {
- if( graph2 != null && graph2.isOpen() ){
- closeGraph(graph2, logger);
- }
- } catch (Exception ex) {
- // Don't throw anything because JanusGraph sometimes is just saying that the graph is already closed{
- logger.warn("WARNING from final graph2.shutdown() " + LogFormatTools.getStackTop(ex));
- }
- }
-
- exit(0);
-
- }// end of main()
-
-
- /**
- * Collect Duplicate Sets for nodes that are NOT dependent on parent nodes.
- *
- * @param transId the trans id
- * @param fromAppId the from app id
- * @param g the g
- * @param version the version
- * @param nType the n type
- * @param passedVertList the passed vert list
- * @return the array list
- */
- private static ArrayList<String> getDupeSets4NonDepNodes( String transId,
- String fromAppId, Graph g, String version, String nType,
- ArrayList<Vertex> passedVertList,
- ArrayList <String> keyPropNamesArr,
- Boolean specialTenantRule, Loader loader, EELFLogger logger ) {
-
- ArrayList<String> returnList = new ArrayList<String>();
-
- // We've been passed a set of nodes that we want to check.
- // They are all NON-DEPENDENT nodes meaning that they should be
- // unique in the DB based on their KEY DATA alone. So, if
- // we group them by their key data - if any key has more than one
- // vertex mapped to it, those vertices are dupes.
- //
- // When we find duplicates, we return then as a String (there can be
- // more than one duplicate for one set of key data):
- // Each element in the returned arrayList might look like this:
- // "1234|5678|keepVid=UNDETERMINED" (if there were 2 dupes, and we
- // couldn't figure out which one to keep)
- // or, "100017|200027|30037|keepVid=30037" (if there were 3 dupes and we
- // thought the third one was the one that should survive)
-
- HashMap <String, ArrayList<String>> keyVals2VidHash = new HashMap <String, ArrayList<String>>();
- HashMap <String,Vertex> vtxHash = new HashMap <String,Vertex>();
- Iterator<Vertex> pItr = passedVertList.iterator();
- while (pItr.hasNext()) {
- try {
- Vertex tvx = pItr.next();
- String thisVid = tvx.id().toString();
- vtxHash.put(thisVid, tvx);
-
- // if there are more than one vertexId mapping to the same keyProps -- they are dupes
- String hKey = getNodeKeyValString( tvx, keyPropNamesArr, logger );
- if( keyVals2VidHash.containsKey(hKey) ){
- // We've already seen this key
- ArrayList <String> tmpVL = keyVals2VidHash.get(hKey);
- tmpVL.add(thisVid);
- keyVals2VidHash.put(hKey, tmpVL);
- }
- else {
- // First time for this key
- ArrayList <String> tmpVL = new ArrayList <String>();
- tmpVL.add(thisVid);
- keyVals2VidHash.put(hKey, tmpVL);
- }
- }
- catch (Exception e) {
- logger.warn(" >>> Threw an error in getDupeSets4NonDepNodes - just absorb this error and move on. " + LogFormatTools.getStackTop(e));
- }
- }
-
- for( Map.Entry<String, ArrayList<String>> entry : keyVals2VidHash.entrySet() ){
- ArrayList <String> vidList = entry.getValue();
- try {
- if( !vidList.isEmpty() && vidList.size() > 1 ){
- // There are more than one vertex id's using the same key info
- String dupesStr = "";
- ArrayList <Vertex> vertList = new ArrayList <Vertex> ();
- for (int i = 0; i < vidList.size(); i++) {
- String tmpVid = vidList.get(i);
- dupesStr = dupesStr + tmpVid + "|";
- vertList.add(vtxHash.get(tmpVid));
- }
-
- if (dupesStr != "") {
- Vertex prefV = getPreferredDupe(transId, fromAppId,
- g, vertList, version, specialTenantRule, loader, logger);
- if (prefV == null) {
- // We could not determine which duplicate to keep
- dupesStr = dupesStr + "KeepVid=UNDETERMINED";
- returnList.add(dupesStr);
- } else {
- dupesStr = dupesStr + "KeepVid=" + prefV.id();
- returnList.add(dupesStr);
- }
- }
- }
- }
- catch (Exception e) {
- logger.warn(" >>> Threw an error in getDupeSets4NonDepNodes - just absorb this error and move on. " + LogFormatTools.getStackTop(e));
- }
-
- }
- return returnList;
-
- }// End of getDupeSets4NonDepNodes()
-
-
- /**
- * Collect Duplicate Sets for nodes that are dependent on parent nodes.
- *
- * @param transId the trans id
- * @param fromAppId the from app id
- * @param g the g
- * @param version the version
- * @param nType the n type
- * @param passedVertList the passed vert list
- * @param keyPropNamesArr Array (ordered) of keyProperty names
- * @param specialTenantRule flag
- * @param logger the logger
- * @return the array list
- */
- private static ArrayList<String> getDupeSets4DependentNodes( String transId,
- String fromAppId, Graph g, String version, String nType,
- ArrayList<Vertex> passedVertList,
- ArrayList <String> keyPropNamesArr, Loader loader,
- Boolean specialTenantRule, EELFLogger logger ) {
-
- // This is for nodeTypes that DEPEND ON A PARENT NODE FOR UNIQUNESS
-
- ArrayList<String> returnList = new ArrayList<String>();
- ArrayList<String> alreadyFoundDupeVidArr = new ArrayList<String>();
-
- // We've been passed a set of nodes that we want to check. These are
- // all nodes that ARE DEPENDENT on a PARENT Node for uniqueness.
- // The first thing to do is to identify the key properties for the node-type
- // and pull from the db just using those properties.
- // Then, we'll check those nodes with their parent nodes to see if there
- // are any duplicates.
- //
- // When we find duplicates, we return then as a String (there can be
- // more than one duplicate for one set of key data):
- // Each element in the returned arrayList might look like this:
- // "1234|5678|keepVid=UNDETERMINED" (if there were 2 dupes, and we
- // couldn't figure out which one to keep)
- // or, "100017|200027|30037|keepVid=30037" (if there were 3 dupes and we
- // thought the third one was the one that should survive)
- HashMap<String, Object> checkVertHash = new HashMap <String,Object> ();
- try {
- Iterator<Vertex> pItr = passedVertList.iterator();
- while (pItr.hasNext()) {
- Vertex tvx = pItr.next();
- String passedId = tvx.id().toString();
- if( !alreadyFoundDupeVidArr.contains(passedId) ){
- // We haven't seen this one before - so we should check it.
- HashMap <String,Object> keyPropValsHash = getNodeKeyVals( tvx, keyPropNamesArr, logger );
- ArrayList <Vertex> tmpVertList = getNodeJustUsingKeyParams( transId, fromAppId, g,
- nType, keyPropValsHash, version, logger );
-
- if( tmpVertList.size() <= 1 ){
- // Even without a parent node, this thing is unique so don't worry about it.
- }
- else {
- for( int i = 0; i < tmpVertList.size(); i++ ){
- Vertex tmpVtx = (tmpVertList.get(i));
- String tmpVid = tmpVtx.id().toString();
- alreadyFoundDupeVidArr.add(tmpVid);
-
- String hKey = getNodeKeyValString( tmpVtx, keyPropNamesArr, logger );
- if( checkVertHash.containsKey(hKey) ){
- // add it to an existing list
- ArrayList <Vertex> tmpVL = (ArrayList <Vertex>)checkVertHash.get(hKey);
- tmpVL.add(tmpVtx);
- checkVertHash.put(hKey, tmpVL);
- }
- else {
- // First time for this key
- ArrayList <Vertex> tmpVL = new ArrayList <Vertex>();
- tmpVL.add(tmpVtx);
- checkVertHash.put(hKey, tmpVL);
- }
- }
- }
- }
- }
-
- // More than one node have the same key fields since they may
- // depend on a parent node for uniqueness. Since we're finding
- // more than one, we want to check to see if any of the
- // vertices that have this set of keys are also pointing at the
- // same 'parent' node.
- // Note: for a given set of key data, it is possible that there
- // could be more than one set of duplicates.
- for (Entry<String, Object> lentry : checkVertHash.entrySet()) {
- ArrayList <Vertex> thisIdSetList = (ArrayList <Vertex>)lentry.getValue();
- if (thisIdSetList == null || thisIdSetList.size() < 2) {
- // Nothing to check for this set.
- continue;
- }
-
- HashMap<String, ArrayList<Vertex>> vertsGroupedByParentHash = groupVertsByDepNodes(
- transId, fromAppId, g, version, nType,
- thisIdSetList, loader);
- for (Map.Entry<String, ArrayList<Vertex>> entry : vertsGroupedByParentHash
- .entrySet()) {
- ArrayList<Vertex> thisParentsVertList = entry
- .getValue();
- if (thisParentsVertList.size() > 1) {
- // More than one vertex found with the same key info
- // hanging off the same parent/dependent node
- String dupesStr = "";
- for (int i = 0; i < thisParentsVertList.size(); i++) {
- dupesStr = dupesStr + thisParentsVertList.get(i).id() + "|";
- }
- if (dupesStr != "") {
- Vertex prefV = getPreferredDupe(transId,
- fromAppId, g, thisParentsVertList,
- version, specialTenantRule, loader, logger);
-
- if (prefV == null) {
- // We could not determine which duplicate to keep
- dupesStr = dupesStr + "KeepVid=UNDETERMINED";
- returnList.add(dupesStr);
- }
- else {
- dupesStr = dupesStr + "KeepVid="
- + prefV.id().toString();
- returnList.add(dupesStr);
- }
- }
- }
- }
- }
-
- } catch (Exception e) {
- logger.warn(" >>> Threw an error in checkAndProcessDupes - just absorb this error and move on. " + LogFormatTools.getStackTop(e));
- }
-
- return returnList;
-
- }// End of getDupeSets4DependentNodes()
-
-
- private static Graph getGraphTransaction(JanusGraph graph, EELFLogger logger){
-
- Graph gt = null;
- try {
- if( graph != null ){
- gt = graph.newTransaction();
- } else {
- String emsg = "could not get graph object in DupeTool. \n";
- System.out.println(emsg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.AVAILABILITY_TIMEOUT_ERROR);
- logger.error(emsg);
- exit(0);
- }
- }
- catch (Exception e) {
- String msg = e.toString();
- System.out.println(msg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.UNKNOWN_ERROR);
- logger.error(msg);
- exit(0);
- }
-
- return gt;
-
- }// End of getGraphTransaction()
-
-
-
- public static void showNodeInfo(EELFLogger logger, Vertex tVert, Boolean displayAllVidsFlag ){
-
- try {
- Iterator<VertexProperty<Object>> pI = tVert.properties();
- String infStr = ">>> Found Vertex with VertexId = " + tVert.id() + ", properties: ";
- System.out.println( infStr );
- logger.info(infStr);
- while( pI.hasNext() ){
- VertexProperty<Object> tp = pI.next();
- infStr = " [" + tp.key() + "|" + tp.value() + "] ";
- System.out.println( infStr );
- logger.info(infStr);
- }
-
- ArrayList <String> retArr = collectEdgeInfoForNode( logger, tVert, displayAllVidsFlag );
- for( String infoStr : retArr ){
- System.out.println( infoStr );
- logger.info(infoStr);
- }
- }
- catch (Exception e){
- String warnMsg = " -- Error -- trying to display edge info. [" + e.getMessage() + "]";
- System.out.println( warnMsg );
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.UNKNOWN_ERROR);
- logger.warn(warnMsg);
- LoggingContext.statusCode(StatusCode.COMPLETE);
- LoggingContext.responseCode(LoggingContext.SUCCESS);
- }
-
- }// End of showNodeInfo()
-
- public static ArrayList <String> collectEdgeInfoForNode( EELFLogger logger, Vertex tVert, boolean displayAllVidsFlag ){
- ArrayList <String> retArr = new ArrayList <String> ();
- Direction dir = Direction.OUT;
- for ( int i = 0; i <= 1; i++ ){
- if( i == 1 ){
- // Second time through we'll look at the IN edges.
- dir = Direction.IN;
- }
- Iterator <Edge> eI = tVert.edges(dir);
- if( ! eI.hasNext() ){
- retArr.add("No " + dir + " edges were found for this vertex. ");
- }
- while( eI.hasNext() ){
- Edge ed = eI.next();
- String lab = ed.label();
- Vertex vtx = null;
- if( dir == Direction.OUT ){
- // get the vtx on the "other" side
- vtx = ed.inVertex();
- }
- else {
- // get the vtx on the "other" side
- vtx = ed.outVertex();
- }
- if( vtx == null ){
- retArr.add(COULD_NOT_FIND_EDGE_ID_ + ed.id() + " <<< ");
- continue;
- }
-
- String nType = vtx.<String>property(AAI_NODE_TYPE).orElse(null);
- if( displayAllVidsFlag ){
- // This should rarely be needed
- String vid = vtx.id().toString();
- retArr.add("Found an " + dir + " edge (" + lab + ") between this vertex and a [" + nType + "] node with VtxId = " + vid );
- }
- else {
- // This is the normal case
- retArr.add("Found an " + dir + " edge (" + lab + ") between this vertex and a [" + nType + "] node. ");
- }
- }
- }
- return retArr;
-
- }// end of collectEdgeInfoForNode()
-
-
- private static long figureWindowStartTime( int timeWindowMinutes ){
- // Given a window size, calculate what the start-timestamp would be.
-
- if( timeWindowMinutes <= 0 ){
- // This just means that there is no window...
- return 0;
- }
- long unixTimeNow = System.currentTimeMillis();
- long windowInMillis = timeWindowMinutes * 60l * 1000l;
-
- return unixTimeNow - windowInMillis;
- } // End of figureWindowStartTime()
-
-
-
- /**
- * Gets the node(s) just using key params.
- *
- * @param transId the trans id
- * @param fromAppId the from app id
- * @param graph the graph
- * @param nodeType the node type
- * @param keyPropsHash the key props hash
- * @param apiVersion the api version
- * @return the node just using key params
- * @throws AAIException the AAI exception
- */
- public static ArrayList <Vertex> getNodeJustUsingKeyParams( String transId, String fromAppId, Graph graph, String nodeType,
- HashMap<String,Object> keyPropsHash, String apiVersion, EELFLogger logger ) throws AAIException{
-
- ArrayList <Vertex> retVertList = new ArrayList <Vertex> ();
-
- // We assume that all NodeTypes have at least one key-property defined.
- // Note - instead of key-properties (the primary key properties), a user could pass
- // alternate-key values if they are defined for the nodeType.
- ArrayList<String> kName = new ArrayList<String>();
- ArrayList<Object> kVal = new ArrayList<Object>();
- if( keyPropsHash == null || keyPropsHash.isEmpty() ) {
- throw new AAIException("AAI_6120", " NO key properties passed for this getNodeJustUsingKeyParams() request. NodeType = [" + nodeType + "]. ");
- }
-
- int i = -1;
- for( Map.Entry<String, Object> entry : keyPropsHash.entrySet() ){
- i++;
- kName.add(i, entry.getKey());
- kVal.add(i, entry.getValue());
- }
- int topPropIndex = i;
- Vertex tiV = null;
- String propsAndValuesForMsg = "";
- Iterator<Vertex> verts = null;
- GraphTraversalSource g = graph.traversal();
- try {
- if( topPropIndex == 0 ){
- propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
- verts= g.V().has(kName.get(0),kVal.get(0)).has(AAI_NODE_TYPE,nodeType);
- }
- else if( topPropIndex == 1 ){
- propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
- + kName.get(1) + " = " + kVal.get(1) + ") ";
- verts = g.V().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(AAI_NODE_TYPE,nodeType);
- }
- else if( topPropIndex == 2 ){
- propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
- + kName.get(1) + " = " + kVal.get(1) + ", "
- + kName.get(2) + " = " + kVal.get(2) + ") ";
- verts= g.V().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);
- }
- else if( topPropIndex == 3 ){
- propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
- + kName.get(1) + " = " + kVal.get(1) + ", "
- + kName.get(2) + " = " + kVal.get(2) + ", "
- + kName.get(3) + " = " + kVal.get(3) + ") ";
- verts= g.V().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);
- }
- else {
- throw new AAIException("AAI_6114", " We only support 4 keys per nodeType for now \n");
- }
- }
- catch( Exception ex ){
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error( " ERROR trying to get node for: [" + propsAndValuesForMsg + "] " + LogFormatTools.getStackTop(ex));
- LoggingContext.statusCode(StatusCode.COMPLETE);
- LoggingContext.responseCode(LoggingContext.SUCCESS);
- }
-
- if( verts != null ){
- while( verts.hasNext() ){
- tiV = verts.next();
- retVertList.add(tiV);
- }
- }
-
- if( retVertList.isEmpty() ){
- logger.debug("DEBUG No node found for nodeType = [" + nodeType +
- "], propsAndVal = " + propsAndValuesForMsg );
- }
-
- return retVertList;
-
- }// End of getNodeJustUsingKeyParams()
-
-
-
- /**
- * Gets the node(s) just using key params.
- *
- * @param transId the trans id
- * @param fromAppId the from app id
- * @param graph the graph
- * @param nodeType the node type
- * @param windowStartTime the window start time
- * @return the nodes
- * @throws AAIException the AAI exception
- */
- public static ArrayList <Vertex> figureOutNodes2Check( String transId, String fromAppId,
- Graph graph, String nodeType, long windowStartTime,
- String propsString, EELFLogger logger ) {
-
- ArrayList <Vertex> retVertList = new ArrayList <Vertex> ();
- String msg = "";
- GraphTraversal<Vertex,Vertex> tgQ = graph.traversal().V().has(AAI_NODE_TYPE,nodeType);
- String qStringForMsg = "graph.traversal().V().has(\"aai-node-type\"," + nodeType + ")";
-
- if( propsString != null && !propsString.trim().isEmpty() ){
- propsString = propsString.trim();
- int firstPipeLoc = propsString.indexOf("|");
- if( firstPipeLoc <= 0 ){
- msg = "Bad props4Collect passed: [" + propsString + "]. \n Expecting a format like, 'propName1|propVal1,propName2|propVal2'";
- System.out.println(msg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error(msg);
- exit(0);
- }
-
- // Note - if they're only passing on parameter, there won't be any commas
- String [] paramArr = propsString.split(",");
- for( int i = 0; i < paramArr.length; i++ ){
- int pipeLoc = paramArr[i].indexOf("|");
- if( pipeLoc <= 0 ){
- msg = "Bad propsString passed: [" + propsString + "]. \n Expecting a format like, 'propName1|propVal1,propName2|propVal2'";
- System.out.println(msg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error(msg);
- exit(0);
- }
- else {
- String propName = paramArr[i].substring(0,pipeLoc);
- String propVal = paramArr[i].substring(pipeLoc + 1);
- tgQ = tgQ.has(propName,propVal);
- qStringForMsg = qStringForMsg + ".has(" + propName + "," + propVal + ")";
- }
- }
- }
-
- if(tgQ != null) {
- Iterator<Vertex> vertItor = tgQ;
- while (vertItor.hasNext()) {
- Vertex tiV = vertItor.next();
- if (windowStartTime <= 0) {
- // We're not applying a time-window
- retVertList.add(tiV);
- continue;
- }
-
- Object objTimeStamp = tiV.property("aai-created-ts").orElse(null);
- if (objTimeStamp == null) {
- // No timestamp - so just take it
- retVertList.add(tiV);
- continue;
- }
-
- long thisNodeCreateTime = (long) objTimeStamp;
- if (thisNodeCreateTime > windowStartTime) {
- // It is in our window, so we can take it
- retVertList.add(tiV);
- }
- }
- } else {
- msg = "Bad JanusGraphQuery object. ";
- System.out.println(msg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.AVAILABILITY_TIMEOUT_ERROR);
- logger.error(msg);
- exit(0);
- }
-
- if( retVertList.isEmpty() ){
- logger.debug("DEBUG No node found for: [" + qStringForMsg + ", with aai-created-ts > " + windowStartTime );
- }
-
- return retVertList;
-
- }// End of figureOutNodes2Check()
-
-
- /**
- * Gets the preferred dupe.
- *
- * @param transId the trans id
- * @param fromAppId the from app id
- * @param g the g
- * @param dupeVertexList the dupe vertex list
- * @param ver the ver
- * @param logger the logger
- * @return Vertex
- * @throws AAIException the AAI exception
- */
- public static Vertex getPreferredDupe( String transId,
- String fromAppId, Graph g,
- ArrayList<Vertex> dupeVertexList, String ver,
- Boolean specialTenantRule, Loader loader, EELFLogger logger )
- throws AAIException {
-
- // This method assumes that it is being passed a List of vertex objects
- // which violate our uniqueness constraints.
-
- Vertex nullVtx = null;
-
- if (dupeVertexList == null) {
- return nullVtx;
- }
- int listSize = dupeVertexList.size();
- if (listSize == 0) {
- return nullVtx;
- }
- if (listSize == 1) {
- return ( dupeVertexList.get(0));
- }
-
- Vertex vtxPreferred = null;
- Vertex currentFaveVtx = dupeVertexList.get(0);
- for (int i = 1; i < listSize; i++) {
- Vertex vtxB = dupeVertexList.get(i);
- vtxPreferred = pickOneOfTwoDupes(transId, fromAppId, g,
- currentFaveVtx, vtxB, ver, specialTenantRule, loader, logger);
- if (vtxPreferred == null) {
- // We couldn't choose one
- return nullVtx;
- } else {
- currentFaveVtx = vtxPreferred;
- }
- }
-
- return (currentFaveVtx);
-
- } // end of getPreferredDupe()
-
-
- /**
- * Pick one of two dupes.
- *
- * @param transId the trans id
- * @param fromAppId the from app id
- * @param g the g
- * @param vtxA the vtx A
- * @param vtxB the vtx B
- * @param ver the ver
- * @param specialTenantRule flag
- * @param logger the logger
- * @return Vertex
- * @throws AAIException the AAI exception
- */
- public static Vertex pickOneOfTwoDupes(String transId,
- String fromAppId, Graph g, Vertex vtxA,
- Vertex vtxB, String ver, Boolean specialTenantRule, Loader loader, EELFLogger logger) throws AAIException {
-
- Vertex nullVtx = null;
- Vertex preferredVtx = null;
-
- Long vidA = new Long(vtxA.id().toString());
- Long vidB = new Long(vtxB.id().toString());
-
- String vtxANodeType = "";
- String vtxBNodeType = "";
- Object obj = vtxA.<Object>property(AAI_NODE_TYPE).orElse(null);
- if (obj != null) {
- vtxANodeType = obj.toString();
- }
- obj = vtxB.<Object>property(AAI_NODE_TYPE).orElse(null);
- if (obj != null) {
- vtxBNodeType = obj.toString();
- }
-
- if (vtxANodeType.isEmpty() || (!vtxANodeType.equals(vtxBNodeType))) {
- // Either they're not really dupes or there's some bad data - so
- // don't pick one
- return nullVtx;
- }
-
- // Check that node A and B both have the same key values (or else they
- // are not dupes)
- // (We'll check dep-node later)
- Collection<String> keyProps = loader.introspectorFromName(vtxANodeType).getKeys();
- Iterator<String> keyPropI = keyProps.iterator();
- while (keyPropI.hasNext()) {
- String propName = keyPropI.next();
- String vtxAKeyPropVal = "";
- obj = vtxA.<Object>property(propName).orElse(null);
- if (obj != null) {
- vtxAKeyPropVal = obj.toString();
- }
- String vtxBKeyPropVal = "";
- obj = vtxB.<Object>property(propName).orElse(null);
- if (obj != null) {
- vtxBKeyPropVal = obj.toString();
- }
-
- if (vtxAKeyPropVal.equals("")
- || (!vtxAKeyPropVal.equals(vtxBKeyPropVal))) {
- // Either they're not really dupes or they are missing some key
- // data - so don't pick one
- return nullVtx;
- }
- }
-
- // Collect the vid's and aai-node-types of the vertices that each vertex
- // (A and B) is connected to.
- ArrayList<String> vtxIdsConn2A = new ArrayList<String>();
- ArrayList<String> vtxIdsConn2B = new ArrayList<String>();
- HashMap<String, String> nodeTypesConn2A = new HashMap<String, String>();
- HashMap<String, String> nodeTypesConn2B = new HashMap<String, String>();
-
- ArrayList <String> retArr = new ArrayList <String> ();
- Iterator <Edge> eAI = vtxA.edges(Direction.BOTH);
- while( eAI.hasNext() ){
- Edge ed = eAI.next();
- Vertex tmpVtx;
- if (vtxA.equals(ed.inVertex())) {
- tmpVtx = ed.outVertex();
- } else {
- tmpVtx = ed.inVertex();
- }
- if( tmpVtx == null ){
- retArr.add(COULD_NOT_FIND_EDGE_ID_ + ed.id() + " <<< ");
- }
- else {
- String conVid = tmpVtx.id().toString();
- String nt = "";
- obj = tmpVtx.<Object>property(AAI_NODE_TYPE).orElse(null);
- if (obj != null) {
- nt = obj.toString();
- }
- nodeTypesConn2A.put(nt, conVid);
- vtxIdsConn2A.add(conVid);
- }
- }
-
- Iterator <Edge> eBI = vtxB.edges(Direction.BOTH);
- while( eBI.hasNext() ){
- Edge ed = eBI.next();
- Vertex tmpVtx;
-
- if (vtxB.equals(ed.inVertex())) {
- tmpVtx = ed.outVertex();
- } else {
- tmpVtx = ed.inVertex();
- }
- if( tmpVtx == null ){
- retArr.add(COULD_NOT_FIND_EDGE_ID_ + ed.id() + " <<< ");
- }
- else {
- String conVid = tmpVtx.id().toString();
- String nt = "";
- obj = tmpVtx.<Object>property(AAI_NODE_TYPE).orElse(null);
- if (obj != null) {
- nt = obj.toString();
- }
- nodeTypesConn2B.put(nt, conVid);
- vtxIdsConn2B.add(conVid);
- }
- }
-
- // 1 - If this kind of node needs a dependent node for uniqueness, then
- // verify that they both nodes point to the same dependent
- // node (otherwise they're not really duplicates)
- // Note - there are sometimes more than one dependent node type since
- // one nodeType can be used in different ways. But for a
- // particular node, it will only have one dependent node that
- // it's connected to.
- Collection<String> depNodeTypes = loader.introspectorFromName(vtxANodeType).getDependentOn();
- if (depNodeTypes.isEmpty()) {
- // This kind of node is not dependent on any other. That is ok.
- } else {
- String depNodeVtxId4A = "";
- String depNodeVtxId4B = "";
- Iterator<String> iter = depNodeTypes.iterator();
- while (iter.hasNext()) {
- String depNodeType = iter.next();
- if (nodeTypesConn2A.containsKey(depNodeType)) {
- // This is the dependent node type that vertex A is using
- depNodeVtxId4A = nodeTypesConn2A.get(depNodeType);
- }
- if (nodeTypesConn2B.containsKey(depNodeType)) {
- // This is the dependent node type that vertex B is using
- depNodeVtxId4B = nodeTypesConn2B.get(depNodeType);
- }
- }
- if (depNodeVtxId4A.isEmpty()
- || (!depNodeVtxId4A.equals(depNodeVtxId4B))) {
- // Either they're not really dupes or there's some bad data - so
- // don't pick either one
- return nullVtx;
- }
- }
-
- if (vtxIdsConn2A.size() == vtxIdsConn2B.size()) {
- // 2 - If they both have edges to all the same vertices, then return
- // the one with the lower vertexId.
-
- // OR (2b)-- if this is the SPECIAL case -- of
- // "tenant|vserver vs. tenant|service-subscription"
- // then we pick/prefer the one that's connected to
- // the service-subscription. AAI-8172
- boolean allTheSame = true;
- Iterator<String> iter = vtxIdsConn2A.iterator();
- while (iter.hasNext()) {
- String vtxIdConn2A = iter.next();
- if (!vtxIdsConn2B.contains(vtxIdConn2A)) {
- allTheSame = false;
- break;
- }
- }
-
- if (allTheSame) {
- if (vidA < vidB) {
- preferredVtx = vtxA;
- } else {
- preferredVtx = vtxB;
- }
- }
- else if ( specialTenantRule && vtxIdsConn2A.size() == 2 && "tenant".equals(vtxANodeType)){
- // They asked us to apply a special rule if it applies
- // We're dealing with two tenant nodes which each just have
- // two connections. One must be the parent (cloud-region)
- // which we check in step 1 above. If one connects to
- // a vserver and the other connects to a service-subscription,
- // our special rule is to keep the one connected
- // to the
- if( nodeTypesConn2A.containsKey("vserver") && nodeTypesConn2B.containsKey("service-subscription") ){
- String infMsg = " WARNING >>> we are using the special tenant rule to choose to " +
- " delete tenant vtxId = " + vidA + ", and keep tenant vtxId = " + vidB ;
- System.out.println(infMsg);
- logger.info( infMsg );
- preferredVtx = vtxB;
- }
- else if( nodeTypesConn2B.containsKey("vserver") && nodeTypesConn2A.containsKey("service-subscription") ){
- String infMsg = " WARNING >>> we are using the special tenant rule to choose to " +
- " delete tenant vtxId = " + vidB + ", and keep tenant vtxId = " + vidA ;
- System.out.println(infMsg);
- logger.info( infMsg );
- preferredVtx = vtxA;
- }
- }
- } else if (vtxIdsConn2A.size() > vtxIdsConn2B.size()) {
- // 3 - VertexA is connected to more things than vtxB.
- // We'll pick VtxA if its edges are a superset of vtxB's edges.
- boolean missingOne = false;
- Iterator<String> iter = vtxIdsConn2B.iterator();
- while (iter.hasNext()) {
- String vtxIdConn2B = iter.next();
- if (!vtxIdsConn2A.contains(vtxIdConn2B)) {
- missingOne = true;
- break;
- }
- }
- if (!missingOne) {
- preferredVtx = vtxA;
- }
- } else if (vtxIdsConn2B.size() > vtxIdsConn2A.size()) {
- // 4 - VertexB is connected to more things than vtxA.
- // We'll pick VtxB if its edges are a superset of vtxA's edges.
- boolean missingOne = false;
- Iterator<String> iter = vtxIdsConn2A.iterator();
- while (iter.hasNext()) {
- String vtxIdConn2A = iter.next();
- if (!vtxIdsConn2B.contains(vtxIdConn2A)) {
- missingOne = true;
- break;
- }
- }
- if (!missingOne) {
- preferredVtx = vtxB;
- }
- } else {
- preferredVtx = nullVtx;
- }
-
- return (preferredVtx);
-
- } // end of pickOneOfTwoDupes()
-
-
- /**
- * Group verts by dep nodes.
- *
- * @param transId the trans id
- * @param fromAppId the from app id
- * @param g the g
- * @param version the version
- * @param nType the n type
- * @param passedVertList the passed vert list
- * @param loader loader
- * @return the hash map
- * @throws AAIException the AAI exception
- */
- private static HashMap<String, ArrayList<Vertex>> groupVertsByDepNodes(
- String transId, String fromAppId, Graph g, String version,
- String nType, ArrayList<Vertex> passedVertList, Loader loader)
- throws AAIException {
-
- // Given a list of JanusGraph Vertices, group them together by dependent
- // nodes. Ie. if given a list of ip address nodes (assumed to all
- // have the same key info) they might sit under several different
- // parent vertices.
- // Under Normal conditions, there would only be one per parent -- but
- // we're trying to find duplicates - so we allow for the case
- // where more than one is under the same parent node.
-
- HashMap<String, ArrayList<Vertex>> retHash = new HashMap<String, ArrayList<Vertex>>();
-
- // Find out what types of nodes the passed in nodes can depend on
- ArrayList<String> depNodeTypeL = new ArrayList<String>();
- Collection<String> depNTColl = loader.introspectorFromName(nType).getDependentOn();
- Iterator<String> ntItr = depNTColl.iterator();
- while (ntItr.hasNext()) {
- depNodeTypeL.add(ntItr.next());
- }
- // For each vertex they passed us, we want find the vertex it
- // is dependent on so we can keep track of who-all is connected
- // to that parent.
- if (passedVertList != null) {
- Iterator<Vertex> iter = passedVertList.iterator();
- while (iter.hasNext()) {
- Vertex thisVert = iter.next();
- Iterator <String> depNtItr = depNTColl.iterator();
- while (depNtItr.hasNext()) {
- GraphTraversal<Vertex, Vertex> modPipe = null;
- // NOTE -- if we change the direction of parent/child edges, we will need
- // the "in" below to become "out"
- modPipe = g.traversal().V(thisVert).in().has(AAI_NODE_TYPE, depNtItr.next() );
- if( modPipe == null || !modPipe.hasNext() ){
- //System.out.println("DEBUG - didn't find any [" + targetStep + "] connected to this guy (which is ok)");
- continue;
- }
-
- while( modPipe.hasNext() ){
- Vertex depVert = modPipe.next();
- String parentVid = depVert.id().toString();
- if (retHash.containsKey(parentVid)) {
- // add this vert to the list for this parent key
- retHash.get(parentVid).add(thisVert);
- } else {
- // This is the first one we found on this parent
- ArrayList<Vertex> vList = new ArrayList<Vertex>();
- vList.add(thisVert);
- retHash.put(parentVid, vList);
- }
- }
- }
- }
- }
-
- return retHash;
-
- }// end of groupVertsByDepNodes()
-
-
- /**
- * Delete non keepers if appropriate.
- *
- * @param g the g
- * @param dupeInfoList the dupe info string
- * @param logger the EELFLogger
- * @return the boolean
- */
- private static Boolean deleteNonKeepers(Graph g,
- ArrayList<String> dupeInfoList, EELFLogger logger ) {
-
- // This assumes that each dupeInfoString is in the format of
- // pipe-delimited vid's followed by either "keepVid=xyz" or "keepVid=UNDETERMINED"
- // ie. "3456|9880|keepVid=3456"
-
- boolean didADelFlag = false;
- for( int n = 0; n < dupeInfoList.size(); n++ ){
- String dupeInfoString = dupeInfoList.get(n);
- boolean tmpFlag = deleteNonKeeperForOneSet( g, dupeInfoString, logger );
- didADelFlag = tmpFlag || didADelFlag;
- }
-
- return didADelFlag;
-
- }// end of deleteNonKeepers()
-
-
- /**
- * Delete non keepers if appropriate.
- *
- * @param g the g
- * @param dupeInfoString the dupe string
- * @param logger the EELFLogger
- * @return the boolean
- */
- private static Boolean deleteNonKeeperForOneSet(Graph g,
- String dupeInfoString, EELFLogger logger ) {
-
- Boolean deletedSomething = false;
- // This assumes that each dupeInfoString is in the format of
- // pipe-delimited vid's followed by either "keepVid=xyz" or "keepVid=UNDETERMINED"
- // ie. "3456|9880|keepVid=3456"
-
-
- String[] dupeArr = dupeInfoString.split("\\|");
- ArrayList<String> idArr = new ArrayList<String>();
- int lastIndex = dupeArr.length - 1;
- for (int i = 0; i <= lastIndex; i++) {
- if (i < lastIndex) {
- // This is not the last entry, it is one of the dupes,
- String vidString = dupeArr[i];
- idArr.add(vidString);
- continue;
- }
-
- // This is the last entry which should tell us if we have a
- // preferred keeper
- String prefString = dupeArr[i];
- if ("KeepVid=UNDETERMINED".equals(prefString)) {
- // They sent us a bad string -- nothing should be deleted if
- // no dupe could be tagged as preferred.
- return false;
- }
- // If we know which to keep, then the prefString should look
- // like, "KeepVid=12345"
- String[] prefArr = prefString.split("=");
- if (prefArr.length != 2 || !KEEP_VID.equals(prefArr[0])) {
- String emsg = "Bad format. Expecting KeepVid=999999";
- System.out.println(emsg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error(emsg);
- LoggingContext.statusCode(StatusCode.COMPLETE);
- LoggingContext.responseCode(LoggingContext.SUCCESS);
- return false;
- }
-
- String keepVidStr = prefArr[1];
- if (idArr.contains(keepVidStr)) {
- idArr.remove(keepVidStr);
- // So now, the idArr should just contain the vid's
- // that we want to remove.
- for (int x = 0; x < idArr.size(); x++) {
- boolean okFlag = true;
- String thisVid = idArr.get(x);
- try {
- long longVertId = Long.parseLong(thisVid);
- Vertex vtx = g.traversal().V(longVertId).next();
- String msg = "--->>> We will delete node with VID = " + thisVid + " <<<---";
- System.out.println(msg);
- logger.info(msg);
- vtx.remove();
- }
- catch (Exception e) {
- okFlag = false;
- String emsg = "ERROR trying to delete VID = " + thisVid + ", [" + e + "]";
- System.out.println(emsg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error(emsg);
- LoggingContext.statusCode(StatusCode.COMPLETE);
- LoggingContext.responseCode(LoggingContext.SUCCESS);
- }
- if (okFlag) {
- String infMsg = " DELETED VID = " + thisVid;
- logger.info(infMsg);
- System.out.println(infMsg);
- deletedSomething = true;
- }
- }
- } else {
- String emsg = "ERROR - Vertex Id to keep not found in list of dupes. dupeInfoString = ["
- + dupeInfoString + "]";
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error(emsg);
- LoggingContext.statusCode(StatusCode.COMPLETE);
- LoggingContext.responseCode(LoggingContext.SUCCESS);
- System.out.println(emsg);
- return false;
- }
-
- }// for each vertex in a group
-
- return deletedSomething;
-
- }// end of deleteNonKeeperForOneSet()
-
-
- /**
- * Get values of the key properties for a node.
- *
- * @param tvx the vertex to pull the properties from
- * @param keyPropNamesArr ArrayList (ordered) of key prop names
- * @param logger the EELFLogger
- * @return a hashMap of the propertyNames/values
- */
- private static HashMap <String,Object> getNodeKeyVals( Vertex tvx,
- ArrayList <String> keyPropNamesArr, EELFLogger logger ) {
-
- HashMap <String,Object> retHash = new HashMap <String,Object>();
- Iterator <String> propItr = keyPropNamesArr.iterator();
- while( propItr.hasNext() ){
- String propName = propItr.next();
- if( tvx != null ){
- Object propValObj = tvx.property(propName).orElse(null);
- retHash.put(propName, propValObj);
- }
- }
- return retHash;
-
- }// End of getNodeKeyVals()
-
-
- /**
- * Get values of the key properties for a node as a single string
- *
- * @param tvx the vertex to pull the properties from
- * @param keyPropNamesArr collection of key prop names
- * @param logger the EELFLogger
- * @return a String of concatenated values
- */
- private static String getNodeKeyValString( Vertex tvx,
- ArrayList <String> keyPropNamesArr, EELFLogger logger ) {
-
- // -- NOTE -- for what we're using this for, we would need to
- // guarantee that the properties are always in the same order
-
- String retString = "";
- Iterator <String> propItr = keyPropNamesArr.iterator();
- while( propItr.hasNext() ){
- String propName = propItr.next();
- if( tvx != null ){
- Object propValObj = tvx.property(propName).orElse(null);
- retString = " " + retString + propValObj.toString();
- }
- }
- return retString;
-
- }// End of getNodeKeyValString()
-
-
- /**
- * Find duplicate sets from two dupe runs.
- *
- * @param firstPassDupeSets from the first pass
- * @param secondPassDupeSets from the second pass
- * @param logger logger
- * @return commonDupeSets that are common to both passes and have a determined keeper
- */
- private static ArrayList <String> figureWhichDupesStillNeedFixing( ArrayList <String>firstPassDupeSets,
- ArrayList <String> secondPassDupeSets, EELFLogger logger ){
-
- ArrayList <String> common2BothSet = new ArrayList <String> ();
-
- // We just want to look for entries from the first set which have identical (almost)
- // entries in the secondary set. I say "almost" because the order of the
- // vid's to delete may be in a different order, but we only want to use it if
- // they have all the same values. Note also - we're just looking for
- // the sets where we have a candidate to delete.
-
- // The duplicate-set Strings are in this format:
- // "1234|5678|keepVid=UNDETERMINED" (if there were 2 dupes, and we
- // couldn't figure out which one to keep)
- // or, "100017|200027|30037|keepVid=30037" (if there were 3 dupes and we
- // thought the third one was the one that should survive)
-
- if( firstPassDupeSets == null || firstPassDupeSets.isEmpty()
- || secondPassDupeSets == null || secondPassDupeSets.isEmpty() ){
- // If either set is empty, then our return list has to be empty too
- return common2BothSet;
- }
-
- boolean needToParse = false;
- for( int x = 0; x < secondPassDupeSets.size(); x++ ){
- String secPassDupeSetStr = secondPassDupeSets.get(x);
- if( secPassDupeSetStr.endsWith("UNDETERMINED") ){
- // This is a set of dupes where we could not pick one
- // to delete - so don't include it on our list for
- // fixing.
- }
- else if( firstPassDupeSets.contains(secPassDupeSetStr) ){
- // We have lucked out and do not even need to parse this since
- // it was in the other array with any dupes listed in the same order
- // This is actually the most common scenario since there is
- // usually only one dupe, so order doesn't matter.
- common2BothSet.add(secPassDupeSetStr);
- }
- else {
- // We'll need to do some parsing to check this one
- needToParse = true;
- }
- }
-
- if( needToParse ){
- // Make a hash from the first and second Pass data
- // where the key is the vid to KEEP and the value is an
- // array of (String) vids that would get deleted.
- HashMap <String,ArrayList<String>> firstPassHash = makeKeeperHashOfDupeStrings( firstPassDupeSets, common2BothSet, logger );
-
- HashMap <String,ArrayList<String>> secPassHash = makeKeeperHashOfDupeStrings( secondPassDupeSets, common2BothSet, logger );
-
- // Loop through the secondPass data and keep the ones
- // that check out against the firstPass set.
- for( Map.Entry<String, ArrayList<String>> entry : secPassHash.entrySet() ){
- boolean skipThisOne = false;
- String secKey = entry.getKey();
- ArrayList <String> secList = entry.getValue();
- if( !firstPassHash.containsKey(secKey) ){
- // The second pass found this delete candidate, but not the first pass
- skipThisOne = true;
- }
- else {
- // They both think they should keep this VID, check the associated deletes for it.
- ArrayList <String> firstList = firstPassHash.get(secKey);
- for( int z = 0; z < secList.size(); z++ ){
- if( !firstList.contains(secList.get(z)) ){
- // The first pass did not think this needed to be deleted
- skipThisOne = true;
- }
- }
- }
- if( skipThisOne ) {
- continue;
- }
-
- // Put the string back together and pass it back
- // Not beautiful, but no time to make it nice right now...
- // Put it back in the format: "3456|9880|keepVid=3456"
- String thisDelSetStr = "";
- for( int z = 0; z < secList.size(); z++ ){
- if( z == 0 ){
- thisDelSetStr = secList.get(z);
- }
- else {
- thisDelSetStr = thisDelSetStr + "|" + secList.get(z);
- }
- }
- thisDelSetStr = thisDelSetStr + "|keepVid=" + secKey;
- common2BothSet.add(thisDelSetStr);
- }
- }
- return common2BothSet;
-
- }// figureWhichDupesStillNeedFixing
-
-
- private static HashMap <String, ArrayList <String>> makeKeeperHashOfDupeStrings( ArrayList <String> dupeSets,
- ArrayList <String> excludeSets, EELFLogger logger ){
-
- HashMap <String,ArrayList<String>> keeperHash = new HashMap <String, ArrayList<String>>();
-
- for( int x = 0; x < dupeSets.size(); x++ ){
- String tmpSetStr = dupeSets.get(x);
- if( excludeSets.contains(tmpSetStr) ){
- // This isn't one of the ones we needed to parse.
- continue;
- }
-
- String[] dupeArr = tmpSetStr.split("\\|");
- ArrayList<String> delIdArr = new ArrayList<String>();
- int lastIndex = dupeArr.length - 1;
- for (int i = 0; i <= lastIndex; i++) {
- if (i < lastIndex) {
- // This is not the last entry, it is one of the dupes
- delIdArr.add(dupeArr[i]);
- continue;
- }
-
- // This is the last entry which should tell us if we
- // have a preferred keeper and how many dupes we had
- String prefString = dupeArr[i];
- if( i == 1 ){
- // There was only one dupe, so if we were gonna find
- // it, we would have found it above with no parsing.
- }
- else if ("KeepVid=UNDETERMINED".equals(prefString)) {
- // This one had no determined keeper, so we don't
- // want it.
- }
- else {
- // If we know which to keep, then the prefString
- // should look like, "KeepVid=12345"
- String[] prefArr = prefString.split("=");
- if( prefArr.length != 2 || !KEEP_VID.equals(prefArr[0]) ) {
- String infMsg = "Bad format in figureWhichDupesStillNeedFixing(). Expecting " +
- " KeepVid=999999 but string looks like: [" + tmpSetStr + "]";
- System.out.println(infMsg);
- logger.info(infMsg);
- }
- else {
- keeperHash.put(prefArr[0], delIdArr);
- }
- }
-
- }
- }
-
- return keeperHash;
-
- }// End makeHashOfDupeStrings()
-
-
- /**
- * Get values of the key properties for a node.
- *
- * @param g the g
- * @param dupeInfoString
- * @param logger the EELFLogger
- * @return void
- */
- static private void showNodeDetailsForADupeSet(Graph g, String dupeInfoString, EELFLogger logger) {
-
- // dang... parsing this string once again...
-
- String[] dupeArr = dupeInfoString.split("\\|");
- int lastIndex = dupeArr.length - 1;
- for (int i = 0; i <= lastIndex; i++) {
- if (i < lastIndex) {
- // This is not the last entry, it is one of the dupes,
- String vidString = dupeArr[i];
- long longVertId = Long.parseLong(vidString);
- Vertex vtx = g.traversal().V(longVertId).next();
- showNodeInfo(logger, vtx, false);
- } else {
- // This is the last entry which should tell us if we have a
- // preferred keeper
- String prefString = dupeArr[i];
- if (prefString.equals("KeepVid=UNDETERMINED")) {
- String msg = " Our algorithm cannot choose from among these, so they will all be kept. -------\n";
- System.out.println(msg);
- logger.info(msg);
- } else {
- // If we know which to keep, then the prefString should look
- // like, "KeepVid=12345"
- String[] prefArr = prefString.split("=");
- if (prefArr.length != 2 || (!prefArr[0].equals(KEEP_VID))) {
- String emsg = "Bad format. Expecting KeepVid=999999";
- System.out.println(emsg);
- LoggingContext.statusCode(StatusCode.ERROR);
- LoggingContext.responseCode(LoggingContext.DATA_ERROR);
- logger.error(emsg);
- LoggingContext.statusCode(StatusCode.COMPLETE);
- LoggingContext.responseCode(LoggingContext.SUCCESS);
- } else {
- String keepVidStr = prefArr[1];
- String msg = " vid = " + keepVidStr + " is the one that we would KEEP. ------\n";
- System.out.println(msg);
- logger.info(msg);
- }
- }
- }
- }
-
- }// End of showNodeDetailsForADupeSet()
-
- private static int graphIndex = 1;
-
- public static JanusGraph setupGraph(EELFLogger logger){
-
- JanusGraph janusGraph = null;
-
-
- try (InputStream inputStream = new FileInputStream(AAIConstants.REALTIME_DB_CONFIG);){
-
- Properties properties = new Properties();
- properties.load(inputStream);
-
- if(INMEMORY.equals(properties.get("storage.backend"))){
- janusGraph = AAIGraph.getInstance().getGraph();
- graphType = INMEMORY;
- } else {
- janusGraph = JanusGraphFactory.open(new AAIGraphConfig.Builder(AAIConstants.REALTIME_DB_CONFIG).forService(DupeTool.class.getSimpleName()).withGraphType("realtime" + graphIndex).buildConfiguration());
- graphIndex++;
- }
- } catch (Exception e) {
- logger.error("Unable to open the graph", LogFormatTools.getStackTop(e));
- }
-
- return janusGraph;
- }
-
- public static void closeGraph(JanusGraph graph, EELFLogger logger){
-
- try {
- if(INMEMORY.equals(graphType)) {
- return;
- }
- if( graph != null && graph.isOpen() ){
- graph.tx().close();
- graph.close();
- }
- } catch (Exception ex) {
- // Don't throw anything because JanusGraph sometimes is just saying that the graph is already closed{
- logger.warn("WARNING from final graph.shutdown()", ex);
- }
- }
-}
-
-