org.glowroot.weaving.AdviceMatcherBase Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glowroot.weaving;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.regex.Pattern;
import org.glowroot.shaded.google.common.collect.ImmutableList;
import org.glowroot.shaded.google.common.collect.Lists;
import org.immutables.value.Value;
import org.glowroot.shaded.objectweb.asm.Type;
import org.glowroot.shaded.slf4j.Logger;
import org.glowroot.shaded.slf4j.LoggerFactory;
import org.glowroot.common.Styles;
import org.glowroot.plugin.api.weaving.MethodModifier;
@Value.Immutable
@Styles.AllParameters
abstract class AdviceMatcherBase {
private static final Logger logger = LoggerFactory.getLogger(AdviceMatcher.class);
static ImmutableList getAdviceMatchers(String className, List advisors) {
List adviceMatchers = Lists.newArrayList();
for (Advice advice : advisors) {
if (AdviceMatcherBase.isDeclaringClassNameMatch(className, advice)) {
adviceMatchers.add(AdviceMatcher.of(advice));
}
}
return ImmutableList.copyOf(adviceMatchers);
}
abstract Advice advice();
boolean isMethodLevelMatch(String methodName, List parameterTypes, Type returnType,
int modifiers) {
if (!isMethodNameMatch(methodName) || !isMethodParameterTypesMatch(parameterTypes)) {
return false;
}
return isMethodReturnMatch(returnType) && isMethodModifiersMatch(modifiers);
}
private boolean isMethodNameMatch(String methodName) {
if (methodName.equals("")) {
// static initializers are not supported
return false;
}
if (methodName.equals("")) {
// constructors only match by exact name (don't want patterns to match constructors)
return advice().pointcut().methodName().equals("");
}
Pattern pointcutMethodNamePattern = advice().pointcutMethodNamePattern();
if (pointcutMethodNamePattern == null) {
return advice().pointcut().methodName().equals(methodName);
} else {
return pointcutMethodNamePattern.matcher(methodName).matches();
}
}
private boolean isMethodParameterTypesMatch(List parameterTypes) {
String[] pointcutMethodParameterTypes = advice().pointcut().methodParameterTypes();
for (int i = 0; i < pointcutMethodParameterTypes.length; i++) {
String pointcutMethodParameterType = pointcutMethodParameterTypes[i];
if (pointcutMethodParameterType.equals("..")) {
if (i != pointcutMethodParameterTypes.length - 1) {
logger.warn("'..' can only be used at the end of methodParameterTypes");
return false;
} else {
// ".." matches everything after this
return true;
}
}
if (parameterTypes.size() == i) {
// have run out of argument types to match
return false;
}
if (!isMethodParameterTypeMatch(pointcutMethodParameterType, parameterTypes.get(i))) {
return false;
}
}
// need this final test since argumentTypes may still have unmatched elements
return parameterTypes.size() == pointcutMethodParameterTypes.length;
}
private boolean isMethodParameterTypeMatch(String pointcutMethodParameterType,
Type parameterType) {
// only supporting * at this point
return pointcutMethodParameterType.equals("*")
|| pointcutMethodParameterType.equals(parameterType.getClassName());
}
private boolean isMethodReturnMatch(Type returnType) {
String pointcutMethodReturn = advice().pointcut().methodReturnType();
return pointcutMethodReturn.isEmpty()
|| pointcutMethodReturn.equals(returnType.getClassName());
}
private boolean isMethodModifiersMatch(int modifiers) {
for (MethodModifier methodModifier : advice().pointcut().methodModifiers()) {
if (!isMethodModifierMatch(methodModifier, modifiers)) {
return false;
}
}
return true;
}
private boolean isMethodModifierMatch(MethodModifier methodModifier, int modifiers) {
switch (methodModifier) {
case PUBLIC:
return Modifier.isPublic(modifiers);
case STATIC:
return Modifier.isStatic(modifiers);
case NOT_STATIC:
return !Modifier.isStatic(modifiers);
default:
return false;
}
}
private static boolean isDeclaringClassNameMatch(String className, Advice advice) {
Pattern pointcutClassNamePattern = advice.pointcutDeclaringClassNamePattern();
if (pointcutClassNamePattern == null) {
return advice.pointcutDeclaringClassName().equals(className);
} else {
return pointcutClassNamePattern.matcher(className).matches();
}
}
}