Skip to content

Commit

Permalink
new feature: @CacheKaeyable to generate a CacheKey for annotated methods
Browse files Browse the repository at this point in the history
  • Loading branch information
winniae committed Dec 11, 2012
1 parent bbf4cc1 commit c39d4ca
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.coremedia.beanmodeller.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Generate a CoreMedia CacheKey for the annotated method and delegate the CacheKeys evaluate() method to the original
* method.
* Makes an easy way to cache methods in the CoreMedia cache.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
public @interface CacheKeyable {

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class AnalyzatorContentBeanInformation implements ContentBeanInformation
private ContentBeanInformation parent;
private Set<ContentBeanInformation> childs = new HashSet<ContentBeanInformation>();
private Set<PropertyInformation> properties = new HashSet<PropertyInformation>();
private Set<CacheKeyableMethodInformation> cacheKeyables = new HashSet<CacheKeyableMethodInformation>();

public AnalyzatorContentBeanInformation(Class beanClass) {
this.contentBean = beanClass;
Expand Down Expand Up @@ -52,6 +53,11 @@ public Set<? extends PropertyInformation> getProperties() {
return properties;
}

@Override
public Set<CacheKeyableMethodInformation> getCacheKeyables() {
return cacheKeyables;
}

public void setParent(AnalyzatorContentBeanInformation parent) {
this.parent = parent;
parent.addChild(this);
Expand Down Expand Up @@ -94,6 +100,10 @@ public void addProperty(PropertyInformation propertyInformation) {
properties.add(propertyInformation);
}

public void addCacheKeyable(CacheKeyableMethodInformation cacheKeyableMethodInformation) {
cacheKeyables.add(cacheKeyableMethodInformation);
}

@Override
public String getHumanUnderstandableRepresentation() {
StringBuilder builder = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.coremedia.beanmodeller.beaninformation;

import java.lang.reflect.Method;

/**
* Store information about methods that should have a CacheKey generated around them.
*/
public class CacheKeyableMethodInformation {

private final Method method;

public CacheKeyableMethodInformation(Method method) {

this.method = method;
}

public Method getMethod() {
return method;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,10 @@ public interface ContentBeanInformation {
* @return empty if contentbean is generated with the BeanModeller
*/
public String getAspectDocumentName();

/**
* Any method of this bean that should be cached with a CacheKey
* @return Set of all methods to generate CacheKeys for.
*/
Set<CacheKeyableMethodInformation> getCacheKeyables();
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,9 @@ public boolean isAbstract() {
public String getAspectDocumentName() {
return null;
}

@Override
public Set<CacheKeyableMethodInformation> getCacheKeyables() {
return Collections.EMPTY_SET;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.coremedia.beanmodeller.processors.analyzator;

import com.coremedia.beanmodeller.annotations.CacheKeyable;
import com.coremedia.beanmodeller.annotations.ContentBean;
import com.coremedia.beanmodeller.annotations.ContentProperty;
import com.coremedia.beanmodeller.beaninformation.AbstractPropertyInformation;
import com.coremedia.beanmodeller.beaninformation.AnalyzatorContentBeanInformation;
import com.coremedia.beanmodeller.beaninformation.BlobPropertyInformation;
import com.coremedia.beanmodeller.beaninformation.BooleanPropertyInformation;
import com.coremedia.beanmodeller.beaninformation.CacheKeyableMethodInformation;
import com.coremedia.beanmodeller.beaninformation.ContentBeanHierarchy;
import com.coremedia.beanmodeller.beaninformation.ContentBeanInformation;
import com.coremedia.beanmodeller.beaninformation.DatePropertyInformation;
Expand Down Expand Up @@ -145,6 +147,8 @@ public ContentBeanHierarchy analyzeContentBeanInformation() throws ContentBeanAn

extractDocProperties(potentialException, hierarchy);

extractCacheKeyables(potentialException, hierarchy);

//have there been errors in the analyzation?
if (potentialException.hasErrors()) {
//and throw the prepared exception
Expand Down Expand Up @@ -846,6 +850,21 @@ private boolean isListed(Collection<Method> declaredMethods, Method method) {
}


private void extractCacheKeyables(ContentBeanAnalyzationException potentialException, ContentBeanHierarchy hierarchy) {

for (ContentBeanInformation contentBeanInformation : hierarchy.getAllContentBeanInformation()) {
Class contentBean = contentBeanInformation.getContentBean();

for (Method method : contentBean.getMethods()) {
CacheKeyable methodAnnotation = method.getAnnotation(CacheKeyable.class);
if (methodAnnotation != null) {
((AnalyzatorContentBeanInformation) contentBeanInformation).addCacheKeyable(new CacheKeyableMethodInformation(method));
}
}
}
}


public int getPropertyDefaultStringLength() {
return propertyDefaultStringLength;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.coremedia.beanmodeller.beaninformation.BlobPropertyInformation;
import com.coremedia.beanmodeller.beaninformation.BooleanPropertyInformation;
import com.coremedia.beanmodeller.beaninformation.CacheKeyableMethodInformation;
import com.coremedia.beanmodeller.beaninformation.ContentBeanInformation;
import com.coremedia.beanmodeller.beaninformation.DatePropertyInformation;
import com.coremedia.beanmodeller.beaninformation.IntegerPropertyInformation;
Expand All @@ -10,6 +11,8 @@
import com.coremedia.beanmodeller.beaninformation.PropertyInformation;
import com.coremedia.beanmodeller.beaninformation.StringPropertyInformation;
import com.coremedia.beanmodeller.processors.MavenProcessor;
import com.coremedia.cache.Cache;
import com.coremedia.cache.CacheKey;
import com.coremedia.cap.content.Content;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JClassAlreadyExistsException;
Expand All @@ -18,6 +21,7 @@
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JDocComment;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
Expand Down Expand Up @@ -125,6 +129,10 @@ public int compare(PropertyInformation o1, PropertyInformation o2) {
}
}

// generate CacheKeys for CacheKeyables
for (CacheKeyableMethodInformation cacheKeyableMethodInformation : bean.getCacheKeyables()) {
generateCacheKeyMethod(beanClass, cacheKeyableMethodInformation, codeModel);
}
}
else {
getLog().info(bean.getContentBean().getCanonicalName() + " is an abstract document - no accessorizer is generated");
Expand All @@ -145,7 +153,7 @@ private void generatePropertyMethod(JDefinedClass beanClass, PropertyInformation
}

//construct the correct modifiers
int modifiers = getModifiersForPropertyMethod(method);
int modifiers = getModifiersForMethod(method);
//create the method
JMethod propertyMethod = beanClass.method(modifiers, methodReturnType, method.getName());
//TODO this comment has to be better
Expand Down Expand Up @@ -200,7 +208,7 @@ private void generatePropertySetterMethod(JDefinedClass beanClass, PropertyInfor
}

//construct the correct modifiers
int modifiers = getModifiersForPropertyMethod(method);
int modifiers = getModifiersForMethod(method);
//create the method
// strip name of 'get' or 'is' and add setter
final String methodName = method.getName().startsWith("is") ? method.getName().substring(2) : method.getName().substring(3);
Expand Down Expand Up @@ -278,7 +286,7 @@ private void createLinkListMethod(JCodeModel codeModel, Class<?> methodReturnTyp
}
}

private int getModifiersForPropertyMethod(Method method) {
private int getModifiersForMethod(Method method) {
//construct the correct modifiers
int modifiers = 0;
int abstractMethodModifiers = method.getModifiers();
Expand All @@ -296,6 +304,59 @@ else if (Modifier.isPublic(abstractMethodModifiers)) {
return modifiers;
}


private void generateCacheKeyMethod(JDefinedClass beanClass, CacheKeyableMethodInformation cacheKeyableMethodInformation, JCodeModel codeModel) throws JClassAlreadyExistsException {
//we will use this quite often
Method method = cacheKeyableMethodInformation.getMethod();
Class<?> methodReturnType = method.getReturnType();

if (getLog().isDebugEnabled()) {
getLog().debug("Generating cached method for " + method.toString());
}

String shortMethodName = method.getName().startsWith("is") ? method.getName().substring(2) : method.getName().substring(3);

// !! create Uncached methodcall
JMethod uncachedMethod = beanClass.method(JMod.PROTECTED, methodReturnType, method.getName() + "Uncached");
uncachedMethod.body()._return(JExpr._super().invoke(method.getName()));


// !! create CacheKey calling uncached method
JDefinedClass cacheKeyClass = beanClass._class(shortMethodName + "CacheKey");
cacheKeyClass._extends(CacheKey.class);
JFieldVar delegateField = cacheKeyClass.field(JMod.PRIVATE | JMod.FINAL, beanClass, "delegate");
JMethod constructor = cacheKeyClass.constructor(JMod.PUBLIC);
JVar delegateParam = constructor.param(beanClass, "delegate");
constructor.body().assign(JExpr._this().ref(delegateField), delegateParam);
JMethod evaluate = cacheKeyClass.method(JMod.PUBLIC, Object.class, "evaluate");
evaluate.param(Cache.class, "cache");
evaluate._throws(Exception.class);
evaluate.body()._return(JExpr._this().ref(delegateField).invoke(uncachedMethod));

JMethod hashCode = cacheKeyClass.method(JMod.PUBLIC, codeModel.INT, "hashCode");
hashCode.body()._return(JExpr._this().ref(delegateField).invoke("hashCode"));
JMethod equals = cacheKeyClass.method(JMod.PUBLIC, codeModel.BOOLEAN, "equals");
JVar o = equals.param(Object.class, "o");
equals.body()._return(JExpr._this().ref(delegateField).invoke("equals").arg(o));

JMethod cacheClass = cacheKeyClass.method(JMod.PUBLIC, String.class, "cacheClass");
cacheClass.param(Cache.class, "cache");
cacheClass.param(Object.class, "value");
cacheClass.body()._return(JExpr.lit("beanmodeller.cacheclass"));

// !! overwrite the method to be cached
//construct the correct modifiers
int modifiers = getModifiersForMethod(method);
//create the method
JMethod cachedMethod = beanClass.method(modifiers, methodReturnType, method.getName());

JVar cacheKey = cachedMethod.body().decl(cacheKeyClass, "cacheKey", JExpr._new(cacheKeyClass).arg(JExpr._this()));
JInvocation cacheCall = JExpr.invoke("getContent").invoke("getRepository").invoke("getConnection").invoke("getCache").invoke("get").arg(cacheKey);
cachedMethod.body()._return(JExpr.cast(codeModel.ref(methodReturnType), cacheCall));
}



public String getPackageName() {
return packageName;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.coremedia.beanmodeller.testcontentbeans.testmodel;

import com.coremedia.beanmodeller.annotations.CacheKeyable;
import com.coremedia.beanmodeller.annotations.ContentBean;
import com.coremedia.beanmodeller.annotations.ContentProperty;
import com.coremedia.beanmodeller.testcontentbeans.externalmodel.ExternalArticleImpl;
Expand Down Expand Up @@ -30,4 +31,9 @@ public abstract class CBGArticle<T extends CBGArticle> extends ExternalArticleIm
public T getMaster() {
return (T) getMasterInternal();
}

@CacheKeyable
public String getSomeMethodToCache() {
return "I am the cachest!.";
}
}

0 comments on commit c39d4ca

Please sign in to comment.