package com.avaje.ebean.enhance.agent;
import java.util.HashMap;
/**
* Helper object used to ignore known classes. We only want to enhance the
* entity beans and perhaps some other user classes (not JDK classes etc).
* <p>
* In looking for classes to enhance we can skip some such as JDK, JDBC and
* other known libraries.
* </p>
* <p>
* The agentArgs can optionally include a "packages" parameter with a comma
* delimited list of packages that SHOULD be processed. All other packages would
* then be ignored.
* </p>
*/
public class IgnoreClassHelper {
private final String[] processPackages;
public IgnoreClassHelper(String agentArgs) {
HashMap<String, String> args = ArgParser.parse(agentArgs);
String packages = args.get("packages");
if (packages != null) {
String[] pkgs = packages.split(",");
processPackages = new String[pkgs.length];
for (int i = 0; i < pkgs.length; i++) {
processPackages[i] = convertPackage(pkgs[i]);
}
} else {
processPackages = new String[0];
}
}
/**
* Convert dots/periods to slashes in the package name.
*/
private String convertPackage(String pkg) {
pkg = pkg.trim().replace('.', '/');
if (pkg.endsWith("*")) {
// wild card, remove the * ... and
// don't add a "/" to the end
return pkg.substring(0, pkg.length() - 1);
} else if (pkg.endsWith("/")) {
// already ends in "/"
return pkg;
} else {
// add "/" so we don't pick up another
// package with a similar starting name
return pkg + "/";
}
}
/**
* Use specific positive matching to determine if the class needs to be
* processed.
* <p>
* Any class at any depth under the package can be processed and all others
* ignored.
* </p>
*
* @return true if the class can be ignored
*/
private boolean specificMatching(String className) {
for (int i = 0; i < processPackages.length; i++) {
if (className.startsWith(processPackages[i])) {
// a positive match
return false;
}
}
// we can ignore this class
return true;
}
/**
* Try to exclude JDK classes and known JDBC Drivers and Libraries.
* <p>
* We want to do this for performance reasons - that is skip checking for
* enhancement on classes that we know are not part of the application code
* and should not be enhanced.
* </p>
*
* @param className
* the className of the class being defined.
* @return true if this class should not be processed.
*/
public boolean isIgnoreClass(String className) {
className = className.replace('.', '/');
// the special entity beans supplied by Ebean SHOULD be processed
if (className.startsWith(EnhanceConstants.EBEAN_META_PREFIX)) {
return false;
}
if (processPackages.length > 0) {
// use specific positive matching
return specificMatching(className);
}
// we don't have specific packages to process so instead
// we will ignore packages that we know we don't want to
// process (they won't contain entity beans etc).
// the rest of Ebean should be ignored
if (className.startsWith(EnhanceConstants.EBEAN_PREFIX)) {
return true;
}
// ignore the JDK classes ...
if (className.startsWith("java/") || className.startsWith("javax/")) {
return true;
}
if (className.startsWith("sun/") || className.startsWith("sunw/") || className.startsWith("com/sun/")) {
return true;
}
if (className.startsWith("org/wc3/") || className.startsWith("org/xml/")) {
return true;
}
if (className.startsWith("org/junit/") || className.startsWith("junit/")) {
return true;
}
// ignore apache libraries
if (className.startsWith("org/apache/")) {
return true;
}
if (className.startsWith("org/eclipse/")) {
return true;
}
if (className.startsWith("org/joda/")) {
return true;
}
// ignore mysql jdbc drivers
if (className.startsWith("com/mysql/jdbc")) {
return true;
}
// ignore postgres jdbc drivers
if (className.startsWith("org/postgresql/")) {
return true;
}
// ignore h2
if (className.startsWith("org/h2/")) {
return true;
}
// ignore oracle
if (className.startsWith("oracle/")) {
return true;
}
// ignore base groovy classes
if (className.startsWith("groovy/")) {
return true;
}
// ignore $Proxy classes
if (className.startsWith("$")) {
return true;
}
return false;
}
}