package org.jboss.weld.metadata;
import java.security.AccessController;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.jboss.weld.bootstrap.spi.ClassAvailableActivation;
import org.jboss.weld.bootstrap.spi.Filter;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.bootstrap.spi.SystemPropertyActivation;
import org.jboss.weld.bootstrap.spi.WeldFilter;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.resources.spi.ResourceLoadingException;
import org.jboss.weld.security.GetSystemPropertyAction;
/**
* A predicate which selects classes to process based on a filter.
* <p/>
* This filter will determine if the filter is active on instantiation, so
* should only be instantiated when it is ready to be used.
*
* @author Pete Muir
*/
public class FilterPredicate implements Predicate<String> {
private final boolean active;
private final Matcher matcher;
public FilterPredicate(Metadata<Filter> filter, ResourceLoader resourceLoader) {
boolean active = true;
if (filter.getValue().getClassAvailableActivations() != null) {
for (Metadata<ClassAvailableActivation> classAvailableActivation : filter.getValue().getClassAvailableActivations()) {
if (classAvailableActivation.getValue() == null) {
throw new IllegalStateException("Class available activation metadata not available at " + classAvailableActivation);
}
String className = classAvailableActivation.getValue().getClassName();
if (className == null) {
throw new IllegalStateException("Must specify class name at " + classAvailableActivation);
}
boolean inverted = isInverted(className) || classAvailableActivation.getValue().isInverted();
if (inverted) {
className = removeInversion(className);
}
active = active && isClassAvailable(className, resourceLoader, inverted);
}
}
if (filter.getValue().getSystemPropertyActivations() != null) {
for (Metadata<SystemPropertyActivation> systemPropertyActivation : filter.getValue().getSystemPropertyActivations()) {
if (systemPropertyActivation.getValue() == null) {
throw new IllegalStateException("System property activation metadata not available at " + systemPropertyActivation);
}
String propertyName = systemPropertyActivation.getValue().getName();
String requiredPropertyValue = systemPropertyActivation.getValue().getValue();
if (propertyName == null) {
throw new IllegalStateException("Must specify system property name at " + systemPropertyActivation);
}
boolean propertyNameInverted = isInverted(propertyName);
if (propertyNameInverted && requiredPropertyValue != null) {
throw new IllegalStateException("Cannot invert property name and specify property value at " + systemPropertyActivation);
}
if (propertyNameInverted) {
propertyName = removeInversion(propertyName);
}
String actualPropertyValue = AccessController.doPrivileged(new GetSystemPropertyAction(propertyName));
if (requiredPropertyValue == null) {
active = active && isNotNull(actualPropertyValue, propertyNameInverted);
} else {
boolean requiredPropertyValueInverted = isInverted(requiredPropertyValue);
if (requiredPropertyValueInverted) {
requiredPropertyValue = removeInversion(requiredPropertyValue);
}
active = active && isEqual(requiredPropertyValue, actualPropertyValue, requiredPropertyValueInverted);
}
}
}
this.active = active;
if (filter.getValue() instanceof WeldFilter) {
WeldFilter weldFilter = (WeldFilter) filter.getValue();
if ((weldFilter.getName() != null && weldFilter.getPattern() != null)
|| (weldFilter.getName() == null && weldFilter.getPattern() == null)) {
throw new IllegalStateException("Cannot specify both a pattern and a name at " + filter);
}
if (weldFilter.getPattern() != null) {
this.matcher = new PatternMatcher(filter, weldFilter.getPattern());
} else {
this.matcher = new AntSelectorMatcher(weldFilter.getName());
}
} else {
if (filter.getValue().getName() == null) {
throw new IllegalStateException("Name must be specified at " + filter);
}
String name = filter.getValue().getName();
String suffixDotDoubleStar = ".**";
String suffixDotStar = ".*";
if (name.endsWith(suffixDotDoubleStar)) {
this.matcher = new PrefixMatcher(name.substring(0, name.length() - suffixDotDoubleStar.length()), filter);
} else if (name.endsWith(suffixDotStar)) {
this.matcher = new PackageMatcher(name.substring(0, name.length() - suffixDotStar.length()), filter);
} else {
this.matcher = new FullyQualifierClassNameMatcher(name, filter);
}
}
}
public boolean test(String className) {
if (active) {
return matcher.matches(className);
} else {
return false;
}
}
private static boolean isClassAvailable(String className, ResourceLoader resourceLoader, boolean invert) {
if (invert) {
return !isClassAvailable(className, resourceLoader);
} else {
return isClassAvailable(className, resourceLoader);
}
}
private static boolean isClassAvailable(String className, ResourceLoader resourceLoader) {
try {
resourceLoader.classForName(className);
} catch (ResourceLoadingException e) {
return false;
}
return true;
}
private static boolean isNotNull(String string, boolean invert) {
if (invert) {
return string == null;
} else {
return string != null;
}
}
private static boolean isEqual(String string1, String string2, boolean invert) {
if (invert) {
return !string1.equals(string2);
} else {
return string1.equals(string2);
}
}
private static boolean isInverted(String string) {
return string.startsWith("!");
}
private static String removeInversion(String string) {
if (!string.startsWith("!")) {
return string;
}
return string.substring(1);
}
private interface Matcher {
boolean matches(String input);
}
private static class PatternMatcher implements Matcher {
private final Pattern pattern;
private PatternMatcher(Metadata<Filter> filter, String pattern) {
try {
this.pattern = Pattern.compile(pattern);
} catch (PatternSyntaxException e) {
throw new IllegalStateException("Error parsing pattern at " + filter, e);
}
}
@Override
public boolean matches(String input) {
return pattern.matcher(input).matches();
}
}
private static class AntSelectorMatcher implements Matcher {
private final String name;
private AntSelectorMatcher(String name) {
this.name = name;
}
@Override
public boolean matches(String input) {
return Selectors.matchPath(this.name, input);
}
}
private abstract static class CDI11Matcher implements Matcher {
private static final Pattern CDI11_EXCLUDE_PATTERN = Pattern.compile("([\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*");
protected final String expression;
private CDI11Matcher(String expression, Metadata<Filter> filter) {
this.expression = expression;
if (!CDI11_EXCLUDE_PATTERN.matcher(expression).matches()) {
throw new IllegalArgumentException("Invalid expression " + filter);
}
}
}
private static class FullyQualifierClassNameMatcher extends CDI11Matcher {
private FullyQualifierClassNameMatcher(String fqcn, Metadata<Filter> filter) {
super(fqcn, filter);
}
@Override
public boolean matches(String input) {
return expression.equals(input);
}
}
private static class PrefixMatcher extends CDI11Matcher {
private PrefixMatcher(String prefix, Metadata<Filter> filter) {
super(prefix, filter);
}
@Override
public boolean matches(String input) {
return input != null && input.startsWith(expression);
}
}
private static class PackageMatcher extends CDI11Matcher {
private PackageMatcher(String pkg, Metadata<Filter> filter) {
super(pkg, filter);
}
@Override
public boolean matches(String input) {
if (input == null) {
return false;
}
int lastDot = input.lastIndexOf('.');
if (lastDot == -1) {
return false;
}
return expression.equals(input.substring(0, lastDot));
}
}
}