/* DineroFrontend.java * * Graphical frontend for DineroIV * (c) 2006 Andrea Spadaccini * * This file is part of the EduMIPS64 project, and is released under the GNU * General Public License. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.edumips64.ui.swing; import org.edumips64.core.Dinero; import org.edumips64.utils.ConfigKey; import org.edumips64.utils.ConfigStore; import org.edumips64.utils.io.LocalWriterAdapter; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.Collections; import java.util.LinkedList; import java.util.logging.Logger; import javax.swing.*; /** Graphical frontend for DineroIV * @author Andrea Spadaccini */ public class DineroFrontend extends JDialog { // Attributes are static in order to make them accessible from // the nested anonymous classes. They can be static, because at most // one instance of DineroFrame will be created in EduMIPS64 private static final Logger logger = Logger.getLogger(DineroFrontend.class.getName()); private static JTextField path, params; private static JButton execute; private static JTextArea result; private class StreamReader extends Thread { private InputStream stream; private String name; private LinkedList<String> contents; private boolean finished = false; StreamReader(InputStream stream, String name) { this.stream = stream; this.name = name; this.contents = new LinkedList<>(); this.finished = false; } public void run() { logger.info("Starting the " + name + " StreamReader"); BufferedReader br = new BufferedReader(new InputStreamReader(stream)); String line; try { while ((line = br.readLine()) != null) { contents.add(line); } logger.info("Finished reading from the " + name + " StreamReader"); } catch (IOException e) { logger.severe("Exception while reading from the " + name + " StreamReader: " + e); } finished = true; } public LinkedList<String> getContents() { return contents; } // Will always be called after join() boolean isFinished() { return finished; } } private LinkedList<String> extractSimulationResults(LinkedList<String> stdout) { LinkedList<String> result = new LinkedList<>(); boolean found = false; for (String line : stdout) { if (line.equals("---Simulation complete.")) { found = true; } if (found) { result.add(line + "\n"); } } return result; } public DineroFrontend(Frame owner, Dinero dinero, ConfigStore config) { super(owner); setTitle("Dinero frontend"); Container cp = rootPane.getContentPane(); cp.setLayout(new BoxLayout(cp, BoxLayout.PAGE_AXIS)); Dimension hSpace = new Dimension(5, 0); Dimension vSpace = new Dimension(0, 5); JLabel pathLabel = new JLabel("DineroIV executable path:"); JLabel paramsLabel = new JLabel("Command line parameters:"); path = new JTextField(config.getString(ConfigKey.DINERO)); params = new JTextField("-l1-usize 512 -l1-ubsize 64"); path.setPreferredSize(new Dimension(400, 26)); path.setMaximumSize(new Dimension(1000, 26)); path.setMinimumSize(new Dimension(50, 25)); params.setPreferredSize(new Dimension(400, 26)); params.setMaximumSize(new Dimension(1000, 26)); params.setMinimumSize(new Dimension(50, 26)); params.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { execute.doClick(); } } }); JButton browse = new JButton("Browse..."); browse.setAlignmentX(Component.RIGHT_ALIGNMENT); execute = new JButton("Execute"); execute.setAlignmentX(Component.CENTER_ALIGNMENT); browse.addActionListener(e -> { JFileChooser jfc = new JFileChooser(); int val = jfc.showOpenDialog(null); if (val == JFileChooser.APPROVE_OPTION) { config.putString(ConfigKey.DINERO, jfc.getSelectedFile().getPath()); path.setText(jfc.getSelectedFile().getPath()); } }); execute.addActionListener(e -> { try { String dineroPath = path.getText(); String paramString = params.getText(); LinkedList<String> paramsList = new LinkedList<>(); paramsList.add(dineroPath); Collections.addAll(paramsList, paramString.split(" ")); // Clean up the JTextArea result.setText(""); logger.info("Starting the Dinero process."); Process process = Runtime.getRuntime().exec(paramsList.toArray(new String[0])); logger.info("Creating and starting reader threads for stdout and stderr"); StreamReader stdoutReader = new StreamReader(process.getInputStream(), "stdout"); StreamReader stderrReader = new StreamReader(process.getErrorStream(), "stderr"); stdoutReader.start(); stderrReader.start(); logger.info("Sending the tracefile to Dinero via stdin"); // Let's send the tracefile to Dinero PrintWriter dineroIn = new PrintWriter(process.getOutputStream()); dinero.writeTraceData(new LocalWriterAdapter(dineroIn)); dineroIn.flush(); dineroIn.close(); // Well, wait for Dinero to terminate logger.info("Data sent. Waiting for Dinero to terminate."); process.waitFor(); logger.info("Dinero terminated."); stdoutReader.join(10000); stderrReader.join(10000); logger.info("Reader threads have been joined. Results: " + stdoutReader.isFinished() + ", " + stderrReader.isFinished()); // Debug info logger.info("STDOUT: " + stdoutReader.getContents()); logger.info("STDERR: " + stderrReader.getContents()); logger.info("Writing data to the JTextArea.."); LinkedList<String> simulationResults = extractSimulationResults(stdoutReader.getContents()); if (simulationResults.isEmpty()) { result.append(">> Errors while retrieving the simulation results."); result.append(">> STDOUT: " + stdoutReader.getContents()); result.append(">> STDERR: " + stderrReader.getContents()); } else { result.append(">> Dinero path: " + dineroPath + "\n"); result.append(">> Dinero parameters: " + paramString + "\n"); result.append(">> Simulation results:\n"); for (String line : simulationResults) { result.append(line); } } logger.info("DineroFrontend: all done."); } catch (InterruptedException ie) { result.append(">> ERROR: " + ie); logger.severe("InterruptedException: " + ie); } catch (IOException ioe) { result.append(">> ERROR: " + ioe); logger.severe("IOException: " + ioe); } catch (Exception ex) { result.append(">> ERROR: " + ex); logger.severe("Exception: " + ex); } }); Box dineroEx = Box.createHorizontalBox(); dineroEx.add(Box.createHorizontalGlue()); dineroEx.add(pathLabel); dineroEx.add(Box.createRigidArea(hSpace)); dineroEx.add(path); dineroEx.add(Box.createRigidArea(hSpace)); dineroEx.add(browse); cp.add(dineroEx); cp.add(Box.createRigidArea(vSpace)); Box cmdLine = Box.createHorizontalBox(); cmdLine.add(Box.createHorizontalGlue()); cmdLine.add(paramsLabel); cmdLine.add(Box.createRigidArea(hSpace)); cmdLine.add(params); cmdLine.add(Box.createRigidArea(hSpace)); cp.add(cmdLine); cp.add(Box.createRigidArea(vSpace)); result = new JTextArea(); result.setBorder(BorderFactory.createTitledBorder("Messages")); result.setEditable(false); result.setFont(new Font("Monospaced", Font.PLAIN, 12)); cp.add(execute); cp.add(Box.createRigidArea(vSpace)); cp.add(new JScrollPane(result)); setSize(850, 500); } }