You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/02/19 19:54:04 UTC

svn commit: r911925 - /tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java

Author: hlship
Date: Fri Feb 19 18:54:03 2010
New Revision: 911925

URL: http://svn.apache.org/viewvc?rev=911925&view=rev
Log:
Recode PersistWorker to use FieldValueConduit

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java?rev=911925&r1=911924&r2=911925&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java Fri Feb 19 18:54:03 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 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.
 // 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,
@@ -14,106 +14,130 @@
 
 package org.apache.tapestry5.internal.transform;
 
+import java.util.List;
+
+import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.annotations.Persist;
-import org.apache.tapestry5.ioc.util.BodyBuilder;
+import org.apache.tapestry5.internal.InternalComponentResources;
+import org.apache.tapestry5.internal.services.ComponentClassCache;
+import org.apache.tapestry5.ioc.services.FieldValueConduit;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.model.MutableComponentModel;
-import org.apache.tapestry5.services.*;
-
-import java.lang.reflect.Modifier;
+import org.apache.tapestry5.runtime.PageLifecycleAdapter;
+import org.apache.tapestry5.services.ClassTransformation;
+import org.apache.tapestry5.services.ComponentClassTransformWorker;
+import org.apache.tapestry5.services.ComponentValueProvider;
+import org.apache.tapestry5.services.TransformField;
 
 /**
  * Converts fields with the {@link org.apache.tapestry5.annotations.Persist} annotation into persistent fields.
  */
 public class PersistWorker implements ComponentClassTransformWorker
 {
-
-    public void transform(ClassTransformation transformation, MutableComponentModel model)
-    {
-        for (String name : transformation.findFieldsWithAnnotation(Persist.class))
-        {
-            makeFieldPersistent(name, transformation, model);
-        }
-    }
-
-    /**
-     * Making a field persistent: <ul> <li>Need a secondary default field that stores the initial value</li> <li>Store
-     * the active value into the default field when the page finishes loading</li> <li>Roll the active value back to the
-     * default when the page detaches</li> <ii>On changes to the active field, post the change via the {@link
-     * org.apache.tapestry5.internal.InternalComponentResources} </li> <li>When the page attaches, pull the persisted
-     * value for the field out of the {@link org.apache.tapestry5.services.PersistentFieldBundle}</li> </ul>
-     *
-     * @see org.apache.tapestry5.runtime.PageLifecycleListener#restoreStateBeforePageAttach()
-     */
-    private void makeFieldPersistent(String fieldName, ClassTransformation transformation,
-                                     MutableComponentModel model)
+    class PersistentFieldConduit implements FieldValueConduit
     {
-        String fieldType = transformation.getFieldType(fieldName);
-        Persist annotation = transformation.getFieldAnnotation(fieldName, Persist.class);
+        private final InternalComponentResources resources;
 
-        transformation.claimField(fieldName, annotation);
+        private final String name;
 
-        // Record the type of persistence, until needed later.
+        private final Object defaultValue;
 
-        String logicalFieldName = model.setFieldPersistenceStrategy(fieldName, annotation.value());
+        private Object currentValue;
 
-        String defaultValue = TransformUtils.getDefaultValue(fieldType);
+        public PersistentFieldConduit(InternalComponentResources resources, String name, Object defaultValue)
+        {
+            this.resources = resources;
+            this.name = name;
+            this.currentValue = defaultValue;
+            this.defaultValue = defaultValue;
+
+            resources.addPageLifecycleListener(new PageLifecycleAdapter()
+            {
+                @Override
+                public void containingPageDidDetach()
+                {
+                    resetToDefaultAtPageDetach();
+                }
+
+                @Override
+                public void restoreStateBeforePageAttach()
+                {
+                    restoreStateAtPageAttach();
+                }
+            });
+        }
 
-        // Force the field back to its default value (null, 0, false) at the end of each request.
+        public Object get()
+        {
+            return currentValue;
+        }
 
-        transformation.extendMethod(
-                TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
-                String.format("%s = %s;", fieldName, defaultValue));
+        public void set(Object newValue)
+        {
+            resources.persistFieldChange(name, newValue);
 
-        String resourcesFieldName = transformation.getResourcesFieldName();
+            currentValue = newValue;
+        }
 
-        String writeMethodName = transformation.newMemberName("write", fieldName);
+        private void resetToDefaultAtPageDetach()
+        {
+            currentValue = defaultValue;
+        }
 
-        BodyBuilder builder = new BodyBuilder();
+        private void restoreStateAtPageAttach()
+        {
+            if (resources.hasFieldChange(name))
+                currentValue = resources.getFieldChange(name);
+        }
+    }
 
-        builder.begin();
-        builder.addln(
-                "%s.persistFieldChange(\"%s\", ($w) $1);",
-                resourcesFieldName,
-                logicalFieldName);
-        builder.addln("%s = $1;", fieldName);
-        builder.end();
+    private final TypeCoercer typeCoercer;
 
-        transformation.addMethod(new TransformMethodSignature(Modifier.PRIVATE, "void", writeMethodName,
-                                                              new String[]
-                                                                      { fieldType }, null), builder.toString());
+    private final ComponentClassCache classCache;
 
-        transformation.replaceWriteAccess(fieldName, writeMethodName);
+    public PersistWorker(TypeCoercer typeCoercer, ComponentClassCache classCache)
+    {
+        this.typeCoercer = typeCoercer;
+        this.classCache = classCache;
+    }
 
-        builder.clear();
-        builder.begin();
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    {
+        List<TransformField> fieldsWithAnnotation = transformation.matchFieldsWithAnnotation(Persist.class);
 
-        // Check to see if there's a recorded change for this component, this field.
+        for (TransformField field : fieldsWithAnnotation)
+        {
+            makeFieldPersistent(field, model);
+        }
+    }
 
-        builder.addln("if (%s.hasFieldChange(\"%s\"))", resourcesFieldName, logicalFieldName);
+    private void makeFieldPersistent(TransformField field, MutableComponentModel model)
+    {
+        Persist annotation = field.getAnnotation(Persist.class);
 
-        String wrapperType = TransformUtils.getWrapperTypeName(fieldType);
+        field.claim(annotation);
 
-        // Get the value, cast it to the correct type (or wrapper type)
-        builder.add(
-                "  %s = ((%s) %s.getFieldChange(\"%s\"))",
-                fieldName,
-                wrapperType,
-                resourcesFieldName,
-                logicalFieldName);
+        final String logicalFieldName = model.setFieldPersistenceStrategy(field.getName(), annotation.value());
 
-        // For primtive types, add in the method call to unwrap the wrapper type to a primitive type
+        final Object defaultValue = determineDefaultValueFromFieldType(field);
 
-        String unwrapMethodName = TransformUtils.getUnwrapperMethodName(fieldType);
+        ComponentValueProvider<FieldValueConduit> provider = new ComponentValueProvider<FieldValueConduit>()
+        {
+            public FieldValueConduit get(ComponentResources resources)
+            {
+                return new PersistentFieldConduit((InternalComponentResources) resources, logicalFieldName,
+                        defaultValue);
+            }
+        };
 
-        if (unwrapMethodName == null)
-            builder.addln(";");
-        else
-            builder.addln(".%s();", unwrapMethodName);
+        field.replaceAccess(provider);
+    }
 
-        builder.end();
+    @SuppressWarnings("unchecked")
+    private Object determineDefaultValueFromFieldType(TransformField field)
+    {
+        Class javaType = classCache.forName(field.getType());
 
-        transformation.extendMethod(
-                TransformConstants.RESTORE_STATE_BEFORE_PAGE_ATTACH_SIGNATURE,
-                builder.toString());
+        return javaType.isPrimitive() ? typeCoercer.coerce(0, javaType) : null;
     }
 }