minor changes in executable jars: removed jdk dependency on simulating computer + temporary files from simulation are stored in a subdirectory + temporary files from building the jar are removed when done

This commit is contained in:
fros4943 2009-10-29 17:05:13 +00:00
parent b4a4572d97
commit a45aa8e89c
2 changed files with 187 additions and 94 deletions

View file

@ -24,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* $Id: GUI.java,v 1.148 2009/10/29 10:16:05 fros4943 Exp $ * $Id: GUI.java,v 1.149 2009/10/29 17:05:13 fros4943 Exp $
*/ */
package se.sics.cooja; package se.sics.cooja;
@ -2595,7 +2595,7 @@ public class GUI extends Observable {
* @return Value * @return Value
*/ */
public static String getExternalToolsSetting(String name) { public static String getExternalToolsSetting(String name) {
return currentExternalToolsSettings.getProperty(name); return getExternalToolsSetting(name, null);
} }
/** /**
@ -4158,35 +4158,71 @@ public class GUI extends Observable {
getSimulation().stopSimulation(); getSimulation().stopSimulation();
/* Info message */ /* Info message */
JOptionPane.showMessageDialog(GUI.getTopParentContainer(), String[] options = new String[] { "OK", "Cancel" };
int n = JOptionPane.showOptionDialog(
GUI.getTopParentContainer(),
"This function attempts to build an executable COOJA JAR from the current simulation.\n" + "This function attempts to build an executable COOJA JAR from the current simulation.\n" +
"The JAR will contain all simulation dependencies, including project JAR files and mote firmware files.\n" + "The JAR will contain all simulation dependencies, including project JAR files and mote firmware files.\n" +
"\nExecutable simulations can be used to run already prepared simulations on several computers.\n" + "\nExecutable simulations can be used to run already prepared simulations on several computers.\n" +
"\nThis is an experimental feature!", "\nThis is an experimental feature!",
"Export simulation to executable JAR", JOptionPane.INFORMATION_MESSAGE); "Export simulation to executable JAR", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
if (n != JOptionPane.OK_OPTION) {
return;
}
/* Select output directory */ /* Select output file */
JFileChooser fc = new JFileChooser(); JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Select directory for " + ExecuteJAR.EXECUTABLE_JAR_FILENAME); FileFilter jarFilter = new FileFilter() {
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); public boolean accept(File file) {
fc.setAcceptAllFileFilterUsed(false); if (file.isDirectory()) {
int returnVal = fc.showSaveDialog(myDesktopPane); return true;
}
if (file.getName().endsWith(".jar")) {
return true;
}
return false;
}
public String getDescription() {
return "Java archive";
}
public String toString() {
return ".jar";
}
};
fc.setFileFilter(jarFilter);
fc.setSelectedFile(new File("cooja_simulation.jar"));
int returnVal = fc.showSaveDialog(GUI.getTopParentContainer());
if (returnVal != JFileChooser.APPROVE_OPTION) { if (returnVal != JFileChooser.APPROVE_OPTION) {
return; return;
} }
File dir = fc.getSelectedFile(); File outputFile = fc.getSelectedFile();
if (!dir.isDirectory()) { if (outputFile.exists()) {
options = new String[] { "Overwrite", "Cancel" };
n = JOptionPane.showOptionDialog(
GUI.getTopParentContainer(),
"A file with the same name already exists.\nDo you want to remove it?",
"Overwrite existing file?", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
if (n != JOptionPane.YES_OPTION) {
return; return;
} }
outputFile.delete();
}
final File finalOutputFile = outputFile;
new Thread() {
public void run() {
try { try {
ExecuteJAR.buildExecutableJAR(GUI.this, dir); ExecuteJAR.buildExecutableJAR(GUI.this, finalOutputFile);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
JOptionPane.showMessageDialog(GUI.getTopParentContainer(), JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
ex.getMessage(), ex.getMessage(),
"Mote type not supported", JOptionPane.ERROR_MESSAGE); "Error", JOptionPane.ERROR_MESSAGE);
} }
} }
}.start();
}
public boolean shouldBeEnabled() { public boolean shouldBeEnabled() {
return getSimulation() != null; return getSimulation() != null;
} }

View file

@ -24,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* $Id: ExecuteJAR.java,v 1.1 2009/10/29 10:17:15 fros4943 Exp $ * $Id: ExecuteJAR.java,v 1.2 2009/10/29 17:05:14 fros4943 Exp $
*/ */
package se.sics.cooja.util; package se.sics.cooja.util;
@ -32,6 +32,8 @@ package se.sics.cooja.util;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.security.AccessControlException; import java.security.AccessControlException;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Properties; import java.util.Properties;
@ -54,10 +56,8 @@ import se.sics.cooja.plugins.ScriptRunner;
public class ExecuteJAR { public class ExecuteJAR {
private static Logger logger = Logger.getLogger(ExecuteJAR.class); private static Logger logger = Logger.getLogger(ExecuteJAR.class);
public final static String EXECUTABLE_JAR_FILENAME = "cooja_simulation.jar";
public final static String EXTERNALTOOLS_FILENAME = "externaltools.config";
public final static String SIMCONFIG_FILENAME = "simulation.csc"; public final static String SIMCONFIG_FILENAME = "simulation.csc";
public final static String FIRMWARE_PREFIX = "firmware"; public final static String EXTERNALTOOLS_FILENAME = "exttools.config";
public final static String FIRMWARE_SUFFIX = ".sky"; public final static String FIRMWARE_SUFFIX = ".sky";
public static void main(String[] args) { public static void main(String[] args) {
@ -72,8 +72,7 @@ public class ExecuteJAR {
} }
if (args.length > 0) { if (args.length > 0) {
/* Generate */ /* Generate executable JAR */
logger.debug("Generating JAR");
if (args.length != 1) { if (args.length != 1) {
throw new RuntimeException( throw new RuntimeException(
"Bad command line arguments: specify only one simulation config!" "Bad command line arguments: specify only one simulation config!"
@ -81,103 +80,140 @@ public class ExecuteJAR {
} }
generate(new File(args[0])); generate(new File(args[0]));
} else { } else {
logger.debug("Executing JAR"); /* Run simulation */
execute(); execute();
} }
} }
private static void generate(File file) { private static void generate(File config) {
if (!file.exists()) { if (!config.exists()) {
throw new RuntimeException( throw new RuntimeException(
"Simulation config not found: " + file.getAbsolutePath() "Simulation config not found: " + config.getAbsolutePath()
); );
} }
/* Load simulation */ /* Load simulation */
logger.debug("Loading " + file); logger.info("Loading " + config);
Simulation s = GUI.quickStartSimulationConfig(file, false); Simulation s = GUI.quickStartSimulationConfig(config, false);
if (s == null) { if (s == null) {
throw new RuntimeException( throw new RuntimeException(
"Error when creating simulation" "Error when creating simulation"
); );
} }
s.stopSimulation(); s.stopSimulation();
logger.debug("Stopped simulation");
buildExecutableJAR(s.getGUI(), new File(".")); buildExecutableJAR(s.getGUI(), new File(config.getName() + ".jar"));
System.exit(1); System.exit(1);
} }
final static boolean OVERWRITE = false;
private static void execute() { private static void execute() {
/* Execute */ String executeDir = null;
GUI.externalToolsUserSettingsFile = new File(EXTERNALTOOLS_FILENAME); try {
executeDir = new File(
ExecuteJAR.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getName();
if (!executeDir.endsWith(".jar")) {
logger.fatal("Not a proper JAR archive: " + executeDir);
System.exit(1);
}
executeDir = executeDir.substring(0, executeDir.length()-".jar".length());
new File(executeDir).mkdir();
} catch (URISyntaxException e1) {
logger.fatal("Can't access JAR file name: " + e1.getMessage());
System.exit(1);
}
/* Unpack JAR dependencies - only when they do not already exist! */ /* Unpack JAR dependencies - only when they do not already exist! */
try { try {
Process process; InputStream inputStream;
if (!new File(SIMCONFIG_FILENAME).exists()) { File diskFile = new File(executeDir, SIMCONFIG_FILENAME);
logger.info("Unpacking simulation config: " + SIMCONFIG_FILENAME); if (OVERWRITE || !diskFile.exists()) {
process = Runtime.getRuntime().exec(new String[] { logger.info("Unpacking simulation config: " + SIMCONFIG_FILENAME + " -> " + diskFile.getName());
"jar", inputStream = GUI.class.getResourceAsStream("/" + SIMCONFIG_FILENAME);
"xf", byte[] fileData = ArrayUtils.readFromStream(inputStream);
EXECUTABLE_JAR_FILENAME, if (fileData == null) {
SIMCONFIG_FILENAME, logger.info("Failed extracting file (read fail)");
}); System.exit(1);
process.waitFor(); }
boolean ok = ArrayUtils.writeToFile(diskFile, fileData);
if (!ok) {
logger.info("Failed extracting file (write fail)");
System.exit(1);
}
} else { } else {
logger.info("Skip: simulation config alrady exists: " + SIMCONFIG_FILENAME); logger.info("Skip: simulation config already exists: " + diskFile);
} }
if (!new File(EXTERNALTOOLS_FILENAME).exists()) { diskFile = new File(executeDir, EXTERNALTOOLS_FILENAME);
logger.info("Unpacking external tools config: " + EXTERNALTOOLS_FILENAME); if (OVERWRITE || !diskFile.exists()) {
process = Runtime.getRuntime().exec(new String[] { logger.info("Unpacking external tools config: " + EXTERNALTOOLS_FILENAME + " -> " + diskFile.getName());
"jar", inputStream = GUI.class.getResourceAsStream("/" + EXTERNALTOOLS_FILENAME);
"xf", byte[] fileData = ArrayUtils.readFromStream(inputStream);
EXECUTABLE_JAR_FILENAME, if (fileData == null) {
EXTERNALTOOLS_FILENAME, logger.info("Failed extracting file (read fail)");
}); System.exit(1);
process.waitFor(); }
} else { boolean ok = ArrayUtils.writeToFile(diskFile, fileData);
logger.info("Skip: external tools config alrady exists: " + EXTERNALTOOLS_FILENAME); if (!ok) {
logger.info("Failed extracting file (write fail)");
System.exit(1);
} }
if (!new File(FIRMWARE_PREFIX + 0 + FIRMWARE_SUFFIX).exists()) {
logger.info("Unpacking firmware files (max 10))");
process = Runtime.getRuntime().exec(new String[] {
"jar",
"xf",
EXECUTABLE_JAR_FILENAME,
FIRMWARE_PREFIX + 0 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 1 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 2 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 3 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 4 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 5 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 6 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 7 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 8 + FIRMWARE_SUFFIX,
FIRMWARE_PREFIX + 9 + FIRMWARE_SUFFIX,
});
process.waitFor();
} else { } else {
logger.info("Skip: firmware files already exist"); logger.info("Skip: external tools config already exists: " + diskFile);
}
GUI.externalToolsUserSettingsFile = diskFile;
int firmwareCounter = 0;
while (true) {
File firmwareFile = new File(firmwareCounter + FIRMWARE_SUFFIX);
diskFile = new File(executeDir, firmwareCounter + FIRMWARE_SUFFIX);
firmwareCounter++;
if (OVERWRITE || !diskFile.exists()) {
logger.info("Unpacking firmware file: " + firmwareFile.getName() + " -> " + diskFile.getName());
inputStream = GUI.class.getResourceAsStream("/" + firmwareFile.getName());
if (inputStream == null) {
/* Not available in simulation */
break;
}
byte[] fileData = ArrayUtils.readFromStream(inputStream);
if (fileData == null) {
logger.info("Failed extracting file (read fail)");
System.exit(1);
}
boolean ok = ArrayUtils.writeToFile(diskFile, fileData);
if (!ok) {
logger.info("Failed extracting file (write fail)");
System.exit(1);
}
} else {
logger.info("Skip: firmware files already exist: " + diskFile);
break;
}
} }
} catch (Exception e) { } catch (Exception e) {
System.err.println("Error when partially unpacking executable JAR: " + e.getMessage()); logger.fatal("Error when unpacking executable JAR: " + e.getMessage());
return; return;
} }
logger.info("Starting simulation"); logger.info("Starting simulation");
GUI.setLookAndFeel(); GUI.setLookAndFeel();
GUI.quickStartSimulationConfig(new File(SIMCONFIG_FILENAME), false); GUI.quickStartSimulationConfig(new File(executeDir, SIMCONFIG_FILENAME), false);
} }
/** /**
* Builds executable JAR from current simulation * Builds executable JAR from current simulation
* *
* @param gui GUI. Must contain simulation * @param gui GUI. Must contain simulation
* @param outputFile Output file
*/ */
public static void buildExecutableJAR(GUI gui, File outputDir) { public static boolean buildExecutableJAR(GUI gui, File outputFile) {
String executeDir = null;
executeDir = outputFile.getName();
if (!executeDir.endsWith(".jar")) {
throw new RuntimeException("Not a proper JAR archive: " + executeDir);
}
executeDir = executeDir.substring(0, executeDir.length()-".jar".length());
Simulation simulation = gui.getSimulation(); Simulation simulation = gui.getSimulation();
if (simulation == null) { if (simulation == null) {
throw new RuntimeException( throw new RuntimeException(
@ -267,7 +303,6 @@ public class ExecuteJAR {
"Project JAR could not be found: " + jarFile.getAbsolutePath() "Project JAR could not be found: " + jarFile.getAbsolutePath()
); );
} }
logger.info("Unpacking core JAR " + jar); logger.info("Unpacking core JAR " + jar);
try { try {
Process unjarProcess = Runtime.getRuntime().exec( Process unjarProcess = Runtime.getRuntime().exec(
@ -299,7 +334,7 @@ public class ExecuteJAR {
((Element)moteTypeElement).removeChildren("commands"); /* Remove build commands */ ((Element)moteTypeElement).removeChildren("commands"); /* Remove build commands */
for (Object pathElement : ((Element)moteTypeElement).getChildren()) { for (Object pathElement : ((Element)moteTypeElement).getChildren()) {
if (((Element) pathElement).getName().equals("firmware")) { if (((Element) pathElement).getName().equals("firmware")) {
String newName = FIRMWARE_PREFIX + firmwareCounter++ + FIRMWARE_SUFFIX; String newName = (firmwareCounter++) + FIRMWARE_SUFFIX;
/* Copy firmwares, and update firmware references */ /* Copy firmwares, and update firmware references */
String firmwarePath = ((Element)pathElement).getText(); String firmwarePath = ((Element)pathElement).getText();
File firmwareFile = gui.restorePortablePath(new File(firmwarePath)); File firmwareFile = gui.restorePortablePath(new File(firmwarePath));
@ -321,8 +356,8 @@ public class ExecuteJAR {
"Error when writing firmware file: " + firmwareFile "Error when writing firmware file: " + firmwareFile
); );
} }
logger.info("Simconfig: Update firmware path reference: " + firmwareFile.getAbsolutePath() + " -> " + newName); logger.info("Simconfig: Update firmware path reference: " + firmwareFile.getAbsolutePath() + " -> " + (executeDir + "/" + newName));
((Element)pathElement).setText(newName); ((Element)pathElement).setText(executeDir + "/" + newName);
} }
} }
} }
@ -344,12 +379,11 @@ public class ExecuteJAR {
"Error when writing simulation configuration: " + configFile "Error when writing simulation configuration: " + configFile
).initCause(e1); ).initCause(e1);
} }
logger.info("Wrote simulation configuration: " + configFile.getAbsolutePath()); logger.info("Wrote simulation configuration: " + configFile.getName());
/* Export external tools config (without projects) */ /* Export external tools config (without projects) */
try { try {
File externalToolsConfig = new File(workingDir, EXTERNALTOOLS_FILENAME); File externalToolsConfig = new File(workingDir, EXTERNALTOOLS_FILENAME);
logger.info("Exporting external tools config: " + externalToolsConfig);
FileOutputStream out = new FileOutputStream(externalToolsConfig); FileOutputStream out = new FileOutputStream(externalToolsConfig);
Properties differingSettings = new Properties(); Properties differingSettings = new Properties();
Enumeration<Object> keyEnum = GUI.currentExternalToolsSettings.keys(); Enumeration<Object> keyEnum = GUI.currentExternalToolsSettings.keys();
@ -367,6 +401,7 @@ public class ExecuteJAR {
differingSettings.store(out, "COOJA External Tools (User specific)"); differingSettings.store(out, "COOJA External Tools (User specific)");
out.close(); out.close();
logger.info("Wrote external tools config: " + externalToolsConfig.getName());
} catch (Exception e2) { } catch (Exception e2) {
throw (RuntimeException) new RuntimeException( throw (RuntimeException) new RuntimeException(
"Error when writing external tools configuration: " + e2.getMessage() "Error when writing external tools configuration: " + e2.getMessage()
@ -378,23 +413,22 @@ public class ExecuteJAR {
if (manifestFile.exists()) { if (manifestFile.exists()) {
manifestFile.delete(); manifestFile.delete();
} }
logger.info("Creating manifest file: " + manifestFile);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Manifest-Version: 1.0\r\n"); sb.append("Manifest-Version: 1.0\r\n");
sb.append("Main-Class: " + ExecuteJAR.class.getName() + "\r\n"); sb.append("Main-Class: " + ExecuteJAR.class.getName() + "\r\n");
sb.append("Class-path: .\r\n"); sb.append("Class-path: .\r\n");
StringUtils.saveToFile(manifestFile, sb.toString()); StringUtils.saveToFile(manifestFile, sb.toString());
logger.info("Wrote manifest file: " + manifestFile.getName());
/* Build executable JAR */ /* Build executable JAR */
File executableJAR = new File(outputDir, EXECUTABLE_JAR_FILENAME); if (outputFile.exists()) {
if (executableJAR.exists()) { outputFile.delete();
executableJAR.delete();
} }
logger.info("Building executable JAR: " + executableJAR); logger.info("Building executable JAR: " + outputFile);
try { try {
Process jarProcess = Runtime.getRuntime().exec( Process jarProcess = Runtime.getRuntime().exec(
new String[] { "jar", "cfm", executableJAR.getAbsolutePath(), "manifest.tmp", "*"}, new String[] { "jar", "cfm", outputFile.getAbsolutePath(), "manifest.tmp", "*"},
null, null,
workingDir workingDir
); );
@ -405,8 +439,31 @@ public class ExecuteJAR {
).initCause(e1); ).initCause(e1);
} }
/* Delete temporary working directory */
logger.info("Deleting temporary files in: " + workingDir.getAbsolutePath());
if (!deleteDirectory(workingDir)) {
if (!deleteDirectory(workingDir)) {
deleteDirectory(workingDir);
}
}
/* We are done! */ /* We are done! */
logger.info("Done! You may remove the temporary working directory: " + workingDir.getAbsolutePath()); logger.info("Done! To run simulation: > java -jar " + outputFile.getName());
logger.info("Run simulation: > java -jar " + EXECUTABLE_JAR_FILENAME); return true;
}
private static boolean deleteDirectory(File path) {
if(path.exists()) {
File[] files = path.listFiles();
for(File file: files) {
if(file.isDirectory()) {
deleteDirectory(file);
} else {
file.delete();
} }
} }
}
return(path.delete());
}
}