package org.jbehave.eclipse.cache; import java.util.concurrent.Executor; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.jbehave.eclipse.util.FJ; import org.jbehave.eclipse.util.StringMatcher; import fj.F; public class JavaScanner<T> { private final IJavaProject project; private final JavaVisitor<T> visitor; private final Executor executor; private F<String, Boolean> packageRootNameFilter = FJ.alwaysTrue(); private F<String, Boolean> packageNameFilter = FJ.alwaysTrue(); private F<String, Boolean> classNameFilter = FJ.alwaysTrue(); private byte[] filterHash; public JavaScanner(IJavaProject project, JavaVisitor<T> visitor, Executor executor) { super(); this.project = project; this.visitor = visitor; this.executor = executor; } public void setPackageNameFilter(StringMatcher packageNameMatcher) { setPackageNameFilter(packageNameMatcher.compile()); } public void setPackageNameFilter(F<String, Boolean> packageNameFilter) { if(packageNameFilter==null) packageNameFilter = FJ.alwaysTrue(); this.packageNameFilter = packageNameFilter; } public void setClassNameFilter(StringMatcher classNameMatcher) { setClassNameFilter(classNameMatcher.compile()); } public void setClassNameFilter(F<String, Boolean> classNameFilter) { if(classNameFilter==null) classNameFilter = FJ.alwaysTrue(); this.classNameFilter = classNameFilter; } public void setPackageRootNameFilter(StringMatcher packageRootNameMatcher) { setPackageRootNameFilter(packageRootNameMatcher.compile()); } public void setPackageRootNameFilter(F<String, Boolean> packageRootNameFilter) { if(packageRootNameFilter==null) packageRootNameFilter = FJ.alwaysTrue(); this.packageRootNameFilter = packageRootNameFilter; } public void traversePackageFragmentRoots(final T argument) throws JavaModelException { for(IPackageFragmentRoot packageFragmentRoot : project.getAllPackageFragmentRoots()) { executor.execute(traverseAsRunnable(packageFragmentRoot, argument)); } } private Runnable traverseAsRunnable(final IPackageFragmentRoot packageFragmentRoot, final T argument) { return new Runnable() { public void run() { if(packageRootNameFilter.f(packageFragmentRoot.getElementName()) && visitor.visit(packageFragmentRoot, argument)) { try { traverse(packageFragmentRoot, argument); } catch (JavaModelException e) { } } } }; } protected void traverse(IPackageFragmentRoot packageFragmentRoot, T argument) throws JavaModelException { final T arg = visitor.argumentFor(packageFragmentRoot, argument); for(IJavaElement elem : packageFragmentRoot.getChildren()) { final IJavaElement jElem = elem; if(jElem.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { executor.execute(traverseAsRunnable((IPackageFragment)jElem, arg)); } } } private Runnable traverseAsRunnable(final IPackageFragment packageFragment, final T arg) { return new Runnable() { public void run() { if(packageNameFilter.f(packageFragment.getElementName()) && visitor.visit(packageFragment, arg)) { try { traverse(packageFragment, arg); } catch (JavaModelException e) { } } } }; } protected void traverse(IPackageFragment packageFragment, T argument) throws JavaModelException { boolean traverseCUnit = visitor.traverseCompilationUnit(packageFragment, argument); boolean traverseClassFile = visitor.traverseClassFile(packageFragment, argument); final T arg = visitor.argumentFor(packageFragment, argument); for(IJavaElement jElem : packageFragment.getChildren()) { switch(jElem.getElementType()) { case IJavaElement.COMPILATION_UNIT: if(!traverseCUnit) break; ICompilationUnit cunit = (ICompilationUnit)jElem; executor.execute(traverseAsRunnable(cunit, arg)); break; case IJavaElement.CLASS_FILE: if(!traverseClassFile) break; IClassFile classFile = (IClassFile)jElem; executor.execute(traverseAsRunnable(classFile, arg)); break; default: visitor.visit(jElem, arg); } } } private Runnable traverseAsRunnable(final IClassFile classFile, final T arg) { return new Runnable() { public void run(){ if(classNameFilter.f(classFile.getElementName()) && visitor.visit(classFile, arg)) { try { traverse(classFile, arg); } catch (JavaModelException e) { } } } }; } private Runnable traverseAsRunnable(final ICompilationUnit cunit, final T arg) { return new Runnable() { public void run() { if(classNameFilter.f(cunit.getElementName()) && visitor.visit(cunit, arg)) { try { traverse(cunit, arg); } catch (JavaModelException e) { } } } }; } protected void traverse(ICompilationUnit compilationUnit, T argument) throws JavaModelException { T arg = visitor.argumentFor(compilationUnit, argument); for(IJavaElement jElem : compilationUnit.getChildren()) { if(jElem.getElementType() == IJavaElement.TYPE) { IType type = (IType)jElem; if(visitor.visit(type, arg)) { traverseMethods(type, arg); } } else { visitor.visit(jElem, arg); } } } protected void traverse(IClassFile classFile, T argument) throws JavaModelException { T arg = visitor.argumentFor(classFile, argument); for(IJavaElement jElem : classFile.getChildren()) { if(jElem.getElementType() == IJavaElement.TYPE) { IType type = (IType)jElem; if(visitor.visit(type, arg)) { traverseMethods(type, arg); } } else { visitor.visit(jElem, arg); } } } protected void traverseMethods(IType type, T argument) throws JavaModelException { T arg = visitor.argumentFor(type, argument); for(IJavaElement jElem : type.getChildren()) { if(jElem.getElementType() == IJavaElement.METHOD) { IMethod method = (IMethod)jElem; visitor.visit(method, arg); } else { visitor.visit(jElem, arg); } } } /** * Define the filter hash. It may be used to optimize scanning between two runs * if the filtering is not changed. It is the responsibility of the caller to * provides a suitable and valid hash according to the current filtering * configuration. * * @param filterHash */ public void setFilterHash(byte[] filterHash) { this.filterHash = filterHash; } /** * Returns the filter hash. It may be used to optimize scanning between two runs * if the filtering is not changed. It is the responsibility of the caller to * provides a suitable and valid hash according to the current filtering * configuration. * * @return */ public byte[] getFilterHash() { return filterHash; } }