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

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