You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2010/01/22 17:31:21 UTC

svn commit: r902156 - in /tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5: annotations/ internal/ internal/services/ internal/structure/ internal/transform/ services/

Author: hlship
Date: Fri Jan 22 16:31:21 2010
New Revision: 902156

URL: http://svn.apache.org/viewvc?rev=902156&view=rev
Log:
Introduce new interface, FieldValueConduit, and add ability to ClassTransformation to redirect all field access through the conduit

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValueConduit.java   (with props)
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/BindParameter.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResources.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterConduit.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker2.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/BindParameter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/BindParameter.java?rev=902156&r1=902155&r2=902156&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/BindParameter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/BindParameter.java Fri Jan 22 16:31:21 2010
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009 , 2010 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.
@@ -20,6 +20,8 @@
 import java.lang.annotation.RetentionPolicy;
 
 import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.MIXIN;
+
+import org.apache.tapestry5.internal.transform.BindParameterWorker;
 import org.apache.tapestry5.ioc.annotations.UseWith;
 
 
@@ -34,7 +36,8 @@
  * uservariable <=> mixin.value <=> component.value.
  * Changes to any one value in the chain will be propagated accordingly.
  *
- * @since 5.2.0.0
+ * @since 5.2.0
+ * @see BindParameterWorker
  */
 @Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResources.java?rev=902156&r1=902155&r2=902156&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResources.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResources.java Fri Jan 22 16:31:21 2010
@@ -4,7 +4,7 @@
 // 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
+// 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,
@@ -18,7 +18,9 @@
 import org.apache.tapestry5.internal.services.PersistentFieldManager;
 import org.apache.tapestry5.internal.structure.Page;
 import org.apache.tapestry5.internal.structure.PageResetListener;
+import org.apache.tapestry5.internal.transform.ParameterConduit;
 import org.apache.tapestry5.runtime.RenderQueue;
+import org.apache.tapestry5.services.FieldValueConduit;
 
 /**
  * An extension of {@link org.apache.tapestry5.ComponentResources} that represents additional
@@ -86,8 +88,17 @@
             String... parentParameterNames);
 
     /**
-     * Delegates to {@link Page#addResetListener(org.apache.tapestry5.internal.structure.PageResetListener)}.
-     * @param listener to register
+     * Delegates to
+     * {@link Page#addResetListener(org.apache.tapestry5.internal.structure.PageResetListener)}.
+     * 
+     * @param listener
+     *            to register
      */
     void addPageResetListener(PageResetListener listener);
+
+    /** @since 5.2.0 */
+    FieldValueConduit getParameterConduit(String parameterName);
+
+    /** @since 5.2.0 */
+    void setParameterConduit(String parameterName, ParameterConduit conduit);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java?rev=902156&r1=902155&r2=902156&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java Fri Jan 22 16:31:21 2010
@@ -55,6 +55,7 @@
 import org.apache.tapestry5.services.ComponentMethodAdvice;
 import org.apache.tapestry5.services.ComponentValueProvider;
 import org.apache.tapestry5.services.FieldFilter;
+import org.apache.tapestry5.services.FieldValueConduit;
 import org.apache.tapestry5.services.MethodFilter;
 import org.apache.tapestry5.services.TransformMethodSignature;
 import org.apache.tapestry5.services.TransformUtils;
@@ -2007,4 +2008,44 @@
         makeReadOnly(fieldName);
     }
 
+    @Override
+    public void replaceFieldAccess(String fieldName,
+            ComponentValueProvider<FieldValueConduit> conduitProvider)
+    {
+        replaceFieldAccess(fieldName, addIndirectInjectedField(FieldValueConduit.class, fieldName
+                + "$conduit", conduitProvider));
+    }
+
+    @Override
+    public void replaceFieldAccess(String fieldName, String conduitFieldName)
+    {
+        String fieldType = getFieldType(fieldName);
+
+        String readMethodName = newMemberName("get", fieldName);
+
+        TransformMethodSignature readSig = new TransformMethodSignature(Modifier.PRIVATE,
+                fieldType, readMethodName, null, null);
+
+        String cast = TransformUtils.getWrapperTypeName(fieldType);
+
+        // The ($r) cast will convert the result to the method return type; generally
+        // this does nothing. but for primitive types, it will unwrap
+        // the wrapper type back to a primitive.
+
+        addMethod(readSig, String.format("return ($r) ((%s) %s.get());", cast, conduitFieldName));
+
+        replaceReadAccess(fieldName, readMethodName);
+
+        String writeMethodName = newMemberName("set", fieldName);
+
+        TransformMethodSignature writeSig = new TransformMethodSignature(Modifier.PRIVATE, "void",
+                writeMethodName, new String[]
+                { fieldType }, null);
+
+        addMethod(writeSig, String.format("%s.set(($w) $1);", conduitFieldName));
+
+        replaceWriteAccess(fieldName, writeMethodName);
+
+        removeField(fieldName);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java?rev=902156&r1=902155&r2=902156&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java Fri Jan 22 16:31:21 2010
@@ -32,6 +32,7 @@
 import org.apache.tapestry5.internal.ParameterChangeListener;
 import org.apache.tapestry5.internal.ParameterChangedEvent;
 import org.apache.tapestry5.internal.services.Instantiator;
+import org.apache.tapestry5.internal.transform.ParameterConduit;
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.Messages;
@@ -45,6 +46,7 @@
 import org.apache.tapestry5.runtime.Component;
 import org.apache.tapestry5.runtime.PageLifecycleListener;
 import org.apache.tapestry5.runtime.RenderQueue;
+import org.apache.tapestry5.services.FieldValueConduit;
 import org.slf4j.Logger;
 
 /**
@@ -79,6 +81,10 @@
     // Case-insensitive map from container-parameter name to ParameterAccess, for BindParameter.
     // Should only ever be used for mixins.
     private Map<String, ParameterAccess> containerParameterAccess;
+    
+    // Case insentive map from parameter name to ParameterConduit, used to support mixins
+    // which need access to the containing component's PC's
+    private Map<String, ParameterConduit> conduits;
 
     private Messages messages;
 
@@ -779,4 +785,20 @@
     {
         page.addResetListener(listener);
     }
+
+    @Override
+    public FieldValueConduit getParameterConduit(String parameterName)
+    {
+        return InternalUtils.get(conduits, parameterName);
+    }
+
+    @Override
+    public void setParameterConduit(String parameterName, ParameterConduit conduit)
+    {
+        if (conduits == null) conduits = CollectionFactory.newCaseInsensitiveMap();
+
+        conduits.put(parameterName, conduit);
+    }
+    
+    
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterConduit.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterConduit.java?rev=902156&r1=902155&r2=902156&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterConduit.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterConduit.java Fri Jan 22 16:31:21 2010
@@ -18,16 +18,17 @@
 import org.apache.tapestry5.annotations.Parameter;
 import org.apache.tapestry5.internal.InternalComponentResources;
 import org.apache.tapestry5.internal.bindings.LiteralBinding;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.runtime.Component;
+import org.apache.tapestry5.services.FieldValueConduit;
 
 /**
  * A facade around {@link Binding} and {@link InternalComponentResources} that is used to instrument
- * fields with the {@link Parameter} annotation.
+ * fields with the {@link Parameter} annotation. Extends {@link FieldValueConduit} so that
+ * the get() method implicitly coerces the value to the field's type.
  * 
  * @since 5.2.0
  */
-public interface ParameterConduit
+public interface ParameterConduit extends FieldValueConduit
 {
     /**
      * Sets the default value for the parameter based on either the current value of the field,
@@ -41,24 +42,6 @@
     void setDefault(Object defaultValue);
 
     /**
-     * Reads the current value of the parameter (via the {@link Binding}) and uses the
-     * {@link TypeCoercer} to convert the actual value to one assignable to the underlying field.
-     * The actual read value may be cached.
-     * 
-     * @throws RuntimeException
-     *             if the parameter does not allow null but the current value is null
-     * @return current value (possibly null)
-     */
-    Object get();
-
-    /**
-     * Sets the value of the parameter, pushing it through the {@link Binding}.
-     * 
-     * @param newValue
-     */
-    void set(Object newValue);
-
-    /**
      * Determines if the parameter is actually bound.
      * 
      * @return

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker2.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker2.java?rev=902156&r1=902155&r2=902156&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker2.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker2.java Fri Jan 22 16:31:21 2010
@@ -14,7 +14,6 @@
 
 package org.apache.tapestry5.internal.transform;
 
-import java.lang.reflect.Modifier;
 import java.util.Iterator;
 import java.util.List;
 
@@ -36,7 +35,6 @@
 import org.apache.tapestry5.services.MethodFilter;
 import org.apache.tapestry5.services.TransformConstants;
 import org.apache.tapestry5.services.TransformMethodSignature;
-import org.apache.tapestry5.services.TransformUtils;
 
 public class ParameterWorker2 implements ComponentClassTransformWorker
 {
@@ -107,7 +105,7 @@
             // better
             // if there was a way to defer until the component's page loaded lifecycle method). The
             // issues
-            // are addressed by deferring some behaviors until the reset() method.
+            // are addressed by deferring some behaviors until the load() method.
 
             @Override
             public ParameterConduit get(ComponentResources resources)
@@ -116,8 +114,6 @@
 
                 final Class fieldType = classCache.forName(fieldTypeName);
 
-                // final ParameterAccess parameterAccess = icr.getParameterAccess(parameterName);
-
                 // Rely on some code generation in the component to set the default binding from
                 // the field, or from a default method.
 
@@ -149,15 +145,11 @@
 
                         if (javaType.isPrimitive())
                         {
-                            if (javaType == boolean.class)
-                            {
-                                defaultValue = false;
-                            }
-                            else
-                            {
-                                defaultValue = typeCoercer.coerce(0l, javaType);
-                            }
+                            // Reminder: 0 coerces to false
+                            defaultValue = typeCoercer.coerce(0l, javaType);
                         }
+
+                        icr.setParameterConduit(parameterName, this);
                     }
 
                     private boolean isInvariant()
@@ -184,19 +176,15 @@
                             return;
                         }
 
-                        // TODO: Disable parameter change listener before updating PA
-
                         // This will catch read-only or unbound parameters.
 
                         parameterAccess.write(newValue);
 
-                        // TODO: Re-enable parameter change listener after updating PA
-
                         value = newValue;
 
                         // If caching is enabled for the parameter (the typical case) and the
                         // component is currently rendering, then the result
-                        // can be cached in the ParameterConduit (until the component finished
+                        // can be cached in the ParameterConduit (until the component finishes
                         // rendering).
 
                         cached = enableCaching && icr.isRendering();
@@ -215,22 +203,19 @@
                     @Override
                     public void load()
                     {
-                        boolean isBound = icr.isBound(parameterName);
-
-
                         // If it's bound at this point, that's because of an explicit binding
                         // in the template or @Component annotation.
-                        
+
                         if (!icr.isBound(parameterName))
                         {
                             // Otherwise, construct a default binding, or use one provided from
                             // the component.
-                            
+
                             Binding binding = getDefaultBindingForParameter();
 
                             if (binding != null)
                                 icr.bindParameter(parameterName, binding);
-                            
+
                             defaultBinding = null;
                         }
 
@@ -250,9 +235,10 @@
                         if (annotation.autoconnect())
                             return defaultProvider.defaultBinding(parameterName, icr);
 
-                        // Return (if not null) the binding from the setDefault() method which is set
-                        // via a default method on the component, or from the field's initial value.
-                        
+                        // Return (if not null) the binding from the setDefault() method which is
+                        // set via a default method on the component, or from the field's initial
+                        // value.
+
                         return defaultBinding;
                     }
 
@@ -277,7 +263,7 @@
                         // If the value is invariant, we can cache it forever. Otherwise, we
                         // we may want to cache it for the remainder of the component render (if the
                         // component is currently rendering).
-                        
+
                         if (isInvariant() || (enableCaching && icr.isRendering()))
                         {
                             value = result;
@@ -313,9 +299,7 @@
 
         addCodeForParameterDefaultMethod(transformation, parameterName, conduitFieldName);
 
-        addParameterWriteMethod(transformation, fieldName, fieldTypeName, conduitFieldName);
-
-        addParameterReadMethod(transformation, fieldName, fieldTypeName, conduitFieldName);
+        transformation.replaceFieldAccess(fieldName, conduitFieldName);
 
         transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, String
                 .format("%s.load();", conduitFieldName));
@@ -323,43 +307,6 @@
         transformation.extendMethod(TransformConstants.POST_RENDER_CLEANUP_SIGNATURE, String
                 .format("%s.reset();", conduitFieldName));
 
-        transformation.removeField(fieldName);
-    }
-
-    private void addParameterReadMethod(ClassTransformation transformation, String fieldName,
-            final String fieldTypeName, String conduitFieldName)
-    {
-        String readMethodName = transformation.newMemberName("read_parameter", fieldName);
-
-        TransformMethodSignature readSig = new TransformMethodSignature(Modifier.PRIVATE,
-                fieldTypeName, readMethodName, null, null);
-
-        String cast = TransformUtils.getWrapperTypeName(fieldTypeName);
-
-        // The ($r) cast will convert the result to the method return type; generally
-        // this does nothing. but for primitive types, it will unwrap
-        // the wrapper type back to a primitive. We pass the desired type name
-        // to readParameter(), since its easier to convert it properly to
-        // a type on that end than in the generated code.
-
-        transformation.addMethod(readSig, String.format("return ($r) ((%s) %s.get());", cast,
-                conduitFieldName));
-
-        transformation.replaceReadAccess(fieldName, readMethodName);
-    }
-
-    private void addParameterWriteMethod(ClassTransformation transformation, String fieldName,
-            String fieldTypeName, String conduitFieldName)
-    {
-        String writeMethodName = transformation.newMemberName("update_parameter", fieldName);
-
-        TransformMethodSignature writeSig = new TransformMethodSignature(Modifier.PRIVATE, "void",
-                writeMethodName, new String[]
-                { fieldTypeName }, null);
-
-        transformation.addMethod(writeSig, String.format("%s.set(($w) $1);", conduitFieldName));
-
-        transformation.replaceWriteAccess(fieldName, writeMethodName);
     }
 
     private void addCodeForParameterDefaultMethod(ClassTransformation transformation,

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java?rev=902156&r1=902155&r2=902156&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java Fri Jan 22 16:31:21 2010
@@ -249,7 +249,7 @@
      * Like {@link #addInjectedField(Class, String, Object)}, but instead of specifying the value,
      * a provider for the value is specified. In the generated class' constructor, the provider
      * will be passed the {@link ComponentResources} and will return the final value; thus
-     * each component <em>instance</em> will receive a unique
+     * each component <em>instance</em> will receive a matching unique instance via the provider.
      * 
      * @param <T>
      * @param type
@@ -519,4 +519,28 @@
      */
     <T> void assignFieldIndirect(String fieldName, TransformMethodSignature methodSig,
             ComponentValueProvider<T> provider);
+
+    /**
+     * Replaces read and write field access with a conduit. The field will be deleted.
+     * 
+     * @param fieldName
+     *            field to replace
+     * @param conduitProvider
+     *            provides the actual conduit at class instantiation time
+     * @since 5.2.0
+     */
+    void replaceFieldAccess(String fieldName,
+            ComponentValueProvider<FieldValueConduit> conduitProvider);
+
+    /**
+     * Replaces read and write field access with a previously injected conduit (identified by its
+     * field name). The conduit must implement {@link FieldValueConduit}. The field will be removed.
+     * 
+     * @since 5.2.0
+     * @param fieldName
+     *            field to replace
+     * @param conduitFieldName
+     *            name of field which will have an instance of {@link FieldValueConduit}
+     */
+    void replaceFieldAccess(String fieldName, String conduitFieldName);
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValueConduit.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValueConduit.java?rev=902156&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValueConduit.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValueConduit.java Fri Jan 22 16:31:21 2010
@@ -0,0 +1,46 @@
+// Copyright 2010 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.tapestry5.services;
+
+import org.apache.tapestry5.Binding;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * A callback object that is used to replace storage of a value inside a component field.
+ * 
+ * @since 5.2.0
+ */
+public interface FieldValueConduit
+{
+
+    /**
+     * Reads the current value of the parameter (via the {@link Binding}) and uses the
+     * {@link TypeCoercer} to convert the actual value to one assignable to the underlying field.
+     * The actual read value may be cached.
+     * 
+     * @throws RuntimeException
+     *             if the parameter does not allow null but the current value is null
+     * @return current value (possibly null)
+     */
+    Object get();
+
+    /**
+     * Sets the value of the parameter, pushing it through the {@link Binding}.
+     * 
+     * @param newValue
+     */
+    void set(Object newValue);
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValueConduit.java
------------------------------------------------------------------------------
    svn:eol-style = native