Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  // Copyright 2004, 2005 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
 package org.apache.tapestry.enhance;
 
 import  org.apache.hivemind.ApplicationRuntimeException;
 import  org.apache.hivemind.ErrorLog;
 import  org.apache.hivemind.Location;
 import  org.apache.hivemind.service.BodyBuilder;
 import  org.apache.hivemind.service.ClassFabUtils;
 import  org.apache.hivemind.service.MethodSignature;
 import  org.apache.hivemind.util.Defense;
 
Responsible for creating properties for connected parameters.

Author(s):
Howard M. Lewis Ship
Since:
4.0
 
 public class ParameterPropertyWorker implements EnhancementWorker
 {
 
     private ErrorLog _errorLog;
 
     {
         Iterator i = spec.getParameterNames().iterator();
         while(i.hasNext())
         {
             String name = (Stringi.next();
 
             IParameterSpecification ps = spec.getParameter(name);
 
             try
             {
                 performEnhancement(opnameps);
             }
             catch (RuntimeException ex)
             {
                 .error(EnhanceMessages.errorAddingProperty(ps.getPropertyName(), op.getBaseClass(), ex),
                                 ps.getLocation(), ex);
             }
         }
     }

    
Performs the enhancement for a single parameter; this is about to change radically in release 4.0 but for the moment we're emulating 3.0 behavior.

Parameters:
op Enhancement operation service.
parameterName Name of the parameter being enhanced.
ps Specification of parameter.
 
 
     private void performEnhancement(EnhancementOperation opString parameterNameIParameterSpecification ps)
     {
         // If the parameter name doesn't match, its because this is an alias
         // for a true parameter; we ignore aliases.
 
         if (!parameterName.equals(ps.getParameterName()))
             return;
 
         String propertyName = ps.getPropertyName();
         String specifiedType = ps.getType();
         boolean cache = ps.getCache();
 
         addParameter(opparameterNamepropertyNamespecifiedTypecacheps.getLocation());
     }

    
Adds a parameter as a (very smart) property.

Parameters:
op the enhancement operation
parameterName the name of the parameter (used to access the binding)
propertyName the name of the property to create (usually, but not always, matches the parameterName)
specifiedType the type declared in the DTD (only 3.0 DTD supports this), may be null (always null for 4.0 DTD)
cache if true, then the value should be cached while the component renders; false (a much less common case) means that every access will work through binding object.
location Used for reporting line-precise errors in binding resolution / setting / etc..
    public void addParameter(EnhancementOperation opString parameterName,
                             String propertyNameString specifiedTypeboolean cache,
                             Location location)
    {
        Defense.notNull(op"op");
        Defense.notNull(parameterName"parameterName");
        Defense.notNull(propertyName"propertyName");
        Class propertyType = EnhanceUtils.extractPropertyType(oppropertyNamespecifiedType);
        // 3.0 would allow connected parameter properties to be fully
        // implemented
        // in the component class. This is not supported in 4.0 and an existing
        // property will be overwritten in the subclass.
        op.claimProperty(propertyName);
        // 3.0 used to support a property for the binding itself. That's
        // no longer the case.
        String fieldName = "_$" + propertyName;
        String defaultFieldName = fieldName + "$Default";
        String cachedFieldName = fieldName + "$Cached";
        op.addField(fieldNamepropertyType);
        op.addField(defaultFieldNamepropertyType);
        op.addField(cachedFieldNameboolean.class);
        String bindingFieldName = buildBindingAccessor(opfieldNameparameterNamelocation);
        buildAccessor(oppropertyNamepropertyTypefieldName,
                      defaultFieldNamecachedFieldNamebindingFieldName,
                      cachelocation);
        buildMutator(opparameterNamepropertyNamepropertyTypefieldName,
                     defaultFieldNamecachedFieldNamebindingFieldNamelocation);
        extendCleanupAfterRender(opbindingFieldNamefieldNamedefaultFieldNamecachedFieldName);
    }
    String buildBindingAccessor(EnhancementOperation opString fieldNameString parameterName, Location location)
    {
        BodyBuilder body = new BodyBuilder();
        body.begin();
        
        String bindingFieldName = fieldName + "$Binding";
        String bindingCheckedName = bindingFieldName + "Checked";
        op.addField(bindingFieldNameIBinding.class);
        op.addField(bindingCheckedName.);
        body.addln("if (!{0})"bindingCheckedName);
        body.begin();
        body.addln("{0} = getBinding(\"{1}\");"bindingFieldNameparameterName);
        body.addln("{0} = true;"bindingCheckedName);
        body.end();
        body.addln("return {0};"bindingFieldName);
        body.end();
        String methodName = EnhanceUtils.createAccessorMethodName(bindingFieldName);
        op.addMethod(.,
                     new MethodSignature(IBinding.classmethodNamenew Class[0], null),
                     body.toString(), location);
        return methodName + "()";
    }
    void extendCleanupAfterRender(EnhancementOperation opString bindingFieldName,
                                  String fieldNameString defaultFieldNameString cachedFieldName)
    {
        BodyBuilder cleanupBody = new BodyBuilder();
        // Cached is only set when the field is updated in the accessor or
        // mutator.
        // After rendering, we want to clear the cached value and cached flag
        // unless the binding is invariant, in which case it can stick around
        // for some future render.
        cleanupBody.addln("if ({0} && ! {1}.isInvariant())"cachedFieldNamebindingFieldName);
        cleanupBody.begin();
        cleanupBody.addln("{0} = false;"cachedFieldName);
        cleanupBody.addln("{0} = {1};"fieldNamedefaultFieldName);
        cleanupBody.end();
        op.extendMethodImplementation(IComponent.class,
                                      .cleanupBody.toString());
    }
    private void buildMutator(EnhancementOperation opString parameterName,
                              String propertyNameClass propertyTypeString fieldName,
                              String defaultFieldNameString cachedFieldName,
                              String bindingFieldName, Location location)
    {
        BodyBuilder builder = new BodyBuilder();
        builder.begin();
        // The mutator method may be invoked from finishLoad(), in which
        // case it changes the default value for the parameter property, if the
        // parameter
        // is not bound.
        builder.addln("if (! isInActiveState())");
        builder.begin();
        builder.addln("{0} = $1;"defaultFieldName);
        builder.addln("return;");
        builder.end();
        // In the normal state, we update the binding first - and it's an error
        // if the parameter is not bound.
        builder.addln("if ({0} == null)"bindingFieldName);
        builder.addln("  throw new {0}(\"Parameter ''{1}'' is not bound and can not be updated.\");",
                      ApplicationRuntimeException.class.getName(), parameterName);
        // Always updated the binding first (which may fail with an exception).
        builder.addln("{0}.setObject(($w) $1);"bindingFieldName);
        // While rendering, we store the updated value for fast
        // access again (while the component is still rendering).
        // The property value will be reset to default by cleanupAfterRender().
        builder.addln("if (isRendering())");
        builder.begin();
        builder.addln("{0} = $1;"fieldName);
        builder.addln("{0} = true;"cachedFieldName);
        builder.end();
        builder.end();
        String mutatorMethodName = EnhanceUtils.createMutatorMethodName(propertyName);
        op.addMethod(.,
                     new MethodSignature(void.classmutatorMethodNamenew Class[] { propertyType }, null),
                     builder.toString(), location);
    }
    // Package private for testing
    void buildAccessor(EnhancementOperation opString propertyNameClass propertyType,
                       String fieldNameString defaultFieldNameString cachedFieldName,
                       String bindingFieldNameboolean cache, Location location)
    {
        BodyBuilder builder = new BodyBuilder();
        builder.begin();
        builder.addln("if ({0}) return {1};"cachedFieldNamefieldName);
        builder.addln("if ({0} == null) return {1};"bindingFieldNamedefaultFieldName);
        String javaTypeName = ClassFabUtils.getJavaClassName(propertyType);
        builder.addln("{0} result = {1};"javaTypeName, EnhanceUtils.createUnwrapExpression(opbindingFieldNamepropertyType));
        // Values read via the binding are cached during the render of
        // the component (if the parameter defines cache to be true, which
        // is the default), or any time the binding is invariant
        // (such as most bindings besides ExpressionBinding.
        String expression = cache ? "isRendering() || {0}.isInvariant()" : "{0}.isInvariant()";
        builder.addln("if (" + expression + ")"bindingFieldName);
        builder.begin();
        builder.addln("{0} = result;"fieldName);
        builder.addln("{0} = true;"cachedFieldName);
        builder.end();
        builder.addln("return result;");
        builder.end();
        String accessorMethodName = op.getAccessorMethodName(propertyName);
        op.addMethod(.new MethodSignature(propertyType,
                                                          accessorMethodNamenullnull), builder.toString(), location);
    }
    public void setErrorLog(ErrorLog errorLog)
    {
         = errorLog;
    }
New to GrepCode? Check out our FAQ X