Avvio di applicazioni Java controllato

Matteo - 26 apr 2005 00:57

Vorrei presentare in questo Koan un metodo per avviare un'applicazione Java da un modulo dell'applicazione stessa.

Con l'uso di questo modulo e' possibile, in maniera cross-platform, avviare l'applicazione vera e propria in modo controllato, ovvero specificando eventuali opzioni della virtual machine che non e' possibile specificare nel manifest, oppure per redirigere l'output verso un file o uno stream specifico.

Questo metodo puo' essere utile ad esempio per specificare la memoria necessaria all'applicazione (opzioni -Xms e -Xmx) senza interventi da parte dell'utente.

Viene inoltre incluso un metodo che genera automaticamente il classpath, includendovi tutti i file jar trovati in una cartella lib, in modo che le librerie possano essere incluse dinamicamente fin dall'avvio, ad esempio per l'inclusione di plugin o per aggiornare le librerie necessarie senza dover modificare il manifest o addirittura il codice dell'applicazione.

Per utilizzare questo metodo, copiate il codice in una classe apposita. Dopo le opportune modifiche, compilatela e mettetela o in un jar apposito, o nel jar dell'applicazione stessa, facendo in modo che il manifest del jar in questione abbia questa classe come main-class. In questo modo con un doppio click sul file jar o eseguendolo da terminale con il classico "java -jar nomeFile.jar", l'applicazione partira' attraverso questo modulo.

Non viene inclusa qui la classe StreamPrinter, molto semplice da realizzare ma che si puo' trovare anche gia' pronta su Internet.

Giusto per cronaca, questo codice fa parte dei miei contributi all'applicazione su cui ho lavorato per la mia tesi di laurea.

import java.io.File;
import java.io.FilenameFilter;
import java.util.Enumeration;
import java.util.Vector;

public class Startup {

private static Vector fileNameVect; private static Vector dirs; private static Process process = null; /** * Builds a classpath for the application, including all * jar's inside the lib folder. */ private static String buildClassPath() { fileNameVect = new Vector(); dirs = new Vector(); dirs.add("lib"); // adds to classpath every jar in the lib folder while(!dirs.isEmpty()) { File currDir = new File(dirs.remove(0).toString()); currDir.list(new FilenameFilter() { public boolean accept(File dir, String name) { File currFile = new File(dir, name); if(currFile.isDirectory()) dirs.add(currFile.getPath()); else if(name.endsWith(".jar")) fileNameVect.add(currFile.getPath()); return false; } }); } // adds to the classpath the lib folder itself, to add // some useful files to the classpath (eg. log4j.properties). String classPath = "lib"; Enumeration libs = fileNameVect.elements(); while(libs.hasMoreElements()) { classPath += File.pathSeparatorChar; classPath += libs.nextElement().toString(); } return classPath; } /** Redirect the app's output to the standard output and waits * for the end of the execution. */ private static int waitFor() throws InterruptedException { // StreamPrinter is a class that redirects an input stream to // an output stream, with a dedicated thread that runs a loop // until the input stream is closed StreamPrinter out = new StreamPrinter( process.getInputStream(), System.out ); StreamPrinter error = new StreamPrinter( process.getErrorStream(), System.err ); out.start(); error.start(); out.join(); error.join(); // Returns the app's exit value. return process.waitFor(); }

public static void main(String[] args) { try { // checks if we are on a Mac boolean isMac = (System.getProperty("os.name", "none"). toLowerCase().indexOf("mac") != -1); String[] execStrings = new String[isMac ? 7 : 6]; // on windows uses "javaw", otherwise uses "java" execStrings[0] = "javaw"; if(System.getProperty("os.name", "none"). toLowerCase().indexOf("windows") == -1) execStrings[0] = "java"; // sets how much memory to use for the app. The value(s) is // probably read from some external configuration int memory = 256; // 256 MBs of both starting and max memory execStrings[1] = "-Xms" + memory + "m"; execStrings[2] = "-Xmx" + memory + "m"; // builds the classpath dynamically execStrings[3] = "-classpath"; execStrings[4] = "" + buildClassPath() + ""; // on Mac sets the app name on the dock if(isMac) execStrings[5] = "-Xdock:name=MyApp"; // this is the main class for the application execStrings[isMac ? 6 : 5] = "myApp.MainAppClass"; // runs the process process = Runtime.getRuntime().exec(execStrings, null, null); } catch (Throwable e) { e.printStackTrace(); } // if process is null then there's been an exception or a problem in // the exec method if(process == null) MessagePanel.error( "Startup Error", "Error launching the App"); else try { // redirect outputs and waits for the app's execution. // The result's check is needed to make sure that the JVM // doesn't optimize the call, not making it... if(waitFor() != 0) System.out.println("Abnormal exit from the app"); else System.out.println("Application terminated"); } catch(Throwable t) { // this error shouldn't be critical: the worst that could happen // is that the app's output doesn't get redirected to the console System.out.println("Error trapping output from app"); t.printStackTrace(); } } }

 
Weblog Koan Progetti Foto Contatti DW.net map