diff --git a/Java/SuperUtilities/.idea/uiDesigner.xml b/Java/SuperUtilities/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/Java/SuperUtilities/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/export/CustomExporter.java b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/export/CustomExporter.java
index 4f8a21a..cc524cf 100644
--- a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/export/CustomExporter.java
+++ b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/export/CustomExporter.java
@@ -7,7 +7,9 @@
import com.nuix.superutilities.SuperUtilities;
import com.nuix.superutilities.loadfiles.*;
+import com.nuix.superutilities.misc.BoundedProgressInfo;
import com.nuix.superutilities.misc.FormatUtility;
+import com.nuix.superutilities.misc.PeriodicGatedConsumer;
import com.nuix.superutilities.misc.PlaceholderResolver;
import com.nuix.superutilities.reporting.SimpleWorksheet;
import com.nuix.superutilities.reporting.SimpleXlsx;
@@ -57,31 +59,35 @@ public class CustomExporter {
private SimpleTextFileWriter errorLog = null;
private boolean exportText = false;
- private Map textExportSettings = new HashMap();
+ private Map textExportSettings = new HashMap<>();
private String textFileNameTemplate = "{export_directory}\\TEXT\\{guid}.txt";
private boolean exportNatives = false;
- private Map emailExportSettings = new HashMap();
+ private Map emailExportSettings = new HashMap<>();
private String nativeFileNameTemplate = "{export_directory}\\NATIVES\\{guid}.{extension}";
private boolean exportPdfs = false;
- private Map pdfExportSettings = new HashMap();
+ private Map pdfExportSettings = new HashMap<>();
private String pdfFileNameTemplate = "{export_directory}\\PDF\\{guid}.pdf";
private boolean exportTiffs = false;
- private Map tiffExportSettings = new HashMap();
+ private Map tiffExportSettings = new HashMap<>();
private String tiffFileNameTemplate = "{export_directory}\\IMAGE\\{guid}.{extension}";
private boolean exportJson = false;
private String jsonFileNameTemplate = "{export_directory}\\JSON\\{guid}.json";
private JsonExporter jsonExporter = null;
+ private Consumer messageLoggedCallback = null;
+ private PeriodicGatedConsumer progressCallback = null;
+
/**
* -- SETTER --
* Sets whether DAT contents should additionally be exported as an XLSX spreadsheet.
*/
@Setter
private boolean exportXlsx = false;
+
/**
* -- SETTER --
* Sets whether final DAT will be kept by moving it to final export directory/
@@ -89,6 +95,12 @@ public class CustomExporter {
@Setter
private boolean keepOriginalDat = false;
+ /**
+ * Whether to skip export of natives for slip-sheeted items.
+ */
+ @Setter
+ private boolean skipNativesSlipsheetedItems = false;
+
/**
* -- SETTER --
* Allows you to provide a Map of headers to rename. Intended to provide a way to rename headers that Nuix automatically adds
@@ -129,6 +141,31 @@ public class CustomExporter {
public CustomExporter() {
}
+ /***
+ * Provides a callback to be invoked when progress is made during initial batch export or during
+ * restructuring phase. Will be wrapped in a {@link PeriodicGatedConsumer} with an interval of 5 seconds
+ * if not already an instance of {@link PeriodicGatedConsumer}.
+ * @param progressCallback The progress info consumer.
+ */
+ public void whenProgressEventOccurs(Consumer progressCallback) {
+ if (progressCallback instanceof PeriodicGatedConsumer) {
+ this.progressCallback = (PeriodicGatedConsumer) progressCallback;
+ } else {
+ this.progressCallback = new PeriodicGatedConsumer<>(progressCallback, 5000);
+ }
+ }
+
+ private void fireProgressEvent(String stage, long current, long total) {
+ BoundedProgressInfo info = new BoundedProgressInfo(stage, current, total);
+ if (progressCallback != null) {
+ progressCallback.accept(info);
+ }
+ }
+
+ public void whenMessageLogged(Consumer messageLoggedCallback) {
+ this.messageLoggedCallback = messageLoggedCallback;
+ }
+
/***
* Assigns a dynamically calculated placeholder to this instance.
* @param placeholderName Placeholder name with "{" or "}". For example "my_value". Placeholder in templates can then be referred to using "{my_value}". It is
@@ -245,7 +282,13 @@ public void setColumnRemovals(Collection columnHeaders) {
private void logInfo(String format, Object... params) {
String message = String.format(format, params);
- System.out.println(message);
+
+ if (messageLoggedCallback != null) {
+ messageLoggedCallback.accept(message);
+ } else {
+ System.out.println(message);
+ }
+
if (generalLog != null) {
try {
generalLog.writeLine(message);
@@ -259,7 +302,13 @@ private void logInfo(String format, Object... params) {
private void logError(String format, Object... params) {
String message = String.format(format, params);
- System.out.println(message);
+
+ if (messageLoggedCallback != null) {
+ messageLoggedCallback.accept("ERROR: " + message);
+ } else {
+ System.err.println(message);
+ }
+
if (errorLog != null) {
try {
errorLog.writeLine(message);
@@ -298,12 +347,7 @@ public String evaluate(Item item) {
}
}
if (!hasGuid) {
- exportProfile = exportProfile.addMetadata("GUID", new ItemExpression() {
- @Override
- public String evaluate(Item item) {
- return item.getGuid();
- }
- });
+ exportProfile = exportProfile.addMetadata("GUID", Item::getGuid);
}
}
return exportProfile;
@@ -421,7 +465,6 @@ public void exportItems(Case nuixCase, File exportDirectory, List- items) t
exporter.addProduct("tiff", productSettings);
}
-
exportDirectory.mkdirs();
File tempDatFile = new File(exportTempDirectory, "loadfile.dat");
File finalDatFile = new File(exportDirectory, "loadfile.dat");
@@ -448,6 +491,8 @@ public void itemProcessed(ItemEventInfo info) {
logError("BatchExporter reports error while exporting item with GUID '%s':\n%s",
info.getItem().getGuid(), FormatUtility.debugString(info.getFailure()));
}
+
+ fireProgressEvent("BatchExport: " + info.getStage(), info.getStageCount(), items.size());
}
});
@@ -469,6 +514,9 @@ public void itemProcessed(ItemEventInfo info) {
exporter.setStampingOptions(stampingSettings);
}
+ // Forward setting regarding natives slipsheet generation
+ exporter.setSkipNativesSlipsheetedItems(skipNativesSlipsheetedItems);
+
logInfo("Beginning temp export using BatchExporter...");
exporter.exportItems(items);
logInfo("Finished temp export using BatchExporter");
@@ -495,6 +543,8 @@ public void itemProcessed(ItemEventInfo info) {
@Override
public void accept(LinkedHashMap record) {
+ fireProgressEvent("Export Restructure", recordsProcessed, items.size());
+
// Periodically log progress
long diffMillis = System.currentTimeMillis() - restructureStartMillis;
if (diffMillis > 2 * 1000 || recordsProcessed % 100 == 0) {
diff --git a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/BoundedProgressInfo.java b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/BoundedProgressInfo.java
new file mode 100644
index 0000000..7ac2b6b
--- /dev/null
+++ b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/BoundedProgressInfo.java
@@ -0,0 +1,34 @@
+package com.nuix.superutilities.misc;
+
+import lombok.Getter;
+
+/***
+ * Represents progress of an operation which has a bounded value, that is, we known what progress
+ * value is considered maximum/done.
+ */
+@Getter
+public class BoundedProgressInfo extends ProgressInfo {
+ /***
+ * The maximum progress value
+ */
+ protected final long maximum;
+
+ public BoundedProgressInfo(String stage, long current, long maximum) {
+ super(stage, current);
+ this.maximum = maximum;
+ }
+
+ /***
+ * Provides a percentage completed value by dividing double value of current by
+ * double value of maximum.
+ * @return A double value representing percentage complete
+ */
+ public double percentageComplete() {
+ return ((double) current) / ((double) maximum);
+ }
+
+ @Override
+ public String toString() {
+ return "BoundedProgressInfo [stage=" + stage + ", " + current + "/" + maximum + "]";
+ }
+}
diff --git a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PeriodicGatedConsumer.java b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PeriodicGatedConsumer.java
new file mode 100644
index 0000000..621fa80
--- /dev/null
+++ b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PeriodicGatedConsumer.java
@@ -0,0 +1,68 @@
+package com.nuix.superutilities.misc;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Consumer;
+
+/***
+ * A wrapper for a {@link Consumer} instance which will only periodically forward call to
accept
+ * method of wrapped instance. Created for taking per item events that Nuix publishes and turning them
+ * into periodic progress reporters.
+ * @param The type of the {@link Consumer} being wrapped
+ */
+public class PeriodicGatedConsumer implements Consumer {
+ private final Consumer wrappedConsumer;
+ private long lastPassThru = 0;
+
+ @Getter
+ @Setter
+ private long intervalMillis = 1000;
+
+ public PeriodicGatedConsumer(@NotNull Consumer wrappedConsumer) {
+ this.wrappedConsumer = wrappedConsumer;
+ }
+
+ public PeriodicGatedConsumer(@NotNull Consumer wrappedConsumer, long intervalMillis) {
+ this.wrappedConsumer = wrappedConsumer;
+ this.intervalMillis = intervalMillis;
+ }
+
+ /***
+ * Convenience method for setting millis interval to a certain number of seconds
+ * @param intervalSeconds The number of seconds
+ */
+ public void setIntervalSeconds(long intervalSeconds) {
+ this.intervalMillis = intervalSeconds * 1000;
+ }
+
+ /***
+ * Convenience method for setting millis interval to a certain number of minutes
+ * @param intervalMinutes The number of minutes
+ */
+ public void setIntervalMinutes(long intervalMinutes) {
+ this.intervalMillis = intervalMinutes * 60 * 1000;
+ }
+
+ /***
+ * Will periodically forward call to wrapped Consumer and then reset current interval
+ * @param t the input argument
+ */
+ @Override
+ public void accept(T t) {
+ if (intervalMillis < 1 || System.currentTimeMillis() - lastPassThru > intervalMillis) {
+ wrappedConsumer.accept(t);
+ lastPassThru = System.currentTimeMillis();
+ }
+ }
+
+ /***
+ * Will immediately forward call to wrapped Consumer and then reset current interval
+ * @param t the input argument
+ */
+ public void acceptImmediately(T t) {
+ wrappedConsumer.accept(t);
+ lastPassThru = System.currentTimeMillis();
+ }
+}
diff --git a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PlaceholderResolver.java b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PlaceholderResolver.java
index 6cc1b3b..c920dbf 100644
--- a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PlaceholderResolver.java
+++ b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PlaceholderResolver.java
@@ -135,7 +135,7 @@ public void setFromItem(Item item) {
* {nuix_version}
- The Nuix version as defined in NUIX_VERSION
*/
public void setStandardValues(DateTime now) {
- if(now == null) {
+ if (now == null) {
now = DateTime.now();
}
set("date_short", now.toString("YYYYMMdd"));
@@ -191,7 +191,7 @@ public String get(String key) {
}
/***
- * Clears all currently associated place holders (keys and values)
+ * Clears all currently associated placeholders (keys and values)
*/
public void clear() {
placeholderData.clear();
@@ -264,6 +264,11 @@ public String resolveTemplatePath(String template) {
}
result = p.matcher(result).replaceAll(value);
}
+
+ // Attempt to prevent double assigned extension. Happens in scenario where item name already
+ // contains the extension and therefore {extension} in template effectively adds it a second time
+ result = result.replaceAll("([a-zA-Z0-9]+)\\.\\1$", "$1");
+
return result;
}
diff --git a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/ProgressInfo.java b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/ProgressInfo.java
new file mode 100644
index 0000000..763f25f
--- /dev/null
+++ b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/ProgressInfo.java
@@ -0,0 +1,31 @@
+package com.nuix.superutilities.misc;
+
+import lombok.Getter;
+
+/***
+ * Represents progress of an indeterminate operation where the maximum progress value
+ * is not known until completion.
+ */
+@Getter
+public class ProgressInfo {
+ /***
+ * A title representing the current stage, may be null or blank if progress
+ * publisher does not populate it!
+ */
+ protected final String stage;
+
+ /***
+ * The current progress value
+ */
+ protected final long current;
+
+ public ProgressInfo(String stage, long current) {
+ this.stage = stage;
+ this.current = current;
+ }
+
+ @Override
+ public String toString() {
+ return "ProgressInfo [stage=" + stage + ", current=" + current + "]";
+ }
+}