001 // 002 // Licensed under the Apache License, Version 2.0 (the "License"); 003 // you may not use this file except in compliance with the License. 004 // You may obtain a copy of the License at 005 // 006 // http://www.apache.org/licenses/LICENSE-2.0 007 // 008 // Unless required by applicable law or agreed to in writing, software 009 // distributed under the License is distributed on an "AS IS" BASIS, 010 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 // See the License for the specific language governing permissions and 012 // limitations under the License. 013 014 package net.sf.tacos.annotations; 015 016 import java.lang.reflect.Method; 017 import java.lang.reflect.Modifier; 018 019 import org.apache.hivemind.ApplicationRuntimeException; 020 import org.apache.hivemind.Location; 021 import org.apache.hivemind.service.BodyBuilder; 022 import org.apache.hivemind.service.MethodSignature; 023 import org.apache.tapestry.annotations.MethodAnnotationEnhancementWorker; 024 import org.apache.tapestry.enhance.EnhancementOperation; 025 import org.apache.tapestry.enhance.EnhanceUtils; 026 import org.apache.tapestry.spec.IComponentSpecification; 027 import org.apache.tapestry.IComponent; 028 029 /** 030 * @author Andreas Andreou 031 */ 032 033 public class CachedAnnotationWorker implements MethodAnnotationEnhancementWorker { 034 035 public void performEnhancement(EnhancementOperation op, IComponentSpecification spec, 036 Method method, Location location) { 037 Class<?> type = method.getReturnType(); 038 if (type.equals(void.class)) 039 throw new ApplicationRuntimeException( 040 "Cached annotation cannot be used with a method that returns void"); 041 042 boolean reset = method.getAnnotation(Cached.class).resetAfterRewind(); 043 044 String fieldName = "_$cached$" + method.getName(); 045 String loadedFlagField = fieldName + "$loadedFlag"; 046 String rewindFlagField = null; 047 op.addField(fieldName, type); 048 op.addField(loadedFlagField, boolean.class); 049 if (reset) { 050 rewindFlagField = fieldName + "$rewindFlag"; 051 op.addField(rewindFlagField, Boolean.class); 052 } 053 054 MethodSignature signature = new MethodSignature(method); 055 BodyBuilder builder = createCacheMethod(signature, fieldName, loadedFlagField, rewindFlagField); 056 op.addMethod(Modifier.PUBLIC, signature, builder.toString(), location); 057 058 extendCleanupAfterRender(op, type.isPrimitive() ? null : fieldName, loadedFlagField, rewindFlagField); 059 } 060 061 BodyBuilder createCacheMethod(MethodSignature sig, String cacheField, String loadedFlagField, String rewindFlagField) 062 { 063 BodyBuilder result = new BodyBuilder(); 064 065 result.begin(); 066 067 if (rewindFlagField!=null) { 068 result.addln("boolean rewinding=getPage().getRequestCycle().isRewinding();"); 069 result.addln("if (!this.{0} || (this.{1}!=null && this.{1}.booleanValue()!=rewinding))", 070 loadedFlagField, rewindFlagField); 071 } else { 072 result.addln("if (!this.{0})", loadedFlagField); 073 } 074 result.addln("{"); 075 result.addln("this.{0} = super.{1}($$);", cacheField, sig.getName()); 076 result.addln("this.{0} = true;", loadedFlagField); 077 if (rewindFlagField!=null) { 078 result.addln("this.{0} = Boolean.valueOf(rewinding);", rewindFlagField); 079 } 080 result.addln("}"); 081 082 result.addln("return this.{0};", cacheField); 083 084 result.end(); 085 086 return result; 087 } 088 089 void extendCleanupAfterRender(EnhancementOperation op, String fieldName, String loadedFlagField, String rewindFlagField) 090 { 091 BodyBuilder cleanupBody = new BodyBuilder(); 092 if (fieldName!=null) { 093 cleanupBody.addln("this.{0} = null;", fieldName); 094 } 095 cleanupBody.addln("this.{0} = false;", loadedFlagField); 096 if (rewindFlagField!=null) { 097 cleanupBody.addln("this.{0} = null;", rewindFlagField); 098 } 099 op.extendMethodImplementation(IComponent.class, 100 EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE, cleanupBody.toString()); 101 } 102 }