/*
* JBoss, Home of Professional Open Source
* Copyright 2010-2016, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.richfaces.tests.metamer.ftest.extension.finder;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;
import org.richfaces.tests.metamer.ftest.extension.finder.ClassFinder.Finder;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
public class SimpleClassFinder implements ClassFinder, Finder {
private static final String DOT = ".";
private static final String DOT_JAVA = DOT + "java";
private static final String DOT_NOT_REGEXP = "\\.";
private static final String EMPTY_STRING = "";
private static final String PACKAGE_STRING = "package";
private static final String SEMICOLON = ";";
private File directory;
private final List<Predicate<Class<?>>> filters = Lists.newArrayList();
private String folderWithJavaFiles;
private List<Class<?>> _findClasses(File fromFile) {
List<Class<?>> classes = Lists.newArrayList();
if (!fromFile.exists()) {
return classes;
}
for (File file : fromFile.listFiles()) {
if (file.isDirectory()) {
if (!file.getName().equals(DOT)) {
classes.addAll(_findClasses(file));
}
} else if (file.getName().endsWith(DOT_JAVA)) {
try {
classes.add(Class.forName(getFQNFromFile(file)));
} catch (ClassNotFoundException ex) {
throw new RuntimeException("ClassLoader does not contain needed class!", ex);
}
}
}
return classes;
}
@Override
public Finder findAllClassesFrom(String directory) {
return findAllClassesFrom(new File(directory));
}
@Override
public Finder findAllClassesFrom(File directory) {
this.directory = directory;
return this;
}
private List<Class<?>> findClasses(File directory) {
Iterable<Class<?>> result = _findClasses(directory);
for (Predicate<Class<?>> filter : filters) {
result = Iterables.filter(result, filter);
}
return Lists.newArrayList(result);
}
@Override
public Finder fromPackageStartingWith(final String packageName) {
filters.add(new Predicate<Class<?>>() {
@Override
public boolean apply(Class<?> t) {
return t.getName().startsWith(packageName);
}
});
return this;
}
private String getFQNFromFile(File javaFile) {
String path = javaFile.getAbsolutePath().replace(DOT_JAVA, EMPTY_STRING);
if (folderWithJavaFiles == null) {
folderWithJavaFiles = getFolderWithJavaFilesFromJavaFilePackage(javaFile);
}
return path.substring(path.indexOf(folderWithJavaFiles) + folderWithJavaFiles.length()).replaceAll("/", ".");
}
private String getFolderWithJavaFilesFromJavaFilePackage(File f) {
BufferedReader bw = null;
try {
bw = new BufferedReader(new FileReader(f));
String line;
while ((line = bw.readLine()) != null) {
if (line.startsWith(PACKAGE_STRING)) {// line with package?
// remove 'package' + white spaces + semicolon
// 'package x.y.z;' >>> 'x.y.z'
line = line.replaceAll(PACKAGE_STRING, EMPTY_STRING).trim().replace(SEMICOLON, EMPTY_STRING);
// 'x.y.z' >>> 'x/y/z'
line = line.replaceAll(DOT_NOT_REGEXP, File.separator);
// '/home/userx/java/files/to/check/org/x/y/z' >>> '/home/userx/java/files/to/check/'
line = f.getAbsolutePath().substring(0, f.getAbsolutePath().indexOf(line));
return line;
}
}
} catch (FileNotFoundException ex) {
throw new RuntimeException(ex);
} catch (IOException ex) {
throw new RuntimeException(ex);
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
throw new RuntimeException("Package was not found in java file");
}
@Override
public Set<Class<?>> scan() {
return Sets.newHashSet(findClasses(directory));
}
@Override
public Finder withAnnotation(final Class<? extends Annotation> annotationClass) {
filters.add(new Predicate<Class<?>>() {
@Override
public boolean apply(Class<?> t) {
return t.getAnnotation(annotationClass) != null;
}
});
return this;
}
@Override
public Finder withClassNameMatching(final String match) {
filters.add(new Predicate<Class<?>>() {
@Override
public boolean apply(Class<?> t) {
return t.getName().matches(match);
}
});
return this;
}
}