    001/* ========================================================================
    002 * JCommon : a free general purpose class library for the Java(tm) platform
    003 * ========================================================================
    004 *
    005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006 *
    007 * Project Info:  http://www.jfree.org/jcommon/index.html
    008 *
    009 * This library is free software; you can redistribute it and/or modify it
    010 * under the terms of the GNU Lesser General Public License as published by
    011 * the Free Software Foundation; either version 2.1 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This library is distributed in the hope that it will be useful, but
    015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017 * License for more details.
    018 *
    019 * You should have received a copy of the GNU Lesser General Public
    020 * License along with this library; if not, write to the Free Software
    021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022 * USA.
    023 *
    024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025 * in the United States and other countries.]
    026 *
    027 * ------------------------
    028 * JavaSourceCollector.java
    029 * ------------------------
    030 * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
    031 *
    032 * Original Author:  Thomas Morgner;
    033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034 *
    035 * $Id: JavaSourceCollector.java,v 1.3 2005/10/18 13:32:20 mungady Exp $
    036 *
    037 * Changes
    038 * -------------------------
    039 * 21.06.2003 : Initial version
    040 *
    041 */
    042
    043package org.jfree.xml.generator;
    044
    045import java.io.File;
    046import java.io.FileFilter;
    047import java.lang.reflect.Modifier;
    048import java.util.ArrayList;
    049
    050import org.jfree.ui.ExtensionFileFilter;
    051import org.jfree.util.Log;
    052import org.jfree.util.ObjectUtilities;
    053
    054/**
    055 * The class collects all class-files and loads the class objects named
    056 * by these files.
    057 */
    058public class JavaSourceCollector implements SourceCollector {
    059
    060    /**
    061     * A file filter.
    062     */
    063    private static class CollectorFileFilter extends ExtensionFileFilter implements FileFilter {
    064        /**
    065         * Creates a new instance.
    066         *
    067         * @param description  the file description.
    068         * @param extension  the file extension.
    069         */
    070        public CollectorFileFilter(final String description, final String extension) {
    071            super(description, extension);
    072        }
    073    }
    074
    075    /** A file filter. */
    076    private CollectorFileFilter eff;
    077
    078    /** The file list. */
    079    private ArrayList fileList;
    080
    081    /** A list of ignored packages. */
    082    private ArrayList ignoredPackages;
    083
    084    /** A list of ignored base classes. */
    085    private ArrayList ignoredBaseClasses;
    086
    087    /** The start directory. */
    088    private File startDirectory;
    089
    090    /** The initial package name. */
    091    private String initialPackageName;
    092
    093    /**
    094     * Creates a new source collector.
    095     *
    096     * @param startDirectory  the start directory.
    097     */
    098    public JavaSourceCollector(final File startDirectory) {
    099        this(startDirectory, "");
    100    }
    101
    102    /**
    103     * Creates a new source collector.
    104     *
    105     * @param startDirectory  the base directory.
    106     * @param packageName  the base package name.
    107     */
    108    public JavaSourceCollector(final File startDirectory, final String packageName) {
    109        this.eff = new CollectorFileFilter("<ignore>", ".java");
    110        this.fileList = new ArrayList();
    111        this.startDirectory = startDirectory;
    112        this.initialPackageName = packageName;
    113        this.ignoredPackages = new ArrayList();
    114        this.ignoredBaseClasses = new ArrayList();
    115    }
    116
    117    /**
    118     * Adds a package that should be ignored.
    119     *
    120     * @param pkg  the package name.
    121     */
    122    public void addIgnoredPackage(final String pkg) {
    123        Log.debug (new Log.SimpleMessage("Added IgnPackage: " , pkg));
    124        this.ignoredPackages.add(pkg);
    125    }
    126
    127    /**
    128     * Adds a base class that should be ignored.
    129     *
    130     * @param baseClass  the base class name.
    131     */
    132    public void addIgnoredBaseClass(final String baseClass) {
    133        final Class loadedClass = loadClass(baseClass);
    134        if (loadedClass != null) {
    135            Log.debug (new Log.SimpleMessage("Added IgnClass: " , baseClass));
    136            this.ignoredBaseClasses.add(loadedClass);
    137        }
    138    }
    139
    140    /**
    141     * Adds a class to the list of ignored base classes.
    142     *
    143     * @param baseClass  the class.
    144     */
    145    public void addIgnoredBaseClass(final Class baseClass) {
    146        this.ignoredBaseClasses.add(baseClass);
    147    }
    148
    149    /**
    150     * Returns <code>true</code> if the named class is being ignored (because of the package that
    151     * it belongs to), and <code>false</code> otherwise.
    152     *
    153     * @param classname  the name of the class to test.
    154     *
    155     * @return A boolean.
    156     */
    157    protected boolean isIgnoredPackage(final String classname) {
    158        for (int i = 0; i < this.ignoredPackages.size(); i++) {
    159            final String ignoredPackage = (String) this.ignoredPackages.get(i);
    160            if (classname.startsWith(ignoredPackage)) {
    161                return true;
    162            }
    163        }
    164        return false;
    165    }
    166
    167    /**
    168     * Returns <code>true</code> if the named class is being ignored (because it is a descendant
    169     * of an ignored base class), and <code>false</code> otherwise.
    170     *
    171     * @param c  the class name.
    172     *
    173     * @return A boolean.
    174     */
    175    protected boolean isIgnoredBaseClass(final Class c) {
    176        for (int i = 0; i < this.ignoredBaseClasses.size(); i++) {
    177            final Class ignoredClass = (Class) this.ignoredBaseClasses.get(i);
    178            if (ignoredClass.isAssignableFrom(c)) {
    179                return true;
    180            }
    181        }
    182        return false;
    183    }
    184
    185    /**
    186     * Collects the files/classes.
    187     */
    188    public void collectFiles() {
    189        collectFiles(this.startDirectory, this.initialPackageName);
    190    }
    191
    192    /**
    193     * Collects the files/classes.
    194     *
    195     * @param directory  the starting directory.
    196     * @param packageName  the initial package name.
    197     */
    198    protected void collectFiles(final File directory, final String packageName) {
    199        final File[] files = directory.listFiles(this.eff);
    200        for (int i = 0; i < files.length; i++) {
    201            if (files[i].isDirectory()) {
    202                collectFiles(files[i], buildJavaName(packageName, files[i].getName()));
    203            }
    204            else {
    205                final String fname = files[i].getName();
    206                final String className = fname.substring(0, fname.length() - 5);
    207                final String fullName = buildJavaName(packageName, className);
    208                if (isIgnoredPackage(fullName)) {
    209                    Log.debug (new Log.SimpleMessage("Do not process: Ignored: ", className));
    210                    continue;
    211                }
    212                final Class jclass = loadClass(fullName);
    213                if (jclass == null || isIgnoredBaseClass(jclass)) {
    214                    continue;
    215                }
    216                if (jclass.isInterface() || Modifier.isAbstract(jclass.getModifiers())) {
    217                    Log.debug (new Log.SimpleMessage("Do not process: Abstract: ", className));
    218                    continue;
    219                }
    220                if (!Modifier.isPublic(jclass.getModifiers())) {
    221                    Log.debug (new Log.SimpleMessage("Do not process: Not public: ", className));
    222                    continue;
    223                }
    224                this.fileList.add(jclass);
    225            }
    226        }
    227    }
    228
    229    /**
    230     * Loads a class by its fully qualified name.
    231     *
    232     * @param name  the class name.
    233     *
    234     * @return The class (or <code>null</code> if there was a problem loading the class).
    235     */
    236    protected Class loadClass(final String name) {
    237        try {
    238            return ObjectUtilities.getClassLoader(JavaSourceCollector.class).loadClass(name);
    239        }
    240        catch (Exception e) {
    241            Log.warn (new Log.SimpleMessage("Do not process: Failed to load class:", name));
    242            return null;
    243        }
    244    }
    245
    246    /**
    247     * Creates a fully qualified Java class or package name.
    248     *
    249     * @param packageName  the base package name.
    250     * @param newPackage  the class/package name.
    251     *
    252     * @return The fully qualified package/class name.
    253     */
    254    protected String buildJavaName(final String packageName, final String newPackage) {
    255        if (packageName.length() == 0) {
    256            return newPackage;
    257        }
    258        else {
    259            return packageName + "." + newPackage;
    260        }
    261    }
    262
    263    /**
    264     * Returns the list of classes as an array.
    265     *
    266     * @return The list of classes.
    267     */
    268    public Class[] getClasses() {
    269        return (Class[]) this.fileList.toArray(new Class[0]);
    270    }
    271
    272}