/****************************************************************************** * WebJavin - Java Web Framework. * * * * Copyright (c) 2011 - Sergey "Frosman" Lukjanov, me@frostman.ru * * * * 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 ru.frostman.web.aop; import com.google.common.collect.Maps; import javassist.CtClass; import javassist.CtMethod; import javassist.NotFoundException; import org.mvel2.MVEL; import org.mvel2.ParserContext; import org.mvel2.compiler.ExecutableStatement; import ru.frostman.web.thr.JavinRuntimeException; import java.lang.annotation.Annotation; import java.util.Map; /** * @author slukjanov aka Frostman */ public class MethodPatternMatcher { private static final ThreadLocal<CtMethod> currentMethod = new ThreadLocal<CtMethod>(); private static final Map<String, Object> vars = Maps.newHashMap(); static { vars.put("any", true); } private final ExecutableStatement expression; public MethodPatternMatcher(String methodPattern) { try { ParserContext context = new ParserContext(); context.setStrongTyping(true); context.addInput("any", boolean.class); context.addImport("package", MethodPatternMatcher.class.getMethod("_package", String.class)); context.addImport("class", MethodPatternMatcher.class.getMethod("_class", String.class)); context.addImport("method", MethodPatternMatcher.class.getMethod("_method", String.class)); context.addImport("return", MethodPatternMatcher.class.getMethod("_return", String.class)); context.addImport("annotation", MethodPatternMatcher.class.getMethod("_annotation", String.class)); context.addImport("params", MethodPatternMatcher.class.getMethod("_params", String.class)); if (methodPattern.trim().length() == 0) { methodPattern = "any"; } expression = (ExecutableStatement) MVEL.compileExpression(methodPattern, context); if (expression.getKnownEgressType() != boolean.class && expression.getKnownEgressType() != Boolean.class) { throw new JavinRuntimeException("Aop method interceptor pattern should return boolean"); } } catch (Exception e) { throw new JavinRuntimeException("Exception while compiling method interceptor pattern: " + methodPattern, e); } } public boolean matches(CtMethod method) { try { currentMethod.set(method); return (Boolean) MVEL.executeExpression(expression, vars); } finally { currentMethod.set(null); } } public static boolean _package(String packageName) { return isMatches(packageName, currentMethod.get().getDeclaringClass().getPackageName()); } public static boolean _class(String className) { return isMatches(className, currentMethod.get().getDeclaringClass().getSimpleName()); } public static boolean _method(String methodName) { return isMatches(methodName, currentMethod.get().getName()); } public static boolean _return(String returnType) { try { return isMatches(returnType, currentMethod.get().getReturnType().getName()); } catch (NotFoundException e) { return false; } } public static boolean _annotation(String annotationName) { Object[] annotationObjects = new Object[0]; try { annotationObjects = currentMethod.get().getAnnotations(); } catch (ClassNotFoundException e) { return false; } for (Object object : annotationObjects) { Annotation annotation = (Annotation) object; if (isMatches(annotationName, annotation.annotationType().getName())) { return true; } } return false; } public static boolean _params(String paramsString) { String[] params = paramsString.split(","); CtClass[] parameterTypes; try { parameterTypes = currentMethod.get().getParameterTypes(); } catch (NotFoundException e) { return false; } if (parameterTypes.length != params.length) { return false; } int idx = 0; for (String param : params) { if (!isMatches(param, parameterTypes[idx].getName())) { return false; } idx++; } return true; } //todo make tests for this method @SuppressWarnings({"StringEquality", "ConstantConditions"}) static boolean isMatches(String pattern, String str) { if (pattern == str || pattern.equals(str)) { return true; } if (pattern == null) { return false; } pattern = pattern.trim(); str = str.trim(); if (pattern.startsWith("*")) { if (pattern.endsWith("*")) { return str.contains(pattern.substring(1, Math.max(1, pattern.length() - 1))); } else { return str.endsWith(pattern.substring(1)); } } return pattern.endsWith("*") && str.startsWith(pattern.substring(0, Math.max(0, pattern.length() - 1))); } }