Commit 1a243dcf authored by Nils Christian Ehmke's avatar Nils Christian Ehmke

Added comments and JavaDoc; Refactoring of the cache interceptor

parent e49a3c5b
package kieker.diagnosis.architecture.service.cache;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
/**
* This interceptor is responsible for handling the caching of method calls to services. It handles the {@link UseCache} and {@link InvalidateCache}
* annotations.
*
* @see UseCache
* @see InvalidateCache
*
* @author Nils Christian Ehmke
*/
public final class CacheInterceptor implements MethodInterceptor {
private final Map<String, Map<Object, Object>> caches = new HashMap<>( );
private final Cache<String, Cache<Object, Object>> ivCaches = CacheBuilder.newBuilder( ).build( );
@Override
public Object invoke( final MethodInvocation aMethodInvocation ) throws Throwable {
......@@ -24,23 +28,20 @@ public final class CacheInterceptor implements MethodInterceptor {
// Check for a UseCache annotation first
final UseCache useCacheAnnotation = method.getAnnotation( UseCache.class );
if ( useCacheAnnotation != null ) {
Map<Object, Object> cache = caches.get( useCacheAnnotation.cacheName( ) );
final String cacheName = useCacheAnnotation.cacheName( );
// Create the cache if necessary
if ( cache == null ) {
cache = new HashMap<>( );
caches.put( useCacheAnnotation.cacheName( ), cache );
}
// Get the cache
final Cache<Object, Object> cache = ivCaches.get( cacheName, ( ) -> CacheBuilder.newBuilder( ).build( ) );
// Check if we already have the entry in the cache
// Get the method result
final Object key = aMethodInvocation.getArguments( )[0];
Object value = cache.get( key );
if ( value == null ) {
// No. We actually have to call the method
value = aMethodInvocation.proceed( );
cache.put( key, value );
}
final Object value = cache.get( key, ( ) -> {
try {
return aMethodInvocation.proceed( );
} catch ( final Throwable ex ) {
throw new RuntimeException( ex );
}
} );
return value;
}
......@@ -48,12 +49,13 @@ public final class CacheInterceptor implements MethodInterceptor {
// Now check the InvalidateCache annotation
final InvalidateCache invalidateCache = method.getAnnotation( InvalidateCache.class );
if ( invalidateCache != null ) {
final Map<Object, Object> cache = caches.get( invalidateCache.cacheName( ) );
final String cacheName = invalidateCache.cacheName( );
final Cache<Object, Object> cache = ivCaches.getIfPresent( cacheName );
// If we have a cache, we remove the entry
if ( cache != null ) {
final Object key = aMethodInvocation.getArguments( )[invalidateCache.keyParameter( )];
cache.remove( key );
cache.invalidate( key );
}
}
......
......@@ -6,12 +6,26 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* This annotation can be used at service methods and makes sure that an entry of a cached method call is invalidated. It is assumed that the method has at
* least one parameter which provides the key to the cache. Entries can be cached by using the {@link UseCache} annotation.
*
* @see UseCache
*
* @author Nils Christian Ehmke
*/
@Retention ( RUNTIME )
@Target ( METHOD )
public @interface InvalidateCache {
/**
* @return The name of the cache.
*/
String cacheName();
/**
* @return Determines which parameter of the method is the key.
*/
int keyParameter();
}
......@@ -10,6 +10,8 @@ import java.lang.annotation.Target;
* This annotation can be used at service methods and makes sure that the results of the method call is cached. It is assumed that the method has exactly one
* parameter which provides the key to the cache. Entries can be invalidated by using the {@link InvalidateCache} annotation.
*
* @see InvalidateCache
*
* @author Nils Christian Ehmke
*/
@Retention ( RUNTIME )
......
......@@ -17,9 +17,19 @@ import kieker.monitoring.timer.SystemNanoTimer;
import kieker.monitoring.writer.filesystem.AsyncBinaryFsWriter;
import kieker.monitoring.writer.filesystem.AsyncBinaryNFsWriter;
/**
* This service can be used to control the monitoring within the application (and from within the application).
*
* @author Nils Christian Ehmke
*/
@Singleton
public class MonitoringService extends ServiceBase {
/**
* Delivers the current status of the monitoring.
*
* @return The monitoring status.
*/
public Status getCurrentStatus( ) {
final IMonitoringController monitoringController = MonitoringControllerHolder.getMonitoringController( );
......@@ -34,6 +44,11 @@ public class MonitoringService extends ServiceBase {
}
}
/**
* Delivers the current configuration of the monitoring. If there is no such configuration, a suitable default configuration is returned.
*
* @return The monitoring configuration.
*/
public MonitoringConfiguration getCurrentConfiguration( ) {
MonitoringConfiguration currentConfiguration = MonitoringControllerHolder.getCurrentConfiguration( );
......@@ -52,6 +67,12 @@ public class MonitoringService extends ServiceBase {
return currentConfiguration;
}
/**
* Configures the application. That means, that the old monitoring is terminated and a new monitoring is started.
*
* @param aConfiguration
* The monitoring configuration.
*/
public void configureMonitoring( final MonitoringConfiguration aConfiguration ) {
// Terminate the old monitoring controller
IMonitoringController monitoringController = MonitoringControllerHolder.clearMonitoringController( );
......@@ -102,6 +123,7 @@ public class MonitoringService extends ServiceBase {
configuration.setProperty( ConfigurationFactory.CONTROLLER_NAME, "Kieker-Trace-Diagnosis" );
configuration.setProperty( ConfigurationFactory.EXPERIMENT_ID, "0" );
configuration.setProperty( ConfigurationFactory.PERIODIC_SENSORS_EXECUTOR_POOL_SIZE, "0" );
// Never use a shutdown hook here. This will lead to a memory leak.
configuration.setProperty( ConfigurationFactory.USE_SHUTDOWN_HOOK, "false" );
configuration.setProperty( ConfigurationFactory.AUTO_SET_LOGGINGTSTAMP, "true" );
configuration.setProperty( ConfigurationFactory.MONITORING_ENABLED, "true" );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment