Power tools in Java

51
1 Power Tools in Java SDK Elek Márton DPC Consulting Kft

Transcript of Power tools in Java

Page 1: Power tools in Java

1

Power Tools in Java SDKElek Márton DPC Consulting Kft

Page 2: Power tools in Java

2

• Modular static html site generator• (like Jekyll, github pages)

• Do custom transformation on each text file• Example transformations:• ascii link break → <br/>• plain text → text with html header/footer

<html>....<body>{...}</body></html>

Example application

Page 3: Power tools in Java

3

Code example – types

public class Resource {

private Map<String, String> headers = new HashMap<>();

private String content;

}

public interface Transformer {

public void transform(Resource resource);

}

Page 4: Power tools in Java

4

Code example – processing

System.out.println("Transforming " + file);

Resource r = new Resource(new String(Files.readAllBytes(file)));

for (Transformer transformations : transformers) {

transformations.transform(r);

}

return r;

Page 5: Power tools in Java

5Modularity

Page 6: Power tools in Java

6

• Kezdeti megoldás: private List<Transformer> transformations = new ArrayList();

public Generator() {

transformations.add(new HtmlFrameTransformator());

transformations.add(new Nl2BrTransfomer());

}

for (Transformer transformations : transformers) {

transformations.transform(r);

}

• Cél• Dinamikusan kiterjeszthető• lib/-be új JAR → automatikusan elinduljon

Modularitás

Page 7: Power tools in Java

7

Step one: using descriptors

• bin/• site-generator.bat• site-generator.sh

• lib/• site-generator-1.0.jar• site-generator-extension-1.0.jar

• config• transform-implementations.cfg:

hu.dpc.javabar.powertools.impl.HtmlFrameTransformator

hu.dpc.javabar.powertools.impl.Nl2BrTransfomer

hu.dpc.javabar.powertools.impl.YoutubeTransformer

Page 8: Power tools in Java

8

Step two: descriptor on classpath

• bin/• site-generator.bat, site-generator.sh

• lib/• site-generator-1.0.jar

• site-generator-1.0.jar:/transform-implementations.cfg hu.dpc.javabar.powertools.impl.HtmlFrameTransformator

hu.dpc.javabar.powertools.impl.Nl2BrTransfomer

• site-generator-extension-1.0.jar• site-generator-extension-1.0.jar:/transform-implementations.cfg

hu.dpc.javabar.powertools.impl.YoutubeTransformer

Enumeration<URL> resources = getClass().getClassLoader().getResources("/transform-implementations.cfg");

Page 9: Power tools in Java

9

Step three:Service Provider Interface

• Standard, part of the JDK• Descriptor are on the classpath• Contains the class names of the implementations• Using nameconvention (META-INF/services/hu.dpc...Interface)

• Simple API (ServiceLoader), only a few classes• Not included:• Dependency management• Versioning• Priority handling

• Only answers the question:• Who implemented a specific interface

Page 10: Power tools in Java

10

SPI code example

• META-INF/services/hu.dpc.javabar.powertools.api.Transformer• hu.dpc.javabar.powertools.impl.HtmlFrameTransformer• hu.dpc.javabar.powertools.impl.Nl2BrTransfomer

ServiceLoader<Transformer> transformers = ServiceLoader.load(Transformer.class);

for (Transformer transfomer : transformers) {

...

}

Page 11: Power tools in Java

11

SPI – where is it used

• (almost) everywhere• multiple location at JDK (eg. XML processor

implementation)• Even the OSGi has adapter for SPI

• Very effective even if it's very simple• Easy solution to avoid circular dependencies

of the projects

Page 12: Power tools in Java

12Automatic SPI generation

Page 13: Power tools in Java

13

How to generate SPI descriptors?

• Service Provider Interface

META-INF/services/...

should be created and filled with implementation automatically

Page 14: Power tools in Java

14

Annotation processors

• Part of the javac from Java 6• Run at compile time• Class/descriptor/... files could be generated

based on specific annotated classes• Could be activated with SPI• META-INF/services/

javax.annotation.processing.Processor

• Multiple iteration (processing the generated files)• Parameters could be used

Page 15: Power tools in Java

15

Annotation processor

public @interface Service {

}

@Service

public class Nl2BrTransfomer implements Transformer {

@Override

public void transform(Resource resource) {

resource.setContent( resource.getContent().replaceAll("\n\n", "<br/>") );

}

}

Page 16: Power tools in Java

16

Annotation processor example

@SupportedAnnotationTypes("hu.dpc.javabar.powertools.Service")

@SupportedSourceVersion(SourceVersion.RELEASE_7)

public class ServiceAnnotationProcessor extends AbstractProcessor {

Map<String, Set<String>> services = new HashMap<String, Set<String>>();

@Override

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

}

}

Page 17: Power tools in Java

17

Annotation processor example

Map<String, Set<String>> services = new HashMap<String, Set<String>>();

@Override

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "@service generation");

if (roundEnv.processingOver()) {

writeOutServices(roundEnv);

return false;

}

//process annotations

...

}

Page 18: Power tools in Java

18

Annotation processor example

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

//write out the file ...

Elements elements = processingEnv.getElementUtils();

for (Element element : roundEnv.getElementsAnnotatedWith(Service.class)) {

TypeElement type = (TypeElement) element;

TypeElement contract = (TypeElement) ((DeclaredType) type.getInterfaces().get(0)).asElement();

String cn = elements.getBinaryName(contract).toString();

Set<String> v = services.get(cn);

if (v == null) {

services.put(cn, v = new TreeSet<String>());

}

v.add(cn);

}

return false;

}

Page 19: Power tools in Java

19

Generating code

for (Element element : roundEnv.getElementsAnnotatedWith(Service.class)) {

TypeElement type = (TypeElement) element;

JavaFileObject jfo = processingEnv.getFiler().createSourceFile(

type.getQualifiedName() + "GeneratedInfo");

BufferedWriter bw = new BufferedWriter(jfo.openWriter());

bw.append("package ");

bw.append(((PackageElement) type.getEnclosingElement()).getQualifiedName());

bw.append(";\n");

bw.append("import hu.dpc.javabar.powertools.Service;\n");

bw.newLine();

bw.newLine();

bw.append("@Service \n");

bw.append(String.format("public class %s{", type.getSimpleName()));

bw.newLine();

bw.append("public static final boolean PROCESSED = true;" );

bw.append("}");

bw.flush();

Page 20: Power tools in Java

20

Project to generate SPI

• To generate SPI descriptors, try• http://metainf-services.kohsuke.org/• https://code.google.com/p/spi/

<dependency>

<groupId>org.kohsuke.metainf-services</groupId>

<artifactId>metainf-services</artifactId>

<version>1.1</version>

<optional>true</optional>

</dependency>

Page 21: Power tools in Java

21Runtime Javadoc access

Page 22: Power tools in Java

22

Documentation of SPI implementation

/**

* Replace new double new lines with html line break.

*/

@Service("Replace new double new lines with html line break")

public class Nl2BrTransfomer implements Transformer {

@Override

public void transform(Resource resource) {

resource.setContent(resource.getContent().replaceAll("\n\n", "<br/>"));

}

}

Available transformations:

HtmlFrameTransformator : ...

Nl2BrTransfomer : Replace new double new lines with html line break

Page 23: Power tools in Java

23

How to access javadoc at runtime?

>>> def hello(name):

... """Print hello for the name"""

... print("Hello", name)

...

>>> hello("Bela")

Hello Bela

>>> print(hello.__doc__)

Print hello for the name

user=> (defn hello "Print hello for the name" [name] (str "Hello " name))

#'user/hellouser=> (hello "Bela")

"Hello Bela"user=> (get (meta (var hello)) :doc)

"Print hello for the name"

• The documentation of the annotated service class should come from javadoc documents

• Easy with other languages(Python, Clojure)

Page 24: Power tools in Java

24

Javadoc – Doclets

• Formatting classes for custom javadoc generation

• Doclet API could access all of the javadoc and class metadata information

• Could be used to generate custom javadoc page but also to generate XML descriptors

Page 25: Power tools in Java

25

Doclet example

public class GenerateDocletResource {

public static boolean start(RootDoc rootDoc) {

for (ClassDoc cd : rootDoc.specifiedClasses()) {

Path p = Paths.get(root + "/.../" + cd.qualifiedTypeName() + ".javadoc");

Files.createDirectories(p.getParent());

Files.write(p, cd.commentText().getBytes());

}

return true;

}

}

Page 26: Power tools in Java

26

Doclet loading

public String getJavadoc(Class type) {

String resourceName = "/" + type.getCanonicalName() + ".javadoc";

try (InputStream s = getClass().getResourceAsStream(resourceName)){

if (s == null) {

return "Javadoc resource is missing for class " + type;

}

return new Scanner(s).useDelimiter("//Z").next();

} catch (IOException ex) {

...

}

}

Page 27: Power tools in Java

27

Using it from Gradle

dependencies {

doclet project(":javadoc-metadata-generator")

}

task generateDocs(type: Javadoc) {

source = sourceSets.main.allJava options = new SimpleJavadocOption()

options.docletpath = configurations.doclet.files.asType(List)

options.doclet = "hu.dpc.javabar.powertools.doc.GenerateDocletResource"

}

compileJava.dependsOn generateDocs

Page 28: Power tools in Java

28

Using it from Maven

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-javadoc-plugin</artifactId>

<version>2.9.1</version>

<executions>

<execution>

<id>doc-resource-generator</id>

<phase>prepare-package</phase>

<goals>javadoc</goals>

</execution>

</executions>

<configuration>

<doclet>org.umlgraph.doclet.UmlGraphDoc</doclet>

<!-- <docletPath>/path/to/UmlGraph.jar</docletPath> -->

<docletArtifact>

<groupId>org.umlgraph</groupId>

<artifactId>doclet</artifactId>

<version>5.1</version>

</docletArtifact>

<additionalparam>-views</additionalparam>

<useStandardDocletOptions>true</useStandardDocletOptions>

</configuration>

</plugin>

Page 29: Power tools in Java

29Runtime metrics

Page 30: Power tools in Java

30

Java Management Extension (JMX)

• Well known solution from the Standard Java API• Management• Monitoring

• All of the JVM information could be accessed as well

• Custom metrics could be added

Page 31: Power tools in Java

31

JMX JSR

• JSR 3: Java Management Extension (JMX)• JSR 160: JMX Remote API• JSR 255: JMX 2.0 = JSR 3 + 160 + …

(Inactive)• JSR 262: Web Services Connector for JMX

(Inactive)• Jolokia: REST interface adapter

Page 32: Power tools in Java

32

JMX Architecture

Source wikipedia

Page 33: Power tools in Java

33

JMX – Probe level

• MBean – Managed Object: bármilyen resource• Attributes• Operations• Notifications

• MBean types• Standard• Dynamic• MXBeans

Page 34: Power tools in Java

34

Simple JMX example

public interface GeneratorMBean {

public void stop();

public int getProcessedFileNo();

}

MBeanServer server = ManagementFactory.getPlatformMBeanServer();

ObjectName name = new ObjectName("hu.dpc.javabar.powertools", "name", "Generator");

server.registerMBean(generator, name);

//generator implements GeneratorMBean

Page 35: Power tools in Java

35

JMX Architecture

Source wikipedia

Page 36: Power tools in Java

36

JMX platform Mbean server

MBeanServer server = ManagementFactory.getPlatformMBeanServer();

Page 37: Power tools in Java

37

JMX custom Mbean server

MBeanServer server = MbeanServerFactory.createMBeanServer();

Registry registry = LocateRegistry.createRegistry(1234);

JMXServiceURL jmxServiceURL = new JMXServiceURL("rmi",

"localhost",

1235,

"/jndi/rmi://localhost:1234/jmx");

JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null, server);connectorServer.start();

System.out.println(jmxServiceURL);

// service:jmx:rmi://localhost:1235/jndi/rmi://localhost:1234/jmx

Page 38: Power tools in Java

38

JMX client API

JMXServiceURL url =

new JMXServiceURL("service:jmx:rmi://localhost:1235/jndi/rmi://localhost:1234/jmx");

JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

ObjectName name = new ObjectName("hu.dpc.javabar.powertools", "name", "Generator");

GeneratorMBean mbean = JMX.newMBeanProxy(mbsc, name, GeneratorMBean.class);

System.out.println(mbean.getProcessedFileNo());

//12

Page 39: Power tools in Java

39

JMX Architecture

Source wikipedia

Page 40: Power tools in Java

40

JMX custom MBeanServer

MBeanServer server = MbeanServerFactory.createMBeanServer();

Registry registry = LocateRegistry.createRegistry(1234);

JMXServiceURL jmxServiceURL = new JMXServiceURL("rmi",

"localhost",

1235,

"/jndi/rmi://localhost:1234/jmx");

JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null, server);connectorServer.start();

System.out.println(jmxServiceURL);

// service:jmx:rmi://localhost:1235/jndi/rmi://localhost:1234/jmx

Page 41: Power tools in Java

41

JMX platform MBeanServer

MBeanServer server = ManagementFactory.getPlatformMBeanServer();

Page 42: Power tools in Java

42Agents

Page 43: Power tools in Java

43

Java Agents

• Written in Java or C/C++• Native: Java Virtual Machine Tool Interface (JVM TI)

• -agentlib, -agentpath

• Java:• -javaagent

• Features• run custom command (in the application JVM-ben)• manipulating bytecode loading

• Activating• Before application startup (-javaagent)• Attaching at runtime (Attach API)

Page 44: Power tools in Java

44

Java Agent interface

public static void premain(String agentArgs, Instrumentation inst) {

}

• Intstrumentation• addTransformer(ClassFileTransformer transformer)

• Registers the supplied transformer.

• appendToBootstrapClassLoaderSearch(JarFile jarfile)• Specifies a JAR file with instrumentation classes to be defined by the bootstrap class

loader.

• appendToSystemClassLoaderSearch(JarFile jarfile) • Specifies a JAR file with instrumentation classes to be defined by the system class

loader

• ClassFileTransformer.• transform(ClassLoader loader, String className, Class<?> classBeingRedefined,

ProtectionDomain protectionDomain, byte[] classfileBuffer)

Page 45: Power tools in Java

45

Activating Java Agent

• Before application start• -javaagent:<jarpath>[=<options>]• META-INF/MANIFEST.MF: Premain-Class: …• public static void premain(...)

• During application run• Attach API• META-INF/MANIFEST.MF: Agent-Class: …• public static void agentmain(...)

Page 46: Power tools in Java

46

Attach API

//JVMs of the CURRENT user

List<VirtualMachineDescriptor> vms = VirtualMachine.list();

for (VirtualMachineDescriptor virtualMachineDescriptor : vms) {

VirtualMachine vm = VirtualMachine.attach(virtualMachineDescriptor);

if (vm != null) {

System.out.println(virtualMachineDescriptor.displayName());

System.out.println("Java version = " + vm.getSystemProperties(). getProperty("java.version"));

}

}

Page 47: Power tools in Java

47

JMX connection – with agents

static final String CONNECTOR_ADDRESS =

"com.sun.management.jmxremote.localConnectorAddress";

VirtualMachine vm = VirtualMachine.attach(id);

String connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);

if (connectorAddress == null) {

String agent = vm.getSystemProperties().getProperty("java.home") +

File.separator + "lib" + File.separator + "management-agent.jar";

vm.loadAgent(agent);

connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);

}

JMXServiceURL url = new JMXServiceURL(connectorAddress);

JMXConnector = JMXConnectorFactory.connect(url);

Page 48: Power tools in Java

48

Where is it used?

• Bytecode manipulation• AspectJ• Spring• Persistence frameworks• BTrace

• premain/agent:• jre/lib/management-agent.jar

Page 49: Power tools in Java

49

Summary

• JDK Power tools• Service Provider Interface – for modularity• Annotation processors – compile time

processing• Javadoc doclet – Javadoc (pre)processing• JMX – runtime metrics, methods• Agentek, Attach API – byte code manipulation,

runtime modification

Page 51: Power tools in Java

51

Elek Márton / DPC [email protected]://www.meetup.com/bpjavabar/