diff --git a/src/main/java/com/avaje/ebeaninternal/api/ClassPathSearchService.java b/src/main/java/com/avaje/ebeaninternal/api/ClassPathSearchService.java
new file mode 100644
index 000000000..28af3e606
--- /dev/null
+++ b/src/main/java/com/avaje/ebeaninternal/api/ClassPathSearchService.java
@@ -0,0 +1,46 @@
+package com.avaje.ebeaninternal.api;
+
+import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
+import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This interface allows us to have more than one ClassPathSearch
+ * to scan the resources by a customized way.
+ *
+ * @author Kefeng Deng (deng@51any.com)
+ */
+public interface ClassPathSearchService {
+
+ /**
+ * Initialize this ClassPathSearchService with given parameters
+ *
+ * @param classLoader is current classLoader
+ * @param filter is filter
+ * @param matcher
+ * @param classPathReaderClassName
+ */
+ void init(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher, String classPathReaderClassName);
+
+ /**
+ * Searches the class path for all matching classes.
+ *
+ * @return a collection of all matching classes
+ * @throws IOException if a resource is un-reachable
+ */
+ List> findClasses() throws IOException;
+
+ /**
+ * Return the set of jars that contained classes that matched.
+ */
+ Set getJarHits();
+
+ /**
+ * Return the set of packages that contained classes that matched.
+ */
+ Set getPackageHits();
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/BootupClassPathSearch.java b/src/main/java/com/avaje/ebeaninternal/server/core/BootupClassPathSearch.java
index cb23d286f..9759c38a8 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/BootupClassPathSearch.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/BootupClassPathSearch.java
@@ -1,109 +1,128 @@
package com.avaje.ebeaninternal.server.core;
-import com.avaje.ebeaninternal.server.util.ClassPathSearch;
+import com.avaje.ebeaninternal.api.ClassPathSearchService;
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
/**
* Searches for interesting classes such as Entities, Embedded and ScalarTypes.
*/
public class BootupClassPathSearch {
- private static final Logger logger = LoggerFactory.getLogger(BootupClassPathSearch.class);
+ private static final Logger logger = LoggerFactory.getLogger(BootupClassPathSearch.class);
- private final Object monitor = new Object();
+ private final Object monitor = new Object();
- private final ClassLoader classLoader;
+ private final ClassLoader classLoader;
- private final List packages;
+ private final List packages;
private final List jars;
-
- private BootupClasses bootupClasses;
+
+ private List classPathSearchServices;
+
+ private BootupClasses bootupClasses;
private final String classPathReaderClassName;
- /**
- * Construct and search for interesting classes.
- */
- public BootupClassPathSearch(ClassLoader classLoader, List packages, List jars, String classPathReaderClassName) {
- this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
- this.packages = packages;
- this.jars = jars;
+ /**
+ * Construct and search for interesting classes.
+ */
+ public BootupClassPathSearch(ClassLoader classLoader, List packages, List jars, String classPathReaderClassName) {
+ this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
+ this.packages = packages;
+ this.jars = jars;
this.classPathReaderClassName = classPathReaderClassName;
- }
- public BootupClasses getBootupClasses() {
- synchronized (monitor) {
-
- if (bootupClasses == null){
- bootupClasses = search();
- }
-
- return bootupClasses;
- }
- }
+ loadAndInitializeClassPathSearchServices();
+ }
- /**
- * Search the classPath for the classes we are interested in.
- */
- private BootupClasses search() {
- synchronized (monitor) {
- try {
-
- BootupClasses bc = new BootupClasses();
+ public BootupClasses getBootupClasses() {
+ synchronized (monitor) {
- long st = System.currentTimeMillis();
+ if (bootupClasses == null) {
+ bootupClasses = search();
+ }
- ClassPathSearchFilter filter = createFilter();
+ return bootupClasses;
+ }
+ }
- ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc, classPathReaderClassName);
+ /**
+ * Search the classPath for the classes we are interested in.
+ */
+ private BootupClasses search() {
+ synchronized (monitor) {
+ try {
- finder.findClasses();
- Set jars = finder.getJarHits();
- Set pkgs = finder.getPackageHits();
+ BootupClasses bc = new BootupClasses();
- long searchTime = System.currentTimeMillis() - st;
+ long st = System.currentTimeMillis();
- String msg = "Classpath search hits in jars" + jars + " pkgs" + pkgs + " searchTime[" + searchTime+ "]";
- logger.info(msg);
+ ClassPathSearchFilter filter = createFilter();
- return bc;
+ Set foundJars = new HashSet();
+ Set foundPkgs = new HashSet();
- } catch (Exception ex) {
- String msg = "Error in classpath search (looking for entities etc)";
- throw new RuntimeException(msg, ex);
- }
- }
- }
-
- private ClassPathSearchFilter createFilter() {
-
- ClassPathSearchFilter filter = new ClassPathSearchFilter();
- filter.addDefaultExcludePackages();
-
- if (packages != null && packages.size() > 0) {
- for (String packageName : packages) {
- filter.includePackage(packageName);
- }
-
- // if they specified include packages, they don't want by default to include everything
- filter.setDefaultPackageMatch(false);
+ for (ClassPathSearchService finder : this.classPathSearchServices) {
+ finder.init(classLoader, filter, bc, classPathReaderClassName);
+ finder.findClasses();
+ foundJars.addAll(finder.getJarHits());
+ foundPkgs.addAll(finder.getPackageHits());
}
- if (jars != null && jars.size() > 0) {
- for (String jarName : jars) {
- filter.includeJar(jarName);
- }
+ long searchTime = System.currentTimeMillis() - st;
- // if they specified jars to specifically include, they don't want everything included
- filter.setDefaultJarMatch(false);
- }
+ logger.info("Classpath search hits in jars {} pkgs {} searchTime [{}]", foundJars, foundPkgs, searchTime);
+ return bc;
+
+ } catch (Exception ex) {
+ String msg = "Error in classpath search (looking for entities etc)";
+ throw new RuntimeException(msg, ex);
+ }
+ }
+ }
+
+ private ClassPathSearchFilter createFilter() {
+
+ ClassPathSearchFilter filter = new ClassPathSearchFilter();
+ filter.addDefaultExcludePackages();
+
+ if (packages != null && packages.size() > 0) {
+ for (String packageName : packages) {
+ filter.includePackage(packageName);
+ }
+
+ // if they specified include packages, they don't want by default to include everything
+ filter.setDefaultPackageMatch(false);
+ }
+
+ if (jars != null && jars.size() > 0) {
+ for (String jarName : jars) {
+ filter.includeJar(jarName);
+ }
+
+ // if they specified jars to specifically include, they don't want everything included
+ filter.setDefaultJarMatch(false);
+ }
+
+ return filter;
+ }
+
+ /**
+ * Load and initialize all ClassPathSearchServices
+ */
+ private void loadAndInitializeClassPathSearchServices() {
+ if (this.classPathSearchServices == null) {
+ this.classPathSearchServices = new ArrayList();
+ }
+
+ for (ClassPathSearchService searchService : ServiceLoader.load(ClassPathSearchService.class, classLoader)) {
+ this.classPathSearchServices.add(searchService);
+ }
+ }
- return filter;
- }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/util/ClassPathSearch.java b/src/main/java/com/avaje/ebeaninternal/server/util/ClassPathSearch.java
index 93d515380..3579c4a02 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/util/ClassPathSearch.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/util/ClassPathSearch.java
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.util;
+import com.avaje.ebeaninternal.api.ClassPathSearchService;
import com.avaje.ebeaninternal.api.ClassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,14 +23,14 @@ import java.util.jar.Manifest;
* For example, used to find all the Entity beans and ScalarTypes for Ebean.
*
*/
-public class ClassPathSearch {
+public class ClassPathSearch implements ClassPathSearchService {
private static final Logger logger = LoggerFactory.getLogger(ClassPathSearch.class);
private ClassLoader classLoader;
private List