Skip to content

Commit

Permalink
Use EnumSet for the checker options (to minimize problems caused by t…
Browse files Browse the repository at this point in the history
…he long chain of booleans)
  • Loading branch information
uschindler committed Aug 23, 2015
1 parent 2b8cb8c commit 5596446
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 16 deletions.
10 changes: 9 additions & 1 deletion src/main/java/de/thetaphi/forbiddenapis/AbstractCheckMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
* limitations under the License.
*/

import static de.thetaphi.forbiddenapis.Checker.Option.*;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
Expand All @@ -32,6 +34,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;

Expand Down Expand Up @@ -207,7 +210,12 @@ public void execute() throws MojoExecutionException, MojoFailureException {
ClassLoader.getSystemClassLoader();

try {
final Checker checker = new Checker(loader, internalRuntimeForbidden, failOnMissingClasses, failOnViolation, failOnUnresolvableSignatures) {
final EnumSet<Checker.Option> options = EnumSet.noneOf(Checker.Option.class);
if (internalRuntimeForbidden) options.add(INTERNAL_RUNTIME_FORBIDDEN);
if (failOnMissingClasses) options.add(FAIL_ON_MISSING_CLASSES);
if (failOnViolation) options.add(FAIL_ON_VIOLATION);
if (failOnUnresolvableSignatures) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
final Checker checker = new Checker(loader, options) {
@Override
protected void logError(String msg) {
log.error(msg);
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/de/thetaphi/forbiddenapis/AntTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* limitations under the License.
*/

import static de.thetaphi.forbiddenapis.Checker.Option.*;

import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
Expand All @@ -36,6 +38,7 @@
import java.io.IOException;
import java.io.File;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -77,7 +80,12 @@ public void execute() throws BuildException {
classFiles.setProject(getProject());
apiSignatures.setProject(getProject());

final Checker checker = new Checker(loader, internalRuntimeForbidden, failOnMissingClasses, failOnViolation, failOnUnresolvableSignatures) {
final EnumSet<Checker.Option> options = EnumSet.noneOf(Checker.Option.class);
if (internalRuntimeForbidden) options.add(INTERNAL_RUNTIME_FORBIDDEN);
if (failOnMissingClasses) options.add(FAIL_ON_MISSING_CLASSES);
if (failOnViolation) options.add(FAIL_ON_VIOLATION);
if (failOnUnresolvableSignatures) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
final Checker checker = new Checker(loader, options) {
@Override
protected void logError(String msg) {
log(msg, Project.MSG_ERR);
Expand Down
32 changes: 21 additions & 11 deletions src/main/java/de/thetaphi/forbiddenapis/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
Expand All @@ -56,6 +57,13 @@
* (which violates the spec).
*/
public abstract class Checker implements RelatedClassLookup {

public static enum Option {
INTERNAL_RUNTIME_FORBIDDEN,
FAIL_ON_MISSING_CLASSES,
FAIL_ON_VIOLATION,
FAIL_ON_UNRESOLVABLE_SIGNATURES
}

public final boolean isSupportedJDK;

Expand All @@ -64,7 +72,7 @@ public abstract class Checker implements RelatedClassLookup {
final Set<File> bootClassPathJars;
final Set<String> bootClassPathDirs;
final ClassLoader loader;
final boolean internalRuntimeForbidden, failOnMissingClasses, failOnViolation, defaultFailOnUnresolvableSignatures;
final EnumSet<Option> options;

// key is the internal name (slashed):
final Map<String,ClassSignature> classesToCheck = new HashMap<String,ClassSignature>();
Expand All @@ -86,12 +94,14 @@ public abstract class Checker implements RelatedClassLookup {
protected abstract void logWarn(String msg);
protected abstract void logInfo(String msg);

public Checker(ClassLoader loader, boolean internalRuntimeForbidden, boolean failOnMissingClasses, boolean failOnViolation, boolean defaultFailOnUnresolvableSignatures) {
//public Checker(ClassLoader loader, boolean internalRuntimeForbidden, boolean failOnMissingClasses, boolean failOnViolation, boolean defaultFailOnUnresolvableSignatures) {
public Checker(ClassLoader loader, Option... options) {
this(loader, EnumSet.copyOf(Arrays.asList(options)));
}

public Checker(ClassLoader loader, EnumSet<Option> options) {
this.loader = loader;
this.internalRuntimeForbidden = internalRuntimeForbidden;
this.failOnMissingClasses = failOnMissingClasses;
this.failOnViolation = failOnViolation;
this.defaultFailOnUnresolvableSignatures = defaultFailOnUnresolvableSignatures;
this.options = options;
this.start = System.currentTimeMillis();

// default (always available)
Expand Down Expand Up @@ -216,7 +226,7 @@ public ClassSignature lookupRelatedClass(String internalName) {
// use binary name, so we need to convert:
c = getClassFromClassLoader(type.getClassName());
} catch (ClassNotFoundException cnfe) {
if (failOnMissingClasses) {
if (options.contains(Option.FAIL_ON_MISSING_CLASSES)) {
throw new WrapperRuntimeException(cnfe);
} else {
logWarn(String.format(Locale.ENGLISH,
Expand Down Expand Up @@ -359,7 +369,7 @@ private void parseSignaturesFile(Reader reader, boolean allowBundled) throws IOE
final BufferedReader r = new BufferedReader(reader);
try {
String line, defaultMessage = null;
boolean failOnUnresolvableSignatures = this.defaultFailOnUnresolvableSignatures;
boolean failOnUnresolvableSignatures = options.contains(Option.FAIL_ON_UNRESOLVABLE_SIGNATURES);
while ((line = r.readLine()) != null) {
line = line.trim();
if (line.length() == 0 || line.startsWith("#"))
Expand Down Expand Up @@ -397,7 +407,7 @@ public final void addClassToCheck(final InputStream in) throws IOException {
}

public final boolean hasNoSignatures() {
return forbiddenMethods.isEmpty() && forbiddenFields.isEmpty() && forbiddenClasses.isEmpty() && forbiddenClassPatterns.isEmpty() && (!internalRuntimeForbidden);
return forbiddenMethods.isEmpty() && forbiddenFields.isEmpty() && forbiddenClasses.isEmpty() && forbiddenClassPatterns.isEmpty() && (!options.contains(Option.INTERNAL_RUNTIME_FORBIDDEN));
}

/** Adds the given annotation class for suppressing errors. */
Expand All @@ -413,7 +423,7 @@ public final void addSuppressAnnotation(String annoName) {
/** Parses a class and checks for valid method invocations */
private int checkClass(final ClassReader reader, Pattern suppressAnnotationsPattern) {
final String className = Type.getObjectType(reader.getClassName()).getClassName();
final ClassScanner scanner = new ClassScanner(this, forbiddenClasses, forbiddenClassPatterns, forbiddenMethods, forbiddenFields, suppressAnnotationsPattern, internalRuntimeForbidden);
final ClassScanner scanner = new ClassScanner(this, forbiddenClasses, forbiddenClassPatterns, forbiddenMethods, forbiddenFields, suppressAnnotationsPattern, options.contains(Option.INTERNAL_RUNTIME_FORBIDDEN));
reader.accept(scanner, ClassReader.SKIP_FRAMES);
final List<ForbiddenViolation> violations = scanner.getSortedViolations();
final Pattern splitter = Pattern.compile(Pattern.quote("\n"));
Expand All @@ -440,7 +450,7 @@ public final void run() throws ForbiddenApiException {
final String message = String.format(Locale.ENGLISH,
"Scanned %d (and %d related) class file(s) for forbidden API invocations (in %.2fs), %d error(s).",
classesToCheck.size(), classesToCheck.isEmpty() ? 0 : classpathClassCache.size(), (System.currentTimeMillis() - start) / 1000.0, errors);
if (failOnViolation && errors > 0) {
if (options.contains(Option.FAIL_ON_VIOLATION) && errors > 0) {
logError(message);
throw new ForbiddenApiException("Check for forbidden API calls failed, see log.");
} else {
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/de/thetaphi/forbiddenapis/CliMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
* limitations under the License.
*/

import static de.thetaphi.forbiddenapis.Checker.Option.*;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Locale;
import java.net.JarURLConnection;
import java.net.URLConnection;
Expand Down Expand Up @@ -220,8 +223,11 @@ public void run() throws ExitException {

final URLClassLoader loader = URLClassLoader.newInstance(urls, ClassLoader.getSystemClassLoader());
try {
final Checker checker = new Checker(loader, cmd.hasOption(internalruntimeforbiddenOpt.getLongOpt()),
!cmd.hasOption(allowmissingclassesOpt.getLongOpt()), true, !cmd.hasOption(allowunresolvablesignaturesOpt.getLongOpt())) {
final EnumSet<Checker.Option> options = EnumSet.of(FAIL_ON_VIOLATION);
if (cmd.hasOption(internalruntimeforbiddenOpt.getLongOpt())) options.add(INTERNAL_RUNTIME_FORBIDDEN);
if (!cmd.hasOption(allowmissingclassesOpt.getLongOpt())) options.add(FAIL_ON_MISSING_CLASSES);
if (!cmd.hasOption(allowunresolvablesignaturesOpt.getLongOpt())) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
final Checker checker = new Checker(loader, options) {
@Override
protected void logError(String msg) {
CliMain.this.logError(msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* limitations under the License.
*/

import static de.thetaphi.forbiddenapis.Checker.Option.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;

Expand All @@ -29,7 +30,7 @@ public final class CheckerSetupTest {
@SuppressForbidden
static final class MyChecker extends Checker {
public MyChecker() {
super(ClassLoader.getSystemClassLoader(), true, true, true, true);
super(ClassLoader.getSystemClassLoader(), INTERNAL_RUNTIME_FORBIDDEN, FAIL_ON_MISSING_CLASSES, FAIL_ON_VIOLATION, FAIL_ON_UNRESOLVABLE_SIGNATURES);
}

@Override
Expand Down

0 comments on commit 5596446

Please sign in to comment.