Skip to content

Instantly share code, notes, and snippets.

@joshdurbin
Last active December 17, 2015 15:39
Show Gist options
  • Save joshdurbin/5632837 to your computer and use it in GitHub Desktop.
Save joshdurbin/5632837 to your computer and use it in GitHub Desktop.
package com.citytechinc.cq.library.services;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheStats;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
/**
*
* @author CITYTECH, INC. 2013.
*/
public abstract class AbstractCacheService implements CacheService {
protected abstract Logger getLogger();
@Override
public void clearAllCaches() {
for (final Field field : collectFields(this.getClass())) {
if (field.getType() == Cache.class || Cache.class.isAssignableFrom(field.getType())) {
try {
field.setAccessible(true);
final Cache cache = (Cache) field.get(this);
cache.invalidateAll();
} catch (final Exception exception) {
getLogger().error("An error has occurred while attempting to invalidate cache values for {} in the class {}. See exception: {}",
new Object[] {field.getName(), this.getClass().getName(), ExceptionUtils.getStackTrace(exception)});
}
}
}
}
@Override
public void clearSpecificCache(String cacheVariableName) {
for (final Field field : collectFields(this.getClass())) {
if ((StringUtils.equals(cacheVariableName, field.getName())) && (field.getType() == Cache.class || Cache.class.isAssignableFrom(field.getType()))) {
try {
field.setAccessible(true);
final Cache cache = (Cache) field.get(this);
cache.invalidateAll();
} catch (final Exception exception) {
getLogger().error("An error has occurred while attempting to invalidate cache values for {} in the class {}. See exception: {}",
new Object[] {field.getName(), this.getClass().getName(), ExceptionUtils.getStackTrace(exception)});
}
}
}
}
@Override
public List<String> listCaches() {
final ImmutableList.Builder<String> cachesBuilder = new ImmutableList.Builder<String>();
for (final Field field : collectFields(this.getClass())) {
if (field.getType() == Cache.class || Cache.class.isAssignableFrom(field.getType())) {
cachesBuilder.add(field.getName());
}
}
return cachesBuilder.build();
}
@Override
public CacheStats getCacheStats(String cacheVariableName) {
CacheStats cacheStats = null;
for (final Field field : collectFields(this.getClass())) {
if ((StringUtils.equals(cacheVariableName, field.getName())) && (field.getType() == Cache.class || Cache.class.isAssignableFrom(field.getType()))) {
try {
field.setAccessible(true);
final Cache cache = (Cache) field.get(this);
cacheStats = cache.stats();
} catch (final Exception exception) {
getLogger().error("An error has occurred while attempting retrieve cache statistics for {} in the class {}. See exception: {}",
new Object[] {field.getName(), this.getClass().getName(), ExceptionUtils.getStackTrace(exception)});
}
}
}
return cacheStats;
}
@Override
public Long getCacheSize(final String cacheVariableName) {
Long cacheSize = 0L;
for (final Field field : collectFields(this.getClass())) {
if ((StringUtils.equals(cacheVariableName, field.getName())) && (field.getType() == Cache.class || Cache.class.isAssignableFrom(field.getType()))) {
try {
field.setAccessible(true);
final Cache cache = (Cache) field.get(this);
cacheSize = cache.size();
} catch (final Exception exception) {
getLogger().error("An error has occurred while attempting retrieve cache size for {} in the class {}. See exception: {}",
new Object[] {field.getName(), this.getClass().getName(), ExceptionUtils.getStackTrace(exception)});
}
}
}
return cacheSize;
}
private List<Field> collectFields(Class clazz){
List<Field> fields = Lists.newArrayList();
if(clazz!=null){
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
fields.addAll(collectFields(clazz.getSuperclass()));
}
return fields;
}
}
package com.citytechinc.cq.library.services;
import com.google.common.cache.CacheStats;
import java.util.List;
/**
*
* @author CITYTECH, INC. 2013
*/
public interface CacheService {
/**
*
*/
void clearAllCaches();
/**
*
* @param cacheVariableName
*/
void clearSpecificCache(String cacheVariableName);
/**
*
* @return
*/
List<String> listCaches();
/**
*
* @param cacheVariableName
* @return
*/
CacheStats getCacheStats(String cacheVariableName);
/**
*
* @param cacheVariableName
* @return
*/
Long getCacheSize(String cacheVariableName);
}
package com.citytechinc.cq.library.jmx;
import com.adobe.granite.jmx.annotation.Description;
import com.adobe.granite.jmx.annotation.Name;
import javax.management.openmbean.TabularDataSupport;
/**
*
* @author CITYTECH, INC. 2013
*
*/
@Description("CITYTECH Google Guava Cache Reporting and Maintenance")
public interface GoogleGuavaCacheReportingAndMaintenanceMBean {
/**
*
*/
@Description("Clear all guava caches within all reporting caching services")
void clearAllCaches();
/**
*
* @param cacheService
*/
@Description("Clear all guava caches within a specific cache service")
void clearAllCachesForService(@Name("cacheService") @Description("The fully qualified path of a cache service listed in the Registered Cache Services") String cacheService);
/**
*
* @param cacheService
* @param cacheKey
*/
@Description("Clear a specific guava cache within a specific cache service")
void clearSpecificCacheForSpecificService(@Name("cacheService") @Description("The fully qualified path of a cache service listed in the Registered Cache Services") String cacheService, @Name("cacheKey") @Description("The cache key listed in the exposed caches") String cacheKey);
/**
*
* @return
*/
@Description("Lists all cache services, the Guava Caches exposed in those services in addition to their stastics and size")
TabularDataSupport getCacheServicesAndStats();
}
package com.citytechinc.cq.library.jmx;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
import com.citytechinc.cq.library.services.CacheService;
import com.google.common.cache.CacheStats;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.NotCompliantMBeanException;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
*
* @author CITYTECH, INC. 2013
*
*/
@Component(immediate = true)
@Property(name = "jmx.objectname", value = "com.citytechinc.cq.library.jmx:type=CITYTECH Google Guava Cache Reporting and Maintenance")
@Service
public final class GoogleGuavaCacheReportingAndMaintenanceMBeanImpl extends AnnotatedStandardMBean implements GoogleGuavaCacheReportingAndMaintenanceMBean {
private static final Logger LOG = LoggerFactory.getLogger(GoogleGuavaCacheReportingAndMaintenanceMBeanImpl.class);
@Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC, referenceInterface = CacheService.class, bind = "bindCacheService", unbind = "unbindCacheService")
private List<CacheService> cacheServices = Lists.newCopyOnWriteArrayList();
public GoogleGuavaCacheReportingAndMaintenanceMBeanImpl() throws NotCompliantMBeanException {
super(GoogleGuavaCacheReportingAndMaintenanceMBean.class);
}
protected void bindCacheService(final CacheService cacheService) {
cacheServices.add(cacheService);
}
protected void unbindCacheService(final CacheService cacheService) {
cacheServices.remove(cacheService);
}
@Override
public void clearAllCaches() {
for (final CacheService cacheService : cacheServices) {
cacheService.clearAllCaches();
}
}
@Override
public void clearAllCachesForService(final String cacheServiceClassName) {
for (final CacheService cacheService : cacheServices) {
if (StringUtils.equalsIgnoreCase(cacheService.getClass().getName(), cacheServiceClassName)) {
cacheService.clearAllCaches();
}
}
}
@Override
public void clearSpecificCacheForSpecificService(final String cacheServiceClassName, final String cacheKey) {
for (final CacheService cacheService : cacheServices) {
if (StringUtils.equalsIgnoreCase(cacheService.getClass().getName(), cacheServiceClassName)) {
cacheService.clearSpecificCache(cacheKey);
}
}
}
@Override
public TabularDataSupport getCacheServicesAndStats() {
TabularDataSupport tabularDataSupport = null;
try {
final String[] itemNamesAndDescriptions = { "Cache Service", "Cache Key", "Average Load Penalty", "Eviction Count", "Hit Count", "% Hit Rate", "Load Count", "Load Exception Count",
"% Load Exception Rate", "Load Success Count", "Miss Count", "% Miss Rate", "Request Count", "Total Load Time (s)", "Cache Size"};
final OpenType[] itemTypes = { SimpleType.STRING, SimpleType.STRING, SimpleType.DOUBLE, SimpleType.LONG, SimpleType.LONG, SimpleType.BIGDECIMAL, SimpleType.LONG, SimpleType.LONG,
SimpleType.BIGDECIMAL, SimpleType.LONG, SimpleType.LONG, SimpleType.BIGDECIMAL, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG };
final String[] indexNames = { "Cache Service", "Cache Key" };
final CompositeType pageType = new CompositeType("page", "Page size info", itemNamesAndDescriptions, itemNamesAndDescriptions, itemTypes);
final TabularType pageTabularType = new TabularType("List of Caches and Statistics", "List of Caches and Statistics", pageType, indexNames);
tabularDataSupport = new TabularDataSupport(pageTabularType);
for (final CacheService cacheService : cacheServices) {
final String cacheServiceClassname = cacheService.getClass().getName();
for (final String cacheName : cacheService.listCaches()) {
final CacheStats cacheStats = cacheService.getCacheStats(cacheName);
final Long cacheSize = cacheService.getCacheSize(cacheName);
final BigDecimal hitRate = new BigDecimal(cacheStats.hitRate()).setScale(2, RoundingMode.HALF_UP).movePointRight(2);
final BigDecimal loadExceptionRate = new BigDecimal(cacheStats.loadExceptionRate()).setScale(2, RoundingMode.HALF_UP).movePointRight(2);
final BigDecimal missRate = new BigDecimal(cacheStats.missRate()).setScale(2, RoundingMode.HALF_UP).movePointRight(2);
final Long loadTimeInSeconds = TimeUnit.SECONDS.convert(cacheStats.totalLoadTime(), TimeUnit.NANOSECONDS);
tabularDataSupport.put(new CompositeDataSupport(pageType, itemNamesAndDescriptions, new Object[] {
cacheServiceClassname, cacheName, cacheStats.averageLoadPenalty(), cacheStats.evictionCount(), cacheStats.hitCount(), hitRate, cacheStats.loadCount(), cacheStats.loadExceptionCount(),
loadExceptionRate, cacheStats.loadSuccessCount(), cacheStats.missCount(), missRate, cacheStats.requestCount(), loadTimeInSeconds, cacheSize }));
}
}
} catch (final Exception exception) {
LOG.error("An exception occurred building tabulardata for cache stats.", exception);
}
return tabularDataSupport;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment