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 2006/09/01 00:49:00 UTC

svn commit: r439080 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/ioc/ main/java/org/apache/tap...

Author: hlship
Date: Thu Aug 31 15:48:58 2006
New Revision: 439080

URL: http://svn.apache.org/viewvc?rev=439080&view=rev
Log:
Incomplete start of component parameter support.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/ParentClass.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java Thu Aug 31 15:48:58 2006
@@ -48,4 +48,10 @@
      * Returns the component this object provides resources for.
      */
     ComponentLifecycle getComponent();
+
+    /**
+     * Returns true if the component is currently rendering, false otherwise. This is most often
+     * used to determine if parameter values should be cached.
+     */
+    boolean isRendering();
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java?rev=439080&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java Thu Aug 31 15:48:58 2006
@@ -0,0 +1,44 @@
+package org.apache.tapestry.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation placed on a field to indicate that it is, in fact, an parameter. Parameters may be
+ * optional or required. Required parameters must be bound.
+ * <p>
+ * TODO: Do we want to support a notNull as well as required?
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Target(FIELD)
+@Documented
+@Retention(RUNTIME)
+public @interface Parameter {
+
+    /**
+     * The name of the parameter. If not specified, the name of the parameter is derived from the
+     * name of the field (after stripping off leading punctuation) from the field name.
+     */
+    String name() default "";
+
+    /**
+     * If true, the parameter is required and and must be bound. If false (the default), then the
+     * parameter is optional.
+     */
+    boolean required() default false;
+
+    /**
+     * If true (the default), then the value for the parameter is cached while the component is,
+     * itself, rendering. Values from invariant bindings (such as literal strings) are always
+     * cached, regardless of this setting. Set this attribute to false to force the parameter to be
+     * {@link org.apache.tapestry.Binding#get() re-read} every time the field is accessed, even
+     * while the component is rendering.
+     */
+    
+    boolean cache() default true;
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java Thu Aug 31 15:48:58 2006
@@ -25,5 +25,30 @@
  */
 public interface InternalComponentResources extends ComponentResources
 {
+    /** Returns true if the parameter is bound, false if not. */
+    boolean isBound(String parameterName);
+
+    /**
+     * Reads the value of a parameter, via the parameter's {@link org.apache.tapestry.Binding}.
+     * 
+     * @param <T>
+     * @param parameterName
+     *            the name of the parameter to read
+     * @param expectedType
+     *            the expected type of parameter
+     * @return the value for the parameter, or null if the parameter is not bound.
+     */
+    <T> T readParameter(String parameterName, Class<T> expectedType);
+
+    /**
+     * Returns true if the named parameter's {@link org.apache.tapestry.Binding} is invariant, false
+     * if otherwise, or if the parameter is not bound. Invariant bindings are cached more
+     * aggresively than variant bindings.
+     * 
+     * @param parameterName
+     *            the name of parameter to check for invariance
+     * @return
+     */
+    boolean isInvariant(String parameterName);
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java Thu Aug 31 15:48:58 2006
@@ -107,7 +107,7 @@
         }
     }
 
-    public RegistryImpl(Collection<ModuleDef> moduleDefs, LogSource logSource)
+    public RegistryImpl(Collection<ModuleDef> moduleDefs, ClassLoader contextClassLoader, LogSource logSource)
     {
         _logSource = logSource;
 
@@ -124,7 +124,7 @@
 
         Log log = _logSource.getLog(RegistryImpl.CLASS_FACTORY_SERVICE_ID);
 
-        _classFactory = new ClassFactoryImpl(log);
+        _classFactory = new ClassFactoryImpl(contextClassLoader, log);
 
         addBuiltin(RegistryImpl.CLASS_FACTORY_SERVICE_ID, ClassFactory.class, _classFactory);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java Thu Aug 31 15:48:58 2006
@@ -42,11 +42,11 @@
      */
     private Set<ClassLoader> _loaders = newSet();
 
-    ClassFactoryClassPool()
+    ClassFactoryClassPool(ClassLoader contextClassLoader)
     {
         super(null);
 
-        appendClassLoader(Thread.currentThread().getContextClassLoader());
+        appendClassLoader(contextClassLoader);
     }
 
     /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java Thu Aug 31 15:48:58 2006
@@ -34,17 +34,30 @@
     /**
      * ClassPool shared by all modules (all CtClassSource instances).
      */
-    private ClassFactoryClassPool _pool = new ClassFactoryClassPool();
+    private final ClassFactoryClassPool _pool;
 
-    private CtClassSource _classSource = new CtClassSource(_pool);
+    private final CtClassSource _classSource;
+
+    private final ClassLoader _loader;
+
+    public ClassFactoryImpl(ClassLoader contextClassLoader)
+    {
+        this(contextClassLoader, LogFactory.getLog(ClassFactoryImpl.class));
+    }
 
     public ClassFactoryImpl()
     {
-        this(LogFactory.getLog(ClassFactoryImpl.class));
+        this(Thread.currentThread().getContextClassLoader());
     }
 
-    public ClassFactoryImpl(Log log)
+    public ClassFactoryImpl(ClassLoader contextClassLoader, Log log)
     {
+        _loader = contextClassLoader;
+
+        _pool = new ClassFactoryClassPool(contextClassLoader);
+
+        _classSource = new CtClassSource(_pool);
+
         _log = log;
     }
 
@@ -78,11 +91,14 @@
         }
     }
 
-    /** @since 1.1 */
-
     public int getCreatedClassCount()
     {
         return _classSource.getCreatedClassCount();
+    }
+
+    public ClassLoader getClassLoader()
+    {
+        return _loader;
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java Thu Aug 31 15:48:58 2006
@@ -14,9 +14,18 @@
 
 package org.apache.tapestry.internal.model;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.Resource;
 import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.model.ParameterModel;
+import org.apache.tapestry.util.Defense;
+
+import static org.apache.tapestry.util.CollectionFactory.newList;
+import static org.apache.tapestry.util.CollectionFactory.newMap;
 
 /**
  * Internal implementation of {@link org.apache.tapestry.model.MutableComponentModel}.
@@ -31,6 +40,8 @@
 
     private final Log _log;
 
+    private Map<String, ParameterModel> _parameters;
+
     public MutableComponentModelImpl(String componentClassName, Log log, Resource baseResource)
     {
         _componentClassName = componentClassName;
@@ -51,6 +62,47 @@
     public String getComponentClassName()
     {
         return _componentClassName;
+    }
+
+    public void addParameter(String name, boolean required)
+    {
+        // TODO: Check for conflict with base model
+
+        if (_parameters == null)
+            _parameters = newMap();
+        else
+        {
+            if (_parameters.containsKey(name))
+                throw new IllegalArgumentException();
+        }
+
+        Defense.notBlank(name, "name");
+
+        _parameters.put(name, new ParameterModelImpl(name, required));
+    }
+
+    public ParameterModel getParameterModel(String parameterName)
+    {
+        // TODO: Parameters defined in base model
+
+        if (_parameters == null)
+            return null;
+
+        return _parameters.get(parameterName);
+    }
+
+    public List<String> getParameterNames()
+    {
+        // TODO: Parameters from base model
+
+        List<String> names = newList();
+
+        if (_parameters != null)
+            names.addAll(_parameters.keySet());
+
+        Collections.sort(names);
+
+        return names;
     }
 
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java?rev=439080&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java Thu Aug 31 15:48:58 2006
@@ -0,0 +1,30 @@
+package org.apache.tapestry.internal.model;
+
+import org.apache.tapestry.model.ParameterModel;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ParameterModelImpl implements ParameterModel
+{
+    private final String _name;
+
+    private final boolean _required;
+
+    public ParameterModelImpl(String name, boolean required)
+    {
+        _name = name;
+        _required = required;
+    }
+
+    public String getName()
+    {
+        return _name;
+    }
+
+    public boolean isRequired()
+    {
+        return _required;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java Thu Aug 31 15:48:58 2006
@@ -102,12 +102,12 @@
                 ctClass)
                 : new InternalClassTransformationImpl(ctClass, parentTransformation);
 
-        // Not all classes in the packages are components.
+        // Not all classes in the packages are components. That's not just sloppy coding by
+        // application developers, it also represents inner classes (including anonymous classes).
 
         if (transformation.getAnnotation(ComponentClass.class) == null)
             return;
 
-        // Eventually these will also be cached or published or something.
         // TODO: child class model should start as deep copy of parent model?
         // Or have pointer to parent model? Or something.
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java Thu Aug 31 15:48:58 2006
@@ -70,11 +70,6 @@
         return _loader;
     }
 
-    public ComponentInstantiatorSourceImpl(ComponentClassTransformer transformer, Log log)
-    {
-        this(Thread.currentThread().getContextClassLoader(), transformer, log);
-    }
-
     public ComponentInstantiatorSourceImpl(ClassLoader parent,
             ComponentClassTransformer transformer, Log log)
     {

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java Thu Aug 31 15:48:58 2006
@@ -36,6 +36,7 @@
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+import org.apache.tapestry.internal.util.InternalUtils;
 import org.apache.tapestry.runtime.ComponentLifecycle;
 import org.apache.tapestry.services.MethodSignature;
 import org.apache.tapestry.util.CollectionFactory;
@@ -76,6 +77,8 @@
 
     private Set<String> _addedFieldNames = newSet();
 
+    private Set<CtMethod> _addedMethods = newSet();
+
     // Cache of class annotations
 
     private List<Annotation> _classAnnotations;
@@ -93,8 +96,6 @@
 
     // All field/method names will have this value as a prefix
 
-    private static final String NAME_PREFIX = "_$";
-
     private final String _resourcesFieldName;
 
     private final StringBuilder _description = new StringBuilder();
@@ -297,93 +298,11 @@
     {
         failIfFrozen();
 
-        String memberName = createMemberName(notBlank(suggested, "suggested"));
+        String memberName = InternalUtils.createMemberName(notBlank(suggested, "suggested"));
 
         return _idAllocator.allocateId(memberName);
     }
 
-    /** Strips leading characters defined by {@link #NAME_PREFIX}. */
-    private String createMemberName(String memberName)
-    {
-        failIfFrozen();
-
-        StringBuilder builder = new StringBuilder(memberName);
-
-        // There may be other prefixes we want to strip off, at some point!
-
-        // Strip off leading characters defined by NAME_PREFIX
-
-        while (true)
-        {
-            char ch = builder.charAt(0);
-
-            if (NAME_PREFIX.indexOf(ch) < 0)
-                break;
-
-            builder.deleteCharAt(0);
-        }
-
-        // Insert the name prefix at the start of the string.
-
-        builder.insert(0, NAME_PREFIX);
-
-        return builder.toString();
-    }
-
-    // public void addFieldEncapsulation(CtField field, String readMethodName, String
-    // writeMethodName)
-    // {
-    // failIfFrozen();
-    //
-    // // TODO: Check if field already encapsulated
-    //
-    // FieldEncapsulation fe = new FieldEncapsulation(readMethodName, writeMethodName);
-    //
-    // _encapsulations.put(field, fe);
-    // }
-    //
-    // public void applyFieldEncapsulations()
-    // {
-    // failIfFrozen();
-    //
-    // ExprEditor editor = new ExprEditor()
-    // {
-    //
-    // @Override
-    // public void edit(FieldAccess f) throws CannotCompileException
-    // {
-    // // Methods added as part of enhancement are NOT subject
-    // // to field encapsulation.
-    //
-    // if (_addedMethods.contains(f.where()))
-    // return;
-    //
-    // try
-    // {
-    // CtField field = f.getField();
-    // FieldEncapsulation fe = _encapsulations.get(field);
-    //
-    // if (fe != null)
-    // fe.encapsulate(f);
-    // }
-    // catch (NotFoundException ex)
-    // {
-    // throw new RuntimeException(ex);
-    // }
-    // }
-    //
-    // };
-    //
-    // try
-    // {
-    // _ctClass.instrument(editor);
-    // }
-    // catch (CannotCompileException ex)
-    // {
-    // throw new RuntimeException(ex);
-    // }
-    // }
-
     public void addImplementedInterface(Class interfaceClass)
     {
         failIfFrozen();
@@ -515,6 +434,58 @@
         _claimedFields.put(fieldName, tag);
     }
 
+    public void addMethod(MethodSignature signature, String methodBody)
+    {
+        failIfFrozen();
+
+        CtClass returnType = findCtClass(signature.getReturnType());
+        CtClass[] parameters = buildCtClassList(signature.getParameterTypes());
+        CtClass[] exceptions = buildCtClassList(signature.getExceptionTypes());
+
+        CtMethod method = new CtMethod(returnType, signature.getMethodName(), parameters, _ctClass);
+
+        // TODO: Check for duplicate method add
+
+        try
+        {
+            method.setModifiers(signature.getModifiers());
+            method.setBody(methodBody);
+            method.setExceptionTypes(exceptions);
+
+            _ctClass.addMethod(method);
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
+        _addedMethods.add(method);
+
+        addMethodToDescription("add", signature, methodBody);
+    }
+
+    private CtClass[] buildCtClassList(String[] typeNames)
+    {
+        CtClass[] result = new CtClass[typeNames.length];
+
+        for (int i = 0; i < typeNames.length; i++)
+            result[i] = findCtClass(typeNames[i]);
+
+        return result;
+    }
+
+    private CtClass findCtClass(String type)
+    {
+        try
+        {
+            return _classPool.get(type);
+        }
+        catch (NotFoundException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+    }
+
     public void extendMethod(MethodSignature methodSignature, String methodBody)
     {
         failIfFrozen();
@@ -530,7 +501,14 @@
             throw new RuntimeException(ex);
         }
 
-        _formatter.format("extend method: %s %s %s(", Modifier.toString(methodSignature
+        addMethodToDescription("extend", methodSignature, methodBody);
+
+    }
+
+    private void addMethodToDescription(String operation, MethodSignature methodSignature,
+            String methodBody)
+    {
+        _formatter.format("%s method: %s %s %s(", operation, Modifier.toString(methodSignature
                 .getModifiers()), methodSignature.getReturnType(), methodSignature.getMethodName());
 
         String[] parameterTypes = methodSignature.getParameterTypes();
@@ -556,7 +534,6 @@
         }
 
         _formatter.format("\n%s\n\n", methodBody);
-
     }
 
     private CtMethod findMethod(MethodSignature methodSignature)
@@ -655,6 +632,9 @@
 
         for (CtField field : _ctClass.getDeclaredFields())
         {
+            if (!isInstanceField(field))
+                continue;
+
             String fieldName = field.getName();
 
             List<Annotation> annotations = findFieldAnnotations(fieldName);
@@ -672,6 +652,8 @@
             }
         }
 
+        Collections.sort(result);
+
         return result;
     }
 
@@ -876,6 +858,7 @@
         }
 
         _formatter.format("add constructor: %s(", _ctClass.getName());
+
         for (int i = 0; i < count; i++)
         {
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Thu Aug 31 15:48:58 2006
@@ -32,10 +32,12 @@
 import org.apache.tapestry.ioc.annotations.Lifecycle;
 import org.apache.tapestry.ioc.annotations.Match;
 import org.apache.tapestry.ioc.annotations.Order;
+import org.apache.tapestry.ioc.services.ClassFactory;
 import org.apache.tapestry.ioc.services.LoggingDecorator;
 import org.apache.tapestry.ioc.services.ThreadCleanupHub;
 import org.apache.tapestry.services.ApplicationInitializer;
 import org.apache.tapestry.services.ApplicationInitializerFilter;
+import org.apache.tapestry.services.BindingSource;
 import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.ComponentClassTransformWorker;
 import org.apache.tapestry.services.MarkupWriterFactory;
@@ -89,11 +91,12 @@
     }
 
     public ComponentInstantiatorSource buildComponentInstantiatorSource(
-            @InjectService("ComponentClassTransformer")
+            @InjectService("tapestry.ioc.ClassFactory")
+            ClassFactory classFactory, @InjectService("ComponentClassTransformer")
             ComponentClassTransformer transformer, Log log)
     {
-        ComponentInstantiatorSourceImpl source = new ComponentInstantiatorSourceImpl(transformer,
-                log);
+        ComponentInstantiatorSourceImpl source = new ComponentInstantiatorSourceImpl(classFactory
+                .getClassLoader(), transformer, log);
 
         _updateListenerHub.addUpdateListener(source);
 
@@ -122,9 +125,13 @@
     }
 
     public PageLoader buildPageLoader(@InjectService("PageElementFactory")
-    PageElementFactory pageElementFactory)
+    PageElementFactory pageElementFactory,
+
+    @InjectService("tapestry.BindingSource")
+    BindingSource bindingSource)
     {
-        PageLoaderImpl service = new PageLoaderImpl(_componentTemplateSource, pageElementFactory);
+        PageLoaderImpl service = new PageLoaderImpl(_componentTemplateSource, pageElementFactory,
+                bindingSource);
 
         _componentInstantiatorSource.addInvalidationListener(service);
 
@@ -157,11 +164,24 @@
         return new UpdateListenerHubImpl();
     }
 
+    /**
+     * Adds a number of standard workers:
+     * <ul>
+     * <li>Retain -- allows fields to retain their values between requests</li>
+     * <li>Parameter</li> -- identifies parameters based on the Parameter annotation</li>
+     * <li>UnclaimedField</li> -- identifies unclaimed fields and resets them to null/0/false at
+     * the end of the request</li>
+     * <li>BeforeRender, RenderTag, etc. -- correspond to component render phases and annotations</li>
+     * </ul>
+     * 
+     * @param configuration
+     */
     @Contribute("tapestry.ComponentClassTransformWorker")
     public void contributeInternalWorkers(
             OrderedConfiguration<ComponentClassTransformWorker> configuration)
     {
         configuration.add("Retain", new RetainWorker());
+        configuration.add("Parameter", new ParameterWorker());
         configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*.*");
 
         // Workers for the component rendering state machine methods; this is in typical

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java Thu Aug 31 15:48:58 2006
@@ -17,8 +17,10 @@
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.events.InvalidationEvent;
 import org.apache.tapestry.events.InvalidationListener;
+import org.apache.tapestry.internal.InternalConstants;
 import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
 import org.apache.tapestry.internal.parser.AttributeToken;
 import org.apache.tapestry.internal.parser.ComponentTemplate;
@@ -30,6 +32,7 @@
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.internal.structure.PageElement;
 import org.apache.tapestry.internal.structure.PageImpl;
+import org.apache.tapestry.services.BindingSource;
 
 import static org.apache.tapestry.util.CollectionFactory.newList;
 
@@ -45,15 +48,18 @@
 
     private final PageElementFactory _pageElementFactory;
 
+    private final BindingSource _bindingSource;
+
     private Page _page;
 
     private Locale _locale;
 
     public PageLoaderImpl(ComponentTemplateSource templateSource,
-            PageElementFactory pageElementFactory)
+            PageElementFactory pageElementFactory, BindingSource bindingSource)
     {
         _templateSource = templateSource;
         _pageElementFactory = pageElementFactory;
+        _bindingSource = bindingSource;
     }
 
     /**
@@ -243,7 +249,9 @@
                     AttributeToken attribute = (AttributeToken) token;
 
                     if (directlyInsideSubcomponent)
-                        activeComponent.addParameter(attribute);
+                    {
+                        addBindingToComponent(activeComponent, attribute);
+                    }
                     else
                         add(loadingComponent, activeComponent, _pageElementFactory
                                 .newAttributeElement(attribute));
@@ -255,6 +263,23 @@
 
         }
 
+    }
+
+    private void addBindingToComponent(ComponentPageElement component, AttributeToken token)
+    {
+        String name = token.getName();
+        String description = "parameter " + name;
+
+        // Default binding prefix inside templates is literal.
+
+        Binding binding = _bindingSource.newBinding(
+                description,
+                component,
+                InternalConstants.LITERAL_BINDING_PREFIX,
+                token.getValue(),
+                token.getLocation());
+
+        component.addParameter(name, binding);
     }
 
     private void addRenderBodyElement(ComponentPageElement loadingComponent)

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java?rev=439080&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java Thu Aug 31 15:48:58 2006
@@ -0,0 +1,131 @@
+package org.apache.tapestry.internal.services;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.internal.ioc.IOCUtilities;
+import org.apache.tapestry.internal.util.InternalUtils;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.TransformConstants;
+import org.apache.tapestry.util.BodyBuilder;
+
+/**
+ * Responsible for identifying parameters via the {@link org.apache.tapestry.annotations.Parameter}
+ * annotation on component fields.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class ParameterWorker implements ComponentClassTransformWorker
+{
+
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    {
+        List<String> fieldNames = transformation.findFieldsWithAnnotation(Parameter.class);
+
+        for (String name : fieldNames)
+        {
+            Parameter annotation = transformation.getFieldAnnotation(name, Parameter.class);
+
+            model.addParameter(name, annotation.required());
+
+            String parameterName = getParameterName(name, annotation.name());
+
+            String type = transformation.getFieldType(name);
+
+            String cachedFieldName = transformation.addField(Modifier.PRIVATE, "boolean", name
+                    + "_cached");
+
+            String invariantFieldName = addParameterSetup(
+                    name,
+                    parameterName,
+                    cachedFieldName,
+                    transformation);
+        }
+    }
+
+    /** Returns the name of a field that stores whether the parameter binding is invariant. */
+
+    private String addParameterSetup(String fieldName, String parameterName,
+            String cachedFieldName, ClassTransformation transformation)
+    {
+        String name = transformation
+                .addField(Modifier.PRIVATE, "boolean", fieldName + "_invariant");
+
+        String resourcesFieldName = transformation.getResourcesFieldName();
+
+        String body = String.format(
+                "%s = %s.isInvariant(\"%s\");",
+                name,
+                resourcesFieldName,
+                parameterName);
+
+        transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, body);
+
+        // Now, when the page detaches, ensure that any variant parameters are
+        // are returned to default value.
+
+        BodyBuilder builder = new BodyBuilder();
+        builder.addln("if (! %s)", name);
+        builder.begin();
+
+        // TODO: Handle primitives
+
+        builder.addln("%s = null;", fieldName);
+        builder.addln("%s = false;", cachedFieldName);
+        builder.end();
+
+        transformation.extendMethod(
+                TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
+                builder.toString());
+
+        return name;
+    }
+
+    private void addCachedReader(String fieldName, String cachedFieldName,
+            String invariantFieldName, boolean cache, String parameterName, String fieldType,
+            ClassTransformation transformation)
+    {
+        BodyBuilder builder = new BodyBuilder();
+        builder.begin();
+
+        builder.addln("if (%s) return %s;", cachedFieldName, fieldName);
+
+        // TODO: Handle primitive types
+
+        String resourcesFieldName = transformation.getResourcesFieldName();
+
+        builder.addln(
+                "%s result = (%1$s) %s.getParameter(\"%s\", %1$s.class);",
+                fieldType,
+                resourcesFieldName,
+                parameterName);
+
+        // If the binding is invariant, then it's ok to cache. Othewise, its only
+        // ok to cache if a) the @Parameter says to cache and b) the component
+        // is rendering at the point when field is accessed.
+
+        builder.add("if (%s", invariantFieldName);
+
+        if (cache)
+            builder.add(" || %s.isRendering()", resourcesFieldName);
+
+        builder.addln(")");
+        builder.begin();
+        builder.addln("%s = result;", fieldName);
+        builder.addln("%s = true;", cachedFieldName);
+        builder.end();
+
+        builder.addln("return result;");
+    }
+
+    private String getParameterName(String fieldName, String annotatedName)
+    {
+        if (IOCUtilities.isNonBlank(annotatedName))
+            return annotatedName;
+
+        return InternalUtils.stripMemberPrefix(fieldName);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java Thu Aug 31 15:48:58 2006
@@ -14,8 +14,8 @@
 
 package org.apache.tapestry.internal.structure;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.internal.InternalComponentResources;
-import org.apache.tapestry.internal.parser.AttributeToken;
 import org.apache.tapestry.runtime.RenderCommand;
 import org.apache.tapestry.runtime.RenderQueue;
 
@@ -54,11 +54,9 @@
     void addToBody(PageElement element);
 
     /**
-     * Used during construction of the page to identify a parameter of the component that is bound
-     * via a template attribute. An error is logged if there is a conflict, or if the attribute
-     * doesn't correspond to a parameter of the component.
+     * Used during construction of the page to identify the binding for a particular parameter.
      */
-    void addParameter(AttributeToken attribute);
+    void addParameter(String parameterName, Binding binding);
 
     /** Adds a child component to its container. The child's id must be unique within the container. */
     void addChild(ComponentPageElement child);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java Thu Aug 31 15:48:58 2006
@@ -18,9 +18,9 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
-import org.apache.tapestry.internal.parser.AttributeToken;
 import org.apache.tapestry.internal.services.Instantiator;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.runtime.ComponentLifecycle;
@@ -66,10 +66,7 @@
 
     private Map<String, ComponentPageElement> _children;
 
-    // This is likely to change shortly to something more involved; we need to introduce the concept
-    // of parameters as well as a component model for the component.
-
-    private final Map<String, AttributeToken> _parameters = newMap();
+    private Map<String, Binding> _bindings;
 
     /** Constructor for the root component of a page. */
     public ComponentPageElementImpl(Page page, Instantiator instantiator, ComponentModel model)
@@ -173,11 +170,14 @@
         _template.add(element);
     }
 
-    public void addParameter(AttributeToken attribute)
+    public void addParameter(String parameterName, Binding binding)
     {
         // TODO: Check for conflicts, etc.
 
-        _parameters.put(attribute.getName(), attribute);
+        if (_bindings == null)
+            _bindings = newMap();
+
+        _bindings.put(parameterName, binding);
     }
 
     public void addChild(ComponentPageElement child)
@@ -372,4 +372,33 @@
     {
         return _component;
     }
+
+    private Binding getBinding(String parameterName)
+    {
+        return _bindings == null ? null : _bindings.get(parameterName);
+    }
+
+    public boolean isBound(String parameterName)
+    {
+        return getBinding(parameterName) != null;
+    }
+
+    public boolean isInvariant(String parameterName)
+    {
+        Binding b = getBinding(parameterName);
+
+        return b != null && b.isInvariant();
+    }
+
+    public <T> T readParameter(String parameterName, Class<T> expectedType)
+    {
+        Binding b = getBinding(parameterName);
+
+        // TODO: If binding is null ...
+
+        // TODO: Type coercion when writing value into binding
+
+        return expectedType.cast(b.get());
+    }
+
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java Thu Aug 31 15:48:58 2006
@@ -26,6 +26,12 @@
 public class InternalUtils
 {
     /**
+     * Leading punctiation on member names that is stripped off to form a property name or new
+     * member name.
+     */
+    public static final String NAME_PREFIX = "_$";
+
+    /**
      * Converts a method to a user presentable string consisting of the containing class name, the
      * method name, and the short form of the parameter list (the class name of each parameter type,
      * shorn of the package name portion).
@@ -63,4 +69,38 @@
     {
         return array == null ? 0 : array.length;
     }
+
+    /** Strips leading punctuation ("_" and "$") from the provided name. */
+    public static String stripMemberPrefix(String memberName)
+    {
+        StringBuilder builder = new StringBuilder(memberName);
+
+        // There may be other prefixes we want to strip off, at some point!
+
+        // Strip off leading characters defined by NAME_PREFIX
+
+        // This code is really ugly and needs to be fixed.
+        
+        while (true)
+        {
+            char ch = builder.charAt(0);
+
+            if (InternalUtils.NAME_PREFIX.indexOf(ch) < 0)
+                break;
+
+            builder.deleteCharAt(0);
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Strips leading characters defined by {@link InternalUtils#NAME_PREFIX}, then adds the prefix
+     * back in.
+     */
+    public static String createMemberName(String memberName)
+    {
+        return NAME_PREFIX + stripMemberPrefix(memberName);
+    }
+
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java Thu Aug 31 15:48:58 2006
@@ -34,7 +34,7 @@
 
 /**
  * Used to construct the IoC {@link org.apache.tapestry.ioc.Registry}. This class is <em>not</em>
- * threadsafe. The registry, once created, <em>is</em> threadsafe.
+ * threadsafe. The Registry, once created, <em>is</em> threadsafe.
  * 
  * @author Howard M. Lewis Ship
  */
@@ -120,7 +120,7 @@
     @OneShot.Lockdown
     public Registry build()
     {
-        return new RegistryImpl(_modules.values(), _logSource);
+        return new RegistryImpl(_modules.values(), _classLoader, _logSource);
     }
 
     public ClassLoader getClassLoader()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFactory.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFactory.java Thu Aug 31 15:48:58 2006
@@ -51,4 +51,10 @@
      */
 
     int getCreatedClassCount();
+
+    /**
+     * Returns the class loader used when creating new classes; this is generally the same as the
+     * current thread's context class loader (except perhaps during testing).
+     */
+    ClassLoader getClassLoader();
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java Thu Aug 31 15:48:58 2006
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry.model;
 
+import java.util.List;
+
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.Resource;
 
@@ -40,4 +42,14 @@
 
     /** Returns object that will be used to log warnings and errors related to this component. */
     Log getLog();
+
+    /**
+     * Returns an alphabetically sorted list of the names of all formal parameters. This includes
+     * parameters defined by a base class.
+     */
+
+    List<String> getParameterNames();
+
+    /** Return a single parameter model by parameter name, or null if the parameter is not defined. */
+    ParameterModel getParameterModel(String parameterName);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java Thu Aug 31 15:48:58 2006
@@ -22,5 +22,15 @@
  */
 public interface MutableComponentModel extends ComponentModel
 {
-
+    /**
+     * Adds a new parameter to the model.
+     * 
+     * @param name
+     *            new, unique name for the parameter
+     * @param required
+     *            if true, the parameter must be bound
+     * @throws IllegalArgumentException
+     *             if a parameter with the given name has already been defined for this model
+     */
+    void addParameter(String name, boolean required);
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java?rev=439080&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java Thu Aug 31 15:48:58 2006
@@ -0,0 +1,15 @@
+package org.apache.tapestry.model;
+
+/**
+ * Model for a parameter of a component.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface ParameterModel
+{
+    /** The name of the parameter. */
+    String getName();
+
+    /** If true, the parameter is required. */
+    boolean isRequired();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java Thu Aug 31 15:48:58 2006
@@ -21,7 +21,6 @@
  * the component for many different events. This interface is part of the public API for Tapestry,
  * but is <em>not</em> expected to be directly implemented by component classes; it should only be
  * implemented as part of the component class transformation process.
- * 
  * <p>
  * This interface is likely to change without notice.
  * 
@@ -30,7 +29,8 @@
 public interface ComponentLifecycle extends ResourceAware
 {
     /**
-     * Invoked when the page finishes loading (including the loading of all components).
+     * Invoked when the page finishes loading. This occurs once all components are loaded and all
+     * parameters have been set.
      */
     void containingPageDidLoad();
 
@@ -39,6 +39,14 @@
      * client specific state.
      */
     void containingPageDidDetach();
+
+    /**
+     * Lifecycle method invoked at the end of the
+     * {@link org.apache.tapestry.annotations.AfterRender} render phase. There is no annotation for
+     * this method, it is part of AfterRender, but is always invoked. It's specific use to to allow
+     * components to clean up cached parameter values.
+     */
+    void cleanupAfterRender();
 
     /**
      * Invoked before rendering a component (or its template).

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java Thu Aug 31 15:48:58 2006
@@ -56,6 +56,7 @@
 
     /**
      * Generates a list of the names of declared instance fields that have the indicated annotation.
+     * Only the names of private instance fields are returned.
      */
     List<String> findFieldsWithAnnotation(Class<? extends Annotation> annotationClass);
 
@@ -184,8 +185,19 @@
      * @param methodBody
      *            the body of code
      * @throws IllegalArgumentException
-     *             if the method body does not include a call to $proceed, or if the provided
-     *             Javassist method body can not be compiled
+     *             if the provided Javassist method body can not be compiled
      */
     void extendMethod(MethodSignature methodSignature, String methodBody);
+
+    /**
+     * Returns the name of a field that provides the {@link org.apache.tapestry.ComponentResources}
+     * for the transformed component. This will be a protected field, accessible to the class and
+     * subclasses.
+     * 
+     * @return name of field
+     */
+    String getResourcesFieldName();
+
+    /** Adds a new method to the transformed class. */
+    void addMethod(MethodSignature signature, String methodBody);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java Thu Aug 31 15:48:58 2006
@@ -38,6 +38,10 @@
     public static final MethodSignature CONTAINING_PAGE_DID_LOAD_SIGNATURE = new MethodSignature(
             "containingPageDidLoad");
 
+    /** Signature for {@link org.apache.tapestry.runtime.ComponentLifecycle#cleanupAfterRender()}. */
+    public static final MethodSignature CLEANUP_AFTER_RENDER_SIGNATURE = new MethodSignature(
+            "cleanupAfterRender");
+
     /**
      * Signature for
      * {@link org.apache.tapestry.runtime.ComponentLifecycle#containingPageDidDetach()}.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml Thu Aug 31 15:48:58 2006
@@ -33,6 +33,7 @@
       <package name="org.apache.tapestry.util"/>
       <package name="org.apache.tapestry.runtime"/>
       <package name="org.apache.tapestry.internal.bindings"/>
+      <package name="org.apache.tapestry.internal.model"/>
     </packages>
   </test>
 </suite>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java Thu Aug 31 15:48:58 2006
@@ -59,7 +59,7 @@
     {
         ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
 
-        ClassFactoryClassPool pool = new ClassFactoryClassPool();
+        ClassFactoryClassPool pool = new ClassFactoryClassPool(threadLoader);
 
         pool.appendClassLoader(threadLoader);
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java?rev=439080&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java Thu Aug 31 15:48:58 2006
@@ -0,0 +1,72 @@
+package org.apache.tapestry.internal.model;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.Resource;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.model.ParameterModel;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class MutableComponentModelImplTest extends InternalBaseTestCase
+{
+    private static final String CLASS_NAME = "org.example.components.Foo";
+
+    @Test
+    public void add_new_parameter()
+    {
+        Resource r = newResource();
+        Log log = newLog();
+
+        replay();
+
+        MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r);
+
+        assertTrue(model.getParameterNames().isEmpty());
+
+        String parameterName = "value";
+
+        model.addParameter(parameterName, true);
+
+        ParameterModel pm = model.getParameterModel(parameterName);
+
+        assertEquals(pm.getName(), parameterName);
+        assertEquals(true, pm.isRequired());
+
+        verify();
+    }
+
+    @Test
+    public void get_parameter_by_name_with_no_parameters_defined()
+    {
+        Resource r = newResource();
+        Log log = newLog();
+
+        replay();
+
+        MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r);
+
+        assertNull(model.getParameterModel("foo"));
+
+        verify();
+    }
+
+    @Test
+    public void get_unknown_parameter()
+    {
+
+        Resource r = newResource();
+        Log log = newLog();
+
+        replay();
+
+        MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r);
+        model.addParameter("fred", true);
+
+        assertNull(model.getParameterModel("barney"));
+
+        verify();
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java Thu Aug 31 15:48:58 2006
@@ -30,7 +30,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.internal.InternalComponentResources;
-import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.internal.transform.pages.BasicComponent;
 import org.apache.tapestry.internal.transform.pages.BasicSubComponent;
 import org.apache.tapestry.ioc.Registry;
@@ -38,8 +38,6 @@
 import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.runtime.ComponentLifecycle;
 import org.apache.tapestry.services.TapestryModule;
-import org.apache.tapestry.test.BaseTestCase;
-import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -51,8 +49,11 @@
  * 
  * @author Howard M. Lewis Ship
  */
-public class ComponentInstantiatorSourceImplTest extends BaseTestCase
+public class ComponentInstantiatorSourceImplTest extends InternalBaseTestCase
 {
+    private static final ClassLoader _contextLoader = Thread.currentThread()
+            .getContextClassLoader();
+
     private static final String SYNTH_COMPONENT_CLASSNAME = "org.apache.tapestry.internal.transform.pages.SynthComponent";
 
     private File _extraClasspath;
@@ -61,10 +62,9 @@
 
     private Registry _registry;
 
-    private final ClassLoader _originalContextClassLoader = Thread.currentThread()
-            .getContextClassLoader();
+    private PropertyAccess _access;
 
-    private final PropertyAccess _access = new PropertyAccessImpl();
+    private ClassLoader _extraLoader;
 
     @Test
     public void controlled_packages() throws Exception
@@ -74,7 +74,8 @@
 
         replay();
 
-        ComponentInstantiatorSourceImpl e = new ComponentInstantiatorSourceImpl(transformer, log);
+        ComponentInstantiatorSourceImpl e = new ComponentInstantiatorSourceImpl(_contextLoader,
+                transformer, log);
 
         assertEquals(e.inControlledPackage("foo.bar.Baz"), false);
 
@@ -106,7 +107,7 @@
         ComponentLifecycle target = createComponent(BasicComponent.class);
 
         // Should not be an instance, since it is loaded by a different class loader.
-        Assert.assertFalse(BasicComponent.class.isInstance(target));
+        assertFalse(BasicComponent.class.isInstance(target));
 
         _access.set(target, "value", "some default value");
         assertEquals(_access.get(target, "value"), "some default value");
@@ -159,7 +160,8 @@
         assertEquals(named.getName(), "Original");
 
         // Sometimes this code runs so fast that the updated file has the same timestamp as
-        // the original; this little blip seems to help.
+        // the original; this little blip seems to help. Fortunately, we now run tests in
+        // parallel.
 
         Thread.sleep(250);
 
@@ -186,7 +188,7 @@
         ClassPool pool = new ClassPool();
         // Inside Maven Surefire, the system classpath is not sufficient to find all
         // the necessary files.
-        pool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
+        pool.appendClassPath(new LoaderClassPath(_extraLoader));
 
         CtClass ctClass = pool.makeClass(SYNTH_COMPONENT_CLASSNAME);
 
@@ -243,18 +245,16 @@
 
         URL url = _extraClasspath.toURL();
 
-        ClassLoader extraLoader = new URLClassLoader(new URL[]
-        { url }, _originalContextClassLoader);
-
-        Thread.currentThread().setContextClassLoader(extraLoader);
-
-        RegistryBuilder builder = new RegistryBuilder();
+        _extraLoader = new URLClassLoader(new URL[]
+        { url }, _contextLoader);
+        RegistryBuilder builder = new RegistryBuilder(_extraLoader);
 
         builder.add(TapestryModule.class, InternalModule.class);
 
         _registry = builder.build();
 
         _source = _registry.getService(ComponentInstantiatorSource.class);
+        _access = _registry.getService(PropertyAccess.class);
 
         _source.addPackage("org.apache.tapestry.internal.transform.pages");
     }
@@ -262,16 +262,10 @@
     @AfterClass
     public void shutdownRegistry()
     {
-        // _registry.shutdown();
+        _registry.shutdown();
 
         _registry = null;
         _source = null;
-
-        Thread.currentThread().setContextClassLoader(_originalContextClassLoader);
-    }
-
-    protected final InternalComponentResources newInternalComponentResources()
-    {
-        return newMock(InternalComponentResources.class);
+        _access = null;
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java?rev=439080&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java Thu Aug 31 15:48:58 2006
@@ -0,0 +1,107 @@
+package org.apache.tapestry.internal.structure;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.internal.InternalComponentResources;
+import org.apache.tapestry.internal.services.Instantiator;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.model.ComponentModel;
+import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.easymock.EasyMock;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ComponentPageElementImplTest extends InternalBaseTestCase
+{
+    @Test
+    public void is_bound()
+    {
+        Page page = newPage();
+        ComponentLifecycle component = newComponentLifecycle();
+        Instantiator ins = newInstantiator(component);
+        ComponentModel model = newComponentModel();
+
+        Binding binding = newBinding();
+
+        replay();
+
+        ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, model);
+
+        assertFalse(cpe.isBound("fred"));
+
+        cpe.addParameter("barney", binding);
+
+        assertFalse(cpe.isBound("fred"));
+        assertTrue(cpe.isBound("barney"));
+
+        verify();
+    }
+
+    @Test
+    public void is_invariant()
+    {
+        Page page = newPage();
+        ComponentLifecycle component = newComponentLifecycle();
+        Instantiator ins = newInstantiator(component);
+        ComponentModel model = newComponentModel();
+
+        Binding binding = newBinding();
+
+        binding.isInvariant();
+        setReturnValue(true);
+
+        replay();
+
+        ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, model);
+
+        assertFalse(cpe.isInvariant("fred"));
+
+        cpe.addParameter("barney", binding);
+
+        assertFalse(cpe.isInvariant("fred"));
+        assertTrue(cpe.isInvariant("barney"));
+
+        verify();
+    }
+
+    @Test
+    public void read_binding()
+    {
+        Page page = newPage();
+        ComponentLifecycle component = newComponentLifecycle();
+        Instantiator ins = newInstantiator(component);
+        ComponentModel model = newComponentModel();
+
+        Binding binding = newBinding();
+
+        binding.get();
+        setReturnValue(new Long(23));
+
+        replay();
+
+        ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, model);
+
+        cpe.addParameter("barney", binding);
+
+        assertEquals(cpe.readParameter("barney", Long.class), new Long(23));
+
+        verify();
+    }
+
+    protected final ComponentModel newComponentModel()
+    {
+        return newMock(ComponentModel.class);
+    }
+
+    private Instantiator newInstantiator(ComponentLifecycle component)
+    {
+        Instantiator ins = newMock(Instantiator.class);
+        ins.newInstance(EasyMock.isA(InternalComponentResources.class));
+
+        setReturnValue(component);
+
+        return ins;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/ParentClass.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/ParentClass.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/ParentClass.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/ParentClass.java Thu Aug 31 15:48:58 2006
@@ -33,8 +33,14 @@
     public String _$conflictField;
 
     @Retain
-    public boolean _annotatedField;
+    private boolean _annotatedField;
 
+    @Retain
+    public String _public_field_annotation_ignored;
+    
+    @Retain
+    private static String _static_field_annotation_ignored;
+    
     public void doNothingParentMethod()
     {
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java?rev=439080&r1=439079&r2=439080&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java Thu Aug 31 15:48:58 2006
@@ -22,6 +22,7 @@
 import java.util.Comparator;
 import java.util.List;
 
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 /**
@@ -84,4 +85,22 @@
 
         assertEquals(InternalUtils.size(array), 3);
     }
+
+    @Test(dataProvider = "memberPrefixData")
+    public void strip_member_prefix(String input, String expected)
+    {
+        assertEquals(InternalUtils.stripMemberPrefix(input), expected);
+    }
+
+    @DataProvider(name = "memberPrefixData")
+    public Object[][] memberPrefixData()
+    {
+        return new Object[][]
+        {
+        { "simple", "simple" },
+        { "_name", "name" },
+        { "$name", "name" },
+        { "$_$__$__$_$___$_$_$_$$name$", "name$" } };
+    }
+
 }