1
2
3
4
5
6
7
8
9
10
11
12
13
14 package net.sf.tacos.annotations;
15
16 import java.lang.reflect.Method;
17 import java.lang.reflect.Modifier;
18
19 import org.apache.hivemind.ApplicationRuntimeException;
20 import org.apache.hivemind.Location;
21 import org.apache.hivemind.service.BodyBuilder;
22 import org.apache.hivemind.service.MethodSignature;
23 import org.apache.tapestry.annotations.MethodAnnotationEnhancementWorker;
24 import org.apache.tapestry.enhance.EnhancementOperation;
25 import org.apache.tapestry.enhance.EnhanceUtils;
26 import org.apache.tapestry.spec.IComponentSpecification;
27 import org.apache.tapestry.IComponent;
28
29
30
31
32
33 public class CachedAnnotationWorker implements MethodAnnotationEnhancementWorker {
34
35 public void performEnhancement(EnhancementOperation op, IComponentSpecification spec,
36 Method method, Location location) {
37 Class<?> type = method.getReturnType();
38 if (type.equals(void.class))
39 throw new ApplicationRuntimeException(
40 "Cached annotation cannot be used with a method that returns void");
41
42 boolean reset = method.getAnnotation(Cached.class).resetAfterRewind();
43
44 String fieldName = "_$cached$" + method.getName();
45 String loadedFlagField = fieldName + "$loadedFlag";
46 String rewindFlagField = null;
47 op.addField(fieldName, type);
48 op.addField(loadedFlagField, boolean.class);
49 if (reset) {
50 rewindFlagField = fieldName + "$rewindFlag";
51 op.addField(rewindFlagField, Boolean.class);
52 }
53
54 MethodSignature signature = new MethodSignature(method);
55 BodyBuilder builder = createCacheMethod(signature, fieldName, loadedFlagField, rewindFlagField);
56 op.addMethod(Modifier.PUBLIC, signature, builder.toString(), location);
57
58 extendCleanupAfterRender(op, type.isPrimitive() ? null : fieldName, loadedFlagField, rewindFlagField);
59 }
60
61 BodyBuilder createCacheMethod(MethodSignature sig, String cacheField, String loadedFlagField, String rewindFlagField)
62 {
63 BodyBuilder result = new BodyBuilder();
64
65 result.begin();
66
67 if (rewindFlagField!=null) {
68 result.addln("boolean rewinding=getPage().getRequestCycle().isRewinding();");
69 result.addln("if (!this.{0} || (this.{1}!=null && this.{1}.booleanValue()!=rewinding))",
70 loadedFlagField, rewindFlagField);
71 } else {
72 result.addln("if (!this.{0})", loadedFlagField);
73 }
74 result.addln("{");
75 result.addln("this.{0} = super.{1}($$);", cacheField, sig.getName());
76 result.addln("this.{0} = true;", loadedFlagField);
77 if (rewindFlagField!=null) {
78 result.addln("this.{0} = Boolean.valueOf(rewinding);", rewindFlagField);
79 }
80 result.addln("}");
81
82 result.addln("return this.{0};", cacheField);
83
84 result.end();
85
86 return result;
87 }
88
89 void extendCleanupAfterRender(EnhancementOperation op, String fieldName, String loadedFlagField, String rewindFlagField)
90 {
91 BodyBuilder cleanupBody = new BodyBuilder();
92 if (fieldName!=null) {
93 cleanupBody.addln("this.{0} = null;", fieldName);
94 }
95 cleanupBody.addln("this.{0} = false;", loadedFlagField);
96 if (rewindFlagField!=null) {
97 cleanupBody.addln("this.{0} = null;", rewindFlagField);
98 }
99 op.extendMethodImplementation(IComponent.class,
100 EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE, cleanupBody.toString());
101 }
102 }