diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml
index 932748cc70..a61dbf5925 100644
--- a/spring-boot-actuator/pom.xml
+++ b/spring-boot-actuator/pom.xml
@@ -97,6 +97,11 @@
hibernate-validator
true
+
+ org.infinispan
+ infinispan-spring4
+ true
+
org.springframework
spring-messaging
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfiguration.java
index 4719ea719d..b985f6ff58 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfiguration.java
@@ -21,6 +21,7 @@ import javax.cache.Caching;
import com.hazelcast.core.IMap;
import com.hazelcast.spring.cache.HazelcastCache;
import net.sf.ehcache.Ehcache;
+import org.infinispan.spring.provider.SpringCache;
import org.springframework.boot.actuate.cache.CacheStatistics;
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
@@ -29,7 +30,8 @@ import org.springframework.boot.actuate.cache.DefaultCacheStatistics;
import org.springframework.boot.actuate.cache.EhCacheStatisticsProvider;
import org.springframework.boot.actuate.cache.GuavaCacheStatisticsProvider;
import org.springframework.boot.actuate.cache.HazelcastCacheStatisticsProvider;
-import org.springframework.boot.actuate.cache.JCacheStatisticsProvider;
+import org.springframework.boot.actuate.cache.InfinispanCacheStatisticsProvider;
+import org.springframework.boot.actuate.cache.JCacheCacheStatisticsProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
@@ -61,8 +63,8 @@ public class CacheStatisticsAutoConfiguration {
static class JCacheCacheStatisticsProviderConfiguration {
@Bean
- public JCacheStatisticsProvider jCacheStatisticsProvider() {
- return new JCacheStatisticsProvider();
+ public JCacheCacheStatisticsProvider jCacheCacheStatisticsProvider() {
+ return new JCacheCacheStatisticsProvider();
}
}
@@ -88,6 +90,17 @@ public class CacheStatisticsAutoConfiguration {
}
}
+ @Configuration
+ @ConditionalOnClass({ SpringCache.class })
+ static class InfinispanCacheStatisticsProviderConfiguration {
+
+ @Bean
+ public InfinispanCacheStatisticsProvider infinispanCacheStatisticsProvider() {
+ return new InfinispanCacheStatisticsProvider();
+ }
+
+ }
+
@Configuration
@ConditionalOnClass(com.google.common.cache.Cache.class)
static class GuavaCacheStatisticsConfiguration {
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/JCacheStatisticsProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/AbstractJmxCacheStatisticsProvider.java
similarity index 53%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/JCacheStatisticsProvider.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/AbstractJmxCacheStatisticsProvider.java
index 8d1c619ca2..d7f6668194 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/JCacheStatisticsProvider.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/AbstractJmxCacheStatisticsProvider.java
@@ -18,42 +18,44 @@ package org.springframework.boot.actuate.cache;
import java.lang.management.ManagementFactory;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
-import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
-import org.springframework.cache.jcache.JCacheCache;
/**
- * {@link CacheStatisticsProvider} implementation for a JSR-107 compliant cache.
+ * Base {@link CacheStatisticsProvider} implementation that uses JMX to
+ * retrieve the cache statistics.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
-public class JCacheStatisticsProvider implements CacheStatisticsProvider {
+public abstract class AbstractJmxCacheStatisticsProvider
+ implements CacheStatisticsProvider {
private static final Logger logger = LoggerFactory
- .getLogger(JCacheStatisticsProvider.class);
+ .getLogger(AbstractJmxCacheStatisticsProvider.class);
private MBeanServer mBeanServer;
- private Map caches = new ConcurrentHashMap();
+ private Map caches =
+ new ConcurrentHashMap();
+
@Override
- public CacheStatistics getCacheStatistics(CacheManager cacheManager, JCacheCache cache) {
+ public CacheStatistics getCacheStatistics(CacheManager cacheManager, C cache) {
try {
- ObjectName objectName = getObjectName(cache);
+ ObjectName objectName = internalGetObjectName(cache);
if (objectName != null) {
return getCacheStatistics(objectName);
}
@@ -64,35 +66,33 @@ public class JCacheStatisticsProvider implements CacheStatisticsProvider 0 || missPercentage > 0)) {
- statistics.setHitRatio(hitPercentage / (double) 100);
- statistics.setMissRatio(missPercentage / (double) 100);
- }
- return statistics;
- }
+ /**
+ * Return the {@link ObjectName} of the MBean that is managing the specified cache or
+ * {@code null} if none is found.
+ * @param cache the cache to handle
+ * @return the object name of the cache statistics MBean
+ */
+ protected abstract ObjectName getObjectName(C cache) throws MalformedObjectNameException;
- protected ObjectName getObjectName(JCacheCache cache)
+ /**
+ * Return the current {@link CacheStatistics} snapshot from the MBean identified by the
+ * specified {@link ObjectName}.
+ * @param objectName the object name of the cache statistics MBean
+ * @return the current cache statistics
+ */
+ protected abstract CacheStatistics getCacheStatistics(ObjectName objectName);
+
+
+ private ObjectName internalGetObjectName(C cache)
throws MalformedObjectNameException {
- if (this.caches.containsKey(cache)) {
- return this.caches.get(cache);
+ String cacheName = cache.getName();
+ ObjectNameWrapper value = this.caches.get(cacheName);
+ if (value != null) {
+ return value.objectName;
}
- Set instances = getMBeanServer().queryMBeans(
- new ObjectName("javax.cache:type=CacheStatistics,Cache="
- + cache.getName() + ",*"), null);
- if (instances.size() == 1) {
- ObjectName objectName = instances.iterator().next().getObjectName();
- this.caches.put(cache, objectName);
- return objectName;
- }
- return null; // None or more than one
+ ObjectName objectName = getObjectName(cache);
+ this.caches.put(cacheName, new ObjectNameWrapper(objectName));
+ return objectName;
}
protected MBeanServer getMBeanServer() {
@@ -102,18 +102,17 @@ public class JCacheStatisticsProvider implements CacheStatisticsProvider T getAttribute(MBeanServer mBeanServer, ObjectName objectName,
- String attributeName, Class type) {
+ protected T getAttribute(ObjectName objectName, String attributeName, Class type) {
try {
- Object attribute = mBeanServer.getAttribute(objectName, attributeName);
+ Object attribute = getMBeanServer().getAttribute(objectName, attributeName);
return type.cast(attribute);
}
catch (MBeanException ex) {
throw new IllegalStateException(ex);
}
catch (AttributeNotFoundException ex) {
- throw new IllegalStateException("Unexpected: jcache provider does not "
- + "expose standard attribute " + attributeName, ex);
+ throw new IllegalStateException("Unexpected: MBean with name '" + objectName + "' " +
+ "does not expose attribute with name " + attributeName, ex);
}
catch (ReflectionException ex) {
throw new IllegalStateException(ex);
@@ -124,4 +123,13 @@ public class JCacheStatisticsProvider implements CacheStatisticsProvider {
+
+ @Override
+ protected ObjectName getObjectName(SpringCache cache) throws MalformedObjectNameException {
+ Set instances = getMBeanServer().queryMBeans(
+ new ObjectName("org.infinispan:component=Statistics,type=Cache," +
+ "name=\"" + cache.getName() + "(local)\",*"), null);
+ if (instances.size() == 1) {
+ return instances.iterator().next().getObjectName();
+ }
+ return null; // None or more than one
+ }
+
+ protected CacheStatistics getCacheStatistics(ObjectName objectName) {
+ DefaultCacheStatistics statistics = new DefaultCacheStatistics();
+ Integer size = getAttribute(objectName, "numberOfEntries",
+ Integer.class);
+ if (size != null) {
+ statistics.setSize((long) size);
+ if (size > 0) { // Let's initialize the stats if we have some data
+ Double hitRatio = getAttribute(objectName, "hitRatio",
+ Double.class);
+ if ((hitRatio != null)) {
+ statistics.setHitRatio(hitRatio);
+ statistics.setMissRatio(1 - hitRatio);
+ }
+ }
+ }
+ return statistics;
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/JCacheCacheStatisticsProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/JCacheCacheStatisticsProvider.java
new file mode 100644
index 0000000000..dce29a125e
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/JCacheCacheStatisticsProvider.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.cache;
+
+import java.util.Set;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.springframework.cache.jcache.JCacheCache;
+
+/**
+ * {@link CacheStatisticsProvider} implementation for a JSR-107 compliant cache.
+ *
+ * @author Stephane Nicoll
+ * @since 1.3.0
+ */
+public class JCacheCacheStatisticsProvider extends AbstractJmxCacheStatisticsProvider {
+
+
+ protected ObjectName getObjectName(JCacheCache cache)
+ throws MalformedObjectNameException {
+
+ Set instances = getMBeanServer().queryMBeans(
+ new ObjectName("javax.cache:type=CacheStatistics,Cache="
+ + cache.getName() + ",*"), null);
+ if (instances.size() == 1) {
+ return instances.iterator().next().getObjectName();
+ }
+ return null; // None or more than one
+ }
+
+ protected CacheStatistics getCacheStatistics(ObjectName objectName) {
+ DefaultCacheStatistics statistics = new DefaultCacheStatistics();
+ Float hitPercentage = getAttribute(objectName, "CacheHitPercentage",
+ Float.class);
+ Float missPercentage = getAttribute(objectName,
+ "CacheMissPercentage", Float.class);
+ if ((hitPercentage != null && missPercentage != null)
+ && (hitPercentage > 0 || missPercentage > 0)) {
+ statistics.setHitRatio(hitPercentage / (double) 100);
+ statistics.setMissRatio(missPercentage / (double) 100);
+ }
+ return statistics;
+ }
+
+}
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfigurationTests.java
index c3128b72ca..cec8aa3a47 100644
--- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfigurationTests.java
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CacheStatisticsAutoConfigurationTests.java
@@ -17,14 +17,24 @@
package org.springframework.boot.actuate.autoconfigure;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Arrays;
-
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;
+import com.google.common.cache.CacheBuilder;
+import com.hazelcast.cache.HazelcastCachingProvider;
+import com.hazelcast.config.Config;
+import com.hazelcast.config.XmlConfigBuilder;
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.spring.cache.HazelcastCacheManager;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.spring.provider.SpringEmbeddedCacheManager;
import org.junit.After;
import org.junit.Test;
-import org.springframework.boot.actuate.autoconfigure.CacheStatisticsAutoConfiguration;
+
import org.springframework.boot.actuate.cache.CacheStatistics;
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
import org.springframework.cache.Cache;
@@ -42,14 +52,6 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
-import com.google.common.cache.CacheBuilder;
-import com.hazelcast.cache.HazelcastCachingProvider;
-import com.hazelcast.config.Config;
-import com.hazelcast.config.XmlConfigBuilder;
-import com.hazelcast.core.Hazelcast;
-import com.hazelcast.core.HazelcastInstance;
-import com.hazelcast.spring.cache.HazelcastCacheManager;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -76,7 +78,7 @@ public class CacheStatisticsAutoConfigurationTests {
public void basicJCacheCacheStatistics() {
load(JCacheCacheConfig.class);
CacheStatisticsProvider provider = this.context.getBean(
- "jCacheStatisticsProvider", CacheStatisticsProvider.class);
+ "jCacheCacheStatisticsProvider", CacheStatisticsProvider.class);
doTestCoreStatistics(provider, false);
}
@@ -96,6 +98,14 @@ public class CacheStatisticsAutoConfigurationTests {
doTestCoreStatistics(provider, true);
}
+ @Test
+ public void basicInfinispanCacheStatistics() {
+ load(InfinispanConfig.class);
+ CacheStatisticsProvider provider = this.context.getBean(
+ "infinispanCacheStatisticsProvider", CacheStatisticsProvider.class);
+ doTestCoreStatistics(provider, true);
+ }
+
@Test
public void basicGuavaCacheStatistics() {
load(GuavaConfig.class);
@@ -246,6 +256,28 @@ public class CacheStatisticsAutoConfigurationTests {
}
+ @Configuration
+ static class InfinispanConfig {
+
+ @Bean
+ public SpringEmbeddedCacheManager cacheManager() throws IOException {
+ return new SpringEmbeddedCacheManager(embeddedCacheManager());
+ }
+
+ @Bean
+ public EmbeddedCacheManager embeddedCacheManager() throws IOException {
+ Resource resource = new ClassPathResource("cache/test-infinispan.xml");
+ InputStream in = resource.getInputStream();
+ try {
+ return new DefaultCacheManager(in);
+ }
+ finally {
+ in.close();
+ }
+ }
+
+ }
+
@Configuration
static class GuavaConfig {
diff --git a/spring-boot-actuator/src/test/resources/cache/test-infinispan.xml b/spring-boot-actuator/src/test/resources/cache/test-infinispan.xml
new file mode 100644
index 0000000000..f23c3e736a
--- /dev/null
+++ b/spring-boot-actuator/src/test/resources/cache/test-infinispan.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-cache/src/main/resources/infinispan.xml b/spring-boot-samples/spring-boot-sample-cache/src/main/resources/infinispan.xml
index acf90677df..0dc58a3b48 100644
--- a/spring-boot-samples/spring-boot-sample-cache/src/main/resources/infinispan.xml
+++ b/spring-boot-samples/spring-boot-sample-cache/src/main/resources/infinispan.xml
@@ -2,7 +2,7 @@
-
+