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<String, String> getCache() {
return cache;
}
public void setCache(org.infinispan.Cache<String, String> 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)