1 15 package org.apache.tapestry.enhance; 16 17 import java.lang.reflect.Modifier ; 18 import java.util.Iterator ; 19 20 import org.apache.hivemind.ApplicationRuntimeException; 21 import org.apache.hivemind.ErrorLog; 22 import org.apache.hivemind.service.BodyBuilder; 23 import org.apache.hivemind.service.ClassFabUtils; 24 import org.apache.hivemind.service.MethodSignature; 25 import org.apache.hivemind.util.Defense; 26 import org.apache.tapestry.IBinding; 27 import org.apache.tapestry.IComponent; 28 import org.apache.tapestry.spec.IComponentSpecification; 29 import org.apache.tapestry.spec.IParameterSpecification; 30 31 37 public class ParameterPropertyWorker implements EnhancementWorker 38 { 39 private ErrorLog _errorLog; 40 41 public void performEnhancement(EnhancementOperation op, IComponentSpecification spec) 42 { 43 Iterator i = spec.getParameterNames().iterator(); 44 while (i.hasNext()) 45 { 46 String name = (String ) i.next(); 47 48 IParameterSpecification ps = spec.getParameter(name); 49 50 try 51 { 52 performEnhancement(op, name, ps); 53 } 54 catch (RuntimeException ex) 55 { 56 _errorLog.error(EnhanceMessages.errorAddingProperty(ps.getPropertyName(), op 57 .getBaseClass(), ex), ps.getLocation(), ex); 58 } 59 } 60 } 61 62 66 67 private void performEnhancement(EnhancementOperation op, String parameterName, 68 IParameterSpecification ps) 69 { 70 String propertyName = ps.getPropertyName(); 71 String specifiedType = ps.getType(); 72 boolean cache = ps.getCache(); 73 74 addParameter(op, parameterName, propertyName, specifiedType, cache); 75 } 76 77 94 95 public void addParameter(EnhancementOperation op, String parameterName, String propertyName, 96 String specifiedType, boolean cache) 97 { 98 Defense.notNull(op, "op"); 99 Defense.notNull(parameterName, "parameterName"); 100 Defense.notNull(propertyName, "propertyName"); 101 102 Class propertyType = EnhanceUtils.extractPropertyType(op, propertyName, specifiedType); 103 104 108 op.claimProperty(propertyName); 109 110 113 String fieldName = "_$" + propertyName; 114 String defaultFieldName = fieldName + "$Default"; 115 String cachedFieldName = fieldName + "$Cached"; 116 117 op.addField(fieldName, propertyType); 118 op.addField(defaultFieldName, propertyType); 119 op.addField(cachedFieldName, boolean.class); 120 121 buildAccessor( 122 op, 123 parameterName, 124 propertyName, 125 propertyType, 126 fieldName, 127 defaultFieldName, 128 cachedFieldName, 129 cache); 130 131 buildMutator( 132 op, 133 parameterName, 134 propertyName, 135 propertyType, 136 fieldName, 137 defaultFieldName, 138 cachedFieldName); 139 140 extendCleanupAfterRender( 141 op, 142 parameterName, 143 propertyName, 144 propertyType, 145 fieldName, 146 defaultFieldName, 147 cachedFieldName); 148 } 149 150 private void extendCleanupAfterRender(EnhancementOperation op, String parameterName, 151 String propertyName, Class propertyType, String fieldName, String defaultFieldName, 152 String cachedFieldName) 153 { 154 BodyBuilder cleanupBody = new BodyBuilder(); 155 156 161 String bindingName = propertyName + "Binding"; 162 163 addBindingReference(cleanupBody, bindingName, parameterName); 164 165 cleanupBody.addln("if ({0} && ! {1}.isInvariant())", cachedFieldName, bindingName); 166 cleanupBody.begin(); 167 cleanupBody.addln("{0} = false;", cachedFieldName); 168 cleanupBody.addln("{0} = {1};", fieldName, defaultFieldName); 169 cleanupBody.end(); 170 171 op.extendMethodImplementation( 172 IComponent.class, 173 EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE, 174 cleanupBody.toString()); 175 } 176 177 private void addBindingReference(BodyBuilder builder, String localVariableName, 178 String parameterName) 179 { 180 builder.addln( 181 "{0} {1} = getBinding(\"{2}\");", 182 IBinding.class.getName(), 183 localVariableName, 184 parameterName); 185 } 186 187 private void buildMutator(EnhancementOperation op, String parameterName, String propertyName, 188 Class propertyType, String fieldName, String defaultFieldName, String cachedFieldName) 189 { 190 BodyBuilder builder = new BodyBuilder(); 191 builder.begin(); 192 193 197 builder.addln("if (! isInActiveState())"); 198 builder.begin(); 199 builder.addln("{0} = $1;", defaultFieldName); 200 builder.addln("return;"); 201 builder.end(); 202 203 206 addBindingReference(builder, "binding", parameterName); 207 208 builder.addln("if (binding == null)"); 209 builder.addln( 210 " throw new {0}(\"Parameter ''{1}'' is not bound and can not be updated.\");", 211 ApplicationRuntimeException.class.getName(), 212 parameterName); 213 214 216 builder.addln("binding.setObject(($w) $1);"); 217 218 222 builder.addln("if (isRendering())"); 223 builder.begin(); 224 builder.addln("{0} = $1;", fieldName); 225 builder.addln("{0} = true;", cachedFieldName); 226 builder.end(); 227 228 builder.end(); 229 230 String mutatorMethodName = EnhanceUtils.createMutatorMethodName(propertyName); 231 232 op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, mutatorMethodName, 233 new Class [] 234 { propertyType }, null), builder.toString()); 235 } 236 237 239 void buildAccessor(EnhancementOperation op, String parameterName, String propertyName, 240 Class propertyType, String fieldName, String defaultFieldName, String cachedFieldName, 241 boolean cache) 242 { 243 BodyBuilder builder = new BodyBuilder(); 244 builder.begin(); 245 246 builder.addln("if ({0}) return {1};", cachedFieldName, fieldName); 247 248 addBindingReference(builder, "binding", parameterName); 249 250 builder.addln("if (binding == null) return {0};", defaultFieldName); 251 252 String javaTypeName = ClassFabUtils.getJavaClassName(propertyType); 253 254 builder.addln("{0} result = {1};", javaTypeName, EnhanceUtils.createUnwrapExpression( 255 op, 256 "binding", 257 propertyType)); 258 259 264 String expression = cache ? "isRendering() || binding.isInvariant()" 265 : "binding.isInvariant()"; 266 267 builder.addln("if ({0})", expression); 268 builder.begin(); 269 builder.addln("{0} = result;", fieldName); 270 builder.addln("{0} = true;", cachedFieldName); 271 builder.end(); 272 273 builder.addln("return result;"); 274 275 builder.end(); 276 277 String accessorMethodName = op.getAccessorMethodName(propertyName); 278 279 op.addMethod(Modifier.PUBLIC, new MethodSignature(propertyType, accessorMethodName, null, 280 null), builder.toString()); 281 } 282 283 public void setErrorLog(ErrorLog errorLog) 284 { 285 _errorLog = errorLog; 286 } 287 } | Popular Tags |