Monitoring WildFly’s Infinispan caches

In this tutorial we will learn how to monitor the Embedded Infinispan Caches contained in JBoss EAP / WildFly using Infinispan Listeners.

An org.infinispan.notifications.Listener is a key element of Infinispan infrastructure. You can define a new Listener by means of the @org.infinispan.notifications.Listener annotation. Objects annotated with this annotation can be attached to a running Cache so users can be notified of Cache events. Let’s see an example of it:

package com.sample;

import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStarted;
import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStopped;
import org.infinispan.notifications.cachemanagerlistener.event.CacheStartedEvent;
import org.infinispan.notifications.cachemanagerlistener.event.CacheStoppedEvent;

@Listener(clustered = true)
public class SimpleListener {

    @CacheEntryCreated
    public void addKey(CacheEntryCreatedEvent event) {
        System.out.println("New entry " + event.getKey() + " created in the cache with value "+event.getValue());
    }

    @CacheEntryRemoved
    public void removeKey(CacheEntryRemovedEvent event) {
        System.out.println("Entry " + event.getKey() + " removed from the cache");
    }

    @CacheStarted
    public void cacheStarted(CacheStartedEvent event) {
        System.out.println("Cache Started");
    }

    @CacheStopped
    public void cacheStopped(CacheStoppedEvent event) {
        System.out.println("Cache Stopped");
    }
}

As you can see, each method is annotated with the event it is interested in. The Listener methods annotated with these events must be public , return a void , and accept a single parameter representing the event type.

As an example, the method annotated with @CacheEntryCreated annotation will be invoked when a new entry is added to the cache, while the corresponding method

annotated with @CacheEntryRemoved will be invoked, and an entry will be removed from the cache.

Now that we have a listener we can apply it to a Cache used by the application server. Out of the box some embedded Cache Containers are available in the application server:

<cache-container name="server" aliases="singleton cluster" module="org.wildfly.clustering.server" default-cache="default">
. . .
</cache-container>

<cache-container name="web" module="org.wildfly.clustering.web.infinispan" default-cache="dist" statistics-enabled="true">
. . .
</cache-container>

<cache-container name="ejb" aliases="sfsb" module="org.wildfly.clustering.ejb.infinispan" default-cache="dist">
. . .
</cache-container>

<cache-container name="hibernate" module="org.hibernate.infinispan" default-cache="local-query">
. . .
</cache-container>

Discussing about the purpose of the above caches is out of the scope of this articles; we will show here how to monitor the “web” cache where the HTTP session is cached. We will create for this purpose a CDI producer.

package com.sample;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStarted;
import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStopped;
 
@ApplicationScoped
public class Producer {

    @Resource(lookup = "java:jboss/infinispan/container/web")
    private EmbeddedCacheManager container;

    private org.infinispan.Cache<String, String> cache;

    @Inject
    SimpleListener listener;

    @PostConstruct
    public void initCache() {

        this.cache = container.getCache("myapp.war");

        System.out.println("Got cache " + cache.getName());
        cache.addListener(listener);

    }

    @Produces
    public org.infinispan.Cache&lt;String, String&gt; getCache() {
        return cache;
    }

    public void setCache(org.infinispan.Cache&lt;String, String&gt; cache) {
        this.cache = cache;
    }

}

The CDI producer references as a Resource the “web” Cache container which is available in the application server. Within the Cache container a Set of Caches are available: one for each application which registers on the Cache container. In our case we will pickup the Cache related to out application:

this.cache = container.getCache("myapp.war");

You can improve this piece of code with some application name’s discovery name or by means of a simple property.

What is important to note is that, once we have got the Cache, we register our Listener on it, so that we can produce a org.infinispan.Cache<String, String> which has got our Listener registered.

Now most of our effort is done. Include a <distributable /> stanza in the web.xml. Within the Web application you can verify with a Simple Servlet that attributes are “captured” by our listener:

@WebServlet(name = "TestServlet", urlPatterns = {"/TestServlet"})
public class TestServlet extends HttpServlet {

 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         request.getSession().setAttribute("key", "value");
. . .            
        }
    }
}

As you can see from the logs, each attribute added in the HTTP Session is captured on the servers that got it replicated/distributed from the Cache:

13:03:46,430 INFO  [stdout] (default task-2) New entry irwU9ly0c8786WLA-Doz147jc79Slj8R1uuoyrNh created in the cache with value {key=value}

That’s all about Infinispan cache and JBoss/WildFly for now! 

BUILD SUCCESSFUL (total time: 2 seconds)