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 2007/02/06 20:54:41 UTC

svn commit: r504259 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/bindings/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/services/ m...

Author: hlship
Date: Tue Feb  6 11:54:40 2007
New Revision: 504259

URL: http://svn.apache.org/viewvc?view=rev&rev=504259
Log:
Add annotations for the page load, page attach and page detach events.
Add a worker to connect the events to component methods.
Use the TypeCoercer to convert context values in URLs to strings for inclusion in the path portion of the URL.
Allow final fields to be treated as if they were @Retain.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageAttached.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageDetached.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageLoaded.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLifecycleAnnotationWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/lifecycle.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/PageLoadedDemo.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/PageLoadedDemo.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/CheckFieldType.java
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingAnnotationProvider.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.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/LinkFactoryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UnclaimedFieldWorker.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/TapestryModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInvocationTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageAttached.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageAttached.java?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageAttached.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageAttached.java Tue Feb  6 11:54:40 2007
@@ -0,0 +1,39 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Method annotation used for methods that should be invoked when the page is first attached to a
+ * request. This is useful for initializations that should occur on each request that involves the
+ * page. Often, such initializations will be balanced by cleanups when the page is detached.
+ * <p>
+ * PageAttached methods should take no parameters and return void. They must either have this
+ * annotation, or be named "pageAttached".
+ * 
+ * @see PageDetached
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface PageAttached {
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageDetached.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageDetached.java?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageDetached.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageDetached.java Tue Feb  6 11:54:40 2007
@@ -0,0 +1,38 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Method annotation used for methods that should be invoked when the page is detached at the end of
+ * a request, before it is returned to the page pool for later reuse.
+ * <p>
+ * PageDetached methods should take no parameters and return void. They must either have this
+ * annotation, or be named "pageDetached".
+ * 
+ * @see PageAttached
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface PageDetached {
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageLoaded.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageLoaded.java?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageLoaded.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/PageLoaded.java Tue Feb  6 11:54:40 2007
@@ -0,0 +1,37 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Method annotation used for methods that should be invoked once the page is fully loaded. This is
+ * useful for one-time component initializations that can't be done at instantance initialzation
+ * time, such as refrerences to embedded components or blocks.
+ * <p>
+ * PageLoaded methods should take no parameters and return void. They must either have this
+ * annotation, or be named "pageLoaded".
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface PageLoaded {
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java Tue Feb  6 11:54:40 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -31,13 +31,13 @@
  */
 public class ComponentInvocation
 {
-    private final Object[] _context;
+    private final String[] _context;
 
     private Map<String, String> _parameters;
 
     private InvocationTarget _target;
 
-    public ComponentInvocation(InvocationTarget target, Object[] context)
+    public ComponentInvocation(InvocationTarget target, String[] context)
     {
         _target = target;
         _context = context;
@@ -102,12 +102,12 @@
 
             // TODO: Need to encode this for URLs? What if the string contains slashes, etc.?
 
-            builder.append(id.toString());
+            builder.append(id);
         }
         return builder.toString();
     }
 
-    public Object[] getContext()
+    public String[] getContext()
     {
         return _context;
     }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java Tue Feb  6 11:54:40 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.

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?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- 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 Tue Feb  6 11:54:40 2007
@@ -970,6 +970,20 @@
         return type.getName();
     }
 
+    public int getFieldModifiers(String fieldName)
+    {
+        failIfFrozen();
+
+        try
+        {
+            return _ctClass.getDeclaredField(fieldName).getModifiers();
+        }
+        catch (NotFoundException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+    }
+
     private CtClass getFieldCtType(String fieldName)
     {
         try

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?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- 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 Tue Feb  6 11:54:40 2007
@@ -517,12 +517,19 @@
 
     /** Service used to create links for components and pages. */
     public LinkFactory buildLinkFactory(@InjectService("ContextPathSource")
-    ContextPathSource contextPathSource, @InjectService("URLEncoder")
-    URLEncoder encoder, @InjectService("ComponentInvocationMap")
-    ComponentInvocationMap componentInvocationMap)
+    ContextPathSource contextPathSource,
+
+    @InjectService("URLEncoder")
+    URLEncoder encoder,
+
+    @InjectService("ComponentInvocationMap")
+    ComponentInvocationMap componentInvocationMap,
+
+    @Inject("infrastructure:TypeCoercer")
+    TypeCoercer typeCoercer)
     {
         return new LinkFactoryImpl(contextPathSource, encoder, _componentClassResolver,
-                componentInvocationMap, _pageCache);
+                componentInvocationMap, _pageCache, typeCoercer);
     }
 
     public ContextPathSource buildContextPathSource()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java Tue Feb  6 11:54:40 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -28,6 +28,7 @@
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.ioc.internal.util.Defense;
+import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.ioc.util.StrategyRegistry;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.services.ComponentClassResolver;
@@ -44,6 +45,8 @@
 
     private final RequestPageCache _pageCache;
 
+    private final TypeCoercer _typeCoercer;
+
     private final List<LinkFactoryListener> _listeners = newThreadSafeList();
 
     private final StrategyRegistry<PassivateContextHandler> _registry;
@@ -55,13 +58,15 @@
 
     public LinkFactoryImpl(ContextPathSource contextPathSource, URLEncoder encoder,
             ComponentClassResolver componentClassResolver,
-            ComponentInvocationMap componentInvocationMap, RequestPageCache pageCache)
+            ComponentInvocationMap componentInvocationMap, RequestPageCache pageCache,
+            TypeCoercer typeCoercer)
     {
         _contextPathSource = contextPathSource;
         _encoder = encoder;
         _componentClassResolver = componentClassResolver;
         _componentInvocationMap = componentInvocationMap;
         _pageCache = pageCache;
+        _typeCoercer = typeCoercer;
 
         Map<Class, PassivateContextHandler> registrations = newMap();
 
@@ -113,7 +118,10 @@
 
         ActionLinkTarget target = new ActionLinkTarget(action, logicalPageName, component
                 .getNestedId());
-        ComponentInvocation invocation = new ComponentInvocation(target, context);
+
+        String[] contextStrings = toContextStrings(context);
+
+        ComponentInvocation invocation = new ComponentInvocation(target, contextStrings);
 
         Link link = new LinkImpl(_encoder, _contextPathSource.getContextPath(), invocation, forForm);
 
@@ -154,7 +162,8 @@
         rootElement.triggerEvent(TapestryConstants.PASSIVATE_EVENT, null, handler);
 
         PageLinkTarget target = new PageLinkTarget(logicalPageName);
-        ComponentInvocation invocation = new ComponentInvocation(target, context.toArray());
+        ComponentInvocation invocation = new ComponentInvocation(target, toContextStrings(context
+                .toArray()));
 
         Link link = new LinkImpl(_encoder, _contextPathSource.getContextPath(), invocation, false);
 
@@ -166,6 +175,19 @@
         // TODO: query parameter for case where active page != component page.
 
         return link;
+    }
+
+    private String[] toContextStrings(Object[] context)
+    {
+        if (context == null)
+            return new String[0];
+
+        String[] result = new String[context.length];
+
+        for (int i = 0; i < context.length; i++)
+            result[i] = _typeCoercer.coerce(context[i], String.class);
+
+        return result;
     }
 
     public Link createPageLink(String pageName)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java Tue Feb  6 11:54:40 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -39,7 +39,7 @@
     public LinkImpl(URLEncoder encoder, String contextPath, String targetPath, boolean forForm)
     {
         this(encoder, contextPath, new ComponentInvocation(new OpaqueConstantTarget(targetPath),
-                new Object[0]), forForm);
+                new String[0]), forForm);
     }
 
     public LinkImpl(URLEncoder encoder, String contextPath, ComponentInvocation invocation,

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLifecycleAnnotationWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLifecycleAnnotationWorker.java?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLifecycleAnnotationWorker.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLifecycleAnnotationWorker.java Tue Feb  6 11:54:40 2007
@@ -0,0 +1,77 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.tapestry.internal.util.MethodInvocationBuilder;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.MethodFilter;
+import org.apache.tapestry.services.MethodSignature;
+
+/**
+ * Similar to {@link ComponentLifecycleMethodWorker} but applies to annotations/methods related to
+ * the overall page lifecycle.
+ */
+public class PageLifecycleAnnotationWorker implements ComponentClassTransformWorker
+{
+    private final Class<? extends Annotation> _methodAnnotationClass;
+
+    private final MethodSignature _lifecycleMethodSignature;
+
+    private final String _methodAlias;
+
+    private final MethodInvocationBuilder _invocationBuilder = new MethodInvocationBuilder();
+
+    public PageLifecycleAnnotationWorker(final Class<? extends Annotation> methodAnnotationClass,
+            final MethodSignature lifecycleMethodSignature, final String methodAlias)
+    {
+        _methodAnnotationClass = methodAnnotationClass;
+        _lifecycleMethodSignature = lifecycleMethodSignature;
+        _methodAlias = methodAlias;
+    }
+
+    public void transform(final ClassTransformation transformation, MutableComponentModel model)
+    {
+        MethodFilter filter = new MethodFilter()
+        {
+            public boolean accept(MethodSignature signature)
+            {
+                if (signature.getMethodName().equals(_methodAlias))
+                    return true;
+
+                return transformation.getMethodAnnotation(signature, _methodAnnotationClass) != null;
+            }
+        };
+
+        // Did this they easy way, because I doubt there will be more than one signature.
+        // If I expected lots of signatures, I'd build up a BodyBuilder in the loop and extend the
+        // method outside the loop.
+
+        for (MethodSignature signature : transformation.findMethods(filter))
+        {
+            // TODO: Filter out the non-void methods (with a non-fatal warning/error?) For the
+            // moment, we just invoke the method anyway, and ignore the result. Also, MethodInvocationBuilder
+            // is very forgiving (and silent) about unexpected parameters (passing null/0/false).
+
+            String body = _invocationBuilder.buildMethodInvocation(signature, transformation);
+
+            transformation.extendMethod(_lifecycleMethodSignature, body + ";");
+        }
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java Tue Feb  6 11:54:40 2007
@@ -21,7 +21,7 @@
  */
 public interface PageLinkHandler
 {
-    void handle(String logicalPageName, Object[] context, PageRenderer renderer);
+    void handle(String logicalPageName, String[] context, PageRenderer renderer);
 
     void handle(ComponentInvocation invocation, PageRenderer renderer);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java Tue Feb  6 11:54:40 2007
@@ -31,7 +31,7 @@
         _cache = cache;
     }
 
-    public void handle(String logicalPageName, Object[] context, PageRenderer renderer)
+    public void handle(String logicalPageName, String[] context, PageRenderer renderer)
     {
         PageLinkTarget target = new PageLinkTarget(logicalPageName);
         ComponentInvocation invocation = new ComponentInvocation(target, context);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java Tue Feb  6 11:54:40 2007
@@ -66,7 +66,7 @@
             {
                 // TODO: UUDecode the strings in the context?
 
-                Object[] context = atEnd ? new Object[0] : path.substring(nextslashx + 1)
+                String[] context = atEnd ? new String[0] : path.substring(nextslashx + 1)
                         .split("/");
 
                 PageRenderer renderer = new PageRenderer()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UnclaimedFieldWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UnclaimedFieldWorker.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UnclaimedFieldWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UnclaimedFieldWorker.java Tue Feb  6 11:54:40 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -26,7 +26,9 @@
 
 /**
  * Designed to be just about the last worker in the pipeline. Its job is to add cleanup code that
- * restores transient fields back to their initial (null) value.
+ * restores transient fields back to their initial (null) value. Fields that have been previously
+ * {@link ClassTransformation#claimField(String, Object) claimed} are ignored, as are fields that
+ * are final.
  */
 public final class UnclaimedFieldWorker implements ComponentClassTransformWorker
 {
@@ -43,6 +45,11 @@
 
     private void transformField(String fieldName, ClassTransformation transformation)
     {
+        int modifiers = transformation.getFieldModifiers(fieldName);
+
+        if (Modifier.isFinal(modifiers))
+            return;
+
         String type = transformation.getFieldType(fieldName);
 
         String defaultFieldName = transformation.addField(Modifier.PRIVATE, type, fieldName

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?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- 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 Tue Feb  6 11:54:40 2007
@@ -58,7 +58,8 @@
     String newMemberName(String suggested);
 
     /**
-     * Generates a list of the names of declared instance fields that have the indicated annotation.
+     * Generates a list of the names of declared instance fields that have the indicated annotation. Non-private and static
+     * fields are ignored.
      * Only the names of private instance fields are returned. Any
      * {@link #claimField(String, Object) claimed} fields are excluded.
      */
@@ -89,7 +90,8 @@
     List<MethodSignature> findMethods(MethodFilter filter);
 
     /**
-     * Finds all unclaimed fields matched by the provided filter.
+     * Finds all unclaimed fields matched by the provided filter.  Only considers
+     * unclaimed, private, instance fields.
      * 
      * @param filter
      *            passed each field name and field type
@@ -311,4 +313,7 @@
      * concerning the class being transformed may be logged.
      */
     Log getLog();
+
+    /** Returns the modifiers for the named field. */
+    int getFieldModifiers(String fieldName);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Tue Feb  6 11:54:40 2007
@@ -39,6 +39,9 @@
 import org.apache.tapestry.annotations.BeginRender;
 import org.apache.tapestry.annotations.CleanupRender;
 import org.apache.tapestry.annotations.InjectPage;
+import org.apache.tapestry.annotations.PageAttached;
+import org.apache.tapestry.annotations.PageDetached;
+import org.apache.tapestry.annotations.PageLoaded;
 import org.apache.tapestry.annotations.SetupRender;
 import org.apache.tapestry.beaneditor.Validate;
 import org.apache.tapestry.dom.DefaultMarkupModel;
@@ -106,6 +109,7 @@
 import org.apache.tapestry.internal.services.MixinWorker;
 import org.apache.tapestry.internal.services.ObjectComponentEventResultProcessor;
 import org.apache.tapestry.internal.services.OnEventWorker;
+import org.apache.tapestry.internal.services.PageLifecycleAnnotationWorker;
 import org.apache.tapestry.internal.services.PageLinkHandler;
 import org.apache.tapestry.internal.services.PageLinkHandlerImpl;
 import org.apache.tapestry.internal.services.PageRenderDispatcher;
@@ -715,14 +719,31 @@
      */
     public static void contributeComponentClassTransformWorker(
             OrderedConfiguration<ComponentClassTransformWorker> configuration,
-            ServiceLocator locator, @InjectService("tapestry.ioc.MasterObjectProvider")
-            ObjectProvider objectProvider, @InjectService("InjectionProvider")
-            InjectionProvider injectionProvider, @InjectService("Environment")
-            Environment environment, @InjectService("tapestry.ComponentClassResolver")
-            ComponentClassResolver resolver, @InjectService("tapestry.internal.RequestPageCache")
-            RequestPageCache requestPageCache, @Inject("infrastructure:AssetSource")
-            AssetSource assetSource, @Inject("infrastructure:BindingSource")
-            BindingSource bindingsource, @Inject("infrastructure:ApplicationStateManager")
+
+            ServiceLocator locator,
+
+            @InjectService("tapestry.ioc.MasterObjectProvider")
+            ObjectProvider objectProvider,
+
+            @InjectService("InjectionProvider")
+            InjectionProvider injectionProvider,
+
+            @Inject("infrastructure:Environment")
+            Environment environment,
+
+            @Inject("infrastructure:ComponentClassResolver")
+            ComponentClassResolver resolver,
+
+            @InjectService("tapestry.internal.RequestPageCache")
+            RequestPageCache requestPageCache,
+
+            @Inject("infrastructure:AssetSource")
+            AssetSource assetSource,
+
+            @Inject("infrastructure:BindingSource")
+            BindingSource bindingsource,
+
+            @Inject("infrastructure:ApplicationStateManager")
             ApplicationStateManager applicationStateManager)
     {
         // TODO: Proper scheduling of all of this. Since a given field or method should
@@ -785,6 +806,25 @@
         add(configuration, TransformConstants.AFTER_RENDER_SIGNATURE, AfterRender.class, true);
         add(configuration, TransformConstants.CLEANUP_RENDER_SIGNATURE, CleanupRender.class, true);
 
+        // Ideally, these should be ordered pretty late in the process to make sure there are no side effects
+        // with other workers that do work inside the page lifecycle methods.
+        
+        add(
+                configuration,
+                PageLoaded.class,
+                TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
+                "pageLoaded");
+        add(
+                configuration,
+                PageAttached.class,
+                TransformConstants.CONTAINING_PAGE_DID_ATTACH_SIGNATURE,
+                "pageAttached");
+        add(
+                configuration,
+                PageDetached.class,
+                TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
+                "pageDetached");
+
         configuration.add("Retain", new RetainWorker());
         configuration.add("Persist", new PersistWorker());
         configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*.*");
@@ -799,6 +839,18 @@
 
         configuration.add(name, new ComponentLifecycleMethodWorker(signature, annotationClass,
                 reverse));
+    }
+
+    private static void add(OrderedConfiguration<ComponentClassTransformWorker> configuration,
+            Class<? extends Annotation> annotationClass, MethodSignature lifecycleMethodSignature,
+            String methodAlias)
+    {
+        ComponentClassTransformWorker worker = new PageLifecycleAnnotationWorker(annotationClass,
+                lifecycleMethodSignature, methodAlias);
+
+        String name = IOCUtilities.toSimpleId(annotationClass.getName());
+
+        configuration.add(name, worker);
     }
 
     @Lifecycle("perthread")

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java Tue Feb  6 11:54:40 2007
@@ -181,7 +181,7 @@
      */
     public Document renderPage(String pageName)
     {
-        return invoke(new ComponentInvocation(new PageLinkTarget(pageName), new Object[0]));
+        return invoke(new ComponentInvocation(new PageLinkTarget(pageName), new String[0]));
     }
 
     /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt Tue Feb  6 11:54:40 2007
@@ -128,18 +128,26 @@
   
   Be aware that you will need to provide getter and setter methods to access your classes'
   instance variables. Tapestry <does not> do this automatically.
-  
-  
+    
   
 Transient Instance Variables
 
   Unless an instance variable is decorated with an annotation, it will be a
   <transient> instance variable. This means that its value resets to its
   default value
-  at the end of reach request.
+  at the end of reach request (when the
+  {{{lifecycle.html}page is detached from the request}}.
+  
+  If you have a variable that can keep its value between requests and you would like
+  to defeat that reset logic, then you should attach a
+  {{{../apidocs/org/apache/tapestry/annotations/Retain.html}Retain}} annotation to the field.  You should take
+  care that no client-specific data is stored into such a field, since on a later request
+  the same page <instance> may be used for a different user. Likewise, on a later request for the <same> user,
+  a <different> page instance may be used.
   
+  Use {{{persist.html}persistent fields} to hold information form one request to the next.
   
-  <<TODO: Setting an initial value with @OnPageLoad>>
+  Further, final fields are (in fact) final, and will not be reset.
   
 Constructors
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/lifecycle.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/lifecycle.apt?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/lifecycle.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/lifecycle.apt Tue Feb  6 11:54:40 2007
@@ -0,0 +1,37 @@
+ ----
+ Page Lifecycle Methods
+ ----
+ 
+Page Lifecycle Methods
+
+  There are a few situations where it is useful for a component to perform some operations, usually some kind of initialization or
+  caching, based on the lifecycle of the page.
+  
+  The page lifecycle is quite simple.  When first needed, a page is loaded.  Loading a page involves instantitating the components of the page
+  and connecting them together.
+  
+  Once a page is loaded, it is <attached> to the current request.  Remember that there will be many threads, each handling its own request.
+  In many cases, there will be multiple copies of the same page attached to different requests (and different threads). This is how Tapestry keeps you
+  from worrying about multi-threading issues ... the objects involved in any request are reserved to <just> that request (and <just> that thread).
+  
+  At the end of a request, after a response has been sent to the client, the page is <detached> from the request.  This is a chance to perform
+  a lot of cleanup of the page, discarding temporary objects (so that they can be reclaimed by the garbage collector) and otherwise returning the
+  page to its pristine state.  After detaching, a page is placed into the page pool, where it will await reuse for some future request (likely by a completely
+  different user).
+  
+  As with {{{rendering.html}component rendering}}, you have the ability to make your components "aware" of these events by identifying methods to be invoked.
+  
+  You have the choice of attaching an annotation to a method, or simply naming the method correctly.  
+  
+  Page lifecycle methods should take no parameters and return void.
+  
+  The annotations / method names are:
+  
+   * {{{../apidocs/org/apache/tapestry/annotations/PageLoaded.html}PageLoaded}} annotation, or method name "pageLoaded"
+   
+   * {{{../apidocs/org/apache/tapestry/annotations/PageAttached.html}PageAttached}} annotation, or method name "pageAttached"
+   
+   * {{{../apidocs/org/apache/tapestry/annotations/PageDetached.html}PageDetached}} annotation, or method name "pageDetached"
+   
+   
+   
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml Tue Feb  6 11:54:40 2007
@@ -40,11 +40,16 @@
             <item name="Apache" href="http://www.apache.org/" />
         </links>
 
-        <head>
+
+<!--
+
+This is probably useful but it drives me crazy whenever I reload a page.
+
+         <head>
             <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
             <script type="text/javascript">_uacct = "UA-400821-1"; urchinTracker();</script>
         </head>
-
+ -->
         <menu name="Tapestry Core">
             <item name="Introduction" href="/index.html"/>
             <item name="Upgrade from Tapestry 4" href="/upgrade.html"/>
@@ -56,7 +61,8 @@
             <item name="Component Templates" href="guide/templates.html"/>
             <item name="Component Parameters" href="guide/parameters.html"/>
             <item name="Input Validation" href="guide/validation.html"/>
-            <item name="Component Events" href="guide/event.html"/>
+            <item name="Component Events" href="guide/event.html"/>
+            <item name="Page Lifecycle" href="guide/lifecycle.html"/>
             <item name="Component Mixins" href="guide/mixins.html"/>
             <item name="Localization" href="guide/localization.html"/>
             <item name="Assets" href="guide/assets.html"/>

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/PageLoadedDemo.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/PageLoadedDemo.html?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/PageLoadedDemo.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/PageLoadedDemo.html Tue Feb  6 11:54:40 2007
@@ -0,0 +1,9 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    
+    <h1>Page Loaded Demo</h1>
+
+    <p>
+        The message: [${message}]
+    </p>    
+
+</html>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html Tue Feb  6 11:54:40 2007
@@ -96,6 +96,9 @@
                         <li>
                             <a href="beaneditordemo">BeanEditor Demo</a> -- demonstrate the BeanEditor mega-component
                         </li>
+                        <li>
+                        <a href="pageloadeddemo">PageLoaded Demo</a> -- shows that page lifecycle methods are invoked
+                        </li>
                     </ul>
                 </td>
             </tr>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Tue Feb  6 11:54:40 2007
@@ -740,4 +740,13 @@
 
         assertTextPresent("[Howard]", "[Lewis Ship]", "[1966]", "[MARTIAN]", "[true]");
     }
+
+    @Test
+    public void pageloaded_lifecycle_method_invoked()
+    {
+        _selenium.open(BASE_URL);
+        clickAndWait("link=PageLoaded Demo");
+
+        assertTextPresent("[pageLoaded() was invoked.]");
+    }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/PageLoadedDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/PageLoadedDemo.java?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/PageLoadedDemo.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/PageLoadedDemo.java Tue Feb  6 11:54:40 2007
@@ -0,0 +1,35 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Retain;
+
+@ComponentClass
+public class PageLoadedDemo
+{
+    @Retain
+    private String _message;
+
+    void pageLoaded()
+    {
+        _message = "pageLoaded() was invoked.";
+    }
+
+    public String getMessage()
+    {
+        return _message;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/CheckFieldType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/CheckFieldType.java?view=auto&rev=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/CheckFieldType.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/CheckFieldType.java Tue Feb  6 11:54:40 2007
@@ -0,0 +1,40 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import java.util.Map;
+
+public class CheckFieldType
+{
+    private boolean _privateField;
+
+    private final Map _map = null;
+
+    public boolean isPrivateField()
+    {
+        return _privateField;
+    }
+
+    public void setPrivateField(boolean privateField)
+    {
+        _privateField = privateField;
+    }
+
+    public Map getMap()
+    {
+        return _map;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInvocationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInvocationTest.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInvocationTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInvocationTest.java Tue Feb  6 11:54:40 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -23,7 +23,7 @@
     public void no_context()
     {
         ComponentInvocation invocation = new ComponentInvocation(new OpaqueConstantTarget("abc"),
-                new Object[0]);
+                new String[0]);
         assertEquals(invocation.buildURI(false), "abc");
         assertEquals(invocation.buildURI(true), "abc");
     }
@@ -32,8 +32,8 @@
     public void context()
     {
         ComponentInvocation invocation = new ComponentInvocation(new OpaqueConstantTarget("abc"),
-                new Object[]
-                { "x", 123 });
+                new String[]
+                { "x", "123" });
         assertEquals(invocation.buildURI(false), "abc/x/123");
         assertEquals(invocation.buildURI(true), "abc/x/123");
     }
@@ -42,8 +42,8 @@
     public void parameters()
     {
         ComponentInvocation invocation = new ComponentInvocation(new OpaqueConstantTarget("abc"),
-                new Object[]
-                { "x", 123 });
+                new String[]
+                { "x", "123" });
         invocation.addParameter("p1", "foo");
         invocation.addParameter("p2", "bar");
         assertEquals(invocation.buildURI(false), "abc/x/123?p1=foo&p2=bar");

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java Tue Feb  6 11:54:40 2007
@@ -248,6 +248,19 @@
     }
 
     @Test
+    public void get_field_modifiers() throws Exception
+    {
+        Log log = newLog();
+
+        replay();
+
+        ClassTransformation ct = createClassTransformation(CheckFieldType.class, log);
+
+        assertEquals(ct.getFieldModifiers("_privateField"), Modifier.PRIVATE);
+        assertEquals(ct.getFieldModifiers("_map"), Modifier.PRIVATE + Modifier.FINAL);
+    }
+
+    @Test
     public void find_fields_of_type_excludes_claimed_fields() throws Exception
     {
         Log log = newLog();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java Tue Feb  6 11:54:40 2007
@@ -23,11 +23,14 @@
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.internal.util.Holder;
+import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.Request;
 import org.apache.tapestry.services.Response;
 import org.easymock.EasyMock;
 import org.easymock.IAnswer;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 public class LinkFactoryImplTest extends InternalBaseTestCase
@@ -38,6 +41,20 @@
 
     private static final String PAGE_CLASS_NAME = "foo.pages.sub.MyPage";
 
+    private TypeCoercer _typeCoercer;
+
+    @BeforeClass
+    public void setup()
+    {
+        _typeCoercer = getObject("service:tapestry.ioc.TypeCoercer", TypeCoercer.class);
+    }
+
+    @AfterClass
+    public void cleanup()
+    {
+        _typeCoercer = null;
+    }
+
     @Test
     public void action_link_root_context_no_ids()
     {
@@ -147,7 +164,8 @@
 
         replay();
 
-        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, map, null);
+        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, map, null,
+                _typeCoercer);
         factory.addListener(listener);
 
         Link link = factory.createPageLink(page);
@@ -235,7 +253,8 @@
 
         replay();
 
-        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, map, cache);
+        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, map, cache,
+                _typeCoercer);
         factory.addListener(listener);
 
         Link link = factory.createPageLink(PAGE_LOGICAL_NAME);
@@ -292,7 +311,8 @@
 
         replay();
 
-        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, map, null);
+        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, map, null,
+                _typeCoercer);
         factory.addListener(listener);
 
         Link link = factory.createActionLink(element, eventName, false, context);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java?view=diff&rev=504259&r1=504258&r2=504259
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java Tue Feb  6 11:54:40 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -24,9 +24,6 @@
 import org.apache.tapestry.services.ClassTransformation;
 import org.testng.annotations.Test;
 
-/**
- * 
- */
 public class UnclaimedFieldWorkerTest extends InternalBaseTestCase
 {
     @Test
@@ -52,7 +49,9 @@
 
         train_findUnclaimedFields(ct, "_fred");
 
-        expect(ct.getFieldType("_fred")).andReturn("foo.Bar");
+        train_getFieldModifiers(ct, "_fred", Modifier.PRIVATE);
+
+        train_getFieldType(ct, "_fred", "foo.Bar");
 
         expect(ct.addField(Modifier.PRIVATE, "foo.Bar", "_fred_default")).andReturn(
                 "_$fred_default");
@@ -65,5 +64,28 @@
         new UnclaimedFieldWorker().transform(ct, model);
 
         verify();
+    }
+
+    @Test
+    public void final_fields_are_skipped()
+    {
+        ClassTransformation ct = newClassTransformation();
+        MutableComponentModel model = newMutableComponentModel();
+
+        train_findUnclaimedFields(ct, "_fred");
+
+        train_getFieldModifiers(ct, "_fred", Modifier.PRIVATE | Modifier.FINAL);
+
+        replay();
+
+        new UnclaimedFieldWorker().transform(ct, model);
+
+        verify();
+    }
+
+    protected final void train_getFieldModifiers(ClassTransformation transformation,
+            String fieldName, int modifiers)
+    {
+        expect(transformation.getFieldModifiers(fieldName)).andReturn(modifiers).atLeastOnce();
     }
 }