KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > yagga > util > BootstrapJarClassLoader


1 /*
2  * This file is part of MiniInstaller, a self installer builder for Java
3  * Copyright (C) 2002 Walter Gamba
4  * mailto:walter@yagga.net
5  * http://www.yagga.net/java/miniinstaller
6  *
7  * MiniInstaller is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * MiniInstaller is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * As the time of writing, the GNU General Public Licene can be
22  * found at http://www.gnu.org/licenses/gpl.txt
23  *
24  */

25 package net.yagga.util;
26
27 import java.net.*;
28 import java.lang.reflect.Method JavaDoc;
29 import java.lang.reflect.Modifier JavaDoc;
30 import java.lang.reflect.InvocationTargetException JavaDoc;
31 import java.util.jar.Attributes JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.util.jar.*;
34 import java.util.zip.*;
35 import java.util.*;
36 import java.io.*;
37
38 /**
39  * A META class loader for loading jar files. interesting the class can load jar
40  * classes from different JARs and from the same jar (if this class is jarred
41  * with other jars... <BR>
42  * This class is a collection of methods and features found in class
43  * MetaJarClassLoader, MetaJarResource, JarClassLoader and MetaUt. THey are
44  * reduced and compacted here for convenience.
45  *
46  * @author Walter Gamba
47  * @see MetaJarResource
48  * @see JarClassLoader
49  * @see MetaUt
50  * @see MetaJarClassLoader
51  */

52 public class BootstrapJarClassLoader extends ClassLoader JavaDoc
53 {
54     /**
55      * Descrizione del metodo
56      *
57      * @param argv Description of the Parameter
58      * @author Walter Gamba
59      */

60     public static void main(String JavaDoc argv[]) {
61
62         String JavaDoc arg = "sample.conf";
63         if (argv.length > 0)
64             arg = argv[0];
65         String JavaDoc[] args = {arg};
66
67         //new MiniInstaller(arg);
68

69         try {
70             BootstrapJarClassLoader jcl = new BootstrapJarClassLoader("MiniInstaller.jar");
71             //String name=jcl.getMainClassName();
72
//System.out.println("Main Class is: "+jcl.getMainClassName() );
73
jcl.invokeClass("net.yagga.miniinstaller.MiniInstaller", args);
74         }
75         catch (ClassNotFoundException JavaDoc e) {
76             System.err.println("1 Class not found: " + e);
77         }
78         //catch (IOException e) { Ut.error("1 IO exurlnd: "+e ); }
79
catch (NoSuchMethodException JavaDoc e) {
80             System.err.println("1 Class does not define a 'main' method: " + e);
81         }
82         catch (InvocationTargetException JavaDoc e) {
83             System.err.println("1 Invoke excpt: " + e);
84             System.err.println("1 Invoke excpt: " + e.getTargetException());
85         }
86
87     }
88
89
90     private String JavaDoc jarFile;
91
92     //private URL jarURL;
93
private Hashtable htSizes = new Hashtable();
94
95     /**
96      * Legge l'attributo actualJarName dell object BootstrapJarClassLoader
97      *
98      * @return Il valore di actualJarName
99      * @author Walter Gamba
100      */

101     public String JavaDoc getActualJarName() {
102         if(executingFromJar)
103             return jarJarFile;
104         else
105             return jarFile;
106     }
107
108     //for self referencing jar
109
private boolean executingFromJar = false;
110     //true if this class is executed inside a jar
111
private Hashtable metaJarContent = new Hashtable();
112     private String JavaDoc jarJarFile;
113     private Manifest metaManifest = null;
114
115     /**
116      * constructor: decides if the jar filename passed belongs to a jar that: a) is
117      * outside the current class/jar file b) is inside the JAR file where this
118      * class is also stored.
119      *
120      * @param jFile jar file to load and use in classpath
121      * @author Walter Gamba
122      */

123     public BootstrapJarClassLoader(String JavaDoc jFile) {
124         super();
125         this.jarFile = jFile;
126
127         try {
128             URL u = this.getClass().getResource("/" + jarFile);
129             URLConnection uc = u.openConnection();
130             if (uc instanceof JarURLConnection) {
131
132                 //System.out.println(jarFile+" is a JAR in a calling JAR ");
133
executingFromJar = true;
134                 JarURLConnection juc = (JarURLConnection)uc;
135                 //jar file is containing file, not the one specified..
136
//decode to take care of spaces.. just in case
137
jarJarFile = URLDecoder.decode(jarFile);
138                 //trying to get this name..
139
jarFile = juc.getJarFileURL().getFile();
140
141                 //now normalize jar FILE taking care of spaces
142
//this fixes "bug" with JDK1.4 which has a more correct Class.getResource
143
// (it is not a bug, actually. It was wrong in JDK1.3 and prior...
144
jarFile=URLDecoder.decode(jarFile);
145
146                 //System.out.println("JARCLASSLOAD URL="+u+", file="+jarFile+", file2="+jarJarFile);
147
//read in sizes for top level jar, anyway
148
initTopJarSizes();
149                 //reads jar-in-jar file
150
readJarInJar();
151             }
152             else {
153                 //if (uc instanceof FileURLConnection){
154

155                 //System.out.println(jarFile+" is a JAR outside the calling class/jar ");
156
executingFromJar = false;
157                 initTopJarSizes();
158                 //jarFile=
159
}
160             //System.out.println("JAR FILE is "+jarFile);
161
//System.out.println("JARCLASSLOD+ URL="+jarURL+", file="+jarFile);
162
}
163         catch (IOException JavaDoc ioe) {
164             System.err.println("Error getting file from file" + jarFile + ":" + ioe);
165             jarFile = "";
166         }
167     }
168
169     /**
170      * reads in self contained jar file this is the case if this class is jarred
171      * with other jar files so: FOO.jar +--Installer.class
172      * +--MetaJarClassLoader.class +--PACK1.jar +--ClassIWantToInvoke.class <===
173      *
174      * @author Walter Gamba
175      */

176     private void readJarInJar() {
177         try {
178             //read entry from top-level jar.
179
//the bytes read are bytes of a JAR file contained in this top-level jar file
180
byte[] jarE = readBytesFromTopJar(jarJarFile);
181
182             //save jar contained in this jar in a temp file
183
//so save PACK1.jar in a temp file
184

185             //to get temp dir
186
String JavaDoc tmpDir = System.getProperty("java.io.tmpdir");
187
188             File jarInJarFile = new File(tmpDir, jarJarFile);
189             FileOutputStream fout = new FileOutputStream(jarInJarFile.getCanonicalPath());
190             //save bytes in temp jar file
191
for (int i = 0; i < jarE.length; i++)
192                 fout.write(jarE[i]);
193             fout.close();
194             fout = null;
195
196             //reads in temp jar file sizes (in this case, PACK1.jar)
197
Hashtable sizes = new Hashtable();
198             JarFile jf = new JarFile(jarInJarFile);
199             try {
200                 Enumeration e = jf.entries();
201                 while (e.hasMoreElements()) {
202                     JarEntry ze = (JarEntry)e.nextElement();
203                     //System.out.println("Entry:"+ze+", Size="+ze.getSize()+", CSize="+ze.getCompressedSize());
204
sizes.put(ze.getName(), new Integer JavaDoc((int)ze.getSize()));
205                 }
206                 //reads in Manifesdt
207
metaManifest = jf.getManifest();
208                 jf.close();
209             }
210             catch (IOException JavaDoc ioe) {
211                 System.err.println("Error reading sizes in '" + fout + "':" + ioe);
212             }
213
214             //once I've read dims i can read data
215
//and thus I can safely delete temp jar file
216
jarInJarFile.delete();
217
218             //read in data from byte array
219
ByteArrayInputStream bais = new ByteArrayInputStream(jarE);
220             JarInputStream jis = new JarInputStream(bais);
221             JarEntry je = null;
222             while ((je = jis.getNextJarEntry()) != null) {
223                 if (je.isDirectory())
224                     continue;
225
226                 int size = (int)je.getSize();
227                 if (size == -1)
228                     size = ((Integer JavaDoc)sizes.get(je.getName())).intValue();
229
230                 byte[] b = new byte[(int)size];
231                 int rb = 0;
232                 int chunk = 0;
233                 while (((int)size - rb) > 0) {
234                     chunk = jis.read(b, rb, (int)size - rb);
235                     if (chunk == -1)
236                         break;
237                     rb += chunk;
238                 }
239                 //save data in hash map
240
metaJarContent.put(je.getName(), b);
241
242                 //System.out.println("Meta entry+ URL="+je+", sz="+size);
243
}
244             jis.close();
245         }
246         catch (FileNotFoundException fnfe) {
247             System.err.println("ERROR:" + fnfe);
248         }
249         catch (IOException JavaDoc ioe) {
250             System.err.println("ERROR:" + ioe);
251         }
252     }
253
254     /**
255      * Returns the name of the jar file main class, or null if no "Main-Class"
256      * manifest attributes was defined.
257      *
258      * @return Il valore di mainClassName
259      * @author Walter Gamba
260      */

261     public String JavaDoc getMainClassName() {
262         try {
263             if (executingFromJar) {
264                 return metaManifest != null ? metaManifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS) : null;
265             }
266             else {
267                 JarFile jf = new JarFile(jarFile);
268                 Manifest mf = jf.getManifest();
269                 return mf != null ? mf.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS) : null;
270             }
271         }
272         catch (IOException JavaDoc ioe) {
273             System.err.println("IOE getting main class " + ioe);
274             return null;
275         }
276     }
277
278     /**
279      * Invokes the application in this jar file given the name of the main class
280      * and an array of arguments. The class must define a static method "main"
281      * which takes an array of String arguemtns and is of return type "void".
282      *
283      * @param name Description of the Parameter
284      * @param args Description of the Parameter
285      * @exception ClassNotFoundException Description of the Exception
286      * @exception NoSuchMethodException Description of the Exception
287      * @exception InvocationTargetException Description of the Exception
288      * @author Walter Gamba
289      */

290     public void invokeClass(String JavaDoc name, String JavaDoc[] args)
291         throws ClassNotFoundException JavaDoc,
292             NoSuchMethodException JavaDoc,
293             InvocationTargetException JavaDoc {
294         Class JavaDoc c = loadClass(name);
295
296         //System.err.println("Class is "+c);
297
Method JavaDoc m = c.getMethod("main", new Class JavaDoc[]{args.getClass()});
298         //System.err.println("Method is "+m);
299
m.setAccessible(true);
300         int mods = m.getModifiers();
301         if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
302                 !Modifier.isPublic(mods)) {
303             throw new NoSuchMethodException JavaDoc("main");
304         }
305         try {
306             m.invoke(null, new Object JavaDoc[]{args});
307         }
308         catch (IllegalAccessException JavaDoc e) {
309             // This should not happen, as we have disabled access checks
310
}
311     }
312
313     /**
314      * method taht actually reads the class from raw bytes
315      *
316      * @param className Description of the Parameter
317      * @return Description of the Return Value
318      * @exception ClassNotFoundException Description of the Exception
319      * @author Walter Gamba
320      */

321     protected Class JavaDoc findClass(String JavaDoc className)
322         throws ClassNotFoundException JavaDoc {
323         String JavaDoc urlName = className.replace('.', '/') + ".class";
324         //System.out.println("findClass:"+className);
325

326         // byte[] b1=getClassFromJar(urlName);
327
byte b1[] = null;
328         if (executingFromJar)
329             b1 = (byte[])metaJarContent.get(urlName);
330         else
331             b1 = readBytesFromTopJar(urlName);
332         if (b1 == null) {
333             System.err.println("Class '" + className + "' not found.");
334             return null;
335         }
336         try {
337             return defineClass(className, b1, 0, b1.length);
338         }
339         catch (ClassFormatError JavaDoc cfe) {
340             System.err.println("'" + className + "':" + cfe);
341         }
342         return null;
343     }
344
345     /**
346      * read sizes fror top-level JAR file. This can be the sole JAR file, or it can
347      * be used to read further into the JAR, for another JAR file JARRED :)
348      *
349      * @author Walter Gamba
350      */

351     private void initTopJarSizes() {
352         try {
353             JarFile zf = new JarFile(jarFile);
354             Enumeration e = zf.entries();
355             while (e.hasMoreElements()) {
356                 JarEntry ze = (JarEntry)e.nextElement();
357                 //System.out.println("Entry:"+ze+", Size="+ze.getSize()+", CSize="+ze.getCompressedSize());
358
htSizes.put(ze.getName(), new Integer JavaDoc((int)ze.getSize()));
359             }
360             zf.close();
361         }
362         catch (IOException JavaDoc ioe) {
363             System.err.println("TOP Error reading sizes in '" + jarFile + "':" + ioe);
364         }
365     }
366
367     /**
368      * reads bytes from Top Jar file. Can be used standalone, or to read in another
369      * JAr file and then, using readJarInJar, filling the metaJarContent hashtable
370      *
371      * @param entryName Description of the Parameter
372      * @return Description of the Return Value
373      * @author Walter Gamba
374      */

375     public byte[] readBytesFromTopJar(String JavaDoc entryName) {
376         try {
377             // extract resources and put them into the hashtable.
378
JarInputStream zis = getTopJIS();
379             JarEntry ze = null;
380             while ((ze = zis.getNextJarEntry()) != null) {
381                 if (ze.isDirectory())
382                     continue;
383
384                 int size = (int)ze.getSize();
385                 if (size == -1)
386                     size = ((Integer JavaDoc)htSizes.get(ze.getName())).intValue();
387
388                 //System.out.println("Entry:"+ze+", Size="+ze.getSize()+", CSize="+ze.getCompressedSize());
389
if (ze.getName().equals(entryName)) {
390                     //System.out.println(">>>>Entry:"+cl+", Size="+ze.getSize()+", CSize="+ze.getCompressedSize());
391
byte[] b = new byte[(int)size];
392                     int rb = 0;
393                     int chunk = 0;
394                     while (((int)size - rb) > 0) {
395                         chunk = zis.read(b, rb, (int)size - rb);
396                         if (chunk == -1)
397                             break;
398                         rb += chunk;
399                     }
400                     zis.close();
401                     return b;
402                 }
403             }
404             zis.close();
405         }
406         catch (NullPointerException JavaDoc e) {
407             System.err.println("'" + jarFile + "':(done)" + e);
408         }
409         catch (FileNotFoundException e) {
410             System.err.println("'" + jarFile + "':" + e);
411         }
412         catch (IOException JavaDoc e) {
413             System.err.println("'" + jarFile + "':" + e);
414         }
415         return null;
416     }
417
418     /**
419      * get top level JAR input stream
420      *
421      * @return Il valore di topJIS
422      * @author Walter Gamba
423      */

424     private JarInputStream getTopJIS() {
425         //
426
try {
427             JarFile jf = new JarFile(jarFile);
428             if (jf != null)
429                 return new JarInputStream(new FileInputStream(jarFile));
430         }
431         catch (Exception JavaDoc e) {
432             System.err.println("ERROR:" + e);
433         }
434         try {
435             //System.out.println("getTopJIS "+jarFile);
436
InputStream is = openResource(jarFile);
437             return new JarInputStream(is);
438         }
439         catch (IOException JavaDoc io) {
440             System.err.println("IOE:" + io);
441         }
442         return null;
443     }
444
445     /**
446      * Descrizione del metodo
447      *
448      * @param filename Description of the Parameter
449      * @return Description of the Return Value
450      * @author Walter Gamba
451      */

452     private InputStream openResource(String JavaDoc filename) {
453         try {
454             InputStream is = BootstrapJarClassLoader.class.getResourceAsStream("/" + filename);
455             is.available();
456             //to generate null ptr exceptio
457
return is;
458         }
459         catch (java.io.IOException JavaDoc e) {
460             System.err.println("RM2: file not found:" + filename);
461             System.exit(1);
462         }
463         catch (NullPointerException JavaDoc e2) {
464             System.err.println("RM2: file not found!" + filename);
465             e2.printStackTrace();
466             System.exit(1);
467         }
468         return null;
469     }
470
471 }
472
473
Popular Tags