From 2fa7c57357dc60e6499e126d88cdc27c558a6fad Mon Sep 17 00:00:00 2001
From: Kefeng Deng
Date: Tue, 28 Jul 2015 21:31:49 +1200
Subject: [PATCH] Introduced a service interface to allow multiple
ClassPathSearchs with its own customized search way
---
.../api/ClassPathSearchService.java | 46 ++
.../server/core/BootupClassPathSearch.java | 82 +-
.../server/util/ClassPathSearch.java | 770 +++++++++---------
...e.ebeaninternal.api.ClassPathSearchService | 1 +
.../server/util/ClassPathSearchTests.java | 6 +-
5 files changed, 489 insertions(+), 416 deletions(-)
create mode 100644 src/main/java/com/avaje/ebeaninternal/api/ClassPathSearchService.java
create mode 100644 src/main/resources/META-INF/services/com.avaje.ebeaninternal.api.ClassPathSearchService
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..7f73d823f
--- /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..6ed9f13dc 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/BootupClassPathSearch.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/BootupClassPathSearch.java
@@ -1,12 +1,11 @@
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.
@@ -21,11 +20,13 @@ public class BootupClassPathSearch {
private final List packages;
- private final List jars;
-
+ private final List jars;
+
+ private List classPathSearchServices;
+
private BootupClasses bootupClasses;
- private final String classPathReaderClassName;
+ private final String classPathReaderClassName;
/**
* Construct and search for interesting classes.
@@ -34,16 +35,18 @@ public class BootupClassPathSearch {
this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
this.packages = packages;
this.jars = jars;
- this.classPathReaderClassName = classPathReaderClassName;
+ this.classPathReaderClassName = classPathReaderClassName;
+
+ loadAndInitializeClassPathSearchServices();
}
public BootupClasses getBootupClasses() {
synchronized (monitor) {
-
- if (bootupClasses == null){
+
+ if (bootupClasses == null) {
bootupClasses = search();
}
-
+
return bootupClasses;
}
}
@@ -54,24 +57,26 @@ public class BootupClassPathSearch {
private BootupClasses search() {
synchronized (monitor) {
try {
-
+
BootupClasses bc = new BootupClasses();
long st = System.currentTimeMillis();
ClassPathSearchFilter filter = createFilter();
- ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc, classPathReaderClassName);
+ Set foundJars = new HashSet();
+ Set foundPkgs = new HashSet();
- finder.findClasses();
- Set jars = finder.getJarHits();
- Set pkgs = finder.getPackageHits();
+ for (ClassPathSearchService finder : this.classPathSearchServices) {
+ finder.init(classLoader, filter, bc, classPathReaderClassName);
+ finder.findClasses();
+ foundJars.addAll(finder.getJarHits());
+ foundPkgs.addAll(finder.getPackageHits());
+ }
long searchTime = System.currentTimeMillis() - st;
- String msg = "Classpath search hits in jars" + jars + " pkgs" + pkgs + " searchTime[" + searchTime+ "]";
- logger.info(msg);
-
+ logger.info("Classpath search hits in jars {} pkgs {} searchTime [{}]", foundJars, foundPkgs, searchTime);
return bc;
} catch (Exception ex) {
@@ -86,24 +91,37 @@ public class BootupClassPathSearch {
ClassPathSearchFilter filter = new ClassPathSearchFilter();
filter.addDefaultExcludePackages();
- if (packages != null && packages.size() > 0) {
- for (String packageName : packages) {
- filter.includePackage(packageName);
- }
+ 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 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 (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);
- }
+ // 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);
+ }
+ }
}
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..866a574fe 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,474 +23,479 @@ 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 static final Logger logger = LoggerFactory.getLogger(ClassPathSearch.class);
- private ClassLoader classLoader;
+ private ClassLoader classLoader;
- private List