diff --git a/docs/MMTC_Users_Guide.adoc b/docs/MMTC_Users_Guide.adoc index 14ea9cf..4245b44 100644 --- a/docs/MMTC_Users_Guide.adoc +++ b/docs/MMTC_Users_Guide.adoc @@ -662,6 +662,13 @@ This option and any other *--clkchgrate-** options are mutually exclusive. |N/A |In a testing environment and in certain operational scenarios, it can be necessary to have MMTC assign the clock change rate of the new time correlation to 1.0, indicating no clock drift, rather than computing it. Also, if this option is selected, MMTC will not replace the existing clock change rate in the SCLK kernel with an interpolated value. The value 1.00000000000 will appear in the new (latest) time correlation record in the SCLK kernel and SCLK/SCET file. This option and any other *--clkchgrate-** options are mutually exclusive. +|-D +|--dry-run +|N/A +|Runs MMTC in dry run mode. No output products will be modified or created and "what-if" output +products will instead be printed to the console and written to the log. The run history file will likewise +remain unappended. Otherwise runs MMTC normally according to other options and config keys. + |-F |--disable-contact-filter |N/A diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/app/TimeCorrelationApp.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/app/TimeCorrelationApp.java index a93c888..33af289 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/app/TimeCorrelationApp.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/app/TimeCorrelationApp.java @@ -2,6 +2,8 @@ import java.math.BigInteger; import java.math.RoundingMode; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.*; import java.math.BigDecimal; @@ -24,6 +26,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.appender.RollingFileAppender; import static edu.jhuapl.sd.sig.mmtc.app.MmtcCli.USER_NOTICE; @@ -94,7 +97,9 @@ private void init() throws Exception { runHistoryFile = new RunHistoryFile(config.getRunHistoryFilePath(), config.getAllOutputProductDefs()); runHistoryFile.updateRowsForNewProducts(); newRunHistoryFileRecord = new TableRecord(runHistoryFile.getHeaders()); - recordRunHistoryFilePreRunValues(); + if (!ctx.config.isDryRun()) { + recordRunHistoryFilePreRunValues(); + } tk_sclk_fine_tick_modulus = config.getTkSclkFineTickModulus(); logger.info("tk_sclk_fine_tick_modulus set to: " + tk_sclk_fine_tick_modulus); @@ -379,6 +384,10 @@ public void run() throws Exception { if (config.isTestMode()) { logger.warn(String.format("Test mode is enabled! One-way light time will be set to the provided value %f and ancillary positional and velocity calculations will be skipped.", config.getTestModeOwlt())); } + if (config.isDryRun()) { + logger.warn("Dry run mode is enabled! No data products from this run will be kept and will instead be printed to the console and recorded in the log file according to log4j2.xml"); + } + // Select telemetry for this new time correlation run final TimeCorrelationTarget tcTarget = selectSampleSetAndTimeCorrelationTarget(); @@ -483,22 +492,31 @@ public void run() throws Exception { // Perform all ancillary post-correlation operations new TimeCorrelationAncillaryOperations(ctx).perform(); - // Write all output products + // Write or log all output products ctx.newSclkVersionString.set(getNextSclkKernelVersionString()); for (OutputProductDefinition prodDef : config.getAllOutputProductDefs()) { final String postRunColProdColName = RunHistoryFile.getPostRunProductColNameFor(prodDef); - if (prodDef.shouldBeWritten(ctx)) { + if (prodDef.shouldBeWritten(ctx) && !ctx.config.isDryRun()) { final ProductWriteResult res = prodDef.write(ctx); newRunHistoryFileRecord.setValue(postRunColProdColName, res.newVersion); + + } else if (prodDef.shouldBeWritten(ctx) && ctx.config.isDryRun()) { + // Log/print output products instead of writing them to files + final String productPrintout = prodDef.getDryRunPrintout(ctx); + logger.info(USER_NOTICE, productPrintout); } else { newRunHistoryFileRecord.setValue(postRunColProdColName, runHistoryFile.getLatestNonEmptyValueOfCol(postRunColProdColName, RunHistoryFile.RollbackEntryOption.IGNORE_ROLLBACKS).orElse("-")); } } - runHistoryFile.writeRecord(newRunHistoryFileRecord); - logger.info(USER_NOTICE, "Appended a new entry to Run History File located at " + runHistoryFile.getPath()); - logger.info(String.format("Run at %s recorded to %s", ctx.appRunTime, config.getRunHistoryFilePath().toString())); + // Update run history file if this isn't a dry run. If it is, delete the previously created temp SCLK kernel. + if (!ctx.config.isDryRun()) { + runHistoryFile.writeRecord(newRunHistoryFileRecord); + logger.info(USER_NOTICE, "Appended a new entry to Run History File located at " + runHistoryFile.getPath()); + logger.info(String.format("Run at %s recorded to %s", ctx.appRunTime, config.getRunHistoryFilePath().toString())); + } + logger.info(USER_NOTICE, "MMTC completed successfully."); } @@ -590,4 +608,4 @@ public static String constructNextSclkKernelCounter(String currentName, String s return nextVersionStr; } -} +} \ No newline at end of file diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/CorrelationCommandLineConfig.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/CorrelationCommandLineConfig.java index d4db8bc..9642141 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/CorrelationCommandLineConfig.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/CorrelationCommandLineConfig.java @@ -92,6 +92,13 @@ public class CorrelationCommandLineConfig implements IConfiguration { "Run in test mode, which allows the user to override one-way-light-time." ); + opts.addOption( + "D", + "dry-run", + false, + "Enables dry-run mode, resulting in correlation outputs being printed & logged but not written to the filesystem. The run history file likewise won't be modified." + ); + opts.addOption("h", "help", false, "Print this message."); for (Option additionalOption : additionalOptions) { @@ -176,6 +183,10 @@ boolean isTestMode() { return cmdLine.hasOption("T") || cmdLine.hasOption("test-mode-owlt"); } + boolean isDryRun() { + return cmdLine.hasOption("D") || cmdLine.hasOption("dry-run"); + } + double getTestModeOwlt() { return Double.parseDouble(cmdLine.getOptionValue('T')); } diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/TimeCorrelationAppConfig.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/TimeCorrelationAppConfig.java index 74eeaf6..b59b009 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/TimeCorrelationAppConfig.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/TimeCorrelationAppConfig.java @@ -280,6 +280,15 @@ public Map getFilters() throws MmtcException { return filters; } + /** + * Indicates if this is a dry run + * + * @return true if -D or --dry-run CLI options are invoked + */ + public boolean isDryRun() { + return cmdLineConfig.isDryRun(); + } + /** * Indicates if an optional Uplink Command File is to be created. This can be specified in either the command line * or in configuration parameters. Command line overrides the configuration parameter. diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/correlation/TimeCorrelationContext.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/correlation/TimeCorrelationContext.java index 0fc0f2b..a2e628f 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/correlation/TimeCorrelationContext.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/correlation/TimeCorrelationContext.java @@ -23,6 +23,7 @@ public class TimeCorrelationContext { public final Settable runId = new Settable<>(); public final Settable currentSclkKernel = new Settable<>(); + public final Settable newSclkKernel = new Settable<>(); public final Settable newSclkVersionString = new Settable<>(); public final Settable newSclkKernelPath = new Settable<>(); public final Settable tk_sclk_fine_tick_modulus = new Settable<>(); diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/OutputProductDefinition.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/OutputProductDefinition.java index 33b7ec9..1ac4e5d 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/OutputProductDefinition.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/OutputProductDefinition.java @@ -6,9 +6,12 @@ import edu.jhuapl.sd.sig.mmtc.correlation.TimeCorrelationContext; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductLocation; +import edu.jhuapl.sd.sig.mmtc.products.model.TextProductException; import edu.jhuapl.sd.sig.mmtc.rollback.TimeCorrelationRollback; import edu.jhuapl.sd.sig.mmtc.util.Settable; +import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException; +import java.io.IOException; import java.nio.file.Path; import java.util.Map; import java.util.Optional; @@ -59,6 +62,19 @@ public final boolean isBuiltIn() { */ public abstract boolean shouldBeWritten(TimeCorrelationContext context); + /** + * Generates a string summarizing the hypothetical changes to an output product that would have been made had this been a real + * run and the dry run flag wasn't passed. This generally involves all the steps usually taken to compute and produce an MMTC + * output product except actually writing it to disk (except the SCLK kernel which must be written but will later be deleted). + * @param ctx The current TimeCorrelationContext + * @return A string representation of any additions that would have been made to an output product + * @throws MmtcException + * @throws TextProductException + * @throws IOException + * @throws TimeConvertException + */ + public abstract String getDryRunPrintout(TimeCorrelationContext ctx) throws MmtcException, TextProductException, IOException, TimeConvertException; + /** * Write the product to the filesystem. Called once per successful time correlation run. * diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/RawTlmTableProductDefinition.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/RawTlmTableProductDefinition.java index 325c0db..e8efaaf 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/RawTlmTableProductDefinition.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/RawTlmTableProductDefinition.java @@ -6,10 +6,12 @@ import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductPath; import edu.jhuapl.sd.sig.mmtc.products.model.RawTelemetryTable; +import edu.jhuapl.sd.sig.mmtc.products.model.TableRecord; import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.IntStream; public class RawTlmTableProductDefinition extends AppendedFileOutputProductDefinition { public RawTlmTableProductDefinition() { @@ -26,6 +28,18 @@ public boolean shouldBeWritten(TimeCorrelationContext context) { return true; } + @Override + public String getDryRunPrintout(TimeCorrelationContext ctx) { + TableRecord rawTlmTableRecord = RawTelemetryTable.calculateUpdatedRawTlmTable(ctx); + List rtHeaders = new RawTelemetryTable(ctx.config.getRawTelemetryTablePath()).getHeaders(); + Collection rtValues = rawTlmTableRecord.getValues(); + String zippedRtRow = IntStream.range(0, rtHeaders.size()) + .mapToObj(i -> "\t" + rtHeaders.get(i) + "\t:\t"+new ArrayList<>(rtValues) + .get(i)) + .collect(Collectors.joining("\n")); + return String.format("[DRY RUN] Updated Raw TLM table records: \n%s", zippedRtRow); + } + @Override public ProductWriteResult appendToProduct(TimeCorrelationContext context) throws MmtcException { return RawTelemetryTable.appendCorrelationFrameSamplesToRawTelemetryTable(context); diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkKernelProductDefinition.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkKernelProductDefinition.java index c4a1749..c038314 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkKernelProductDefinition.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkKernelProductDefinition.java @@ -45,6 +45,27 @@ public boolean shouldBeWritten(TimeCorrelationContext context) { return true; } + /** + * This implementation is distinct from that of other output products in that it does still write the SCLK kernel to + * disk. The only difference is that it's written to the /tmp directory and its latest two lines are recorded here. + * @param ctx The active run's TimeCorrelationContext + * @return A string with details about the changed SCLK kernel(s) ready to be logged. + * @throws MmtcException if there are any problems generating the SCLK kernel + */ + @Override + public String getDryRunPrintout(TimeCorrelationContext ctx) throws MmtcException { + SclkKernel.writeNewProduct(ctx); + + String[] newSclkEntries = ctx.newSclkKernel.get().getLastXRecords(2); + // If an interpolated clock change rate has replaced the rate in the existing SCLK kernel record, retrieve the two latest records. + // Otherwise, just return the new record + if (ctx.newSclkKernel.get().hasNewClkChgRateSet()) { + return String.format("[DRY RUN] Updated SCLK entries: \n" + newSclkEntries[0] + "\n" + newSclkEntries[1]); + } else { + return String.format("[DRY RUN] New SCLK entry: \n" + newSclkEntries[0]); + } + } + @Override public Map getSandboxConfigUpdates(MmtcConfig originalConfig, Path newProductOutputDir) { final Map confUpdates = new HashMap<>(); diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkScetProductDefinition.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkScetProductDefinition.java index 56af78f..e400f1a 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkScetProductDefinition.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/SclkScetProductDefinition.java @@ -7,6 +7,18 @@ import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductDirPrefixSuffix; import edu.jhuapl.sd.sig.mmtc.products.model.SclkKernel; import edu.jhuapl.sd.sig.mmtc.products.model.SclkScetFile; +import edu.jhuapl.sd.sig.mmtc.products.model.TextProductException; +import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException; + +import java.io.IOException; +import java.util.Arrays; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.nio.file.Path; import java.util.HashMap; @@ -20,6 +32,7 @@ public class SclkScetProductDefinition extends EntireFileOutputProductDefinition public SclkScetProductDefinition() { super("SCLKSCET File"); } + private final int ENTRIES_TO_PRINT = 4; @Override public ResolvedProductDirPrefixSuffix resolveLocation(MmtcConfig conf) throws MmtcException { @@ -37,6 +50,22 @@ public boolean shouldBeWritten(TimeCorrelationContext ctx) { return ctx.config.createSclkScetFile(); } + @Override + public String getDryRunPrintout(TimeCorrelationContext ctx) throws MmtcException { + SclkScetFile scetFile = SclkScetFile.calculateNewProduct(ctx); + try { + scetFile.setSourceFilespec(ctx.newSclkKernel.get().getPath()); + scetFile.updateFile(); + } catch (TextProductException | TimeConvertException | IOException e) { + throw new MmtcException("Failed to generate SCLKSCET file"); + } + List newProductLines = scetFile.getNewProductLines(); + String newRecs = IntStream.range(Math.max(0, newProductLines.size() - (ENTRIES_TO_PRINT+1)), newProductLines.size()-1) // Ignore footer row + .mapToObj(newProductLines::get) + .collect(Collectors.joining("\n\t")); + return String.format("[DRY RUN] Latest %d SCLKSCET file entries: \n\t%s\n\t%s", ENTRIES_TO_PRINT, scetFile.getSclkscetFields(), newRecs); + } + /** * Writes a new SCLK-SCET File * @param ctx the current time correlation context from which to pull information for the output product diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/TimeHistoryFileProductDefinition.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/TimeHistoryFileProductDefinition.java index c612a75..f8a9c00 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/TimeHistoryFileProductDefinition.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/TimeHistoryFileProductDefinition.java @@ -5,11 +5,14 @@ import edu.jhuapl.sd.sig.mmtc.correlation.TimeCorrelationContext; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductPath; +import edu.jhuapl.sd.sig.mmtc.products.model.TableRecord; import edu.jhuapl.sd.sig.mmtc.products.model.TimeHistoryFile; +import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException; import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.IntStream; public class TimeHistoryFileProductDefinition extends AppendedFileOutputProductDefinition { public TimeHistoryFileProductDefinition() { @@ -26,6 +29,24 @@ public boolean shouldBeWritten(TimeCorrelationContext ctx) { return ctx.config.createTimeHistoryFile(); } + @Override + public String getDryRunPrintout(TimeCorrelationContext ctx) throws MmtcException { + TimeHistoryFile timeHistFile = new TimeHistoryFile(ctx.config.getTimeHistoryFilePath(), ctx.config.getTimeHistoryFileExcludeColumns()); + TableRecord timeHistRecord = new TableRecord(timeHistFile.getHeaders()); + try { + TimeHistoryFile.generateNewTimeHistRec(ctx, timeHistFile, timeHistRecord); + } catch (TimeConvertException e) { + throw new RuntimeException(e); + } + List thHeaders = new TimeHistoryFile(ctx.config.getTimeHistoryFilePath()).getHeaders(); + Collection thValues = timeHistRecord.getValues(); + String zippedThRow = IntStream.range(0, thHeaders.size()) + .mapToObj(i -> "\t" + thHeaders.get(i) + "\t:\t"+new ArrayList<>(thValues) + .get(i)) + .collect(Collectors.joining("\n")); + return String.format("[DRY RUN] Updated Time History file records: \n%s", zippedThRow); + } + @Override public ProductWriteResult appendToProduct(TimeCorrelationContext ctx) throws MmtcException { return TimeHistoryFile.appendRowFor(ctx); diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/UplinkCommandFileProductDefinition.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/UplinkCommandFileProductDefinition.java index 2fabe79..8b03053 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/UplinkCommandFileProductDefinition.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/UplinkCommandFileProductDefinition.java @@ -6,6 +6,7 @@ import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductDirPrefixSuffix; import edu.jhuapl.sd.sig.mmtc.products.model.*; +import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException; import java.nio.file.Path; import java.nio.file.Paths; @@ -37,6 +38,16 @@ public boolean shouldBeWritten(TimeCorrelationContext context) { return context.config.isCreateUplinkCmdFile(); } + @Override + public String getDryRunPrintout(TimeCorrelationContext ctx) throws MmtcException { + try { + UplinkCommand uplinkCommand = UplinkCmdFile.generateNewProduct(ctx); + return String.format("[DRY RUN] Generated Uplink Command string: \n\t"+ uplinkCommand); + } catch (TimeConvertException e) { + throw new MmtcException("Unable to generate the Uplink Command File: ", e); + } + } + /** * Writes the Uplink Command File * @param ctx the current time correlation context from which to pull information for the output product diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RawTelemetryTable.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RawTelemetryTable.java index 3d5b23c..16de2fd 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RawTelemetryTable.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RawTelemetryTable.java @@ -54,6 +54,24 @@ public List getHeaders() { ); } + /** + * Generate an updated RawTelemetryTable based on the current run, but don't append the new rows to the file. + * Intended for use in dry runs where the updated table is desired but not the changes to the file. + * @param ctx the current time correlation context from which to pull information for the output product + * @return an updated RawTelemetryTable + */ + public static TableRecord calculateUpdatedRawTlmTable(TimeCorrelationContext ctx) { + final RawTelemetryTable rawTlmTable = new RawTelemetryTable(ctx.config.getRawTelemetryTablePath()); + TableRecord rawTlmTableRecord = new TableRecord(rawTlmTable.getHeaders()); + + for (FrameSample sample : ctx.correlation.target.get().getSampleSet()) { + rawTlmTableRecord = sample.toRawTelemetryTableRecord(rawTlmTable.getHeaders()); + } + rawTlmTableRecord.setValue(RawTelemetryTable.RUN_TIME, ctx.appRunTime.toString()); + + return rawTlmTableRecord; + } + /** * Write the current time correlation's sample set to the raw telemetry table. * diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RunHistoryFile.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RunHistoryFile.java index ff40a40..60643c9 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RunHistoryFile.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RunHistoryFile.java @@ -270,4 +270,4 @@ public boolean anyValuesInColumn(String columnName) throws MmtcException { List recs = readRecords(RollbackEntryOption.INCLUDE_ROLLBACKS); return recs.stream().anyMatch(r -> ! r.getValue(columnName).equals("-")); } -} +} \ No newline at end of file diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkKernel.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkKernel.java index d86a0eb..0e474b7 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkKernel.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkKernel.java @@ -37,7 +37,7 @@ public class SclkKernel extends TextProduct { /* Clock change rate for the new time correlation record. */ private Double clockChgRate; - /* New interpolated clock change reate to ovewrite the predicted rate in the existing SCLK kernel record. */ + /* New interpolated clock change rate to overwrite the predicted rate in the existing SCLK kernel record. */ private Double updatedClockChgRate; /* Indicates if the new time correlation data have been set. */ @@ -363,6 +363,17 @@ public void createNewSclkKernel(String sourceSclkFilespec) throws TextProductExc createFile(); } + public String[] getLastXRecords(int numRecords) { + if(numRecords < 1) { return new String[0]; } + int lastRecordIndex = lastDataRecNum(newProductLines); + + String[] records = new String[numRecords]; + for(int i=lastRecordIndex-(numRecords-1), j=0;i < lastRecordIndex+1; i++, j++) { + records[j] = newProductLines.get(i); + } + return records; + } + @Override public void readSourceProduct() throws IOException, TextProductException { super.readSourceProduct(); @@ -376,6 +387,34 @@ public String getVersionString(final String sclkBaseName, final String separator return Paths.get(getPath()).getFileName().toString().replace(sclkBaseName + separator, "").replace(FILE_SUFFIX, ""); } + public boolean hasNewClkChgRateSet() { + return newClkChgRateSet; + } + + + /** + * Generates a new SCLK Kernel but doesn't yet write it to file. Helper method for writeNewProduct + * @param ctx The current TimeCorrelationContext + * @throws TimeConvertException + */ + public static void calculateNewProduct(TimeCorrelationContext ctx) throws TimeConvertException, TextProductException { + final SclkKernel newSclkKernel = new SclkKernel(ctx.currentSclkKernel.get()); + + newSclkKernel.setProductCreationTime(ctx.appRunTime); + newSclkKernel.setDir(ctx.config.getSclkKernelOutputDir().toString()); + newSclkKernel.setName(ctx.config.getSclkKernelBasename() + ctx.config.getSclkKernelSeparator() + ctx.newSclkVersionString.get() + ".tsc"); + newSclkKernel.setNewTriplet( + ctx.correlation.target.get().getTargetSampleEncSclk(), + TimeConvert.tdtToTdtStr(ctx.correlation.target.get().getTargetSampleTdtG()), + ctx.correlation.predicted_clock_change_rate.get() + ); + + if (ctx.correlation.interpolated_clock_change_rate.isSet()) { + newSclkKernel.setReplacementClockChgRate(ctx.correlation.interpolated_clock_change_rate.get()); + } + ctx.newSclkKernel.set(newSclkKernel); + } + /** * Writes a new SCLK Kernel * @param ctx the current time correlation context from which to pull information for the output product @@ -385,24 +424,17 @@ public String getVersionString(final String sclkBaseName, final String separator */ public static ProductWriteResult writeNewProduct(TimeCorrelationContext ctx) throws MmtcException { try { - final SclkKernel newSclkKernel = new SclkKernel(ctx.currentSclkKernel.get()); - - newSclkKernel.setProductCreationTime(ctx.appRunTime); - newSclkKernel.setDir(ctx.config.getSclkKernelOutputDir().toString()); - newSclkKernel.setName(ctx.config.getSclkKernelBasename() + ctx.config.getSclkKernelSeparator() + ctx.newSclkVersionString.get() + ".tsc"); - newSclkKernel.setNewTriplet( - ctx.correlation.target.get().getTargetSampleEncSclk(), - TimeConvert.tdtToTdtStr(ctx.correlation.target.get().getTargetSampleTdtG()), - ctx.correlation.predicted_clock_change_rate.get() - ); - - if (ctx.correlation.interpolated_clock_change_rate.isSet()) { - newSclkKernel.setReplacementClockChgRate(ctx.correlation.interpolated_clock_change_rate.get()); + calculateNewProduct(ctx); + + // If this is a dry run, write the new kernel to the temp output path for subsequent deletion. If not, + // write it to the usual location. + if(ctx.config.isDryRun()) { + ctx.newSclkKernel.get().createFile("/tmp"); + } else { + ctx.newSclkKernel.get().createFile(); } - newSclkKernel.createFile(); - - final Path path = Paths.get(newSclkKernel.getPath()); + final Path path = Paths.get(ctx.newSclkKernel.get().getPath()); ctx.newSclkKernelPath.set(path); return new ProductWriteResult( diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkScetFile.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkScetFile.java index 304f09e..67ba4cf 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkScetFile.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/SclkScetFile.java @@ -21,6 +21,11 @@ */ public class SclkScetFile extends TextProduct { + /** + * The TimeCorrelationContext for the current run. The newly created SCLK kernel is accessed from here. + */ + private TimeCorrelationContext ctx; + /** * The time in UTC that the product was created. */ @@ -123,7 +128,7 @@ public void setClockTickRate(Integer clockTickRate) { * @param product_version_id IN the version of this product */ private void setHeaderData(String mission_name, int mission_id, String spacecraft_name, int spacecraft_id, - String data_set_id, String producer_id, String product_version_id, int applicableDurationDays) { + String data_set_id, String producer_id, String product_version_id, int applicableDurationDays) { this.missionId = mission_id; this.missionName = mission_name; @@ -145,7 +150,8 @@ public void setEndSclkScetTime(OffsetDateTime datetime) { endSclkScetTime = datetime; } - /** + + /** * Creates the new SCLK kernel product. Implements the corresponding abstract method in the parent class. * * @throws TextProductException if the product cannot be created @@ -253,7 +259,7 @@ public static boolean isNegativeLeapSecondEntryPair(SclkScet a, SclkScet b) { } // SCET values should be exactly two seconds apart - if (Duration.between(a.getScet(), b.getScet()).getSeconds() != 2.0 ) { + if (Duration.between(a.getScet(), b.getScet()).getSeconds() != 2.0 ) { return false; } @@ -623,6 +629,27 @@ public Path createNewSclkScetFile(String originalFilespec) throws TextProductExc return createFile(); } + public static SclkScetFile calculateNewProduct(TimeCorrelationContext ctx) { + final TimeCorrelationAppConfig conf = ctx.config; + final String newSclkScetFilename = conf.getSclkScetFileBasename() + + conf.getSclkScetFileSeparator() + + ctx.newSclkVersionString.get() + + conf.getSclkScetFileSuffix(); + + // Create the new SCLK/SCET file from the newly-created SCLK kernel. + final SclkScetFile scetFile = new SclkScetFile( + conf, + newSclkScetFilename, + ctx.newSclkVersionString.get() + ); + + scetFile.setCtx(ctx); + scetFile.setProductCreationTime(ctx.appRunTime); + scetFile.setClockTickRate(ctx.sclk_kernel_fine_tick_modulus.get()); + SclkScet.setScetStrSecondsPrecision(conf.getSclkScetScetUtcPrecision()); + + return scetFile; + } /** * Writes a new SCLK-SCET File * @param ctx the current time correlation context from which to pull information for the output product @@ -631,24 +658,9 @@ public Path createNewSclkScetFile(String originalFilespec) throws TextProductExc * @return a ProductWriteResult describing the updated product */ public static ProductWriteResult writeNewProduct(TimeCorrelationContext ctx) throws MmtcException { - final TimeCorrelationAppConfig conf = ctx.config; try { - final String newSclkScetFilename = conf.getSclkScetFileBasename() + - conf.getSclkScetFileSeparator() + - ctx.newSclkVersionString.get() + - conf.getSclkScetFileSuffix(); - - // Create the new SCLK/SCET file from the newly-created SCLK kernel. - final SclkScetFile scetFile = new SclkScetFile( - conf, - newSclkScetFilename, - ctx.newSclkVersionString.get() - ); - - scetFile.setProductCreationTime(ctx.appRunTime); - scetFile.setClockTickRate(ctx.sclk_kernel_fine_tick_modulus.get()); - SclkScet.setScetStrSecondsPrecision(conf.getSclkScetScetUtcPrecision()); + final SclkScetFile scetFile = calculateNewProduct(ctx); return new ProductWriteResult( scetFile.createNewSclkScetFile(ctx.newSclkKernelPath.get().toString()), @@ -658,4 +670,30 @@ public static ProductWriteResult writeNewProduct(TimeCorrelationContext ctx) thr throw new MmtcException("Unable to write SCLK/SCET file", ex); } } -} + + + /** + * Reads the product file and place its contents into the local sourceProduct buffer. + * Differs from inherited method in that it doesn't read a source product file and instead + * retrieves sourceProductLines from the newSclkKernel in the TimeCorrelationContext. + * + */ + @Override + public void readSourceProduct() { + + this.sourceProductLines = ctx.newSclkKernel.get().newProductLines; + sourceProductReadIn = true; + } + + public void setCtx(TimeCorrelationContext ctx) { + this.ctx = ctx; + } + + public List getNewProductLines() { + return this.newProductLines; + } + + public String getSclkscetFields() { + return SCLKSCET_FLDS; + } +} \ No newline at end of file diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TableRecord.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TableRecord.java index 0394e1c..3b06ba3 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TableRecord.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TableRecord.java @@ -1,9 +1,6 @@ package edu.jhuapl.sd.sig.mmtc.products.model; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; import java.util.function.Supplier; @@ -42,8 +39,8 @@ public TableRecord(TableRecord other) { * * @return the list of values as strings. */ - public Collection getValues() { - return data.values(); + public List getValues() { + return new ArrayList<>(data.values()); } /** diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TextProduct.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TextProduct.java index 06048c0..a962fd0 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TextProduct.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TextProduct.java @@ -5,6 +5,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import javax.xml.soap.Text; import java.io.*; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; @@ -163,7 +164,6 @@ public String getLastSourceProdDataRec() { return sourceProductLines.get(lastDataRecNum(sourceProductLines)).trim(); } - /** * Creates a new product file from an existing source file and writes it to the directory * and name specified with the current time in UTC as the product creation time. This is @@ -178,6 +178,21 @@ public Path createFile() throws TextProductException, TimeConvertException { return createFile(sourceFilespec, dirname, filename); } + /** + * Creates a new product file from an existing source file and writes it to the directory + * and name specified with the current time in UTC as the product creation time. This is + * the top-level method in this class and the one that would be called from an external + * method. This overload is intended for dry runs where a temporary output dir is to be + * specified. + * + * @throws TextProductException if the file cannot be created + * @throws TimeConvertException if an error occurred in a computation + * @return the Path representing the location where the new file was written + */ + public Path createFile(String tempPath) throws TextProductException, TimeConvertException { + return createFile(sourceFilespec, tempPath, filename); + } + /** * Creates a new product file from an existing source file and writes it to the directory @@ -200,14 +215,18 @@ public Path createFile(String sourceFilespec, String dirname, String filename) t try { /* Read the source file */ - readSourceProduct(); - createNewProduct(); /* <-- Abstract method defined in derived class. */ + updateFile(); return writeNewProduct(); } catch (IOException e) { throw new TextProductException("Unable to read source product \"" + sourceFilespec + "\".", e); } } + public void updateFile() throws TextProductException, IOException, TimeConvertException { + readSourceProduct(); + createNewProduct(); /* <-- Abstract method defined in derived class. */ + } + /** * Reads the product file and place its contents into the local sourceProduct buffer. @@ -344,12 +363,22 @@ protected Path writeNewProduct() throws TextProductException { } try { + if(dirname.equals("/tmp")) { + File tempKernel = File.createTempFile("temp_sclk_kernel-", "-"+filename); + newFile = tempKernel.toPath(); + filename = tempKernel.getName(); + tempKernel.deleteOnExit(); + } Files.write(newFile, newProductLines); } catch (IOException e) { throw new TextProductException("Error creating new Time Correlation file \"" + newFilePath + "\".", e); } - logger.info(MmtcCli.USER_NOTICE, "Created new time correlation product file: " + newFilePath); + if (dirname.equals("/tmp")) { + logger.debug("Wrote temporary SCLK kernel {} to {} and set to delete on exit", filename, dirname); + } else { + logger.info(MmtcCli.USER_NOTICE, "Created new time correlation product file: " + newFilePath); + } return newFile; } diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TimeHistoryFile.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TimeHistoryFile.java index 7399657..25f8b16 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TimeHistoryFile.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/TimeHistoryFile.java @@ -142,16 +142,19 @@ public static ProductWriteResult appendRowFor(TimeCorrelationContext ctx) throws } /** - * Writes the next record for the Time History File (and updates the prior interpolated clock change rate, if applicable) - * - * @throws MmtcException if an unhandled MMTC configuraiton or other operation fails - * @throws TimeConvertException if a time conversion operation fails + * Helper function for creation of a new Time History file record. Takes a reference to a time history file record + * and modifies it in place so its caller can eventually write it or print it in the case of dry runs + * @param ctx The current TimeCorrelationContext + * @param timeHistoryFile The Time hist file to be modified + * @param newThfRec A reference to the TableRecord that will be modified by this method + * @throws MmtcException + * @throws TimeConvertException */ - private static void writeNewRow(TimeCorrelationContext ctx, TimeHistoryFile timeHistoryFile, TableRecord newThfRec) throws MmtcException, TimeConvertException, TextProductException { + public static void generateNewTimeHistRec(TimeCorrelationContext ctx, TimeHistoryFile timeHistoryFile, TableRecord newThfRec) throws MmtcException, TimeConvertException { final DecimalFormat tdf = new DecimalFormat("#.000000"); tdf.setRoundingMode(RoundingMode.HALF_UP); - if (timeHistoryFile.exists() && ctx.correlation.interpolated_clock_change_rate.isSet()) { + if (timeHistoryFile.exists() && ctx.correlation.interpolated_clock_change_rate.isSet() && !ctx.config.isDryRun()) { Map lastRecord = timeHistoryFile.readLastRecord(); lastRecord.replace(TimeHistoryFile.INTERP_CLK_CHANGE_RATE, String.valueOf(ctx.correlation.interpolated_clock_change_rate.get())); timeHistoryFile.replaceLastRecord(lastRecord); @@ -300,7 +303,16 @@ private static void writeNewRow(TimeCorrelationContext ctx, TimeHistoryFile time newThfRec.setValue(TimeHistoryFile.RADIO_ID, ctx.ancillary.active_radio_id.get()); newThfRec.setValue(TimeHistoryFile.OSCILLATOR, ctx.ancillary.oscillator_id.get()); newThfRec.setValue(TimeHistoryFile.OSCILLATOR_TEMP_DEGC, String.valueOf(ctx.ancillary.oscillator_temperature_deg_c.get())); + } + /** + * Writes the next record for the Time History File (and updates the prior interpolated clock change rate, if applicable) + * + * @throws MmtcException if an unhandled MMTC configuration or other operation from the helper function fails + * @throws TimeConvertException if a time conversion operation fails + */ + private static void writeNewRow(TimeCorrelationContext ctx, TimeHistoryFile timeHistoryFile, TableRecord newThfRec) throws MmtcException, TimeConvertException, TextProductException { + generateNewTimeHistRec(ctx, timeHistoryFile, newThfRec); timeHistoryFile.writeRecord(newThfRec); } } diff --git a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/UplinkCmdFile.java b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/UplinkCmdFile.java index 2d13630..8a11245 100644 --- a/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/UplinkCmdFile.java +++ b/mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/UplinkCmdFile.java @@ -47,6 +47,18 @@ public Path write(UplinkCommand commandString) throws IOException { return Paths.get(filespec); } + public static UplinkCommand generateNewProduct(TimeCorrelationContext ctx) throws TimeConvertException { + UplinkCommand uplinkCmd = new UplinkCommand( + ctx.correlation.target.get().getTargetSample().getTkSclkCoarse(), + ctx.correlation.target.get().getTargetSampleEtG(), + ctx.correlation.target.get().getTargetSampleTdtG(), + TimeConvert.tdtToTdtStr(ctx.correlation.target.get().getTargetSampleTdtG()), + ctx.correlation.predicted_clock_change_rate.get() + ); + + return uplinkCmd; + } + /** * Writes a new Uplink Command File * @param ctx the current time correlation context from which to pull information for the output product @@ -57,13 +69,7 @@ public Path write(UplinkCommand commandString) throws IOException { public static ProductWriteResult writeNewProduct(TimeCorrelationContext ctx) throws MmtcException { String cmdFilespec = ""; try { - final UplinkCommand uplinkCmd = new UplinkCommand( - ctx.correlation.target.get().getTargetSample().getTkSclkCoarse(), - ctx.correlation.target.get().getTargetSampleEtG(), - ctx.correlation.target.get().getTargetSampleTdtG(), - TimeConvert.tdtToTdtStr(ctx.correlation.target.get().getTargetSampleTdtG()), - ctx.correlation.predicted_clock_change_rate.get() - ); + final UplinkCommand uplinkCmd = generateNewProduct(ctx); final String cmdFilename = ctx.config.getUplinkCmdFileBasename() + ctx.appRunTime.toEpochSecond() + diff --git a/mmtc-core/src/test/java/edu/jhuapl/sd/sig/mmtc/SclkScetFileTests.java b/mmtc-core/src/test/java/edu/jhuapl/sd/sig/mmtc/SclkScetFileTests.java index 7bdad76..af28a03 100644 --- a/mmtc-core/src/test/java/edu/jhuapl/sd/sig/mmtc/SclkScetFileTests.java +++ b/mmtc-core/src/test/java/edu/jhuapl/sd/sig/mmtc/SclkScetFileTests.java @@ -1,29 +1,12 @@ package edu.jhuapl.sd.sig.mmtc; -import edu.jhuapl.sd.sig.mmtc.cfg.TimeCorrelationAppConfig; import edu.jhuapl.sd.sig.mmtc.products.model.SclkScet; import edu.jhuapl.sd.sig.mmtc.products.model.SclkScetFile; -import edu.jhuapl.sd.sig.mmtc.products.model.TextProductException; import edu.jhuapl.sd.sig.mmtc.util.TimeConvert; import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import spice.basic.KernelDatabase; -import spice.basic.SpiceErrorException; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.when; public class SclkScetFileTests { @BeforeAll @@ -31,46 +14,6 @@ static void teardown() throws TimeConvertException { TestHelper.ensureSpiceIsLoadedAndUnloadAllKernels(); } - /** - * Create a new SCLK/SCET file from an SCLK kernel. Uses 10-Jun-2019 kernel. - * Using NH data. - */ - @Test - public void createNewSclkKScetFile_Test3() throws SpiceErrorException, TextProductException, TimeConvertException, IOException { - System.loadLibrary("JNISpice"); - - String sclkKernel = "src/test/resources/nh_kernels/sclk/new-horizons_1876.tsc"; - KernelDatabase.load("src/test/resources/nh_kernels/lsk/naif0012.tls"); - KernelDatabase.load(sclkKernel); - - String dir = "src/test/resources/SclkScetTests"; - String filename = "new-horizons_1876.scet"; - String newFilePath = dir + File.separator + filename; - Path newFile = Paths.get(newFilePath); - - Files.deleteIfExists(newFile); - - TimeCorrelationAppConfig config = Mockito.mock(TimeCorrelationAppConfig.class); - when(config.getSclkScetOutputDir()).thenReturn(Paths.get(dir)); - when(config.getMissionName()).thenReturn("NEW_HORIZONS"); - when(config.getMissionId()).thenReturn(98); - when(config.getSpacecraftName()).thenReturn("NEW_HORIZONS"); - when(config.getSpacecraftId()).thenReturn(98); - when(config.getDataSetId()).thenReturn("SCLK_SCET"); - when(config.getProducerId()).thenReturn("MMTC"); - when(config.getSclkScetApplicableDurationDays()).thenReturn(0); - when(config.getNaifSpacecraftId()).thenReturn(-98); - when(config.getSclkScetLeapSecondRateMode()).thenReturn(TimeCorrelationAppConfig.SclkScetFileLeapSecondSclkRate.ONE); - - SclkScetFile scetfile = new SclkScetFile(config, filename, "11"); - - SclkScet.setScetStrSecondsPrecision(3); - scetfile.setProductCreationTime(OffsetDateTime.now(ZoneOffset.UTC)); - scetfile.setClockTickRate(50000); - // scetfile.setEndSclkScetTime(TimeConvert.parseIsoDoyUtcStr(scetfile.getProductDateTimeIsoUtc())); - scetfile.createNewSclkScetFile(sclkKernel); - } - @Test public void testIsNegativeLeapSecond() { SclkScet a = new SclkScet( diff --git a/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleAppendedFileOutputProductDefinition.java b/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleAppendedFileOutputProductDefinition.java index f8a86bb..ef1dad1 100644 --- a/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleAppendedFileOutputProductDefinition.java +++ b/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleAppendedFileOutputProductDefinition.java @@ -5,6 +5,8 @@ import edu.jhuapl.sd.sig.mmtc.correlation.TimeCorrelationContext; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductPath; +import edu.jhuapl.sd.sig.mmtc.products.model.TextProductException; +import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -59,6 +61,13 @@ public boolean shouldBeWritten(TimeCorrelationContext ctx) { return true; } + @Override + public String getDryRunPrintout(TimeCorrelationContext ctx) throws MmtcException, TextProductException, IOException, TimeConvertException { + return String.format("This is the product's results for this run in the form of a string that will be printed and logged when the dry run option is used.\n" + + "This will generally be the new entry that would have been added to the appended product: \n" + + "\t%s\n\t%d,%s,%.11f\n", HEADER, ctx.runId.get(), ctx.newSclkVersionString.get(), ctx.correlation.predicted_clock_change_rate.get()); + } + @Override public Map getSandboxConfigUpdates(MmtcConfig originalConfig, Path newProductOutputPath) { return Collections.emptyMap(); diff --git a/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleEntireFileOutputProductDefinition.java b/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleEntireFileOutputProductDefinition.java index 3d555df..041830a 100644 --- a/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleEntireFileOutputProductDefinition.java +++ b/mmtc-output-plugin-sdk/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/ExampleEntireFileOutputProductDefinition.java @@ -5,6 +5,8 @@ import edu.jhuapl.sd.sig.mmtc.correlation.TimeCorrelationContext; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult; import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductDirPrefixSuffix; +import edu.jhuapl.sd.sig.mmtc.products.model.TextProductException; +import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -69,6 +71,13 @@ public boolean shouldBeWritten(TimeCorrelationContext ctx) { return true; } + @Override + public String getDryRunPrintout(TimeCorrelationContext ctx) throws MmtcException, TextProductException, IOException, TimeConvertException { + return String.format("This is the product's results for this run in the form of a string that will be printed and logged when the dry run option is used.\n" + + "This will generally be the latest x entries in the new product: \n" + + "\t%d,%s,%.11f\n", ctx.runId.get(), ctx.newSclkVersionString.get(), ctx.correlation.predicted_clock_change_rate.get()); + } + @Override public Map getSandboxConfigUpdates(MmtcConfig originalConfig, Path newProductOutputDir) { return Collections.emptyMap();