1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. "...
TRANSCRIPT
![Page 1: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/1.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/2.jpg)
Welcome
2
![Page 3: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/3.jpg)
About me
3
![Page 4: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/4.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/5.jpg)
Quick demo
5
![Page 6: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/6.jpg)
Java agents primer
6
![Page 7: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/7.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/8.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/9.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/10.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/11.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/12.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/13.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/14.jpg)
Usage scenarios
14
![Page 15: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/15.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/16.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/17.jpg)
OSGi integration
17
![Page 18: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/18.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/19.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/20.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/21.jpg)
Integration testing
21
![Page 22: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/22.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/23.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/24.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/25.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/26.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/27.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/28.jpg)
Testing demo
28
![Page 29: 1 )/. ) $...ÊÊq 2#$ #% 1 /-$)"% 1 *( 4./ ( " / -*+ -/4Ä % 1 #*( Å /#% 1 3 /#. " /Ä% 1 *( $) % 1 Å ÊÊr 2#$ #% - /-$)"% !$) " )/ -ÄÅ ÊÊs 2#$ # ' ..+ /# /-$)" ' .. /# 0](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/29.jpg)
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](https://reader036.vdocuments.site/reader036/viewer/2022071211/6023075ce89ad541b513e86e/html5/thumbnails/30.jpg)
30