source: trunk/JFCMonitor/src/de/ugoe/cs/eventbench/jfcmonitor/JarLauncher.java @ 265

Last change on this file since 265 was 265, checked in by sherbold, 12 years ago
  • code documentation and formatting
  • Property svn:mime-type set to text/plain
File size: 6.9 KB
Line 
1package de.ugoe.cs.eventbench.jfcmonitor;
2
3import java.io.FileInputStream;
4import java.io.FileNotFoundException;
5import java.io.IOException;
6import java.lang.reflect.InvocationTargetException;
7import java.lang.reflect.Method;
8import java.net.MalformedURLException;
9import java.net.URL;
10import java.net.URLClassLoader;
11import java.util.jar.JarInputStream;
12import java.util.jar.Manifest;
13
14/**
15 * <p>
16 * Class that launches an executable Jar-file in the same thread and VM where
17 * the JarLauncher instance is created. The requirements on the Jar file are:
18 * <li>Must contain a MANIFEST.</li>
19 * <li>The MANIFEST must define the main-class of the application ("Main-Class"
20 * entry).</li>
21 * <li>The MANIFEST must define the classpath of the application ("Class-Path"
22 * entry).</li>
23 * </p>
24 *
25 * @author Steffen Herbold
26 * @version 1.0
27 */
28public class JarLauncher {
29
30        /**
31         * <p>
32         * Name of the Jar file to be executed.
33         * </p>
34         */
35        private String jarfile;
36
37        /**
38         * <p>
39         * Arguments for launching the Jar file.
40         * </p>
41         */
42        private String[] args;
43
44        /**
45         * <p>
46         * Helper variable with the path to the working directory.
47         * </p>
48         */
49        final String workingDir = System.getProperty("user.dir") + "/";
50
51        /**
52         * <p>
53         * Internal variable used to store the classpath extracted from the Jar
54         * file's MANIFEST.
55         * </p>
56         */
57        private String[] classPath = new String[] {};
58
59        /**
60         * <p>
61         * Internal variable used to store the name (including package information)
62         * of the Jar file's main function extracted from the Jar file's MANIFEST.
63         * </p>
64         */
65        private String mainClassName = "";
66
67        /**
68         * <p>
69         * Inner class that defines an exception that is thrown if launching the
70         * application in the Jar file fails.
71         * </p>
72         *
73         * @author Steffen Herbold
74         * @version 1.0
75         */
76        private class JarLaunchException extends Exception {
77
78                /**
79                 * <p>
80                 * Id for object serialization.
81                 * </p>
82                 */
83                private static final long serialVersionUID = 1L;
84
85                /**
86                 * <p>
87                 * Constructor. Creates a new JarLaunchException.
88                 * </p>
89                 *
90                 * @param string
91                 *            error message of the exception
92                 */
93                public JarLaunchException(String string) {
94                        super(string);
95                }
96
97                /**
98                 * <p>
99                 * Constructor. Creates a new JarLaunchException as a copy of an
100                 * existing exception.
101                 * </p>
102                 *
103                 * @param e
104                 *            exception that is copied
105                 */
106                public JarLaunchException(Exception e) {
107                        super(e);
108                }
109
110        }
111
112        /**
113         * <p>
114         * Constructor. Creates a new JarLauncher.
115         * </p>
116         *
117         * @param jarfileJjar
118         *            file to be launched; must not be complete path but in relation
119         *            to the current working directory
120         * @param args
121         *            arguments with which the main function of the Jar file is
122         *            called
123         */
124        public JarLauncher(String jarfile, String[] args) {
125                this.jarfile = jarfile;
126                this.args = args;
127        }
128
129        /**
130         * <p>
131         * Executes the main function of the Jar file associated with this launcher.
132         * </p>
133         */
134        public void exec() {
135                try {
136                        getInfoFromJar();
137                        initClassLoader();
138                        runMain();
139                } catch (JarLaunchException e) {
140                        System.err.println("Failure to launch application.");
141                        System.err.println(e.getMessage());
142                }
143        }
144
145        /**
146         * <p>
147         * Retrieves the classpath and main function from the Jar file's MANIFEST.
148         * </p>
149         *
150         * @throws JarLaunchException
151         *             thrown if reading of Jar file or MANIFEST fails
152         */
153        private void getInfoFromJar() throws JarLaunchException {
154                JarInputStream jarInputStream;
155                try {
156                        jarInputStream = new JarInputStream(new FileInputStream(workingDir
157                                        + jarfile));
158                } catch (FileNotFoundException e) {
159                        throw new JarLaunchException(e);
160                } catch (IOException e) {
161                        throw new JarLaunchException(e);
162                }
163                Manifest manifest = jarInputStream.getManifest();
164                mainClassName = manifest.getMainAttributes().getValue("Main-Class");
165                String jarClassPath = manifest.getMainAttributes().getValue(
166                                "Class-Path");
167                String[] jarClassPathElements = jarClassPath.split(" ");
168                classPath = new String[jarClassPathElements.length];
169                for (int i = 0; i < jarClassPathElements.length; i++) {
170                        classPath[i] = "file:" + workingDir + jarClassPathElements[i];
171                }
172        }
173
174        /**
175         * <p>
176         * Modifies the {@link ClassLoader} of the current VM such that it includes
177         * the class path defined in the Jar file's MANIFEST.
178         * </p>
179         *
180         * @throws JarLaunchException
181         *             thrown if modification of {@link ClassLoader} fails.
182         */
183        private void initClassLoader() throws JarLaunchException {
184                URLClassLoader classLoader = (URLClassLoader) ClassLoader
185                                .getSystemClassLoader();
186                Method method;
187                try {
188                        method = URLClassLoader.class.getDeclaredMethod("addURL",
189                                        new Class[] { URL.class });
190                } catch (SecurityException e) {
191                        throw new JarLaunchException(
192                                        "addURL method of URLClassLoader not accessible via reflection.");
193                } catch (NoSuchMethodException e) {
194                        throw new JarLaunchException(
195                                        "URLClassLoader does not have addURL method. Should be impossible!!");
196                }
197                method.setAccessible(true);
198
199                try {
200                        method.invoke(classLoader, new Object[] { new URL("file:"
201                                        + workingDir + jarfile) });
202                        for (String element : classPath) {
203                                method.invoke(classLoader, new Object[] { new URL(element) });
204                        }
205                } catch (IllegalArgumentException e) {
206                        throw new JarLaunchException(
207                                        "Illegal arguments for addURL method. Should be impossible!!");
208                } catch (MalformedURLException e) {
209                        throw new JarLaunchException(e);
210                } catch (IllegalAccessException e) {
211                        throw new JarLaunchException(
212                                        "addURL method of URLClassLoader not accessible via reflection.");
213                } catch (InvocationTargetException e) {
214                        e.printStackTrace();
215                }
216        }
217
218        /**
219         * <p>
220         * Executes the main function.
221         * </p>
222         *
223         * @throws JarLaunchException
224         *             thrown if execution of main function fails or the main
225         *             function itself throws an exception
226         */
227        private void runMain() throws JarLaunchException {
228                Class<?> mainClass;
229                try {
230                        mainClass = Class.forName(mainClassName);
231                } catch (ClassNotFoundException e) {
232                        throw new JarLaunchException("Main class not found: "
233                                        + mainClassName);
234                }
235                Method mainMethod;
236                try {
237                        mainMethod = mainClass.getMethod("main",
238                                        new Class[] { String[].class });
239                } catch (SecurityException e) {
240                        throw new JarLaunchException("Main method not accessible.");
241                } catch (NoSuchMethodException e) {
242                        throw new JarLaunchException("Main method not found.");
243                }
244                try {
245                        mainMethod.invoke(null, new Object[] { args });
246                } catch (IllegalArgumentException e) {
247                        throw new JarLaunchException(
248                                        "Illegal arguments for main method. Should be impossible!!");
249                } catch (IllegalAccessException e) {
250                        throw new JarLaunchException("Main method not accessible.");
251                } catch (InvocationTargetException e) {
252                        throw new JarLaunchException(e);
253                }
254        }
255}
Note: See TracBrowser for help on using the repository browser.