/*
* Copyright 2015 S. Webber
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.oakgp.function;
import static java.nio.file.FileVisitResult.CONTINUE;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/** Tree-walks a directory to find all classes assignable from (i.e. extend or implement) a specified class. */
class SubClassFinder extends SimpleFileVisitor<Path> {
private final Class<?> parentClass;
private final List<Class<?>> result = new ArrayList<>();
static List<Class<?>> find(Class<?> parentClass, String directoryName) throws IOException {
SubClassFinder w = new SubClassFinder(parentClass);
Files.walkFileTree(new File(directoryName).toPath(), w);
return w.result;
}
SubClassFinder(Class<?> parentClass) {
this.parentClass = parentClass;
}
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
File file = path.toFile();
Optional<Class<?>> optional = getSubClass(file);
if (optional.isPresent()) {
result.add(optional.get());
}
return CONTINUE;
}
private Optional<Class<?>> getSubClass(File file) {
if (!isJavaSource(file)) {
return Optional.empty();
}
String className = getClassName(file);
Class<?> c = createClass(className);
if (isSubClass(c)) {
return Optional.of(c);
} else {
return Optional.empty();
}
}
private Class<?> createClass(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Could not create " + className, e);
}
}
private boolean isSubClass(Class<?> c) {
return isConcrete(c) && isAssignableFromParentClass(c);
}
private boolean isConcrete(Class<?> c) {
return !Modifier.isAbstract(c.getModifiers());
}
private boolean isAssignableFromParentClass(Class<?> c) {
return parentClass.isAssignableFrom(c);
}
private boolean isJavaSource(File f) {
String name = f.getName();
return name.endsWith(".java") && !name.equals("package-info.java");
}
private String getClassName(File javaFile) {
String filePath = removeFileExtension(javaFile.getPath()).replace(File.separatorChar, '.');
int packagePos = filePath.lastIndexOf("org.oakgp");
return filePath.substring(packagePos, filePath.length());
}
private String removeFileExtension(String fileName) {
int extensionPos = fileName.lastIndexOf('.');
if (extensionPos == -1) {
return fileName;
} else {
return fileName.substring(0, extensionPos);
}
}
}