1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. "...

30
1

Upload: others

Post on 02-Oct-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Will it blend? Java agents and OSGiSlides revision: 20190923-ea7c311

1

Page 2: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Welcome

2

Page 3: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

About me

3

Page 4: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Outline

Quick demo

Java agents primer

Usage scenarios

OSGi integration

Integration testing

Testing demo

4

Page 5: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Quick demo

5

Page 6: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Java agents primer

6

Page 7: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Java instrumentation APIs

java.lang.instrument Javadoc, Java SE 8

Provides services that allow Java programming

language agents to instrument programs running

on the JVM.

7

Page 8: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 9: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 10: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Class transformation

public interface ClassFileTransformer {

byte[] transform(ClassLoader loader,

String className,

Class<?> classBeingRedefined,

ProtectionDomain protectionDomain,

byte[] classfileBuffer)

throws IllegalClassFormatException;

}

10

Page 11: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Java bytecodepublic 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

Page 12: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Bytecode generation libraries

Apache Commons BCEL

ByteBuddy

CGLib

Javassist

ObjectWeb ASM

12

Page 13: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 14: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Usage scenarios

14

Page 15: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

When to use agents

1. Code outside of your control

2. No better platform facilities exist

3. (Usually) Cross-cutting concerns

15

Page 16: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Agent examples

1. Monitoring (logging, tracing, error reporting ...)

2. Profiling

3. Debugging

4. Mocking libraries

5. Code reload/Hot swap

16

Page 17: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

OSGi integration

17

Page 18: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 19: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 20: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

OSGi alternatives - Weaving Hooks

Simplified deployment - OSGi bundle

Simple registration via OSGi whiteboard

Handles updated bundle package imports

OSGi-only solution

20

Page 21: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Integration testing

21

Page 22: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 23: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 24: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 25: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Verifying side effects

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

Page 26: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Adding code coverage

ProcessBuilder pb = new ProcessBuilder(

javaExe.toString(),

"-javaagent:" + codeCoverageAgent,

"-javaagent:" + ja,

"-cp",

classPath,

TestApplication.class.getName()

);

26

Page 27: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 28: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

Testing demo

28

Page 29: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

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

Page 30: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0

30