    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
    043    package org.jfree.xml.generator;
    044
    045    import java.io.File;
    046    import java.io.FileFilter;
    047    import java.lang.reflect.Modifier;
    048    import java.util.ArrayList;
    049
    050    import org.jfree.ui.ExtensionFileFilter;
    051    import org.jfree.util.Log;
    052    import org.jfree.util.ObjectUtilities;
    053
    054    /**
    055     * The class collects all class-files and loads the class objects named
    056     * by these files.
    057     */
    058    public 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    }