November 18, 2017

Java EE 7 Implementing Statistics with Interceptor, CDI Observes and LongSummaryStatistics

Java EE 7 comes with many built in techniques. Lets add statistics to our application.

First we use the Interceptor to interceptor our method that we want to get performance statistics from.

package se.magnuskkarlsson.example.javaee7.monitoring.control;

import se.magnuskkarlsson.example.javaee7.monitoring.entity.PerformanceEvent;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public class PerformanceInterceptor {

    Event events;
    public Object intercept(InvocationContext ctx) throws Exception {
        String className = ctx.getTarget().getClass().getName();
        String methodName = ctx.getMethod().getName();
        long start = System.currentTimeMillis();
        Object object = null;
        try {
            object = ctx.proceed();
        } finally {
            long duration = System.currentTimeMillis() - start;
   PerformanceEvent(className, methodName, duration));
        return object;


Above we only collect information and then use EE Event to fire it to a Observes. The data Object is a POJO.

package se.magnuskkarlsson.example.javaee7.monitoring.entity;

import javax.xml.bind.annotation.XmlRootElement;

public class PerformanceEvent {
    private final String clazz;
    private final String method;
    private final long duration;

    public PerformanceEvent(String clazz, String method, long duration) {
        this.clazz = clazz;
        this.method = method;
        this.duration = duration;

    public String getClazz() {
        return clazz;

    public String getMethod() {
        return method;

    public long getDuration() {
        return duration;

    public String toString() {
        return "PerformanceEvent{" + "clazz=" + clazz + ", method=" + method + ", duration=" + duration + '}';

And the Observes that recieves the Event.

package se.magnuskkarlsson.example.javaee7.monitoring.control;

import java.util.LongSummaryStatistics;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.enterprise.event.Observes;
import javax.inject.Singleton;
import se.magnuskkarlsson.example.javaee7.monitoring.entity.PerformanceEvent;

// ConcurrencyManagement.Bean will make singleton bean open for concurrent calls
// see
public class StatisticsObserver {

    CopyOnWriteArraySet events = new CopyOnWriteArraySet<>();
    public void log(@Observes PerformanceEvent event) {

    public LongSummaryStatistics getStatistics() {

To be able to collect statistics from many concurrent methods, we first make the class a Singleton and then make it concurrent by using ConcurrencyManagement.Bean. Now we will receive concurrent incoming calls, so to make it thread safe we use CopyOnWriteArraySet.

So the now the collection is done with Interceptor and the calculation is done with LongSummaryStatistics. Now expose it via REST.

package se.magnuskkarlsson.example.javaee7.monitoring.boundary;

import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import se.magnuskkarlsson.example.javaee7.monitoring.control.StatisticsObserver;

public class StatisticsRest {
    StatisticsObserver bean;
    public JsonObject getStatistics() {
        return Json.createObjectBuilder().add("statistics", bean.getStatistics().toString()).build();

Then call the application a couple of times, then test the statistics via, e.g. a curl command.

$ curl -i -H"Accept: application/json" http://localhost:8080/example-javaee7/rest/statistics
HTTP/1.1 200 OK
Connection: keep-alive
X-Powered-By: Undertow/1
Server: JBoss-EAP/7
Content-Type: application/json
Content-Length: 90
Date: Sat, 18 Nov 2017 03:32:41 GMT

{"statistics":"LongSummaryStatistics{count=18, sum=111, min=0, average=6.166667, max=75}"}

To see more for Interceptor, please see my previous blog Java EE 7 Performance Monitor with Interceptors, Event and Observes .

No comments: