/** * PackageLoader.java * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.expeditee.reflection; import java.io.File; import java.io.IOException; import java.net.JarURLConnection; import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; public class PackageLoader { // The following is adapted from: // http://stackoverflow.com/questions/1456930/how-do-i-read-all-classes-from-a-java-package-in-the-classpath public static List> getClassesNew(String packageName) throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ArrayList names = new ArrayList(); final ArrayList> classes = new ArrayList>(); String realPackageName = packageName; packageName = packageName.replace(".", "/"); URL packageURL = classLoader.getResource(packageName); if (packageURL.getProtocol().equals("jar")) { // build jar file name, then loop through zipped entries String jarFileNameUndecoded = packageURL.getFile(); try { JarURLConnection ju_connection = (JarURLConnection) packageURL .openConnection(); JarFile jf = ju_connection.getJarFile(); Enumeration jarEntries = jf.entries(); while (jarEntries.hasMoreElements()) { String entryName = jarEntries.nextElement().getName(); if (entryName.startsWith(packageName)) { if (entryName.endsWith(".class") && !entryName.contains("$")) { // Deal with situation where the class found might // be a further sub-package // e.g. for "org.expeditee.action" // there is: // org/expeditee/action/widgets/Chart.class // which would produce a value of 'entryName' as // widgets/Chart.class entryName = entryName.substring(0, entryName.length() - 6); // 6 = '.class' entryName = entryName.replace('/', '.'); names.add(entryName); classes.add(Class.forName(entryName)); } } } } catch (Exception e) { System.err.println("Failed to decode jar file: " + jarFileNameUndecoded); e.printStackTrace(); } } else if (packageURL.getProtocol().equals("bundleresource")) { try { final URLConnection urlConnection = packageURL.openConnection(); final Class c = urlConnection.getClass(); final java.lang.reflect.Method toInvoke = c.getMethod("getFileURL"); final URL fileURL = (URL)toInvoke.invoke(urlConnection); final File folder = new File(fileURL.getFile()); final List files = findFiles(folder); for (final String s : files) { String entryName = realPackageName + s; if (entryName.endsWith(".class") && !entryName.contains("$")) { entryName = entryName.substring(0, entryName.lastIndexOf('.')); entryName = entryName.replace('/', '.'); names.add(entryName); try { final Class tmpc = Class.forName(entryName); classes.add(tmpc); } catch (NoClassDefFoundError e) { System.err.println("Unable to instantiate class " + entryName); System.err.println(e.getMessage()); } } } } catch (final Exception e) { System.err.println("Failed to process file: " + packageName); e.printStackTrace(); } } else { // loop through files in classpath String packageURLString = packageURL.toString(); try { URI uri = new URI(packageURLString); File folder = new File(uri.getPath()); List files = findFiles(folder); for (String s : files) { String entryName = realPackageName + s; if (entryName.endsWith(".class") && !entryName.contains("$")) { entryName = entryName.substring(0, entryName.lastIndexOf('.')); entryName = entryName.replace('/', '.'); names.add(entryName); classes.add(Class.forName(entryName)); } } } catch (Exception e) { System.err.println("Failed to process file: " + packageURLString); e.printStackTrace(); } } return classes; } /** * Finds all files in a directory and it's subdirectories * * @param directory * The folder to start in * * @return A list of Strings containing file paths relative to the starting * directory */ private static List findFiles(File directory) { List files = new LinkedList(); for (File f : directory.listFiles()) { if (f.isDirectory()) { for (String s : findFiles(f)) { files.add(f.getName() + "/" + s); } } else { files.add(f.getName()); } } return files; } public static List> getClasses(final String pckgname) throws ClassNotFoundException { final ArrayList> classes = new ArrayList>(); // Must be a forward slash for loading resources final String packagePath = pckgname.replace('.', '/'); if (System.getProperty("eclipse.expeditee.home") == null) { final ClassLoader cld = Thread.currentThread() .getContextClassLoader(); if (cld == null) { throw new ClassNotFoundException("Can't get class loader."); } URL resource = null; try { final Enumeration resources = cld .getResources(packagePath); while (resources.hasMoreElements()) { URL url = resources.nextElement(); resource = url; } } catch (IOException e) { System.err .println("A IO Error has occured when trying to use the ContextClassLoader" + System.getProperty("line.separator") + "Are you running from within Eclipse? (or just not with Jar) Then make sure your" + " 'eclipse.expeditee.home' property is set correctly. It is currently: '" + System.getProperty("eclipse.expeditee.home") + "'" + System.getProperty("line.separator") + "You can set it by adding a VM argument. " + "Example: -Declipse.expeditee.home=D:\\Desktop\\Research\\expeditee-svn"); e.printStackTrace(); } if (resource == null) { throw new ClassNotFoundException("No resource for " + packagePath); } final File directory = new File(resource.getFile()); final int splitPoint = directory.getPath().indexOf('!'); if (splitPoint > 0) { String jarName = directory.getPath().substring( "file:".length(), splitPoint); // Windows HACK if (jarName.indexOf(":") >= 0) jarName = jarName.substring(1); if (jarName.indexOf("%20") > 0) { jarName = jarName.replace("%20", " "); } // System.out.println("JarName:" + jarName); try { final JarFile jarFile = new JarFile(jarName); final Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { final ZipEntry entry = (ZipEntry) entries.nextElement(); final String className = entry.getName(); if (className.startsWith(packagePath)) { if (className.endsWith(".class") && !className.contains("$")) { // The forward slash below is a forwards slash // for // both windows and linux String class_forname = className.substring(0, className.length() - 6); class_forname = class_forname.replace('/', '.'); classes.add(Class.forName(class_forname)); } } } try { jarFile.close(); } catch (IOException e) { System.err .println("Error attempting to close Jar file"); e.printStackTrace(); } } catch (IOException e) { System.err.println("Error Instantiating Jar File Object"); e.printStackTrace(); } } else { System.err .println("A Error has occured when trying to use a Jar file to find actions or agents." + System.getProperty("line.separator") + "Are you running from within Eclipse? (or just not with Jar) Then make sure your" + " 'eclipse.expeditee.home' property is set correctly. It is currently: '" + System.getProperty("eclipse.expeditee.home") + "'" + System.getProperty("line.separator") + "You can set it by adding a VM argument. " + "Example: -Declipse.expeditee.home=D:\\Desktop\\Research\\expeditee-svn"); } } else { String eclipse_expeditee_home = System.getProperty( "eclipse.expeditee.home", ""); String full_package_path = eclipse_expeditee_home + File.separator + "bin" + File.separator + packagePath; final File directory = new File(full_package_path); if (directory.exists()) { // Get the list of the files contained in the package String[] files = directory.list(); for (int i = 0; i < files.length; i++) { // we are only interested in .class files if (files[i].endsWith(".class") && !files[i].contains("$") && !files[i].equals("Actions.class")) { // removes the .class extension classes.add(Class.forName(pckgname + files[i].substring(0, files[i].length() - 6))); } } } else { throw new ClassNotFoundException("The package '" + pckgname + "' in the directory '" + directory + "' does not appear to be a valid package"); } } return classes; } }