View Javadoc

1   //
2   // Licensed under the Apache License, Version 2.0 (the "License");
3   // you may not use this file except in compliance with the License.
4   // You may obtain a copy of the License at
5   //
6   //     http://www.apache.org/licenses/LICENSE-2.0
7   //
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
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   * @author Andreas Andreou
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 }