![JAR search and dependency download from the Maven repository](/logo.png)
uk.ac.liv.pgb.analytica.lib.wrappedr.RRuntime Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of analytica-lib Show documentation
Show all versions of analytica-lib Show documentation
Library allowing generation of plots and data from proteomics and
metabolomics mass spectrometry data through the use of R and java
methods.
The newest version!
package uk.ac.liv.pgb.analytica.lib.wrappedr;
import java.io.File;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
import org.rosuda.JRI.RMainLoopCallbacks;
import org.rosuda.JRI.Rengine;
import uk.ac.liv.pgb.analytica.lib.wrappedr.FileSystem.SystemType;
/**
* Manages the interaction with the R runtime itself.
*
* @author sperkins
*/
public final class RRuntime implements RMainLoopCallbacks {
/**
* The singleton instance of this class.
*/
private static final RRuntime INSTANCE = new RRuntime();
/**
* Gets the singleton instance of this class. This method is synchronized as
* it may involve creation of a static object. Synchronization may be
* overkill here.
*
* @return Singleton instance of RRuntime.
*/
public static synchronized RRuntime getInstance() {
return INSTANCE;
}
/**
* The folder containing the R application files.
*/
private File rApplicationFolder;
/**
* The R engine object.
*/
private Rengine localEngine;
/**
* The current state of this runtime.
*/
private RRuntimeState state;
/**
* Private constructor to prevent external instantiation.
*/
private RRuntime() {
// First need to check if R is installed.
findRHomeFolder();
if (rApplicationFolder == null) {
state = RRuntimeState.R_APPLICATION_FOLDER_NOT_FOUND;
return;
}
// Load the JRI (rJava) and hence its dependencies.
loadJri();
}
/**
* Load the JRI linked library.
*
* @return True if the library is loaded successfully.
*/
private boolean loadJri() {
boolean jriDllFound = false;
boolean dependenciesFixed = false;
while (true) {
try {
System.loadLibrary("jri");
} catch (UnsatisfiedLinkError linkError) {
if (dependencyFailure(linkError)) {
if (dependenciesFixed) {
// Oh dear. We think we have fixed the dependencies, but the loading still failed.
// Either we didn't find the correct dll, or there was an error we haven't anticipated.
state = RRuntimeState.JRI_DEPENDENCY_FIX_FAIL;
return false;
}
dependenciesFixed = fixDependentLibraries();
if (!dependenciesFixed) {
state = RRuntimeState.JRI_DEPENDENCY_FIX_FAIL;
return false;
}
continue;
} else {
if (jriDllFound) {
// Oh dear. We think we have found the correct jriDll, but the loading failed.
// Either we didn't find the correct Dll, or there was an error we haven't anticipated.
state = RRuntimeState.JRI_WRONG_FOUND_OR_OTHER;
return false;
}
File jriDll = null;
jriDll = findJriDll();
if (jriDll == null) {
// We still didn't find the Jri Dll.
// This not recoverable.
state = RRuntimeState.JRI_NOT_FOUND;
return false;
}
// Let's add the Jri Dll's folder to the path for this java session.
FileSystem.addFolderToPathForJavaSession(jriDll.getParentFile());
// Let's add the jri Dll's folder to the path. For future sessions.
FileSystem.addFolderToPathPermanent(jriDll.getParentFile());
jriDllFound = true;
continue;
}
}
state = RRuntimeState.READY;
break;
}
return true;
}
/**
* Fix the depending libraries error reported when attempting to load the
* JRI library.
*
* @return True if the dependent library issues 'appear' to be fixed.
*/
private boolean fixDependentLibraries() {
// So we have dependent libraries to load.
// Documentation says that this error is solvable by setting the 'R_HOME' environmental variable.
// We can certainly do that, but that may not take until the next restart of the application.
// Not for now: We could load every Dll in the R application folder.
SystemType system = FileSystem.getSystemType();
File rBinFolder = new File(rApplicationFolder.getAbsolutePath() + File.separator + "bin");
if (!rBinFolder.exists()) {
// Oh dear, this is bad, but should never happen.
return false;
}
if (system == SystemType.WIN64) {
File rBinFolder64 = new File(rBinFolder.getAbsolutePath() + File.separator + "x64");
if (rBinFolder64.exists()) {
if (FileSystem.addFolderToPathPermanent(rBinFolder64)) {
return true;
}
}
}
if (system == SystemType.WIN32 || system == SystemType.WIN64) {
File rBinFolder32 = new File(rBinFolder.getAbsolutePath() + File.separator + "i386");
if (rBinFolder32.exists()) {
if (FileSystem.addFolderToPathPermanent(rBinFolder32)) {
return true;
}
}
}
return FileSystem.addFolderToPathPermanent(rBinFolder);
}
/**
* Checks whether the UnsatisfiedLinkError is due to dependencies.
*
* @param linkError The link exception.
* @return True if the error is due to dependencies.
*/
private boolean dependencyFailure(final UnsatisfiedLinkError linkError) {
return linkError.getLocalizedMessage().toUpperCase().contains("DEPENDENT");
}
/**
* Checks whether the R engine is available for use.
*
* @return True if available for use.
*/
public boolean isAvailable() {
return this.localEngine != null;
}
/**
* Gets the current state of this runtime.
*
* @return The current runtime state.
*/
public RRuntimeState getState() {
return this.state;
}
/**
* Install and load a package.
*
* @param dependency The name of the package to be installed/loaded.
*/
public synchronized void loadPackageDependency(final String dependency) {
// First install the package - this will have no effect if the package is already installed.
this.localEngine.eval("install.package(" + dependency + ")");
// Now load the package.
this.localEngine.eval("library(" + dependency + ")");
}
/**
* Loads the file graphics device, as a PNG in the specified file.
*
* @param outputFile The file to write the PNG data to.
*/
public synchronized void loadFileGraphicsDevice(final File outputFile) {
this.localEngine.eval("png(filename=\"" + outputFile.getAbsolutePath() + "\")");
}
/**
* Loads the java graphics device.
*/
public synchronized void loadJavaGraphicsDevice() {
}
/**
* Closes the graphics device, whatever it was.
*/
public synchronized void closeGraphicsDevice() {
this.localEngine.eval("dev.off()");
}
/**
* Executes the given function by name, with the specified arguments.
*
* @param function The name of the function to be executed.
* @param arguments The arguments to the function to be executed.
*/
public synchronized void executeFunction(final String function, final String... arguments) {
StringBuilder execBuilder = new StringBuilder();
execBuilder.append(function).append("(");
execBuilder.append(String.join(", ", Arrays.stream(arguments).filter(p -> p != null).collect(Collectors.toList())));
execBuilder.append(")");
this.localEngine.eval(execBuilder.toString());
}
/**
* Reads and evaluates an R source file.
*
* @param sourceFile The R source file.
*/
public synchronized void source(final File sourceFile) {
this.localEngine.eval("source(" + sourceFile.getAbsolutePath() + ")");
}
/**
* Take action when an R source file cannot be 'sourced'.
*/
private void doSourcingFailAction() {
}
/**
* Take action when a dependency cannot be loaded.
*/
private void doDependencyLoadFailAction() {
}
/**
* Execute naked R code.
*
* @param command The R code to be executed.
*/
public synchronized void execute(final String command) {
this.localEngine.eval(command);
}
/**
* Find the R home folder and set it as an environment variable.
*/
private void findRHomeFolder() {
SystemType system = FileSystem.getSystemType();
if (system == SystemType.WIN32) {
rApplicationFolder = FileSystem.findFile("R", new File("C:\\Program Files"), true, true);
} else if (system == SystemType.WIN64) {
rApplicationFolder = FileSystem.findFile("R", new File("C:\\Program Files"), true, true);
if (rApplicationFolder == null) {
rApplicationFolder = FileSystem.findFile("R", new File("C:\\Program Files (x86)"), true, true);
}
} else {
throw new RuntimeException("Only Windows OS are currently supported.");
}
if (rApplicationFolder != null) {
// Scan it's children to make sure we have the correct R home.
File[] children = rApplicationFolder.listFiles();
if (children != null) {
if (Arrays.stream(children).anyMatch(p -> p.getName().equalsIgnoreCase("etc")) && Arrays.stream(children).anyMatch(p -> p.getName().equalsIgnoreCase("bin"))) {
return;
} else if (children.length == 1) {
rApplicationFolder = children[0];
} else {
rApplicationFolder = null;
}
}
if (rApplicationFolder != null) {
FileSystem.setEnvironmentVariablePermanent("R_HOME", rApplicationFolder.getAbsolutePath());
}
}
}
/**
* Finds the JRI linked library file.
*
* @return The JRI linked library file.
*/
private File findJriDll() {
SystemType system = FileSystem.getSystemType();
if (rApplicationFolder == null) {
return null;
}
File rJavaFolder = new File(rApplicationFolder.getAbsolutePath() + File.separator + "library" + File.separator + "rJava");
if (rJavaFolder.exists()) {
File jriFolder = FileSystem.findFile("jri", rJavaFolder, true, true);
if (jriFolder == null) {
return null;
}
if (system == SystemType.WIN32) {
Optional i386 = Arrays.stream(jriFolder.listFiles()).filter(p -> p.getName().equalsIgnoreCase("i386")).findAny();
if (i386.isPresent()) {
File jriDll = FileSystem.findFile("jri.dll", i386.get(), true, false);
if (jriDll != null) {
return jriDll;
}
}
File jriDll = FileSystem.findFile("jri.dll", jriFolder, true, false);
return jriDll;
} else if (system == SystemType.WIN64) {
Optional x64 = Arrays.stream(jriFolder.listFiles()).filter(p -> p.getName().equalsIgnoreCase("x64")).findAny();
if (x64.isPresent()) {
File jriDll = FileSystem.findFile("jri.dll", x64.get(), true, false);
if (jriDll != null) {
return jriDll;
}
}
File jriDll = FileSystem.findFile("jri.dll", jriFolder, true, false);
return jriDll;
}
}
return null;
}
/**
* Write text to the console.
* @param engine The R engine.
* @param outText The text to write out.
* @param outputType Type of output. 0=Regular, 1=Error/Warning.
*/
@Override
public void rWriteConsole(final Rengine engine, final String outText, final int outputType) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Indicate that the engine has changed its busy state.
* @param engine The R engine.
* @param stateEvent The type of event being indicated. 1=Busy, 0=NotBusy
*/
@Override
public void rBusy(final Rengine engine, final int stateEvent) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Read text into the console.
* @param engine The R engine.
* @param consolePrompt The console prompt text.
* @param addToHistory Whether to add the returned output to the history. 0=No, !0=Yes
* @return Text to be read in to the console.
*/
@Override
public String rReadConsole(final Rengine engine, final String consolePrompt, final int addToHistory) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Show warning/error text.
* @param engine The R engine.
* @param errorWarning The error/warning text.
*/
@Override
public void rShowMessage(final Rengine engine, final String errorWarning) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Choose file for use in console.
* @param engine The R engine.
* @param newFile Whether a new or existing file is needed.
* @return The path of the chosen file.
*/
@Override
public String rChooseFile(final Rengine engine, final int newFile) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Flush any buffered output.
* @param engine The R engine.
*/
@Override
public void rFlushConsole(final Rengine engine) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Save the history to file.
* @param engine The R engine.
* @param historyFile The path of the history file to save.
*/
@Override
public void rSaveHistory(final Rengine engine, final String historyFile) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Load the history from file.
* @param engine The R engine.
* @param historyFile The path of the history file to load.
*/
@Override
public void rLoadHistory(final Rengine engine, final String historyFile) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* The possible states of the runtime.
*/
public enum RRuntimeState {
/**
* The JRI was successfully found but its location is not in the path.
*/
JRI_FOUND_NOT_IN_PATH,
/**
* There was an error while finding the JRI.
*/
JRI_ERROR_FINDING,
/**
* The JRI could not be found.
*/
JRI_NOT_FOUND,
/**
* The JRI was found in the path and there are no errors.
*/
READY,
/**
* The R application folder could not be found.
*/
R_APPLICATION_FOLDER_NOT_FOUND,
/**
* The JRI was found but loading failed due to a non-dependency error issue.
*/
JRI_WRONG_FOUND_OR_OTHER,
/**
* The dependency fixing did not resolve the issue with the dependencies.
*/
JRI_DEPENDENCY_FIX_FAIL
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy