package org.dart.imagej;
import ij.ImageJ;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
/**
* Invokes commands in a remote instance of ImageJ.
* @author Tony O'Hagan, ITEE, University of Queensland
*/
public class IJClientRemote
implements IJClient {
// private static final Log log = LogFactory.getLog(IJClientRemote.class);
// private static final boolean isDebugging = log.isDebugEnabled();
/**
* @throws IOException Thrown if we cannot connect to a running instance of ImageJ
*/
public IJClientRemote() throws IOException {
// IJClientFactory.getIJClient() uses the fact that this contructor
// throws an exception to test when the ImageJ server (ij.SocketListener) is active.
setDefaultDirectory(new File(System.getProperty("user.dir")));
}
public void quit() {
try {
// Attempt to quit application
runMenuCommand("Quit");
} catch (IOException e) {
// ignore
}
}
public void setDefaultDirectory(File dir) throws IOException {
send("user.dir " + dir.getAbsolutePath());
}
public void openImage(File file) throws IOException {
send("open " + file.getAbsolutePath());
}
public void runMacro(String macro, String macroArg) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void runMacro(String macro) throws IOException {
// An alternative compromise if temporary files prove to be a problem
// String[] macroLines = macro.split("\n");
// for (int line = 0; line < macroLines.length; line++) {
// send("eval " + macroLines[line]);
// }
if (macro.indexOf('\n') == -1) {
send("eval " + macro); // Remote protocol only works for single line macros
} else {
// Hack to avoid that problem that the ImageJ server only supports single line commands
// TODO: Fix ImageJ server to support multiline commands. Possibly replace it with an RMI solution.
// Write macro to a temporary file and execute the file
final File tempFile = writeMacroToTempFile(macro);
runMacroFile(tempFile);
// Delete the temporary file after 10 seconds (in a new thread)
// Plenty of time for the ImageJ server to read the file.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
tempFile.delete();
}
}, 10 * 1000);
}
}
private File writeMacroToTempFile(String macro) {
File tempFile = null;
PrintStream out = null;
try {
tempFile = File.createTempFile("ij", ".ijm");
FileOutputStream fout = new FileOutputStream(tempFile);
out = new PrintStream(fout);
out.println(macro);
} catch (IOException e) {
// if (tempFile == null) {
// log.error("Failed to create or write to temporary ImageJ macro file");
// } else {
// log.error(tempFile.getAbsoluteFile() + ": Failed to create or write to temporary ImageJ macro file");
// }
} finally {
if (out != null) {
out.close();
}
}
return tempFile;
}
public void runMacroFile(File file) throws IOException {
runMacroFile(file, null);
}
public void runMacroFile(File file, String arg) throws IOException {
String cmd = "macro " + file.getAbsolutePath() + (arg == null ? "" : ("(" + arg + ")"));
send(cmd);
}
public void runMenuCommand(String menuCommand) throws IOException {
send("run " + menuCommand);
}
/**
* Send commands to ImageJ SocketLister
* @param arg
* @throws IOException
*/
private void send(String cmd) throws IOException {
int port = ImageJ.getPort();
Socket socket = null;
PrintWriter out = null;
try {
socket = new Socket("localhost", port);
out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
out.println(cmd);
} finally {
if (out != null) {
out.close();
}
if (socket != null) {
socket.close();
}
}
}
}