Permalink
Browse files

METRICS-3169: Errors in advice execution - apparently related to old …

…Spring version being used
  • Loading branch information...
1 parent 3773a58 commit b58e39d1e538e5d6eb58f2575779d2a9ddf77fea lgoldstein committed Dec 17, 2012
@@ -16,15 +16,29 @@
package com.springsource.insight.plugin.springcore;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
import org.springframework.context.ApplicationContext;
-import org.springframework.context.event.ApplicationContextEvent;
+import org.springframework.context.ApplicationEvent;
import com.springsource.insight.intercept.operation.OperationType;
+import com.springsource.insight.util.ArrayUtil;
+import com.springsource.insight.util.ExtraReflectionUtils;
+import com.springsource.insight.util.ReflectionUtils;
/**
*
*/
public abstract aspect SpringEventReferenceCollectionAspect extends SpringLifecycleMethodOperationCollectionAspect {
+ static final Set<Class<?>> nonContextEvents=Collections.synchronizedSet(new HashSet<Class<?>>());
+ static final Map<Class<?>,Method> contextMethods=Collections.synchronizedMap(new HashMap<Class<?>,Method>());
+
protected SpringEventReferenceCollectionAspect (OperationType opType) {
super(opType);
}
@@ -35,12 +49,74 @@ public abstract aspect SpringEventReferenceCollectionAspect extends SpringLifecy
return Object.class.getName();
}
- Class<?> eventType=event.getClass();
- if (ApplicationContextEvent.class.isAssignableFrom(eventType)) {
- ApplicationContext context=((ApplicationContextEvent) event).getApplicationContext();
+ Class<?> eventType=event.getClass();
+ ApplicationContext context=getApplicationContext(event);
+ if (context != null) {
return eventType.getSimpleName() + ": " + context.getDisplayName();
} else {
return eventType.getName();
}
}
+
+ /**
+ * Due to <A HREF="https://issuetracker.springsource.com/browse/METRICS-3169">METRICS-3169</A>
+ * and in order to support pre-<I>3.x</I> versions we need to extract the
+ * application context using reflection API
+ * @param event The event that <U>might</U> be carrying an application context
+ * @return The extracted {@link ApplicationContext} - <code>null</code>
+ * if none available
+ */
+ static ApplicationContext getApplicationContext(Object event) {
+ if (!(event instanceof ApplicationEvent)) {
+ return null;
+ }
+
+ Class<?> eventType=event.getClass();
+ if (nonContextEvents.contains(eventType)) {
+ return null;
+ }
+
+ Method method=contextMethods.get(eventType);
+ if (method == null) {
+ if ((method=findContextMethod(eventType)) == null) {
+ nonContextEvents.add(eventType);
+ } else {
+ contextMethods.put(eventType, method);
+ }
+ }
+
+ if (method == null) {
+ return null;
+ }
+
+ try {
+ return ExtraReflectionUtils.invoke(method, event, ApplicationContext.class);
+ } catch(RuntimeException e) {
+ nonContextEvents.add(eventType); // mark it as unreliable from here on
+ return null;
+ }
+ }
+
+ static Method findContextMethod(Class<?> eventType) {
+ if (eventType == null) {
+ return null;
+ }
+
+ Method method=ReflectionUtils.findMethod(eventType, "getApplicationContext", ArrayUtil.EMPTY_CLASSES);
+ if (method == null) {
+ return null;
+ }
+
+ int mod=method.getModifiers();
+ if (Modifier.isStatic(mod) || (!Modifier.isPublic(mod))) {
+ return null;
+ }
+
+ Class<?> returnType=method.getReturnType();
+ if (!ApplicationContext.class.isAssignableFrom(returnType)) {
+ return null;
+ }
+
+ return method;
+ }
}
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved.
+ *
+ * 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 com.springsource.insight.plugin.springcore;
+
+import il.co.springsource.insight.MyEvent;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+import com.springsource.insight.collection.test.AbstractCollectionTestSupport;
+
+/**
+ *
+ */
+public class SpringEventReferenceCollectionAspectTest extends AbstractCollectionTestSupport {
+ public SpringEventReferenceCollectionAspectTest() {
+ super();
+ }
+
+ @Test
+ public void testNonApplicationContextEvent() {
+ MyEvent event=new MyEvent("testNonApplicationContextEvent");
+ assertNullValue("Unexpected initial context", SpringEventReferenceCollectionAspect.getApplicationContext(event));
+ assertTrue("Event class not marked without context", SpringEventReferenceCollectionAspect.nonContextEvents.contains(event.getClass()));
+ assertNullValue("Unexpected extraction method mapping", SpringEventReferenceCollectionAspect.contextMethods.get(event.getClass()));
+ }
+
+ @Test
+ public void testApplicationContextEvent() {
+ ApplicationContext expected=Mockito.mock(ApplicationContext.class);
+ ContextRefreshedEvent event=new ContextRefreshedEvent(expected);
+ ApplicationContext actual=SpringEventReferenceCollectionAspect.getApplicationContext(event);
+ assertSame("Mismatched context instances", expected, actual);
+ assertNotNull("Missing extraction method mapping", SpringEventReferenceCollectionAspect.contextMethods.get(event.getClass()));
+ assertFalse("Event class marked as without context", SpringEventReferenceCollectionAspect.nonContextEvents.contains(event.getClass()));
+ }
+
+ @Test
+ public void testStaticContextEventMethod() {
+ StaticContextMethodEvent event=new StaticContextMethodEvent();
+ assertNullValue("Unexpected static context", SpringEventReferenceCollectionAspect.getApplicationContext(event));
+ assertTrue("Event class not marked without context", SpringEventReferenceCollectionAspect.nonContextEvents.contains(event.getClass()));
+ assertNullValue("Unexpected extraction method mapping", SpringEventReferenceCollectionAspect.contextMethods.get(event.getClass()));
+ }
+
+ @Test
+ public void testExceptionInContextRetrieval() {
+ ExceptionContextEvent event=new ExceptionContextEvent();
+ assertNullValue("Unexpected initial context", SpringEventReferenceCollectionAspect.getApplicationContext(event));
+ assertTrue("Event class not marked without context", SpringEventReferenceCollectionAspect.nonContextEvents.contains(event.getClass()));
+ assertNotNull("Missing extraction method mapping", SpringEventReferenceCollectionAspect.contextMethods.get(event.getClass()));
+ }
+
+ static class StaticContextMethodEvent extends ApplicationEvent {
+ private static final long serialVersionUID = 1L;
+
+ public StaticContextMethodEvent() {
+ super(Void.class);
+ }
+
+ public static ApplicationContext getApplicationContext() {
+ return Mockito.mock(ApplicationContext.class);
+ }
+ }
+
+ static class ExceptionContextEvent extends ApplicationEvent {
+ private static final long serialVersionUID = 1L;
+
+ public ExceptionContextEvent() {
+ super(Void.class);
+ }
+
+ public final ApplicationContext getApplicationContext() {
+ throw new UnsupportedOperationException("N/A");
+ }
+ }
+}

0 comments on commit b58e39d

Please sign in to comment.