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)