/* * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.utils; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class ClassUtils { /** * Attempts to list all the classes in the specified package as determined * by the context class loader * * @param pckgname * the package name to search * @return a list of classes that exist within that package * @throws ClassNotFoundException * if something went wrong */ public static ArrayList<Class<?>> getClassesForPackage( final ClassLoader cld, String pckgname) throws ClassNotFoundException { final ArrayList<Class<?>> classes = new ArrayList<Class<?>>(); try { if (cld == null) throw new ClassNotFoundException("Can't get class loader."); final Enumeration<URL> resources = cld.getResources(pckgname .replace('.', '/')); URLConnection connection; for (URL url = null; resources.hasMoreElements() && ((url = resources.nextElement()) != null);) { try { connection = url.openConnection(); if (connection instanceof JarURLConnection) { checkJarFile((JarURLConnection) connection, pckgname, classes); } else { try { checkDirectory( new File(URLDecoder.decode(url.getPath(), "UTF-8")), pckgname, classes); } catch (final UnsupportedEncodingException ex) { throw new ClassNotFoundException( pckgname + " does not appear to be a valid package (Unsupported encoding)", ex); } } } catch (final IOException ioex) { throw new ClassNotFoundException( "IOException was thrown when trying to get all resources for " + pckgname, ioex); } } } catch (final NullPointerException ex) { throw new ClassNotFoundException( pckgname + " does not appear to be a valid package (Null pointer exception)", ex); } catch (final IOException ioex) { throw new ClassNotFoundException( "IOException was thrown when trying to get all resources for " + pckgname, ioex); } return classes; } /** * Private helper method * * @param directory * The directory to start with * @param pckgname * The package name to search for. Will be needed for getting the * Class object. * @param classes * if a file isn't loaded but still is in the directory * @throws ClassNotFoundException */ private static void checkDirectory(File directory, String pckgname, ArrayList<Class<?>> classes) throws ClassNotFoundException { File tmpDirectory; if (directory.exists() && directory.isDirectory()) { final String[] files = directory.list(); for (final String file : files) { if (file.endsWith(".class")) { try { classes.add(Class.forName(pckgname + '.' + file.substring(0, file.length() - 6))); } catch (final NoClassDefFoundError e) { // do nothing. this class hasn't been found by the // loader, and we don't care. } } else if ((tmpDirectory = new File(directory, file)) .isDirectory()) { checkDirectory(tmpDirectory, pckgname + "." + file, classes); } } } } /** * Private helper method. * * @param connection * the connection to the jar * @param pckgname * the package name to search for * @param classes * the current ArrayList of all classes. This method will simply * add new classes. * @throws ClassNotFoundException * if a file isn't loaded but still is in the jar file * @throws IOException * if it can't correctly read from the jar file. */ private static void checkJarFile(JarURLConnection connection, String pckgname, ArrayList<Class<?>> classes) throws ClassNotFoundException, IOException { final JarFile jarFile = connection.getJarFile(); final Enumeration<JarEntry> entries = jarFile.entries(); String name; for (JarEntry jarEntry = null; entries.hasMoreElements() && ((jarEntry = entries.nextElement()) != null);) { name = jarEntry.getName(); if (name.contains(".class")) { name = name.substring(0, name.length() - 6).replace('/', '.'); if (name.contains(pckgname)) { classes.add(Class.forName(name)); } } } } }