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 }