mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-1568,CLOUDSTACK-1664: Fix ActionEvent interception and optimize @DB lookup with caching
This commit is contained in:
parent
d9b85e397d
commit
fb94b72213
@ -19,22 +19,29 @@ package com.cloud.event;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.utils.component.ComponentMethodProxyCache;
|
||||
|
||||
public class ActionEventInterceptor {
|
||||
private static final Logger s_logger = Logger.getLogger(ActionEventInterceptor.class);
|
||||
|
||||
public ActionEventInterceptor() {
|
||||
}
|
||||
|
||||
public Object AroundAnyMethod(ProceedingJoinPoint call) throws Throwable {
|
||||
MethodSignature methodSignature = (MethodSignature)call.getSignature();
|
||||
Method targetMethod = methodSignature.getMethod();
|
||||
if(needToIntercept(targetMethod)) {
|
||||
|
||||
// Note: AOP for ActionEvent is triggered annotation, no need to check the annotation on method again
|
||||
Method targetMethod = ComponentMethodProxyCache.getTargetMethod(
|
||||
methodSignature.getMethod(), call.getTarget());
|
||||
|
||||
if(targetMethod != null) {
|
||||
EventVO event = interceptStart(targetMethod);
|
||||
|
||||
|
||||
boolean success = true;
|
||||
Object ret = null;
|
||||
try {
|
||||
@ -49,6 +56,8 @@ public class ActionEventInterceptor {
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
s_logger.error("Unable to find the proxied method behind. Method: " + methodSignature.getMethod().getName());
|
||||
}
|
||||
return call.proceed();
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ public class ConsoleProxyHttpHandlerHelper {
|
||||
ConsoleProxyClientParam param = encryptor.decryptObject(ConsoleProxyClientParam.class, map.get("token"));
|
||||
|
||||
// make sure we get information from token only
|
||||
map.clear();
|
||||
guardUserInput(map);
|
||||
if(param != null) {
|
||||
if(param.getClientHostAddress() != null)
|
||||
map.put("host", param.getClientHostAddress());
|
||||
@ -72,9 +72,19 @@ public class ConsoleProxyHttpHandlerHelper {
|
||||
}
|
||||
} else {
|
||||
// we no longer accept information from parameter other than token
|
||||
map.clear();
|
||||
guardUserInput(map);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void guardUserInput(Map<String, String> map) {
|
||||
map.remove("host");
|
||||
map.remove("port");
|
||||
map.remove("tag");
|
||||
map.remove("sid");
|
||||
map.remove("consoleurl");
|
||||
map.remove("sessionref");
|
||||
map.remove("ticket");
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// 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 com.cloud.utils.component;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class ComponentMethodProxyCache {
|
||||
|
||||
private static WeakHashMap<TargetKey, WeakReference<Method>> s_cache = new WeakHashMap<TargetKey, WeakReference<Method>>();
|
||||
|
||||
public ComponentMethodProxyCache() {
|
||||
}
|
||||
|
||||
public static Method getTargetMethod(Method method, Object target) {
|
||||
synchronized(s_cache) {
|
||||
WeakReference<Method> targetMethod = s_cache.get(new TargetKey(method, target));
|
||||
if(targetMethod != null && targetMethod.get() != null)
|
||||
return targetMethod.get();
|
||||
|
||||
Class<?> clazz = target.getClass();
|
||||
for(Method m : clazz.getMethods()) {
|
||||
if(isMethodMatched(method, m)) {
|
||||
s_cache.put(new TargetKey(method, target), new WeakReference<Method>(m));
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isMethodMatched(Method m1, Method m2) {
|
||||
if(!m1.getName().equals(m2.getName()))
|
||||
return false;
|
||||
|
||||
Class<?>[] params1 = m1.getParameterTypes();
|
||||
Class<?>[] params2 = m2.getParameterTypes();
|
||||
|
||||
if(params1.length != params2.length)
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < params1.length; i++) {
|
||||
if(!params1[i].isAssignableFrom(params2[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class TargetKey {
|
||||
Method _method;
|
||||
Object _target;
|
||||
|
||||
public TargetKey(Method method, Object target) {
|
||||
_method = method;
|
||||
_target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof TargetKey))
|
||||
return false;
|
||||
|
||||
// for target object, we just check the reference
|
||||
return _method.equals(((TargetKey)obj)._method) &&
|
||||
_target == ((TargetKey)obj)._target;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return _target.hashCode() ^ _target.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,5 +38,4 @@ public class SpringComponentScanUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -22,9 +22,10 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import com.cloud.utils.component.ComponentMethodProxyCache;
|
||||
|
||||
public class TransactionContextBuilder implements MethodInterceptor {
|
||||
private static final Logger s_logger = Logger.getLogger(TransactionContextBuilder.class);
|
||||
public TransactionContextBuilder() {
|
||||
@ -72,14 +73,9 @@ public class TransactionContextBuilder implements MethodInterceptor {
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
if(clazz.isInterface()) {
|
||||
clazz = target.getClass();
|
||||
for(Method m : clazz.getMethods()) {
|
||||
// it is supposed that we need to check against type arguments,
|
||||
// this can be simplified by just checking method name
|
||||
if(m.getName().equals(method.getName())) {
|
||||
if(m.getAnnotation(DB.class) != null)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Method targetMethod = ComponentMethodProxyCache.getTargetMethod(method, target);
|
||||
if(targetMethod != null && targetMethod.getAnnotation(DB.class) != null)
|
||||
return true;
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user