View Javadoc

1   /*
2    * File:    JarClassLoader.java
3    * Created: 29.05.2007 11:18:33 
4    *
5    * Copyright 2007 Michal Burda.
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20   */
21  
22  package net.sf.webmancer.util.lang;
23  
24  import java.io.ByteArrayOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.util.HashMap;
28  import java.util.jar.JarFile;
29  import java.util.zip.ZipEntry;
30  
31  /**
32   * @author Michal Burda
33   *
34   */
35  public class JarClassLoader extends ClassLoader {
36      /**
37       * 
38       */
39      private JarFile jarFiles[];
40      
41      /**
42       * 
43       */
44      private HashMap<String, Boolean> fromDefault;
45  
46      /**
47       * Constructs the JarClassLoader.
48       *
49       * @param jarFileNames
50       * @param whatLoadFromDefault
51       * @throws IOException
52       */
53      public JarClassLoader(String[] jarFileNames, String[] whatLoadFromDefault) throws IOException {
54          jarFiles = new JarFile[jarFileNames.length];
55          for (int i = 0; i < jarFileNames.length; i++) {
56              jarFiles[i] = new JarFile(jarFileNames[i]);
57          }
58          fromDefault = new HashMap<String, Boolean>();
59          for (String element: whatLoadFromDefault) {
60              fromDefault.put(element, true);
61          }
62      }
63  
64      /**
65       * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
66       */
67      @Override
68      protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
69          Class c = findLoadedClass(name);
70          if (c == null && !fromDefault.containsKey(name)) {
71              c = findClass(name);
72          }
73          if (c == null) {
74              c = super.loadClass(name, resolve);
75          } else {
76              if (resolve) {
77                  resolveClass(c);
78              }
79          }
80          return c;
81      }
82  
83      /**
84       * @see java.lang.ClassLoader#findClass(java.lang.String)
85       */
86      @Override
87      public Class<?> findClass(String name) {
88          byte[] b = loadClassData(name);
89          if (b == null) {
90              return null;
91          } else {
92              return defineClass(name, b, 0, b.length);
93          }
94      }
95  
96      /**
97       * @param name
98       * @return
99       */
100     private synchronized byte[] loadClassData(String name) {
101         for (JarFile element: jarFiles) {
102             byte[] result = tryJarfile(element, name);
103             if (result != null) {
104                 return result;
105             }
106         }
107         return null;
108     }
109 
110     /**
111      * @param jarFile
112      * @param name
113      * @return
114      */
115     private byte[] tryJarfile(JarFile jarFile, String name) {
116         ZipEntry entry = jarFile.getEntry(formatName(name));
117         if (entry == null) {
118             return null;
119         }
120         try {
121             InputStream input = jarFile.getInputStream(entry);
122             ByteArrayOutputStream output = new ByteArrayOutputStream();
123             byte[] buf = new byte[1024];
124             int r;
125             while ((r = input.read(buf)) > 0) {
126                 output.write(buf, 0, r);
127             }
128             input.close();
129             output.close();
130             return output.toByteArray();
131         } catch (IOException e) {
132             // TODO Auto-generated catch block
133             e.printStackTrace();
134         }
135         return null;
136 
137     }
138 
139     /**
140      * @param className
141      * @return
142      */
143     private String formatName(String className) {
144         return className.replace('.', '/') + ".class";
145     }
146 }