You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sirona.apache.org by rm...@apache.org on 2013/11/26 17:16:30 UTC

svn commit: r1545708 - in /incubator/sirona/trunk/agent/javaagent/src: main/java/org/apache/sirona/javaagent/ main/java/org/apache/sirona/javaagent/listener/ main/java/org/apache/sirona/javaagent/spi/ test/java/org/apache/sirona/javaagent/ test/java/or...

Author: rmannibucau
Date: Tue Nov 26 16:16:29 2013
New Revision: 1545708

URL: http://svn.apache.org/r1545708
Log:
adding a test to show how to do a custom InvocationListener + adding ConfigurableListener helper

Added:
    incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/ConfigurableListener.java
    incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/HttpUrlConnectionAddHeaderTest.java
    incubator/sirona/trunk/agent/javaagent/src/test/resources/
    incubator/sirona/trunk/agent/javaagent/src/test/resources/META-INF/
    incubator/sirona/trunk/agent/javaagent/src/test/resources/META-INF/services/
    incubator/sirona/trunk/agent/javaagent/src/test/resources/META-INF/services/org.apache.sirona.javaagent.spi.InvocationListener
Modified:
    incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java
    incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java
    incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java
    incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java
    incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/spi/InvocationListener.java
    incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java
    incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/AgentPerfInterceptorAgentContractTest.java
    incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/IncludeExcludeTest.java

Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java Tue Nov 26 16:16:29 2013
@@ -134,18 +134,18 @@ public class AgentContext {
         context.put(key, data);
     }
 
-    public void stop() {
-        stopListeners(null);
+    public void stop(final Object result) {
+        stopListeners(result, null);
     }
 
     public void stopWithException(final Throwable error) {
-        stopListeners(error);
+        stopListeners(null, error);
     }
 
-    private void stopListeners(final Throwable error) {
+    private void stopListeners(final Object result, final Throwable error) {
         if (hasListeners) {
             for (final InvocationListener listener : listeners) {
-                listener.after(this, error);
+                listener.after(this, result, error);
             }
         }
     }

Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java Tue Nov 26 16:16:29 2013
@@ -24,6 +24,7 @@ import org.objectweb.asm.ClassWriter;
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.IllegalClassFormatException;
 import java.lang.instrument.Instrumentation;
+import java.lang.instrument.UnmodifiableClassException;
 import java.security.ProtectionDomain;
 
 public class SironaAgent {
@@ -36,6 +37,13 @@ public class SironaAgent {
         Configuration.is("", true); // a touch to force eager init
 
         instrumentation.addTransformer(new SironaTransformer(agentArgs), true);
+        try {
+            instrumentation.retransformClasses(SironaAgent.class.getClassLoader().loadClass("sun.net.www.protocol.http.HttpURLConnection"));
+        } catch (UnmodifiableClassException e) {
+            e.printStackTrace();
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
     }
 
 
@@ -79,29 +87,30 @@ public class SironaAgent {
         }
 
         private byte[] doTransform(final String className, final byte[] classfileBuffer) {
-            final ClassReader reader = new ClassReader(classfileBuffer);
-            final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
-            final SironaClassVisitor advisor = new SironaClassVisitor(writer, className);
             try {
+                final ClassReader reader = new ClassReader(classfileBuffer);
+                final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                final SironaClassVisitor advisor = new SironaClassVisitor(writer, className);
                 reader.accept(advisor, ClassReader.SKIP_DEBUG);
+                return writer.toByteArray();
             } catch (final RuntimeException re) {
-                re.printStackTrace(); // log it otherwise hard to know if it fails
+                if (Boolean.getBoolean("sirona.agent.debug")) {
+                    re.printStackTrace();
+                }
                 throw re;
             }
-            return writer.toByteArray();
         }
 
         private boolean shouldTransform(final String className, final ClassLoader loader) {
-            return !(
-                           loader == null
-                        || className == null
-                        || loader.getClass().getName().equals(DELEGATING_CLASS_LOADER)
-                        || className.startsWith("org/apache/sirona")
-                        || className.startsWith("com/sun/proxy")
-                    )
+            return !(loader == null // bootstrap classloader
+                || className == null // framework with bug
+                || loader.getClass().getName().equals(DELEGATING_CLASS_LOADER)
+                || className.startsWith("sun/reflect")
+                || className.startsWith("com/sun/proxy")
+                || className.startsWith("org/apache/sirona"))
+
                 && includeEvaluator.matches(className.replace("/", "."))
                 && !excludeEvaluator.matches(className.replace("/", "."));
-
         }
     }
 }

Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java Tue Nov 26 16:16:29 2013
@@ -143,6 +143,7 @@ public class SironaClassVisitor extends 
         private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
         private static final Type[] STOP_WITH_THROWABLE_ARGS_TYPES = new Type[]{ THROWABLE_TYPE };
         private static final Type OBJECT_TYPE = Type.getType(Object.class);
+        private static final Type[] STOP_WITH_OBJECT_ARGS_TYPES = new Type[]{ OBJECT_TYPE };
         private static final Type[] START_ARGS_TYPES = new Type[]{ KEY_TYPE, OBJECT_TYPE };
 
         // methods
@@ -185,7 +186,12 @@ public class SironaClassVisitor extends 
 
             // take metrics before returning
             loadLocal(agentIdx);
-            invokeVirtual(AGENT_CONTEXT, new Method(STOP_METHOD, NO_PARAM_RETURN_VOID));
+            if (result != -1) {
+                loadLocal(result);
+            } else {
+                visitInsn(ACONST_NULL); // result == null for static methods
+            }
+            invokeVirtual(AGENT_CONTEXT, new Method(STOP_METHOD, Type.VOID_TYPE, STOP_WITH_OBJECT_ARGS_TYPES));
 
             // return result
             returnResult(result);

Added: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/ConfigurableListener.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/ConfigurableListener.java?rev=1545708&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/ConfigurableListener.java (added)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/ConfigurableListener.java Tue Nov 26 16:16:29 2013
@@ -0,0 +1,79 @@
+/*
+ * 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 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.apache.sirona.javaagent.listener;
+
+import org.apache.sirona.configuration.predicate.PredicateEvaluator;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.javaagent.AgentContext;
+import org.apache.sirona.javaagent.spi.InvocationListener;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public abstract class ConfigurableListener implements InvocationListener {
+    private static final AtomicInteger ID_GENERATOR = new AtomicInteger(1); // 0 is reserved for CounterListener
+
+    private int id = ID_GENERATOR.incrementAndGet();
+
+    private PredicateEvaluator includes = new PredicateEvaluator("true:true", ",");
+    private PredicateEvaluator excludes = new PredicateEvaluator(null, null);
+
+    protected void before(final Counter.Key key, final Object reference) {
+        // no-op
+    }
+
+    protected void onSuccess(final Counter.Key key, final Object reference, final Object result) {
+        // no-op
+    }
+
+    protected void onError(final Counter.Key key, final Object reference, final Throwable error) {
+        // no-op
+    }
+
+    @Override
+    public void before(final AgentContext context) {
+        context.put(id, this);
+        before(context.getKey(), context.getReference());
+    }
+
+    @Override
+    public void after(final AgentContext context, final Object result, final Throwable error) {
+        final ConfigurableListener listener = context.get(id, ConfigurableListener.class);
+        if (listener != null) {
+            if (error != null) {
+                listener.onSuccess(context.getKey(), context.getReference(), result);
+            } else {
+                listener.onError(context.getKey(), context.getReference(), error);
+            }
+        }
+    }
+
+    @Override
+    public boolean accept(final Counter.Key key, final Object instance) {
+        final String name = key.getName();
+        return includes.matches(name) && !excludes.matches(name);
+    }
+
+    // @AutoSet should be added to children
+    public void setIncludes(final String includes) {
+        this.includes = new PredicateEvaluator(includes, ",");
+    }
+
+    // @AutoSet should be added to children
+    public void setExcludes(final String excludes) {
+        this.excludes = new PredicateEvaluator(excludes, ",");
+    }
+}

Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java Tue Nov 26 16:16:29 2013
@@ -55,7 +55,7 @@ public class CounterListener extends Abs
     }
 
     @Override
-    public void after(final AgentContext context, final Throwable error) {
+    public void after(final AgentContext context, final Object result, final Throwable error) {
         final Context perfCtx = context.get(KEY, Context.class);
         if (error == null) {
             perfCtx.stop();

Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/spi/InvocationListener.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/spi/InvocationListener.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/spi/InvocationListener.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/spi/InvocationListener.java Tue Nov 26 16:16:29 2013
@@ -21,6 +21,6 @@ import org.apache.sirona.javaagent.Agent
 
 public interface InvocationListener {
     void before(AgentContext context);
-    void after(AgentContext context, Throwable error);
+    void after(AgentContext context, Object result, Throwable error);
     boolean accept(Counter.Key key, Object instance);
 }

Modified: incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java Tue Nov 26 16:16:29 2013
@@ -123,7 +123,7 @@ public class JavaAgentRunner extends Blo
     private static String[] buildProcessArgs(final FrameworkMethod mtd) throws IOException {
         final Collection<String> args = new ArrayList<String>();
         args.add(findJava());
-        args.add("-javaagent:" + buildJavaagent() + "=excludes=regex:org.apache.test.*Test" /*+ "=includes=regex:org.apache.test.sirona.*Transform"*/);
+        args.add("-javaagent:" + buildJavaagent() + "=excludes=regex:org.apache.test.*Test,prefix:org.junit,prefix:junit" /*+ "=includes=regex:org.apache.test.sirona.*Transform"*/);
         if (Boolean.getBoolean("test.debug.remote")) {
             args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005");
         }

Modified: incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/AgentPerfInterceptorAgentContractTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/AgentPerfInterceptorAgentContractTest.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/AgentPerfInterceptorAgentContractTest.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/AgentPerfInterceptorAgentContractTest.java Tue Nov 26 16:16:29 2013
@@ -36,7 +36,7 @@ public class AgentPerfInterceptorAgentCo
     public void start() {
         final Counter.Key key = AgentContext.key("start");
         final AgentContext context = AgentContext.startOn(key, null);
-        context.stop();
+        context.stop(null);
         assertEquals("org.apache.sirona.javaagent.AgentContext", context.getClass().getName());
         assertEquals(1, Repository.INSTANCE.getCounter(key).getHits());
     }
@@ -46,7 +46,7 @@ public class AgentPerfInterceptorAgentCo
         final Counter.Key key = AgentContext.key("ref");
         final Object instance = new Object();
         final AgentContext context = AgentContext.startOn(key, instance);
-        context.stop();
+        context.stop(null);
         assertEquals(instance, context.getReference());
         assertEquals(key, context.getKey());
         assertEquals(1, Repository.INSTANCE.getCounter(key).getHits());

Added: incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/HttpUrlConnectionAddHeaderTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/HttpUrlConnectionAddHeaderTest.java?rev=1545708&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/HttpUrlConnectionAddHeaderTest.java (added)
+++ incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/HttpUrlConnectionAddHeaderTest.java Tue Nov 26 16:16:29 2013
@@ -0,0 +1,84 @@
+/*
+ * 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 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.apache.test.sirona.javaagent;
+
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.javaagent.AgentContext;
+import org.apache.sirona.javaagent.JavaAgentRunner;
+import org.apache.sirona.javaagent.spi.InvocationListener;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(JavaAgentRunner.class)
+public class HttpUrlConnectionAddHeaderTest {
+    @Test
+    public void addHeader() throws IOException {
+        final URLConnection connection = ConnectionFactory.createConnection();
+        try {
+            connection.connect();
+        } catch (final Exception e) {
+            // we don't care if the connection fails
+        } finally {
+            try {
+                HttpURLConnection.class.cast(connection).disconnect();
+            } catch (final Exception e) {
+                // no-op
+            }
+        }
+
+        assertEquals("sirona", connection.getRequestProperty("origin-test"));
+    }
+
+    // we can't do it on JVm classes directly ATM (sun HttpURLConnection) so using another abstraction
+    public static class ConnectionFactory {
+        private ConnectionFactory() {
+            // no-op
+        }
+
+        private static URLConnection createConnection() throws IOException {
+            final URL url = new URL("http://doesntexist:12354");
+            final URLConnection connection = url.openConnection();
+            connection.setConnectTimeout(200);
+            connection.setReadTimeout(100);
+            return connection;
+        }
+    }
+
+    public static class HttpUrlConnectionHeaderAdder implements InvocationListener {
+        @Override
+        public void before(final AgentContext context) {
+            // no-op
+        }
+
+        @Override
+        public void after(final AgentContext context, final Object result, final Throwable error) {
+            HttpURLConnection.class.cast(result).setRequestProperty("origin-test", "sirona");
+        }
+
+        @Override
+        public boolean accept(final Counter.Key key, final Object instance) { // static => instance == null
+            return key.getName().equals("org.apache.test.sirona.javaagent.HttpUrlConnectionAddHeaderTest$ConnectionFactory.createConnection");
+        }
+    }
+}

Modified: incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/IncludeExcludeTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/IncludeExcludeTest.java?rev=1545708&r1=1545707&r2=1545708&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/IncludeExcludeTest.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/IncludeExcludeTest.java Tue Nov 26 16:16:29 2013
@@ -17,8 +17,11 @@
 package org.apache.test.sirona.javaagent;
 
 import org.apache.sirona.javaagent.SironaAgent;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
 import java.lang.instrument.ClassDefinition;
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.IllegalClassFormatException;
@@ -30,6 +33,18 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.fail;
 
 public class IncludeExcludeTest {
+    private static PrintStream err;
+
+    @BeforeClass
+    public static void noDebug() {
+        System.setProperty("sirona.agent.debug", "false");
+    }
+
+    @BeforeClass
+    public static void resetDebug() {
+        System.clearProperty("sirona.agent.debug");
+    }
+
     @Test
     public void include() throws IllegalClassFormatException {
         final InstrumentationForTestPurpose instrumentation = new InstrumentationForTestPurpose();

Added: incubator/sirona/trunk/agent/javaagent/src/test/resources/META-INF/services/org.apache.sirona.javaagent.spi.InvocationListener
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/test/resources/META-INF/services/org.apache.sirona.javaagent.spi.InvocationListener?rev=1545708&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/test/resources/META-INF/services/org.apache.sirona.javaagent.spi.InvocationListener (added)
+++ incubator/sirona/trunk/agent/javaagent/src/test/resources/META-INF/services/org.apache.sirona.javaagent.spi.InvocationListener Tue Nov 26 16:16:29 2013
@@ -0,0 +1 @@
+org.apache.test.sirona.javaagent.HttpUrlConnectionAddHeaderTest$HttpUrlConnectionHeaderAdder