/* * ${file_name} of project cpdetector, <purpose> * Copyright ${year} (C) Achim Westermann, created on 11.04.2004. * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this collection are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the cpDetector code in [sub] packages info.monitorenter and * cpdetector. * * The Initial Developer of the Original Code is * Achim Westermann <achim.westermann@gmx.de>. * * Portions created by the Initial Developer are Copyright (c) 2007 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** * */ package info.monitorenter.cpdetector.io; import info.monitorenter.util.Entry; import info.monitorenter.util.FileUtil; import info.monitorenter.util.StringUtil; import java.io.File; import java.io.FileFilter; import java.lang.reflect.Modifier; import java.net.URL; import java.net.URLClassLoader; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; /** * @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann </a> * */ public class ClassFileFilterIsA implements IClassFileFilter, FileFilter { protected Set superclasses = new TreeSet(); protected File[] classpaths; /** * */ public ClassFileFilterIsA() { super(); this.scanClassPath(); } private void scanClassPath() { URLClassLoader urlcl = (URLClassLoader) this.getClass().getClassLoader(); URL[] urls = urlcl.getURLs(); // TODO: remove debug printing. List collect = new LinkedList(); File f; for (int i = 0; i < urls.length; i++) { f = this.urlToFile(urls[i]); if (f != null) { collect.add(f); } } this.classpaths = (File[]) collect.toArray(new File[collect.size()]); } private File urlToFile(URL url) { File ret = null; if (url.getProtocol().equalsIgnoreCase("file")) { ret = new File(url.getFile()); } return ret; } /** * <p> * Adds the given argument to the acceptance filter. The filter will only * return true for a Class a in the following condition: * * <pre> * (a instanceof c) * </pre> * * <p> * This method may be called several times. The accept method will return true * if the given Class is derived from any of the internal super classes. * </p> * * @param c * A non-final Class. * @return true, if the given class could be added. It is not added, if * argument c is final (makes no sense as a final class is never a * superclass) or the given Class was already contained. * */ public synchronized boolean addSuperClass(Class c) { boolean ret = false; if ((c.getModifiers() & Modifier.FINAL) != 0) { } else { ret = this.superclasses.add(c); } return ret; } /** * @return true if the given Class is derived from any of the internal super * classes. * @see #addSuperClass(Class) * @see IClassFileFilter#accept(Class) */ public boolean accept(Class c) { boolean ret = false; Iterator it = this.superclasses.iterator(); while (it.hasNext() && !ret) { ret = ((Class) it.next()).isAssignableFrom(c); } return ret; } /** * Tries to detect (from the file path and the Classloaders urls) and load the * corresponding class and delegates to {@link #accept(Class)}. * * @see java.io.FileFilter#accept(java.io.File) */ public boolean accept(File pathname) { boolean ret = false; if (pathname.isDirectory()) { ret = true; } else { String ext = FileUtil.cutExtension(pathname.getName()).getValue().toString(); if (ext.equals("jar")) { // is a "directory": ret = true; } else if (ext.equals("class")) { Class cl = this.forFile(pathname); if (cl != null) { ret = this.accept(cl); } } else { ret = false; } } return ret; } private Class forFile(File f) { Class ret = null; Map.Entry searchpath = new Entry("", ""); String filename = f.getAbsolutePath(); for (int i = 0; i < this.classpaths.length && (searchpath.getKey().equals("")); i++) { searchpath = StringUtil.prefixIntersection(this.classpaths[i].getAbsolutePath(), filename); } if (!searchpath.getKey().equals("")) { // the given file might be a full match of the classpath (e.g. a jarfile) if (!searchpath.getValue().equals("")) { // remove trailing .class: // bad reuse of filename filename = (String) FileUtil.cutExtension((String) searchpath.getValue()).getKey(); // file path to class syntax. First worked with "file.separator", but the file may be some // facade (e.g. a jar entry) that sticks to unix syntax even on windows machines.... filename = (filename).replace('/', '.'); filename = (filename).replace('\\', '.'); // remove potential leading dots: if (filename.charAt(0) == '.') { filename = filename.substring(1); } try { ret = Class.forName(filename); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } return ret; } public static void main(String[] args) { ClassFileFilterIsA test = new ClassFileFilterIsA(); System.out.println("Adding interface: " + FileFilter.class.getName() + " to instance test (" + test.getClass().getName() + ")"); test.addSuperClass(FileFilter.class); System.out.println("test.accept(" + test.getClass().getName() + " : " + test.accept(test.getClass())); System.out.println("test.accept(new File(\"bin/cpdetector/io/ClassfileFilterIsA.class\").getAbsoluteFile()) : " + test.accept(new File("bin/cpdetector/io/ClassfileFilterIsA.class").getAbsoluteFile())); } }