Will it blend ? Java agents and OSGi Slides revision : 20190923- ea 7 c 311 1
Welcome 2
About me 3
Outline Quick demo Java agents primer Usage scenarios OSGi integration Integration testing Testing demo 4
Quick demo 5
Java agents primer 6
Java instrumentation APIs Provides services that allow Java programming language agents to instrument programs running on the JVM . java.lang.instrument Javadoc , Java SE 8 7
Static agents # loaded at application startup $ java - javaagent : agent . jar - jar app . jar Premain - Class : org . example . my . Agent import java . lang . instrument .*; public class Agent { public static void premain ( String args , ⏎ Instrumentation inst ) { inst . addTransformer ( new ClassFileTransformer () { /* implementation elided */ }); } } 8
Dynamic agents // dynamically attached to a running JVM VirtualMachine vm = VirtualMachine . attach ( vmPid ); vm . loadAgent ( agentFilePath ); vm . detach (); Agent - Class : org . example . my . Agent import java . lang . instrument .*; public class Agent { public static void agentmain ( String args , ⏎ Instrumentation inst ) { inst . addTransformer ( new ClassFileTransformer () { /* implementation elided */ }); } } 9
Class transformation public interface ClassFileTransformer { byte [] transform ( ClassLoader loader , String className , Class < ? > classBeingRedefined , ProtectionDomain protectionDomain , byte [] classfileBuffer ) throws IllegalClassFormatException ; } 10
Java bytecode public static void main ( java . lang . String []); Code : 0: getstatic #16 ⏎ // Field java / lang / System . out : Ljava / io / PrintStream ; 3: ldc #22 ⏎ // String Hello , world 5: invokevirtual #24 ⏎ // Method java / io / PrintStream . println :( Ljava / lang / String ; 8: return 11
Bytecode generation libraries Apache Commons BCEL ByteBuddy CGLib Javassist ObjectWeb ASM 12
Bytecode generation with Javassist public byte [] transform (...) throws ... { ClassPool classPool = ClassPool . getDefault (); CtMethod method = classPool . getMethod ( ⏎ Descriptor . toJavaName ( className ), " main "); method . insertAfter (" System . out . println " + ⏎ "(\"... hello yourself !...\");"); byte [] newClass = method . getDeclaringClass () ⏎ . toBytecode (); method . getDeclaringClass (). detach (); return newClass ; } 13
Usage scenarios 14
When to use agents 1. Code outside of your control 2. No better platform facilities exist 3. ( Usually ) Cross - cutting concerns 15
Agent examples 1. Monitoring ( logging , tracing , error reporting ...) 2. Profiling 3. Debugging 4. Mocking libraries 5. Code reload / Hot swap 16
OSGi integration 17
Mind the classloader - ClassPool defaultPool = ClassPool . getDefault (); - CtClass cc = defaultPool . get ( ⏎ - Descriptor . toJavaName ( className )); + ClassPool classPool = new ClassPool ( true ); + classPool . appendClassPath ( new LoaderClassPath ( loader )); + classPool . insertClassPath ( new ByteArrayClassPath ( ⏎ + Descriptor . toJavaName ( className ), classfileBuffer )); 18
Carefully manage dependencies New requirements typically fail since they are not defined by the bundle Bundles can be processed at build - time Patching Import - Package DynamicImport-Package: * 19
OSGi alternatives - Weaving Hooks Simplified deployment - OSGi bundle Simple registration via OSGi whiteboard Handles updated bundle package imports OSGi - only solution 20
Integration testing 21
Packaging challenges Java agents ... must be packaged as a Jar file , with a specific manifest not trivially attached to the current process usually a one - way deal , no support for rolling back class changes 22
Custom test launchers " unit " tests launch Java process with custom agents attached require separate communication channel with java agent no out - of - the - box support for code coverage and other tools 23
Bootstrapping the test // 1. which java ? String javaHome = System . getProperty (" java . home "); Path javaExe = Paths . get ( javaHome , " bin ", " java "); // 2. which jar ? String ja = findAgentJar (); // 3. which classpath ? String classPath = buildClassPath (); // 4. launch ProcessBuilder pb = new ProcessBuilder ( javaExe . toString (), "- javaagent :" + ja , "- cp ", classPath , TestApplication . class . getName () ); 24
Verifying side e ff ects Path stdout = Paths . get (" target ", " stdout . txt "); Path stderr = Paths . get (" target ", " stderr . txt "); pb . redirectInput ( Redirect . INHERIT ); pb . redirectOutput ( stdout . toFile ()); pb . redirectError ( stderr . toFile ()); 25
Adding code coverage ProcessBuilder pb = new ProcessBuilder ( javaExe . toString (), "- javaagent :" + codeCoverageAgent , "- javaagent :" + ja , "- cp ", classPath , TestApplication . class . getName () ); 26
OSGi integration testing // note - must run in a forked container @ RunWith ( PaxExam . class ) public class OsgiIT { @ Configuration public Option [] config () throws IOException { return options ( junitBundles (), ⏎ vmOption ("- javaagent :" + agentJar ) ); } @ Test public void callTimesOut () throws IOException { assertTrue ( agentReallyWorks ()); } } 27
Testing demo 28
Resources https :// docs . oracle . com / javase /8/ docs / api / java / lang / instrum summary . html https :// www . javassist . org / https :// sling . apache . org / documentation / bundles / connectio agent . html 29
30
Recommend
More recommend