package common.processing; import org.apache.commons.logging.Log; import org.trianacode.annotation.CustomGUIComponent; import org.trianacode.annotation.Process; import org.trianacode.annotation.TextFieldParameter; import org.trianacode.annotation.Tool; import org.trianacode.enactment.StreamToOutput; import org.trianacode.enactment.logging.Loggers; import org.trianacode.taskgraph.Task; import org.trianacode.taskgraph.annotation.TaskConscious; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** * Created by IntelliJ IDEA. * User: Ian Harvey * Date: Aug 19, 2010 * Time: 11:08:09 AM * To change this template use File | Settings | File Templates. */ @Tool public class ExecuteString implements TaskConscious { @TextFieldParameter private String executableString = ""; @TextFieldParameter private String runtimeDirectory = ""; @TextFieldParameter private String concurrentProcesses = ""; private int runningProcesses = 0; ConcurrentHashMap<Integer, Object> returnCodes;// = new ConcurrentHashMap<Integer, returnCode>(); private static final String EXIT_CODE = "exitCode"; // enum returnCode { // SUCCESS, // FAIL // } private Task task; @Process(gather = true) public ConcurrentHashMap<Integer, Object> process(List list) throws Exception { ArrayList<String> executableStrings = new ArrayList<String>(); executableString = execField.getText(); if (!executableString.equals("")) { executableStrings.add(executableString); } for (Object object : list) { if (object instanceof String[]) { Collections.addAll(executableStrings, (String[]) object); } else if (object instanceof String) { executableStrings.add((String) object); } } runtimeDirectory = runtimeField.getText(); if (runtimeDirectory == null || runtimeDirectory.equals("")) { runtimeDirectory = "."; } String concurrent = concurrentField.getText(); int allowedProcesses; if (concurrent != null) { if (concurrent.equals("")) { allowedProcesses = 1; } else { allowedProcesses = Integer.parseInt(concurrent); } } else { allowedProcesses = 1; } int run = 0; System.out.println(executableStrings.size() + " processes to run."); System.out.println("Allowing " + allowedProcesses + " concurrent processes."); returnCodes = new ConcurrentHashMap<Integer, Object>(); while (run < executableStrings.size()) { if (runningProcesses < allowedProcesses) { System.out.println("Beginning run " + run); String exec = executableStrings.get(run); System.out.println("Run " + run + ", executing : " + exec); StringExecutor executor = new StringExecutor(exec, new File(runtimeDirectory), run); executor.addPropertyChangeListener(new ExitCodeListener(run)); executor.execute(); run++; } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } int wait = 0; int time = 0; while (returnCodes.size() < executableStrings.size()) { if (wait > 10000) { time += 10; System.out.println(returnCodes.size() + "/" + executableStrings.size() + " complete. " + "~" + time + " seconds past." ); wait = 0; } try { Thread.sleep(1000); wait += 1000; } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(returnCodes.size() + " return codes recorded " + returnCodes.values().toString()); int errorHappened = 0; for (Object value : returnCodes.values()) { if (!((String) value).equals("0")) { errorHappened++; } } if (errorHappened > 0) { throw new RuntimeException(errorHappened + " of the " + returnCodes.size() + "processes in " + task.getToolName() + " has returned an error code"); } return returnCodes; } class StringExecutor extends SwingWorker<Void, Void> { private String execString; private File execLocation; private int runID; public StringExecutor(String execString, File execLocation, int runID) { this.execString = execString; this.execLocation = execLocation; this.runID = runID; } @Override protected Void doInBackground() throws Exception { runningProcesses++; String exitCode = String.valueOf(executeProcess(execString, execLocation)); this.getPropertyChangeSupport().firePropertyChange(EXIT_CODE, null, exitCode); return null; } public void done() { System.out.println("Finished " + this.runID); runningProcesses--; } private int executeProcess(String executableString, File execLocation) { List<String> options = new ArrayList<String>(); String[] optionsStrings = executableString.split(" "); Collections.addAll(options, optionsStrings); java.lang.Process process = null; try { ProcessBuilder processBuilder = new ProcessBuilder(optionsStrings); processBuilder.directory(execLocation); System.out.println(processBuilder.directory().getAbsolutePath()); process = processBuilder.start(); new StreamToOutput(process.getInputStream(), "std.out").start(); new StreamToOutput(process.getErrorStream(), "err").start(); return process.waitFor(); } catch (Exception except) { except.printStackTrace(); this.cancel(true); } return 1; } } private void log(String s) { Log log = Loggers.DEV_LOGGER; log.debug(s); System.out.println(s); } JTextField execField = new JTextField(""); JTextField runtimeField = new JTextField(""); ///Users/ian/Work/testBundles/DART"); JTextField concurrentField = new JTextField(""); private JPanel mainPanel; @CustomGUIComponent public Component getComponent() { mainPanel = new JPanel(); getParams(); mainPanel.setLayout(new BorderLayout(5, 5)); JPanel topPanel = new JPanel(new GridLayout(0, 2, 5, 5)); JLabel execLabel = new JLabel("Executable string : "); JLabel folderLabel = new JLabel("Runtime folder : "); JLabel concurrentExecutionsLabel = new JLabel("Concurrent executions : "); topPanel.add(execLabel); topPanel.add(execField); topPanel.add(folderLabel); topPanel.add(runtimeField); topPanel.add(concurrentExecutionsLabel); topPanel.add(concurrentField); mainPanel.add(topPanel, BorderLayout.NORTH); JPanel lowerPanel = new JPanel(new GridLayout(0, 2, 5, 5)); JButton helpButton = new JButton("Help"); helpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { new helpFrame(); } }); JButton okButton = new JButton("Set"); helpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { apply(); } }); lowerPanel.add(okButton); lowerPanel.add(helpButton); mainPanel.add(lowerPanel, BorderLayout.SOUTH); return mainPanel; } public void applyClicked() { apply(); } public void okClicked() { apply(); } public void apply() { task.setParameter("executable", execField.getText() == null ? "" : execField.getText()); task.setParameter("runtimeDirectory", runtimeField.getText() == null ? "" : runtimeField.getText()); task.setParameter("concurrentProcesses", concurrentField.getText()); } private void getParams() { executableString = (String) task.getParameter("executable"); execField.setText(executableString); runtimeDirectory = (String) task.getParameter("runtimeDirectory"); runtimeField.setText(runtimeDirectory); concurrentProcesses = (String) task.getParameter("concurrentProcesses"); concurrentField.setText(concurrentProcesses); } @Override public void setTask(Task task) { this.task = task; getParams(); } class helpFrame extends JFrame { public helpFrame() { this.setTitle("Help"); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); JLabel helpLabel = new JLabel("This is helpful"); JTextArea helpArea = new JTextArea("Executable String is a line of text which will be run in a process " + "\n\nRuntime folder is the location which the process will be run." + "\n\nConcurrent executions is the number of processes which will run at the same time. If the " + "input array has multiple strings to run, then this number dictates how many to do at the same time. " + "Once a process finishes, another starts till they are all complete." ); helpArea.setEditable(false); helpArea.setLineWrap(true); helpArea.setWrapStyleWord(true); JScrollPane scrollPane = new JScrollPane(helpArea); panel.add(helpLabel); panel.add(scrollPane); JButton ok = new JButton("Ok"); ok.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dispose(); } }); panel.add(ok); this.add(panel); this.setSize(400, 200); this.setVisible(true); } } private class ExitCodeListener implements PropertyChangeListener { private Integer runID; public ExitCodeListener(int runID) { this.runID = runID; } @Override public void propertyChange(PropertyChangeEvent propertyChangeEvent) { Object returned = propertyChangeEvent.getNewValue(); if (returned instanceof String) { System.out.println("Run " + runID + " returned " + returned); String code = (String) returned; if (code.equals("0")) { returnCodes.put(runID, returned); } else { returnCodes.put(runID, returned); } } } } }