1336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustpackage org.testng.internal;
2336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
3336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.io.File;
4336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.io.FileFilter;
5336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.io.IOException;
6c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstormimport java.io.UnsupportedEncodingException;
7cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohlimport java.lang.reflect.Method;
8336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.net.JarURLConnection;
9336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.net.URL;
10cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohlimport java.net.URLConnection;
11336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.net.URLDecoder;
12336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.util.Enumeration;
13ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.Iterator;
14336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.util.List;
15ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.Vector;
16336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.util.jar.JarEntry;
17336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.util.jar.JarFile;
18336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport java.util.regex.Pattern;
19ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beust
20ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport org.testng.TestNG;
21ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport org.testng.collections.Lists;
22336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
23336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust/**
24336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust * Utility class that finds all the classes in a given package.
250f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin *
26336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust * Created on Feb 24, 2006
27336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
28336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust */
29336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustpublic class PackageUtils {
307276490328112458615706cc32cff29353d20170the.mindstorm  private static String[] s_testClassPaths;
310f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
32cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl  /** The additional class loaders to find classes in. */
3384a155a8aefdfa32796b3dfed8964bdf4bd097f4Stas Gromov  private static final List<ClassLoader> m_classLoaders = new Vector<>();
34cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl
35cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl  /** Add a class loader to the searchable loaders. */
36cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl  public static void addClassLoader(final ClassLoader loader) {
37cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    m_classLoaders.add(loader);
38cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl  }
39cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl
40336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /**
41336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   *
42336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * @param packageName
43336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * @return The list of all the classes inside this package
44336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * @throws IOException
45336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   */
460f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin  public static String[] findClassesInPackage(String packageName,
47336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      List<String> included, List<String> excluded)
480f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    throws IOException
49336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  {
50336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String packageOnly = packageName;
51336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    boolean recursive = false;
52336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (packageName.endsWith(".*")) {
53336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      packageOnly = packageName.substring(0, packageName.lastIndexOf(".*"));
54336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      recursive = true;
55336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
560f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
570a050892401fb27d1c7629e37fe9c8796ea5a349Cédric Beust    List<String> vResult = Lists.newArrayList();
58c239c0e20e9d99cc41a8cd9f884ae5654bbec339Konstantin Savin    String packageDirName = packageOnly.replace('.', '/') + (packageOnly.length() > 0 ? "/" : "");
59c239c0e20e9d99cc41a8cd9f884ae5654bbec339Konstantin Savin
60cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl
6184a155a8aefdfa32796b3dfed8964bdf4bd097f4Stas Gromov    Vector<URL> dirs = new Vector<>();
62cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    // go through additional class loaders
6384a155a8aefdfa32796b3dfed8964bdf4bd097f4Stas Gromov    Vector<ClassLoader> allClassLoaders = new Vector<>();
64cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
65cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    if (contextClassLoader != null) {
66cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      allClassLoaders.add(contextClassLoader);
67cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    }
68cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    if (m_classLoaders != null) {
69cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      allClassLoaders.addAll(m_classLoaders);
70cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    }
71cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl
72cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    int count = 0;
73cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    for (ClassLoader classLoader : allClassLoaders) {
74cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      ++count;
75cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      if (null == classLoader) {
76cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl        continue;
77cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      }
78cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      Enumeration<URL> dirEnumeration = classLoader.getResources(packageDirName);
79cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      while(dirEnumeration.hasMoreElements()){
80cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl        URL dir = dirEnumeration.nextElement();
81cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl        dirs.add(dir);
82cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      }
83cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    }
84cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl
85cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    Iterator<URL> dirIterator = dirs.iterator();
86cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl    while (dirIterator.hasNext()) {
87cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      URL url = dirIterator.next();
88336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      String protocol = url.getProtocol();
89c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm      if(!matchTestClasspath(url, packageDirName, recursive)) {
90c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm        continue;
91c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm      }
920f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
93336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      if ("file".equals(protocol)) {
94336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        findClassesInDirPackage(packageOnly, included, excluded,
95336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                URLDecoder.decode(url.getFile(), "UTF-8"),
96336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                recursive,
97336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                vResult);
98336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
99336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      else if ("jar".equals(protocol)) {
100336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
101336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        Enumeration<JarEntry> entries = jar.entries();
102336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        while (entries.hasMoreElements()) {
103336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          JarEntry entry = entries.nextElement();
104336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          String name = entry.getName();
105336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          if (name.charAt(0) == '/') {
106336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            name = name.substring(1);
107336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          }
108336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          if (name.startsWith(packageDirName)) {
109336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            int idx = name.lastIndexOf('/');
110336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            if (idx != -1) {
111336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust              packageName = name.substring(0, idx).replace('/', '.');
112336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            }
1130f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
11484a155a8aefdfa32796b3dfed8964bdf4bd097f4Stas Gromov            if (recursive || packageName.equals(packageOnly)) {
115336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust              //it's not inside a deeper dir
11684a155a8aefdfa32796b3dfed8964bdf4bd097f4Stas Gromov              Utils.log("PackageUtils", 4, "Package name is " + packageName);
117336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust              if (name.endsWith(".class") && !entry.isDirectory()) {
118336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                String className = name.substring(packageName.length() + 1, name.length() - 6);
1194dd3d8657dd6a9cf09617c7f5fb9338c7df316d6the.mindstorm                Utils.log("PackageUtils", 4, "Found class " + className + ", seeing it if it's included or excluded");
120336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                includeOrExcludeClass(packageName, className, included, excluded, vResult);
121336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust              }
122336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            }
123336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          }
124336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        }
125336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
126cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      else if ("bundleresource".equals(protocol)) {
12741ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust        try {
12841ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          Class params[] = {};
12941ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          // BundleURLConnection
13041ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          URLConnection connection = url.openConnection();
13141ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          Method thisMethod = url.openConnection().getClass()
13241ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust              .getDeclaredMethod("getFileURL", params);
13341ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          Object paramsObj[] = {};
13441ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          URL fileUrl = (URL) thisMethod.invoke(connection, paramsObj);
13541ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          findClassesInDirPackage(packageOnly, included, excluded,
13641ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust              URLDecoder.decode(fileUrl.getFile(), "UTF-8"), recursive, vResult);
13741ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust        } catch (Exception ex) {
13841ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust          // ignore - probably not an Eclipse OSGi bundle
13941ddbc20b3d60f08d93b82a744a8010414a2fcb7Cédric Beust        }
140cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl      }
141336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
1420f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1430f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    String[] result = vResult.toArray(new String[vResult.size()]);
144336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result;
145336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
146336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
1477276490328112458615706cc32cff29353d20170the.mindstorm  private static String[] getTestClasspath() {
1488664905a47b4f139d20e83ba4937c8135b9d2aadCédric Beust    if (null != s_testClassPaths) {
1497276490328112458615706cc32cff29353d20170the.mindstorm      return s_testClassPaths;
1507276490328112458615706cc32cff29353d20170the.mindstorm    }
1510f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
152ebadb61b818627fe0e9de16896c2e3215bcb0328Cédric Beust    String testClasspath = System.getProperty(TestNG.TEST_CLASSPATH);
1538664905a47b4f139d20e83ba4937c8135b9d2aadCédric Beust    if (null == testClasspath) {
1547276490328112458615706cc32cff29353d20170the.mindstorm      return null;
1557276490328112458615706cc32cff29353d20170the.mindstorm    }
1560f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1577276490328112458615706cc32cff29353d20170the.mindstorm    String[] classpathFragments= Utils.split(testClasspath, File.pathSeparator);
1587276490328112458615706cc32cff29353d20170the.mindstorm    s_testClassPaths= new String[classpathFragments.length];
1590f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1607276490328112458615706cc32cff29353d20170the.mindstorm    for(int i= 0; i < classpathFragments.length; i++)  {
1617276490328112458615706cc32cff29353d20170the.mindstorm      String path= null;
1627276490328112458615706cc32cff29353d20170the.mindstorm      if(classpathFragments[i].toLowerCase().endsWith(".jar") || classpathFragments[i].toLowerCase().endsWith(".zip")) {
1637276490328112458615706cc32cff29353d20170the.mindstorm        path= classpathFragments[i] + "!/";
1647276490328112458615706cc32cff29353d20170the.mindstorm      }
1657276490328112458615706cc32cff29353d20170the.mindstorm      else {
1667276490328112458615706cc32cff29353d20170the.mindstorm        if(classpathFragments[i].endsWith(File.separator)) {
1677276490328112458615706cc32cff29353d20170the.mindstorm          path= classpathFragments[i];
1687276490328112458615706cc32cff29353d20170the.mindstorm        }
1697276490328112458615706cc32cff29353d20170the.mindstorm        else {
1707276490328112458615706cc32cff29353d20170the.mindstorm          path= classpathFragments[i] + "/";
1717276490328112458615706cc32cff29353d20170the.mindstorm        }
1727276490328112458615706cc32cff29353d20170the.mindstorm      }
1730f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1747276490328112458615706cc32cff29353d20170the.mindstorm      s_testClassPaths[i]= path.replace('\\', '/');
1757276490328112458615706cc32cff29353d20170the.mindstorm    }
1760f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1777276490328112458615706cc32cff29353d20170the.mindstorm    return s_testClassPaths;
1787276490328112458615706cc32cff29353d20170the.mindstorm  }
1790f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
180c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm  private static boolean matchTestClasspath(URL url, String lastFragment, boolean recursive) {
1817276490328112458615706cc32cff29353d20170the.mindstorm    String[] classpathFragments= getTestClasspath();
1827276490328112458615706cc32cff29353d20170the.mindstorm    if(null == classpathFragments) {
183c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm      return true;
184c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    }
1850b2ac5eab08098da2c2b63d4a3f87ba72ad5d6a1nullin
186c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    String fileName= null;
187c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    try {
188c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm      fileName= URLDecoder.decode(url.getFile(), "UTF-8");
189c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    }
190c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    catch(UnsupportedEncodingException ueex) {
191c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm      ; // ignore. should never happen
192c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    }
1930f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
194c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    for(String classpathFrag: classpathFragments) {
1957276490328112458615706cc32cff29353d20170the.mindstorm      String path=  classpathFrag + lastFragment;
1967276490328112458615706cc32cff29353d20170the.mindstorm      int idx= fileName.indexOf(path);
1977276490328112458615706cc32cff29353d20170the.mindstorm      if((idx == -1) || (idx > 0 && fileName.charAt(idx-1) != '/')) {
1987276490328112458615706cc32cff29353d20170the.mindstorm        continue;
199c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm      }
2000f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2010f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if(fileName.endsWith(classpathFrag + lastFragment)
2027276490328112458615706cc32cff29353d20170the.mindstorm          || (recursive && fileName.charAt(idx + path.length()) == '/')) {
203c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm        return true;
204c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm      }
205c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    }
206c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm
207c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm    return false;
208c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm  }
209c4b6d9a15b51a7cca13140961292367c8dd84d45the.mindstorm
210336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private static void findClassesInDirPackage(String packageName,
211336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                              List<String> included,
212336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                              List<String> excluded,
213336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                              String packagePath,
214336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                              final boolean recursive,
215336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                              List<String> classes) {
216336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    File dir = new File(packagePath);
2170f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
218336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (!dir.exists() || !dir.isDirectory()) {
219336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      return;
220336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
2210f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
222336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    File[] dirfiles = dir.listFiles(new FileFilter() {
2234a2d63441b758ad719e84dfd2e148223faf7601bCédric Beust          @Override
224336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          public boolean accept(File file) {
22527fb384d559a927244134facd776fded48731aafCédric Beust            return (recursive && file.isDirectory())
22627fb384d559a927244134facd776fded48731aafCédric Beust              || (file.getName().endsWith(".class"))
22727fb384d559a927244134facd776fded48731aafCédric Beust              || (file.getName().endsWith(".groovy"));
228336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          }
229336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        });
2300f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2314dd3d8657dd6a9cf09617c7f5fb9338c7df316d6the.mindstorm    Utils.log("PackageUtils", 4, "Looking for test classes in the directory: " + dir);
232336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (File file : dirfiles) {
233336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      if (file.isDirectory()) {
234f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust        findClassesInDirPackage(makeFullClassName(packageName, file.getName()),
235336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                included,
236336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                excluded,
237336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                file.getAbsolutePath(),
238336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                recursive,
239336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                classes);
240336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
241336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      else {
24227fb384d559a927244134facd776fded48731aafCédric Beust        String className = file.getName().substring(0, file.getName().lastIndexOf("."));
243f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust        Utils.log("PackageUtils", 4, "Found class " + className
244f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust            + ", seeing it if it's included or excluded");
245336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        includeOrExcludeClass(packageName, className, included, excluded, classes);
246336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
247336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
248336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
249336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
250f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust  private static String makeFullClassName(String pkg, String cls) {
251f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust    return pkg.length() > 0 ? pkg + "." + cls : cls;
252f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust  }
253f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust
2540f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin  private static void includeOrExcludeClass(String packageName, String className,
2550f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      List<String> included, List<String> excluded, List<String> classes)
256336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  {
2576c8bbde0bc3db4b97bfa371acfa889a51b0c57d4Cédric Beust    if (isIncluded(packageName, included, excluded)) {
2584dd3d8657dd6a9cf09617c7f5fb9338c7df316d6the.mindstorm      Utils.log("PackageUtils", 4, "... Including class " + className);
259f4bff96ccba4529912e8f66458338e94505859c1Cédric Beust      classes.add(makeFullClassName(packageName, className));
260336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
261336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    else {
2624dd3d8657dd6a9cf09617c7f5fb9338c7df316d6the.mindstorm      Utils.log("PackageUtils", 4, "... Excluding class " + className);
263336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
264336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
265336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
266336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /**
267336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * @return true if name should be included.
268336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   */
2690f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin  private static boolean isIncluded(String name,
270336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      List<String> included, List<String> excluded)
271336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  {
272336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    boolean result = false;
2730f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
274336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    //
275336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    // If no includes nor excludes were specified, return true.
276336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    //
277336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (included.size() == 0 && excluded.size() == 0) {
278336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      result = true;
2790f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    }
280336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    else {
281336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      boolean isIncluded = PackageUtils.find(name, included);
282336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      boolean isExcluded = PackageUtils.find(name, excluded);
283336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      if (isIncluded && !isExcluded) {
284336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        result = true;
285336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
286336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      else if (isExcluded) {
287336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        result = false;
288336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
289336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      else {
290336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        result = included.size() == 0;
291336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
292336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
293336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result;
294336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
295336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
296336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private static boolean find(String name, List<String> list) {
297336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (String regexpStr : list) {
2980f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if (Pattern.matches(regexpStr, name)) {
2990f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        return true;
3000f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
301336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
302336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return false;
303336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
304cf247f3636af0892736f481bdb245fd12b7b819aAleksander Pohl}
305