Java tutorial
/** * Squidy Interaction Library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * Squidy Interaction Library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squidy Interaction Library. If not, see * <http://www.gnu.org/licenses/>. * * 2009 Human-Computer Interaction Group, University of Konstanz. * <http://hci.uni-konstanz.de> * * Please contact info@squidy-lib.de or visit our website * <http://www.squidy-lib.de> for further information. */ package org.squidy.manager.scanner; import java.io.File; import java.io.FilenameFilter; import java.lang.annotation.Annotation; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.squidy.SquidyException; import org.squidy.common.dynamiccode.DynamicCodeClassLoader; import org.squidy.manager.data.Processor; /** * <code>PackageScanner</code>. * * <pre> * Date: Feb 8, 2008 * Time: 12:29:40 PM * </pre> * * @author Roman Rädle, <a * href="mailto:Roman.Raedle@uni-konstanz.de">Roman. * Raedle@uni-konstanz.de</a>, University of Konstanz * @version $Id: PackageScanner.java 772 2011-09-16 15:39:44Z raedle $$ * * $Id: PackageScanner.java 772 2011-09-16 15:39:44Z raedle $ */ public class PackageScanner { // Logger to log info, error, debug,... messages. private static final Log LOG = LogFactory.getLog(PackageScanner.class); public static final Collection<Class<?>> CLASS_CACHE = new HashSet<Class<?>>(); /** * @param type * @return */ public static String[] findAllClassesWithProcessorAndType(Processor.Type type) { if (CLASS_CACHE.size() == 0) { Class<?>[] classes = findAllClassesWithAnnotation(Processor.class); for (Class<?> foundType : classes) { CLASS_CACHE.add(foundType); } } List<String> returnTypes = new ArrayList<String>(); for (Class<?> clazz : CLASS_CACHE) { Processor processor = (Processor) clazz.getAnnotation(Processor.class); for (Processor.Type ofType : processor.types()) { if (ofType.equals(type)) { returnTypes.add(clazz.getName()); } } } Collections.sort(returnTypes, new Comparator<String>() { public int compare(String o1, String o2) { String type1 = o1.substring(o1.lastIndexOf('.') + 1, o1.length()); String type2 = o2.substring(o2.lastIndexOf('.') + 1, o2.length()); return type1.compareTo(type2); } }); return returnTypes.toArray(new String[0]); } /** * @param annotationType * @return */ public static String[] findAllClassNamesWithAnnotation(Class<? extends Annotation> annotationType) { Class<?>[] foundTypes = findAllClassesWithAnnotation(annotationType); List<String> foundTypeNames = new ArrayList<String>(); for (Class<?> foundType : foundTypes) { if (!foundTypeNames.contains(foundType.getName())) { foundTypeNames.add(foundType.getName()); } } return foundTypeNames.toArray(new String[0]); } /** * @param <T> * @param annotationType * @return */ public static <T> Class<T>[] findAllClassesWithAnnotation(Class<? extends Annotation> annotationType) throws SquidyException { List<String> foundClassNames = new ArrayList<String>(); String packagePrefix = "org.squidy"; String thePackagePattern = packagePrefix.replace('.', '/') + "/[/\\w]*\\.class"; String classPath = System.getProperty("sun.boot.class.path") + System.getProperty("path.separator", ";") + System.getProperty("java.class.path"); URL[] classPathUrls = getClasspathUrls(classPath); for (URL url : classPathUrls) { File resource = urlToFile(url); // if (System.getProperty("os.name").contains("Windows") && // resource.startsWith("/")) { // resource = resource.substring(1, resource.length()); // } // resource = resource.replace('/', File.separatorChar); if (resource.getName().endsWith(".jar")) { foundClassNames.addAll(findAllClassesInJarContainedBy(thePackagePattern, resource)); } else { // Url is Directory findAllClassesInDirectoryContainedBy0(foundClassNames, packagePrefix, resource); } } List<Class<T>> types = new ArrayList<Class<T>>(); for (String className : foundClassNames) { try { Class<T> type = null; try { type = (Class<T>) PackageScanner.class.getClassLoader().loadClass(className); } catch (Exception e) { // if (LOG.isErrorEnabled()) { // LOG.error("Could not load class on first sight: " + e.getMessage()); // } type = (Class<T>) PackageScanner.class.getClassLoader().loadClass(className); } if (type.isAnnotationPresent(annotationType)) { types.add(type); } } catch (ClassNotFoundException e) { // throw new SquidyException(e); if (LOG.isErrorEnabled()) { LOG.error("Could not load class " + e.getMessage(), e); } } } return types.toArray(new Class[types.size()]); } public static String[] findAllClassesContainedBy(String... packages) { List<String> classes = new ArrayList<String>(); for (String thePackage : packages) { String thePackagePattern = thePackage.replace('.', '/') + "/[_$\\w]*.class"; String classPath = System.getProperty("sun.boot.class.path") + System.getProperty("path.separator", ";") + System.getProperty("java.class.path"); URL[] classPathUrls = getClasspathUrls(classPath); for (URL url : classPathUrls) { File resource = urlToFile(url); // if (System.getProperty("os.name").contains("Windows") && // resource.startsWith("/")) { // resource = resource.substring(1, resource.length()); // } // resource = resource.replace('/', File.separatorChar); if (resource.getName().endsWith(".jar")) { classes.addAll(findAllClassesInJarContainedBy(thePackagePattern, resource)); } else { // Url is Directory classes.addAll(findAllClassesInDirectoryContainedBy(thePackage, resource)); } } } Collections.sort(classes); return classes.toArray(new String[0]); } /** * @param classes * @param thePackage * @param file */ private static void findAllClassesInDirectoryContainedBy0(List<String> classes, String thePackage, File file) { try { if (!file.exists()) { return; } String thePackagePattern = thePackage.replace('.', '/'); File thePackageFolder = new File(file, thePackagePattern); if (!thePackageFolder.exists()) { return; } String[] fileNames = thePackageFolder.list(new FilenameFilter() { public boolean accept(File dir, String name) { return (name.endsWith(".java") && !name.endsWith("DummyValve.java")) || (name.endsWith(".class") && name.indexOf('$') == -1 && !name.equals("package-info.class")); } }); String[] packageNames = thePackageFolder.list(new FilenameFilter() { /* * (non-Javadoc) * * @see java.io.FilenameFilter#accept(java.io.File, * java.lang.String) */ public boolean accept(File dir, String name) { return dir.isDirectory(); } }); for (String packageName : packageNames) { findAllClassesInDirectoryContainedBy0(classes, thePackage + "." + packageName, file); } for (int i = 0; i < fileNames.length; i++) { if (fileNames[i].endsWith(".java")) { String fileName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".java")); fileNames[i] = thePackage + "." + fileName.replace(".java", ""); } else if (fileNames[i].endsWith(".class")) { String fileName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".class")); fileNames[i] = thePackage + "." + fileName.replace(".class", ""); } } // Avoid duplicates. for (String fileName : fileNames) { if (!classes.contains(fileName)) { classes.add(fileName); } } } catch (Exception e) { e.printStackTrace(); } } /** * @param thePackage * @param file * @return */ private static Collection<? extends String> findAllClassesInDirectoryContainedBy(String thePackage, File file) { List<String> classes = new ArrayList<String>(); try { if (!file.exists()) { return classes; } String thePackagePattern = thePackage.replace('.', '/'); File thePackageFolder = new File(file, thePackagePattern); if (!thePackageFolder.exists()) { return classes; } String[] fileNames = thePackageFolder.list(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".class") && name.indexOf('$') == -1 && !name.equals("package-info.class"); } }); for (int i = 0; i < fileNames.length; i++) { String fileName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".class")); fileNames[i] = thePackage + "." + fileName.replace(".class", ""); } return Arrays.asList(fileNames); } catch (Exception e) { e.printStackTrace(); } return classes; } /** * @param thePackagePattern * @param file * @return */ private static Collection<? extends String> findAllClassesInJarContainedBy(String thePackagePattern, File file) { List<String> classes = new ArrayList<String>(); try { if (!file.exists()) { // if (LOG.isDebugEnabled()) { // LOG.debug("Jar file does not exist. Skipping " + file); // } return classes; } JarFile jarFile = new JarFile(file); Enumeration<JarEntry> jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); if (jarEntry.getName().matches(thePackagePattern)) { String fileName = jarEntry.getName().substring(0, jarEntry.getName().lastIndexOf(".class")); fileName = fileName.replace('/', '.'); classes.add(fileName); } } } catch (Exception e) { e.printStackTrace(); } return classes; } /** * * @param classPath * @return */ private static URL[] getClasspathUrls(String classPath) { String[] classPaths = classPath.split(System.getProperty("path.separator", ";")); URL[] classPathUrls = new URL[classPaths.length + 1]; for (int i = 0; i < classPaths.length; i++) { String url = classPaths[i]; try { classPathUrls[i] = new File(url).toURI().toURL(); } catch (MalformedURLException e) { e.printStackTrace(); } } try { classPathUrls[classPathUrls.length - 1] = DynamicCodeClassLoader.DYNAMIC_CODE_REPOSITORY.toURL(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return classPathUrls; } /** * TODO: out-source me to a FileUtility or FileUtils helper class. * * @param url * @return */ private static File urlToFile(URL url) { URI uri; try { // this is the step that can fail, and so // it should be this step that should be fixed uri = url.toURI(); } catch (URISyntaxException e) { // OK if we are here, then obviously the URL did // not comply with RFC 2396. This can only // happen if we have illegal unescaped characters. // If we have one unescaped character, then // the only automated fix we can apply, is to assume // all characters are unescaped. // If we want to construct a URI from unescaped // characters, then we have to use the component // constructors: try { uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); } catch (URISyntaxException e1) { // The URL is broken beyond automatic repair throw new IllegalArgumentException("broken URL: " + url); } } return new File(uri); } }