View Javadoc

1   package com.explosion.utilities.classes;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.net.MalformedURLException;
6   import java.net.URL;
7   import java.util.ArrayList;
8   import java.util.Enumeration;
9   import java.util.List;
10  import java.util.jar.JarEntry;
11  import java.util.jar.JarFile;
12  
13  import org.apache.log4j.LogManager;
14  import org.apache.log4j.Logger;
15  
16  import com.explosion.utilities.FileIterator;
17  
18  /*
19   * =============================================================================
20   * 
21   * Copyright 2004 Stephen Cowx
22   * 
23   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
24   * use this file except in compliance with the License. You may obtain a copy of
25   * the License at
26   * 
27   * http://www.apache.org/licenses/LICENSE-2.0
28   * 
29   * Unless required by applicable law or agreed to in writing, software
30   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
31   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
32   * License for the specific language governing permissions and limitations under
33   * the License.
34   * 
35   * =============================================================================
36   */
37  
38  /***
39   * @author Stephen This class contains some handy methods for working with
40   *         classes and types Created on Apr 17, 2004
41   */
42  public class ClassUtilities
43  {
44  
45      private static Logger log = LogManager.getLogger(ClassUtilities.class);
46  
47      /***
48       * This method finds all of the classes of a particular type in a particular
49       * set if Files. The file scan be directories or libraries. The libraries
50       * must be in jar or zip format
51       * 
52       * @param jarFile
53       * @param superClass
54       * @return @throws Exception
55       */
56      public static List findClassesOfType(Class superClass, List classPath) throws Exception
57      {
58          /* Initialise a classloader with all the files on this classpath */
59          log.debug("Creating new loader.");
60          String[] resolvedClasspath = resolveClasspath(classPath);
61          StandardClassLoader loader = new StandardClassLoader(resolvedClasspath);
62          loader.setDelegate(true);
63          
64          return findClassesOfType(superClass, loader, classPath);
65      }
66      
67      /***
68       * @param classPath
69       * @throws MalformedURLException
70       * @throws IOException
71       */
72      private static String[] resolveClasspath(List classPath) throws MalformedURLException, IOException
73      {
74          /*
75           * Initiliase a list to hold the resolved classpath until we can create
76           * the repo for the classloader
77           */
78          List resolvedClasspath = new ArrayList();
79          
80          /* Resolve the classpath */ 
81          for (int i=0;i<classPath.size();i++)
82          {
83              File file = (File) classPath.get(i);
84              if (file.isFile() && file.exists() && (file.getName().endsWith(".jar") || file.getName().endsWith(".zip"))
85                 || (file.isDirectory() && file.exists()))
86              {
87                  // A bit of a complicated if but bascially quite simple.
88                  // If it is a .jar file or a .zip file or a directory which exists
89                  // then add it to the repo
90                  URL url = new URL("file", null, new File(file.getAbsolutePath()).getCanonicalPath());
91                  resolvedClasspath.add("file:///" + file.getAbsolutePath());                
92              }
93          }
94          
95          String[] repo = new String[resolvedClasspath.size()];
96          if (resolvedClasspath.size() > 0)
97          {
98      	  return (String[]) resolvedClasspath.toArray(repo);
99      	}
100         
101         return new String[0];
102     }
103 
104     /***
105      * This method finds all of the classes of a particular type in the classpath of a 
106      * 
107      * @param jarFile, this must be a jar file or a zip file
108      * @param superClass
109      * @return @throws Exception
110      */
111     public static List findClassesOfType(Class superClass, ClassLoader loader, List files) throws Exception
112     {
113         ArrayList classNames = new ArrayList();
114         log.debug("called findClassesOfType");
115         
116         if (loader != null)
117         {
118            log.debug("loader is not null and there are " + files.size() + " files on the classpath.");
119            ClassLoader originalLoader = Thread.currentThread().getContextClassLoader();
120            Thread.currentThread().setContextClassLoader(loader);
121            
122            for (int i=0;i<files.size();i++)
123            {
124                File theFile = (File) files.get(i);
125                if (theFile.isFile())
126                {
127                    JarFile file = new JarFile(theFile.getAbsolutePath());
128                    log.debug("Checking  " + file.getName() + " for instances of " + superClass.getName());
129                    Enumeration en = file.entries();
130                    while (en.hasMoreElements())
131                    {
132                        JarEntry entry = (JarEntry) en.nextElement();
133                        log.debug("Checking entry " + entry.getName());
134                        if (entry.getName().endsWith(".class"))
135                        {
136                            log.debug("Examining " + entry.getName());
137                            try
138                            {
139                                String name = entry.getName().substring(0, entry.getName().length() - 6).replaceAll("/",".");
140                                log.debug("Loading class " + name);
141                                
142                                Class c = Class.forName(name,true, loader);
143                                if (superClass.isAssignableFrom(c))
144                                {
145                                    log.debug("Yes, " + c.getName() + " is a " + c.getName());
146                                    classNames.add(c.getName());
147                                }
148                                else
149                                {
150                                    log.debug("No, " + c.getName() + " is a " + c.getName());
151                                }
152                            } 
153                            catch (Throwable e)
154                            {
155                                log.error("Exception checking for classes of type " + superClass.getName(), e);
156                            }
157                        }
158                    }
159 
160                }
161            }
162            Thread.currentThread().setContextClassLoader(originalLoader);
163             
164         }
165 
166         return classNames;
167     }
168     
169     /***
170      * This method finds all of the classes of a particular type in a particular
171      * JarFile
172      * 
173      * @param jarFile, this must be a jar file or a zip file
174      * @param superClass
175      * @return @throws Exception
176      */
177     public static List findClassesOfType(Class superClass, String jarFilePath) throws Exception
178     {
179         ArrayList classNames = new ArrayList();
180         
181         if (jarFilePath != null)
182         {
183             JarFile file = new JarFile(jarFilePath);
184             log.debug("Checking  " + file.getName() + " for instances of " + superClass.getName());
185             StandardClassLoader loader = null;
186             Enumeration en = file.entries();
187             while (en.hasMoreElements())
188             {
189                 JarEntry entry = (JarEntry) en.nextElement();
190                 if (entry.getName().endsWith(".class"))
191                 {
192                     log.debug("Examining " + entry.getName());
193                     try
194                     {
195                         /*
196                          * Lazy initialise a JarFileClassLoader to read this
197                          * class and otherrs in this jarfile
198                          */
199                         if (loader == null)
200                         {
201                             log.debug("Creating new loader.");
202                             URL url = new URL("file", null, new File(jarFilePath).getCanonicalPath());
203                             String[] repo = {url.toString()};
204                             loader = new StandardClassLoader(repo);
205                             loader.setDelegate(true);
206                         }
207                          
208                         String name = entry.getName().substring(0, entry.getName().length() - 6).replaceAll("/",".");
209                         log.debug("Loading class " + name);
210                         Class c = Class.forName(name,false, loader);
211                         if (superClass.isAssignableFrom(c))
212                         {
213                             log.debug("Yes, " + c.getName() + " is a " + c.getName());
214                             classNames.add(c.getName());
215                         }
216                         else
217                         {
218                             log.debug("No, " + c.getName() + " is a " + c.getName());
219                         }
220                     } catch (Exception e)
221                     {
222                         log.error("Exception checking for classes of type " + superClass.getName(), e);
223                     }
224                 }
225             }
226 
227         }
228 
229         return classNames;
230     }
231     
232     /***
233      * This method finds all of the classes of a particular type in a particular
234      * JarFile
235      * 
236      * @param directory, this must be a directory with class files in it
237      * @param superClass
238      * @return @throws Exception
239      */
240     public static List findClassesOfType(Class superClass, File directory) throws Exception
241     {
242         ArrayList classNames = new ArrayList();
243         
244         if (directory != null && directory.isDirectory())
245         {
246             log.debug("Checking  " + directory.getName() + " for instances of " + superClass.getName());
247             StandardClassLoader loader = null;
248             FileIterator it = new FileIterator(directory.getAbsolutePath(),"//.class",true,true, true);
249             while (it.hasNext())
250             {
251                 File file = it.next();
252                   log.debug("Examining " + file.getName());
253                     try
254                     {
255                         /*
256                          * Lazy initialise a JarFileClassLoader to read this
257                          * class and otherrs in this jarfile
258                          */
259                         if (loader == null)
260                         {
261                             log.debug("Creating new loader.");
262                             URL url = new URL("file", null, directory.getCanonicalPath());
263                             String[] repo = {url.toString()};
264                             loader = new StandardClassLoader(repo);
265                             loader.setDelegate(true);
266                         }
267                          
268                         String name = file.getAbsolutePath().substring(directory.getAbsolutePath().length(), file.getAbsolutePath().length() - 6).replaceAll("/",".");
269                         log.debug("Loading class " + name);
270                         Class c = Class.forName(name,false, loader);
271                         if (superClass.isAssignableFrom(c))
272                         {
273                             log.debug("Yes, " + c.getName() + " is a " + c.getName());
274                             classNames.add(c.getName());
275                         }
276                         else
277                         {
278                             log.debug("No, " + c.getName() + " is a " + c.getName());
279                         }
280                     } catch (Exception e)
281                     {
282                         log.error("Exception checking for classes of type " + superClass.getName(), e);
283                     }                
284             }
285 
286         }
287 
288         return classNames;
289     }
290     
291     /***
292      * This method finds all of the classes of a particular type in a particular
293      * JarFile
294      * 
295      * @param jarFile
296      * @param superClass
297      * @return @throws Exception
298      */
299     public static boolean containsClassWithName(String name, String jarFilePath, boolean caseSensitive) throws Exception
300     {
301         ArrayList classNames = new ArrayList();
302         
303         if (jarFilePath != null)
304         {
305             JarFile file = new JarFile(jarFilePath);
306             log.debug("Checking  " + file.getName() + " for classes with name " + name);
307             
308             Enumeration en = file.entries();
309             while (en.hasMoreElements())
310             {
311                 JarEntry entry = (JarEntry) en.nextElement();
312                 if (entry.getName().endsWith(".class"))
313                 {
314                     log.debug("Examining " + entry.getName());
315                     try
316                     {
317                         String foundName = entry.getName().substring(0, entry.getName().length() - 6).replaceAll("/",".");
318                         if ( !caseSensitive && foundName.equalsIgnoreCase(name))
319                            return true;
320                         else if (caseSensitive && foundName.equals(name))
321                            return true;
322                         
323                     } catch (Exception e)
324                     {
325                         log.error("Exception checking for classes with a name " + name, e);
326                     }
327                 }
328             }
329         }
330         
331         return false;
332     }
333 
334     /***
335      * This method determines if srgument1 is an instance of argument2
336      *  
337      */
338     public static boolean instanceOf(Class theClass, Class instanceOf)
339     {
340         log.debug("Is " + theClass + " an instance of " + instanceOf);
341         ArrayList superClasses = new ArrayList();
342 
343         getSuperClasses(theClass, superClasses);
344 
345         for (int i = 0; i < superClasses.size(); i++)
346         {
347             Class superClass = (Class) superClasses.get(i);
348             if (superClass.getName().equals(instanceOf.getName()))
349                 return true;
350         }
351 
352         return false;
353     }
354 
355     /***
356      * This is a recursive method which fills up the provided list with all of
357      * the super classes and super interfaces of the class provided
358      *  
359      */
360     private static void getSuperClasses(Class theClass, List fillMeUp)
361     {
362         log.debug("Getting superclasses of " + theClass);
363         /* Get interfaces first */
364         Class[] theClassInterfaces = theClass.getInterfaces();
365 
366         for (int zx = 0; zx < theClassInterfaces.length; zx++)
367         {
368             fillMeUp.add(theClassInterfaces[zx]);
369             getSuperClasses(theClassInterfaces[zx], fillMeUp);
370         }
371 
372         /* Get its super class */
373         Class superClass = theClass.getSuperclass();
374         if (superClass != null)
375         {
376             fillMeUp.add(superClass);
377             Class[] superClassInterfaces = superClass.getInterfaces();
378 
379             /* Add the interfaces first */
380             for (int zx = 0; zx < superClassInterfaces.length; zx++)
381             {
382                 fillMeUp.add(superClassInterfaces[zx]);
383                 getSuperClasses(superClassInterfaces[zx], fillMeUp);
384             }
385 
386             getSuperClasses(superClass, fillMeUp);
387         }
388     }
389 }