Assume you have methods that (almost) always return the same result for the same input arguments. If preparing method result is a heavy operation and/or it consumes time, it is reasonable to cache these results.
One way of building method cache in Tapestry5 is by implementing MethodAdvice interface like this:
public class CacheMethodResultAdvice implements MethodAdvice {
private static final Logger logger = LoggerFactory.getLogger(CacheMethodResultAdvice.class);
private final Cache cache;
private final Class<?> advisedClass;
private final Object nullObject = new Object();
public CacheMethodResultAdvice(Class<?> advisedClass, Cache cache) {
this.advisedClass = advisedClass;
this.cache = cache;
}
@Override
public void advise(Invocation invocation) {
String invocationSignature = getInvocationSignature(invocation);
String entityCacheKey = String.valueOf(invocationSignature.hashCode());
Object result;
if (cache.containsKey(entityCacheKey))
{
result = cache.get(entityCacheKey);
logger.debug("Using invocation result ({}) from cache '{}'", invocationSignature, result);
invocation.overrideResult(result);
}
else
{
invocation.proceed();
if (!invocation.isFail())
{
result = invocation.getResult();
cache.put(entityCacheKey, result);
}
}
}
private String getInvocationSignature(Invocation invocation) {
StringBuilder builder = new StringBuilder(150);
builder.append(advisedClass.getName());
builder.append('.');
builder.append(invocation.getMethodName());
builder.append('(');
for (int i = 0; i < invocation.getParameterCount(); i++) {
if (i > 0) {
builder.append(',');
}
Class<?> type = invocation.getParameterType(i);
builder.append(type.getName());
builder.append(' ');
Object param = invocation.getParameter(i);
builder.append(param != null ? param : nullObject);
}
builder.append(')');
return builder.toString();
}
}
Implementation of
getInvocationSignature(...)
is not ideal, but you may improve it to match your requirements. One issue I see here is building invocation signature for
null
-value parameters in a clustered environment (which is GAE). In this implementation method
nullObject.toString()
will return something like
java.lang.Object@33aa9b
. And this value will vary in different instances of your application. You may replace
nullObject
with just
"null"
string. Just keep in mind that
"null" != null
.