package org.trianacode.enactment; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.ArrayUtils; import org.trianacode.TrianaInstance; import org.trianacode.config.Locations; import org.trianacode.config.cl.ArgumentParsingException; import org.trianacode.config.cl.OptionValues; import org.trianacode.config.cl.OptionsHandler; import org.trianacode.config.cl.TrianaOptions; import org.trianacode.enactment.addon.CLIaddon; import org.trianacode.enactment.io.*; import org.trianacode.enactment.logging.Loggers; import org.trianacode.taskgraph.ExecutionState; import org.trianacode.taskgraph.Node; import org.trianacode.taskgraph.TaskGraph; import org.trianacode.taskgraph.TaskGraphException; import org.trianacode.taskgraph.databus.DataBus; import org.trianacode.taskgraph.databus.DataBusInterface; import org.trianacode.taskgraph.databus.DataNotResolvableException; import org.trianacode.taskgraph.databus.packet.WorkflowDataPacket; import org.trianacode.taskgraph.ser.XMLReader; import org.trianacode.taskgraph.service.ExecutionEvent; import org.trianacode.taskgraph.service.ExecutionListener; import org.trianacode.taskgraph.tool.Tool; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.*; /** * @author Andrew Harrison * @version 1.0.0 Sep 24, 2010 */ public class Exec implements ExecutionListener { public static final String RUNS_DIR = "runs"; public static File RUNS = new File(Locations.getApplicationDataDir(), RUNS_DIR); private HashMap<String, String> executionProperties = new HashMap<String, String>(); static { System.out.println("PID runs path : " + RUNS.getAbsolutePath()); RUNS.mkdirs(); } private String pid = UUID.randomUUID().toString(); // private UUID parentUUID = null; private TrianaRun runner; public Exec(String pid) { if (pid != null && pid.length() > 0) { this.pid = pid; } System.out.println("Started exec with pid : " + pid); } public String getPid() { return pid; } // public void setParentUUID(UUID parentUUID) { // this.parentUUID = parentUUID; // } public static void main(String[] args) { int exitNumber = exec(args); System.exit(exitNumber); } public static int exec(String[] args) { cleanPids(); try { OptionsHandler parser = new OptionsHandler("Exec", TrianaOptions.TRIANA_OPTIONS); OptionValues vals = null; try { vals = parser.parse(args); } catch (ArgumentParsingException e) { System.out.println(e.getMessage()); System.out.println(parser.usage()); return 0; // System.exit(0); } String logLevel = vals.getOptionValue("l"); String logger = vals.getOptionValue("i"); if (logger != null) { Loggers.isolateLogger(logger, logLevel == null ? "INFO" : logLevel); } else { if (logLevel != null) { Loggers.setLogLevel(logLevel); } } String pid = vals.getOptionValue("u"); String data = vals.getOptionValue("d"); List<String> wfs = vals.getOptionValues("w"); if (wfs != null) { if (wfs.size() != 1) { System.out.println("Only one workflow can be specified."); return 1; // System.exit(1); } System.out.println("running workflow file in new triana"); String wf = wfs.get(0); System.out.println("Workflow : " + wf); System.out.println("pid : " + pid); try { System.out.println("Sleeping..."); Thread.sleep(2000); System.out.println("OK"); } catch (InterruptedException e) { e.printStackTrace(); } Exec exec = new Exec(pid); String execute = exec.executeNewTriana(wfs.get(0), data); System.out.println("Executed : " + execute); return 0; // System.exit(0); } // String com = vals.getOptionValue("c"); // if (com != null && pid != null) { // int i = commandToInt(com); // writeFile(i, pid, false); // System.exit(0); // } wfs = vals.getOptionValues("e"); if (wfs != null) { if (wfs.size() != 1) { System.out.println("Only one workflow can be specified."); return 1; // System.exit(1); } else { System.out.println("this should appear in the output"); try { System.out.println("Sleeping..."); Thread.sleep(2000); System.out.println("OK"); } catch (InterruptedException e) { e.printStackTrace(); } Exec exec = new Exec(pid); exec.executeWorkflowFile(wfs.get(0), data, args, vals); return 0; } } else { if (pid != null) { int val = readFile(pid); System.out.println(statusToString(val)); return 0; // System.exit(0); } } } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("Fell off end of options, or major error occurred."); return 1; } private static int commandToInt(String command) { if (command.equalsIgnoreCase("pause")) { return 100; } else if (command.equalsIgnoreCase("resume")) { return 101; } else if (command.equalsIgnoreCase("reset")) { return 102; } else if (command.equalsIgnoreCase("stop")) { return 103; } return -1; } private static String statusToString(int status) { ExecutionState state = ExecutionState.getState(status); if (state != null) { return state.toString(); } switch (status) { case -1: return "unknown error"; case 100: return "pause"; case 101: return "resume"; case 102: return "reset"; case 103: return "stop"; case 200: return "finished"; default: return "unknown"; } } private String executeNewTriana(String wf, String data) throws IOException { System.out.println("new triana workflow : " + wf + " data : " + data); try { System.out.println("Sleeping..."); Thread.sleep(2000); System.out.println("OK"); } catch (InterruptedException e) { e.printStackTrace(); } File f = new File(wf); if (!f.exists()) { return "Workflow File cannot be found:" + wf; } if (data != null) { File conf = new File(data); if (conf.exists() && conf.length() > 0) { data = conf.getAbsolutePath(); } } createFile(pid); String home = Locations.getHomeProper(); File bin; if (home.endsWith(".jar")) { bin = new File(new File(home).getParent()); } else { bin = new File(Locations.getHomeProper(), "bin"); } String script = "triana"; if (Locations.os().equals("windows")) { script += ".bat"; } else { script = "./" + script + ".sh"; //HACK - Check if triana.sh is in current folder, // if so, use that one instead String currentFolder = System.getProperty("user.dir"); if(currentFolder != null){ File currentFile = new File(currentFolder); File scriptFile = new File(currentFile, "triana.sh"); if(scriptFile.exists() && scriptFile.isFile() && scriptFile.canExecute()){ bin = currentFile; } } } System.out.println(bin.getCanonicalPath()); List<String> args = new ArrayList<String>(); args.add(script); args.add("-e"); args.add(wf); args.add("-u"); args.add(pid); if (data != null) { args.add("-d"); args.add(data); } System.out.println(ArrayUtils.toString(args)); execProcess(args, bin); // runProcess(args, bin); return pid; } private void executeWorkflowFile(String wf, String data, String[] args, OptionValues vals) throws Exception { File f = new File(wf); if (!f.exists()) { System.out.println("Cannot find workflow file:" + wf); System.exit(1); } System.out.println("Starting Triana"); TrianaInstance engine = new TrianaInstance(args); engine.addExtensionClass(CLIaddon.class); engine.init(); System.out.println("init-ed"); try { System.out.println("Sleeping..."); Thread.sleep(2000); System.out.println("OK"); } catch (InterruptedException e) { e.printStackTrace(); } XMLReader reader = new XMLReader(new FileReader(f)); Tool tool = reader.readComponent(engine.getProperties()); System.out.println("Loaded tool"); execute(tool, data); System.out.println("Executed"); engine.shutdown(0); System.out.println("Shut down"); } public void execute(final Tool tool, final String data) throws Exception { runner = new TrianaRun(tool); // if (parentUUID != null) { // runner.getScheduler().setParentUUID(parentUUID); runner.getScheduler().setExecutionProperties(executionProperties); // } runner.getScheduler().addExecutionListener(this); NodeMappings mappings = null; IoConfiguration ioc = null; if (data != null) { System.out.println("Config file : " + data); File conf = new File(data); if (!conf.exists()) { System.out.println("Cannot find data configuration file:" + data); System.exit(1); } IoHandler handler = new IoHandler(); ioc = handler.deserialize(new FileInputStream(conf)); mappings = handler.map(ioc, runner.getTaskGraph()); System.out.println("Data mappings size : " + mappings.getMap().size()); } else { System.out.println("No input data mapping"); } runner.runTaskGraph(); if (((TaskGraph) tool).getInputNodeCount() > 0) { if (mappings != null) { Iterator<Integer> it = mappings.iterator(); while (it.hasNext()) { Integer integer = it.next(); Object val = mappings.getValue(integer); System.out.println("Data : " + val.toString() + " will be sent to input number " + integer); runner.sendInputData(integer, val); } } else { System.out.println("No input file mappings " + ((TaskGraph) tool).getInputNodeCount() + " data input nodes."); runner.dispose(); return; } } while (!runner.isFinished()) { synchronized (this) { try { wait(100); } catch (InterruptedException e) { } } } Node[] nodes = runner.getTaskGraph().getDataOutputNodes(); for (Node node : nodes) { Object out = runner.receiveOutputData(0); Object o = null; if (out instanceof WorkflowDataPacket) { try { DataBusInterface db = DataBus.getDataBus(((WorkflowDataPacket) out).getProtocol()); o = db.get((WorkflowDataPacket) out); } catch (DataNotResolvableException e) { e.printStackTrace(); } } if(ioc != null){ System.out.println(ioc.getOutputs().size() + " outputs in config"); for(IoMapping mapping : ioc.getOutputs()){ System.out.println(mapping.getNodeName() + " " + mapping.getIoType().getType() + " " + mapping.getIoType().getValue() + " " + mapping.getIoType().isReference() + " node : " + node.getAbsoluteNodeIndex() ); if(mapping.getNodeName().equals("" + node.getAbsoluteNodeIndex())){ String value = mapping.getIoType().getValue(); //Irrelevant, probably, if the object doesnt match the IoType String type = mapping.getIoType().getType(); if (mapping.getIoType().isReference()) { File file = new File(value); if(o instanceof File){ File outputFile = (File) o; FileUtils.copyFile(outputFile, file); } else { IoTypeHandler handler = IoHandler.getHandler(o); OutputStream outputStream = new FileOutputStream(file); handler.write(o, outputStream); } } } } } else { System.out.println("Output config null"); writeData(o, node.getAbsoluteNodeIndex()); } System.out.println("Exec.execute output node " + node.getName() + " data : " + o); } runner.dispose(); } private int execProcess(List<String> optionsStrings, File bin) { String[] args = new String[optionsStrings.size()]; for (int i = 0; i < optionsStrings.size(); i++) { args[i] = optionsStrings.get(i).trim(); } try { // Runtime runtime = Runtime.getRuntime(); // Process process = runtime.exec(args, new String[]{}, bin); ProcessBuilder pb = new ProcessBuilder(args); pb.directory(bin); // pb.redirectErrorStream(true); Process process = pb.start(); System.out.println("Running " + process.toString()); new StreamToOutput(process.getErrorStream(), "err").start(); new StreamToOutput(process.getInputStream(), "std.out").start(); int returnCode = process.waitFor(); System.out.println("Runtime process finished with code " + returnCode); return returnCode; } catch (Exception e) { e.printStackTrace(); } return -1; } public InputStream readData(String name) throws FileNotFoundException { File lockDir = new File(RUNS, pid); if (!lockDir.exists()) { return null; } File dataFile = new File(lockDir, name); if (dataFile.exists() && dataFile.length() > 0) { return new FileInputStream(dataFile); } return null; } private void writeData(Object o, int index) throws IOException, TaskGraphException { // File lockDir = new File(RUNS, pid); // if (!lockDir.exists()) { // return; // } // File dataFile = new File(lockDir, "output_" + index); File dataFile = new File("output_" + index); IoTypeHandler ioth = IoHandler.getHandler(o); if (ioth != null) { FileOutputStream fout = new FileOutputStream(dataFile); ioth.write(o, fout); fout.close(); } System.out.println("wrote output " + dataFile.getAbsolutePath()); } public void createFile() throws IOException { writeFile(ExecutionState.NOT_INITIALIZED.ordinal(), pid, true); } private static void createFile(String pid) throws IOException { writeFile(ExecutionState.NOT_INITIALIZED.ordinal(), pid, true); } public String readUuidFile() throws IOException { int val = readFile(pid); return statusToString(val); } private static int readFile(String pid) throws IOException { File lockDir = new File(RUNS, pid); if (lockDir.exists()) { File lockfile = new File(lockDir, pid); if (lockfile.exists() && lockfile.length() > 0) { RandomAccessFile file = new RandomAccessFile(lockfile, "rw"); FileChannel f = file.getChannel(); FileLock fl = f.lock(); ByteBuffer bb = ByteBuffer.allocate(4); f.read(bb); bb.flip(); int command = bb.getInt(); fl.release(); file.close(); return command; } } return -1; } private static void writeFile(int command, String pid, boolean create) throws IOException { File lockDir = new File(RUNS, pid); lockDir.mkdirs(); File lockfile = new File(lockDir, pid); if (!create) { if (!lockfile.exists() || lockfile.length() == 0) { return; } } RandomAccessFile file = new RandomAccessFile(lockfile, "rw"); FileChannel f = file.getChannel(); FileLock fl = f.lock(); if (lockfile.length() == 4) { ByteBuffer bb = ByteBuffer.allocate(4); f.read(bb); bb.flip(); int curr = bb.getInt(); if (curr == ExecutionState.COMPLETE.ordinal()) { return; } } ByteBuffer bytes = ByteBuffer.allocate(4); bytes.putInt(command).flip(); f.write(bytes); f.force(false); fl.release(); file.close(); } private static void deleteFile(String pid) throws IOException { File lockDir = new File(RUNS, pid); if (!lockDir.exists()) { return; } File lockfile = new File(lockDir, pid); if (!lockfile.exists()) { return; } RandomAccessFile file = new RandomAccessFile(lockfile, "rw"); FileChannel f = file.getChannel(); FileLock fl = f.lock(); lockfile.delete(); fl.release(); file.close(); } @Override public void executionStateChanged(ExecutionEvent event) { } @Override public void executionRequested(ExecutionEvent event) { try { writeFile(event.getState().ordinal(), pid, false); } catch (IOException e) { e.printStackTrace(); } } @Override public void executionStarting(ExecutionEvent event) { try { writeFile(event.getState().ordinal(), pid, false); } catch (IOException e) { e.printStackTrace(); } } @Override public void executionFinished(ExecutionEvent event) { try { writeFile(event.getState().ordinal(), pid, false); } catch (IOException e) { e.printStackTrace(); } //runner.dispose(); } @Override public void executionReset(ExecutionEvent event) { try { writeFile(event.getState().ordinal(), pid, false); } catch (IOException e) { e.printStackTrace(); } } public HashMap<String, String> getExecutionProperties() { return executionProperties; } public void setExecutionProperties(HashMap<String, String> executionProperties) { this.executionProperties = executionProperties; } public class Poller extends TimerTask { @Override public void run() { try { int val = readFile(pid); if (val >= 100) { switch (val) { case 100: runner.getScheduler().pauseTaskGraph(); break; case 101: runner.getScheduler().resumeTaskGraph(); break; case 102: runner.getScheduler().resetTaskGraph(); break; case 103: runner.dispose(); writeFile(ExecutionState.COMPLETE.ordinal(), pid, false); break; default: break; } } } catch (Exception e) { e.printStackTrace(); } } } // // private void log(String log) throws Exception { // File file = new File(System.getProperty("user.home"), pid + ".log"); // RandomAccessFile raf = new RandomAccessFile(file, "rw"); // raf.seek(file.length()); // FileChannel f = raf.getChannel(); // FileLock fl = f.lock(); // ByteBuffer bb = ByteBuffer.allocate((log + "\n").getBytes().length); // bb.put((log + "\n").getBytes()).flip(); // f.write(bb); // f.force(false); // fl.release(); // raf.close(); // } private static void cleanPids() { File[] pids = RUNS.listFiles(); long now = System.currentTimeMillis(); for (File file : pids) { long mod = file.lastModified(); if (mod + (3600000 * 24) < now && file.isDirectory()) { file.delete(); } } } }