Last active
December 17, 2015 15:39
-
-
Save joshdurbin/5632837 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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