From bbc6f8a7cdc17a20f577071eb78c0148ed9b9a51 Mon Sep 17 00:00:00 2001 From: eric Date: Sat, 29 Aug 2026 07:48:19 +1200 Subject: [PATCH 1/3] Allow the ability to specify a custom temp directory and ensure that it is used by RCodeUtils for new data frames. --- .../com/github/rcaller/TempFileService.java | 34 ++++++---- .../com/github/rcaller/rstuff/RCaller.java | 32 ++++++--- .../java/com/github/rcaller/rstuff/RCode.java | 67 +++++++++++++++---- .../com/github/rcaller/util/RCodeUtils.java | 13 ++-- 4 files changed, 106 insertions(+), 40 deletions(-) diff --git a/RCaller/src/main/java/com/github/rcaller/TempFileService.java b/RCaller/src/main/java/com/github/rcaller/TempFileService.java index 41e7293..eace76f 100644 --- a/RCaller/src/main/java/com/github/rcaller/TempFileService.java +++ b/RCaller/src/main/java/com/github/rcaller/TempFileService.java @@ -7,24 +7,30 @@ import java.io.File; import java.io.IOException; import java.nio.channels.FileChannel; +import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; - public class TempFileService { private static final Logger logger = Logger.getLogger(TempFileService.class.getName()); - private final ArrayList> tempFiles; - - public TempFileService(){ - tempFiles = new ArrayList<>(); + private final ArrayList> tempFiles = new ArrayList<>(); + private final Path tempDir; + + public TempFileService() { + this.tempDir = null; + } + + public TempFileService(final Path tempDir) { + this.tempDir = tempDir; } - - public File createTempFile(String prefix, String suffix) throws IOException { - File f = File.createTempFile(prefix, suffix); + + public File createTempFile(final String prefix, + final String suffix) throws IOException { + File f = File.createTempFile(prefix, suffix, toFileOrNull(tempDir)); FileChannel fileChannel = FileChannel.open( f.toPath(), StandardOpenOption.READ, @@ -32,10 +38,10 @@ public File createTempFile(String prefix, String suffix) throws IOException { StandardOpenOption.CREATE ); tempFiles.add(new ImmutablePair<>(f, fileChannel)); - return(f); + return f; } - - public void deleteRCallerTempFiles(){ + + public void deleteRCallerTempFiles() { for (Pair tempFileAndChannel : tempFiles) { var fileChannel = tempFileAndChannel.getRight(); var tempFile = tempFileAndChannel.getLeft(); @@ -66,4 +72,8 @@ public File createControlFile() { throw new ExecutionException("Can not create a temporary file for storing the R results: " + e.getMessage()); } } -} + + private File toFileOrNull(final Path tempDir) { + return tempDir == null ? null : tempDir.toFile(); + } +} \ No newline at end of file diff --git a/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java b/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java index 9f40850..0973d53 100644 --- a/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java +++ b/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java @@ -18,7 +18,6 @@ import static java.lang.String.join; import static java.lang.System.currentTimeMillis; - public class RCaller { private static final Logger logger = Logger.getLogger(RCaller.class.getName()); @@ -40,14 +39,13 @@ protected RCaller(RCode rCode, RStreamHandler rOutput, RStreamHandler rError, MessageSaver messageSaver, - TempFileService tempFileService, RCallerOptions rCallerOptions) { this.rCode = rCode; this.parser = parser; this.rOutput = rOutput; this.rError = rError; this.errorMessageSaver = messageSaver; - this.tempFileService = tempFileService; + this.tempFileService = rCode.getTempFileService(); this.rCallerOptions = rCallerOptions; this.rError.addEventHandler(errorMessageSaver); @@ -60,7 +58,12 @@ protected RCaller(RCode rCode, */ public static RCaller create() { RCallerOptions rCallerOptions = RCallerOptions.create(); - return new RCaller(RCode.create(), ROutputParser.create(rCallerOptions), new RStreamHandler(null, "Output"), new RStreamHandler(null, "Error"), new MessageSaver(), new TempFileService(), rCallerOptions); + return new RCaller(RCode.create(), + ROutputParser.create(rCallerOptions), + new RStreamHandler(null, "Output"), + new RStreamHandler(null, "Error"), + new MessageSaver(), + rCallerOptions); } /*** @@ -69,8 +72,13 @@ public static RCaller create() { * @param rCallerOptions given startup options * @return RCaller object */ - public static RCaller create(RCallerOptions rCallerOptions) { - return new RCaller(RCode.create(rCallerOptions), ROutputParser.create(rCallerOptions), new RStreamHandler(null, "Output"), new RStreamHandler(null, "Error"), new MessageSaver(), new TempFileService(), rCallerOptions); + public static RCaller create(final RCallerOptions rCallerOptions) { + return new RCaller(RCode.create(rCallerOptions), + ROutputParser.create(rCallerOptions), + new RStreamHandler(null, "Output"), + new RStreamHandler(null, "Error"), + new MessageSaver(), + rCallerOptions); } /** @@ -80,11 +88,16 @@ public static RCaller create(RCallerOptions rCallerOptions) { * @param rCallerOptions given startup object * @return RCaller object */ - public static RCaller create(RCode rcode, RCallerOptions rCallerOptions) { - return new RCaller(rcode, ROutputParser.create(rCallerOptions), new RStreamHandler(null, "Output"), new RStreamHandler(null, "Error"), new MessageSaver(), new TempFileService(), rCallerOptions); + public static RCaller create(final RCode rcode, + final RCallerOptions rCallerOptions) { + return new RCaller(rcode, + ROutputParser.create(rCallerOptions), + new RStreamHandler(null, "Output"), + new RStreamHandler(null, "Error"), + new MessageSaver(), + rCallerOptions); } - /** * Stops the threads that are emptying the output and error streams of the * live but idle R process. If R is still working, this may cause it to @@ -139,7 +152,6 @@ public void setGraphicsTheme(GraphicsTheme theme) { */ public void deleteTempFiles() { tempFileService.deleteRCallerTempFiles(); - this.rCode.deleteTempFiles(); } /** diff --git a/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java b/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java index 4c027cb..b6947ad 100644 --- a/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java +++ b/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java @@ -10,22 +10,33 @@ import javax.swing.*; import java.io.*; +import java.nio.file.Path; public class RCode { - private StringBuilder code; - private TempFileService tempFileService = null; + private StringBuilder code = new StringBuilder(); + private final TempFileService tempFileService; private final RCallerOptions rCallerOptions; - private RCode() { - this.code = new StringBuilder(); - rCallerOptions = RCallerOptions.create(); + this.rCallerOptions = RCallerOptions.create(); + this.tempFileService = new TempFileService(); + } + + private RCode(Path tempDir) { + this.rCallerOptions = RCallerOptions.create(); + this.tempFileService = new TempFileService(tempDir); } private RCode(RCallerOptions rCallerOptions) { - this.code = new StringBuilder(); this.rCallerOptions = rCallerOptions; + this.tempFileService = new TempFileService(); + } + + private RCode(Path tempDir, + RCallerOptions rCallerOptions) { + this.rCallerOptions = rCallerOptions; + this.tempFileService = new TempFileService(tempDir); } public static RCode create() { @@ -34,24 +45,53 @@ public static RCode create() { return rCode; } + public static RCode create(Path tempDir) { + RCode rCode = new RCode(tempDir); + rCode.clear(); + return rCode; + } + public static RCode create(StringBuffer stringBuffer) { RCode rCode = RCode.create(); rCode.getCode().append(stringBuffer.toString()); return rCode; } + public static RCode create(Path tempDir, + StringBuffer stringBuffer) { + RCode rCode = RCode.create(tempDir); + rCode.getCode().append(stringBuffer.toString()); + return rCode; + } + public static RCode create(RCallerOptions rCallerOptions) { RCode rCode = new RCode(rCallerOptions); rCode.clear(); return rCode; } - public static RCode create(StringBuffer stringBuffer, RCallerOptions rCallerOptions) { + public static RCode create(Path tempDir, + RCallerOptions rCallerOptions) { + RCode rCode = new RCode(tempDir, rCallerOptions); + rCode.clear(); + return rCode; + } + + public static RCode create(StringBuffer stringBuffer, + RCallerOptions rCallerOptions) { RCode rCode = RCode.create(rCallerOptions); rCode.getCode().append(stringBuffer.toString()); return rCode; } + public static RCode create(Path tempDir, + StringBuffer stringBuffer, + RCallerOptions rCallerOptions) { + RCode rCode = RCode.create(tempDir, rCallerOptions); + rCode.getCode().append(stringBuffer.toString()); + return rCode; + } + public void setCode(StringBuffer sb) { this.code = new StringBuilder(); clear(); @@ -68,6 +108,10 @@ public StringBuilder getCode() { return (this.code); } + public TempFileService getTempFileService() { + return tempFileService; + } + public final void clear() { this.code.setLength(0); addRCode(RCodeIO.getInterprocessDependencies(rCallerOptions)); @@ -171,7 +215,7 @@ public void addString(String name, String value){ } public void addDataFrame(String name, DataFrame dataFrame) { - RCodeUtils.addDataFrame(code, name, dataFrame); + RCodeUtils.addDataFrame(code, name, dataFrame, tempFileService); } public File startPlot() throws IOException { @@ -179,9 +223,6 @@ public File startPlot() throws IOException { } public File startPlot(GraphicsType type) throws IOException { - if(tempFileService == null){ - tempFileService = new TempFileService(); - } //File f = File.createTempFile("RPlot", "." + type.name()); File f = tempFileService.createTempFile("RPlot", "." + type.name()); switch (type) { @@ -227,9 +268,7 @@ public void R_source(String sourceFile) { } public void deleteTempFiles(){ - if (tempFileService != null){ - tempFileService.deleteRCallerTempFiles(); - } + tempFileService.deleteRCallerTempFiles(); } @Override diff --git a/RCaller/src/main/java/com/github/rcaller/util/RCodeUtils.java b/RCaller/src/main/java/com/github/rcaller/util/RCodeUtils.java index 52707e5..361b2d8 100644 --- a/RCaller/src/main/java/com/github/rcaller/util/RCodeUtils.java +++ b/RCaller/src/main/java/com/github/rcaller/util/RCodeUtils.java @@ -1,6 +1,7 @@ package com.github.rcaller.util; import com.github.rcaller.JavaObject; +import com.github.rcaller.TempFileService; import com.github.rcaller.datatypes.DataFrame; import com.github.rcaller.exception.ExecutionException; import com.github.rcaller.io.CSVFileWriter; @@ -201,21 +202,25 @@ public static void addRespectToType(StringBuilder rCode, String name, Object o, throw new ExecutionException("Cannot convert Java object " + o.toString() + " in type of " + o.getClass().getCanonicalName() + " to R code due to " + iae.toString()); } } - } public static void addDataFrame(StringBuilder rCode, String name, DataFrame dataFrame) { + addDataFrame(rCode, name, dataFrame, null); + } + + public static void addDataFrame(StringBuilder rCode, String name, DataFrame dataFrame, TempFileService tempFileService) { + if (tempFileService == null) { + tempFileService = new TempFileService(); + } try { - File file = File.createTempFile("dataFrame", ".csv"); + File file = tempFileService.createTempFile("dataFrame", ".csv"); try (CSVFileWriter csvFileWriter = CSVFileWriter.create(file)) { csvFileWriter.writeDataFrameToFile(dataFrame); } rCode.append(name).append(" <- read.csv(\"").append(Globals.getSystemSpecificRPathParameter(file)).append("\")\n"); - } catch (IOException e) { Logger.getLogger(RCodeUtils.class.getName()).log(Level.WARNING, "Couldn't export data frame to csv-file!", e.getStackTrace()); } - } public static void addResourceScript(StringBuilder rCode, String name) { From bfcb8dc36dfad1fe87c73bcd031c45f0d606c7fe Mon Sep 17 00:00:00 2001 From: eric Date: Sat, 29 Aug 2026 08:18:45 +1200 Subject: [PATCH 2/3] Add javadocs to factory methods for RCode.java --- .../java/com/github/rcaller/rstuff/RCode.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java b/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java index b6947ad..4a3532e 100644 --- a/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java +++ b/RCaller/src/main/java/com/github/rcaller/rstuff/RCode.java @@ -39,24 +39,48 @@ private RCode(Path tempDir, this.tempFileService = new TempFileService(tempDir); } + /** + * Static factory creator for the default object + * + * @return default RCode object + */ public static RCode create() { RCode rCode = new RCode(); rCode.clear(); return rCode; } + /** + * Static factory creator with given temporary file directory + * + * @param tempDir the directory to use to store temporary files + * @return RCode object + */ public static RCode create(Path tempDir) { RCode rCode = new RCode(tempDir); rCode.clear(); return rCode; } + /** + * Static factory creator with given string buffer + * + * @param stringBuffer the string buffer used for holding R code + * @return RCode object + */ public static RCode create(StringBuffer stringBuffer) { RCode rCode = RCode.create(); rCode.getCode().append(stringBuffer.toString()); return rCode; } + /** + * Static factory creator with given temporary file directory and string buffer + * + * @param tempDir the directory to use to store temporary files + * @param stringBuffer the string buffer used for holding R code + * @return RCode object + */ public static RCode create(Path tempDir, StringBuffer stringBuffer) { RCode rCode = RCode.create(tempDir); @@ -64,12 +88,25 @@ public static RCode create(Path tempDir, return rCode; } + /** + * Static factory creator with given startup options + * + * @param rCallerOptions given startup object + * @return RCode object + */ public static RCode create(RCallerOptions rCallerOptions) { RCode rCode = new RCode(rCallerOptions); rCode.clear(); return rCode; } + /** + * Static factory creator with given temporary file directory and startup options + * + * @param tempDir the directory to use to store temporary files + * @param rCallerOptions given startup object + * @return RCode object + */ public static RCode create(Path tempDir, RCallerOptions rCallerOptions) { RCode rCode = new RCode(tempDir, rCallerOptions); @@ -77,6 +114,13 @@ public static RCode create(Path tempDir, return rCode; } + /** + * Static factory creator with given string buffer and startup options + * + * @param stringBuffer the string buffer used for holding R code + * @param rCallerOptions given startup object + * @return RCode object + */ public static RCode create(StringBuffer stringBuffer, RCallerOptions rCallerOptions) { RCode rCode = RCode.create(rCallerOptions); @@ -84,6 +128,14 @@ public static RCode create(StringBuffer stringBuffer, return rCode; } + /** + * Static factory creator with given temporary file directory and string buffer and startup options + * + * @param tempDir the directory to use to store temporary files + * @param stringBuffer the string buffer used for holding R code + * @param rCallerOptions given startup object + * @return RCode object + */ public static RCode create(Path tempDir, StringBuffer stringBuffer, RCallerOptions rCallerOptions) { From e41f8dd8d48ea96262ee757f03091b2086302a51 Mon Sep 17 00:00:00 2001 From: eric Date: Sat, 29 Aug 2026 08:48:26 +1200 Subject: [PATCH 3/3] revert change to delete temp files if rcode and rcaller do not share the same tempfileservice - i.e. setRCode has been called with a new rcode object --- RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java | 1 + 1 file changed, 1 insertion(+) diff --git a/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java b/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java index 0973d53..e8f0b7f 100644 --- a/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java +++ b/RCaller/src/main/java/com/github/rcaller/rstuff/RCaller.java @@ -152,6 +152,7 @@ public void setGraphicsTheme(GraphicsTheme theme) { */ public void deleteTempFiles() { tempFileService.deleteRCallerTempFiles(); + this.rCode.deleteTempFiles(); } /**