You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2006/11/19 22:59:58 UTC

svn commit: r476940 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/dom/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/structure/ main/...

Author: hlship
Date: Sun Nov 19 13:59:56 2006
New Revision: 476940

URL: http://svn.apache.org/viewvc?view=rev&rev=476940
Log:
Add InjectPage annotation.
Add support for Component and String return types from component event handler methods.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/InjectPage.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectPageWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StringEventHandler.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Barney.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Fred.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectDemo.java
      - copied, changed from r476234, tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Wilma.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldRemoval.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Barney.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Fred.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectDemo.html
      - copied, changed from r476234, tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Wilma.html
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/EndTagStyle.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandler.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.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/OnEventWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.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/site/apt/guide/event.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
    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/ComponentInstanceEventHandlerTest.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/OnEventWorkerTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/log4j.properties

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/InjectPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/InjectPage.java?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/InjectPage.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/InjectPage.java Sun Nov 19 13:59:56 2006
@@ -0,0 +1,38 @@
+// Copyright 2006 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.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Allows a a page (really, the root component of the page) to be injected into another component as
+ * a read-only field.
+ */
+@Target(FIELD)
+@Documented
+@Retention(RUNTIME)
+public @interface InjectPage {
+    /**
+     * The name of the page to inject, which is used when the field type is not sufficient to
+     * identify the page (for example, when the field type is an interface implemented by the page).
+     * A non-blank value here overrides the lookup by class name (from the field type).
+     */
+    String value() default "";
+}
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/EndTagStyle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/EndTagStyle.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/EndTagStyle.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/EndTagStyle.java Sun Nov 19 13:59:56 2006
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-// http://www.apache.org/licenses/LICENSE-2.0
+//     http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandler.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandler.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandler.java Sun Nov 19 13:59:56 2006
@@ -1,3 +1,17 @@
+// Copyright 2006 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 org.apache.commons.logging.Log;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java Sun Nov 19 13:59:56 2006
@@ -79,7 +79,8 @@
             transformation.addMethod(sig, body);
 
             transformation.replaceReadAccess(name, methodName);
-            transformation.makeReadOnly(name);
+            transformation.makeReadOnly(name);
+            transformation.removeField(name);
 
             transformation.claimField(name, annotation);
         }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectPageWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectPageWorker.java?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectPageWorker.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectPageWorker.java Sun Nov 19 13:59:56 2006
@@ -0,0 +1,97 @@
+// Copyright 2006 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.reflect.Modifier;
+import java.util.List;
+
+import org.apache.tapestry.annotations.InjectPage;
+import org.apache.tapestry.internal.structure.Page;
+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.MethodSignature;
+import org.apache.tapestry.util.BodyBuilder;
+
+/**
+ * Peforms transformations that allow pages to be injected into components.
+ * 
+ * @see InjectPage
+ */
+public class InjectPageWorker implements ComponentClassTransformWorker
+{
+    private final RequestPageCache _requestPageCache;
+
+    public InjectPageWorker(final RequestPageCache requestPageCache)
+    {
+        _requestPageCache = requestPageCache;
+    }
+
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    {
+        List<String> names = transformation.findFieldsWithAnnotation(InjectPage.class);
+
+        if (names.isEmpty())
+            return;
+
+        String cacheFieldName = transformation.addInjectedField(
+                RequestPageCache.class,
+                "_requestPageCache",
+                _requestPageCache);
+
+        for (String name : names)
+            addInjectedPage(transformation, name, cacheFieldName);
+
+    }
+
+    private void addInjectedPage(ClassTransformation transformation, String fieldName,
+            String cacheFieldName)
+    {
+        InjectPage annotation = transformation.getFieldAnnotation(fieldName, InjectPage.class);
+
+        String pageName = annotation.value();
+
+        String fieldType = transformation.getFieldType(fieldName);
+        String methodName = transformation.newMemberName("_read_inject_page_"
+                + InternalUtils.stripMemberPrefix(fieldName));
+
+        MethodSignature sig = new MethodSignature(Modifier.PRIVATE, fieldType, methodName, null,
+                null);
+
+        BodyBuilder builder = new BodyBuilder();
+        builder.begin();
+
+        builder.add("%s page = %s.", Page.class.getName(), cacheFieldName);
+
+        if (InternalUtils.isBlank(pageName))
+            builder.add("getByClassName(\"%s\")", fieldType);
+        else
+            builder.add("get(\"%s\")", pageName);
+
+        builder.addln(";");
+
+        builder.addln("return (%s) page.getRootElement().getComponent();", fieldType);
+
+        builder.end();
+
+        transformation.addMethod(sig, builder.toString());
+        transformation.replaceReadAccess(fieldName, methodName);
+        transformation.makeReadOnly(fieldName);
+        transformation.removeField(fieldName);
+
+        transformation.claimField(fieldName, annotation);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java Sun Nov 19 13:59:56 2006
@@ -12,85 +12,83 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
-import org.apache.tapestry.annotations.Inject;
-import org.apache.tapestry.internal.util.InternalUtils;
-import org.apache.tapestry.ioc.ObjectProvider;
-import org.apache.tapestry.ioc.ServiceLocator;
-import org.apache.tapestry.model.MutableComponentModel;
-import org.apache.tapestry.services.ClassTransformation;
-import org.apache.tapestry.services.ComponentClassTransformWorker;
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.annotations.Inject;
+import org.apache.tapestry.internal.util.InternalUtils;
+import org.apache.tapestry.ioc.ObjectProvider;
+import org.apache.tapestry.ioc.ServiceLocator;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
 import org.apache.tapestry.services.InjectionProvider;
-
-/**
- * Worker for the {@link org.apache.tapestry.annotations.Inject} annotation.
- * 
- * 
- */
-public class InjectWorker implements ComponentClassTransformWorker
-{
-    private final ObjectProvider _objectProvider;
-
-    private final ServiceLocator _locator;
-
-    // Really, a chain of command
-
-    private final InjectionProvider _injectionProvider;
-
-    public InjectWorker(ObjectProvider objectProvider, ServiceLocator locator,
-            InjectionProvider injectionProvider)
-    {
-        _objectProvider = objectProvider;
-        _locator = locator;
-        _injectionProvider = injectionProvider;
-    }
-
-    public void transform(ClassTransformation transformation, MutableComponentModel model)
-    {
-        for (String fieldName : transformation.findFieldsWithAnnotation(Inject.class))
-        {
-            Inject annotation = transformation.getFieldAnnotation(fieldName, Inject.class);
-
-            String value = annotation.value();
-
-            if (InternalUtils.isBlank(value))
-                injectAnnonymous(fieldName, transformation, model);
-            else
-                injectNamed(fieldName, value, transformation, model);
-
-            transformation.claimField(fieldName, annotation);
-        }
-
-    }
-
-    @SuppressWarnings("unchecked")
-    private void injectNamed(String fieldName, String value, ClassTransformation transformation,
-            MutableComponentModel model)
-    {
-        String fieldType = transformation.getFieldType(fieldName);
-
-        Class type = transformation.toClass(fieldType);
-
-        Object inject = _objectProvider.provide(value, type, _locator);
-
-        transformation.injectField(fieldName, inject);
-    }
-
-    private void injectAnnonymous(String fieldName, ClassTransformation transformation,
-            MutableComponentModel model)
-    {
-        String fieldType = transformation.getFieldType(fieldName);
-
-        boolean result = _injectionProvider.provideInjection(
-                fieldName,
-                fieldType,
-                _locator,
-                transformation,
-                model);
-
-        if (!result)
-            throw new RuntimeException(ServicesMessages.noInjectionFound(transformation
-                    .getClassName(), fieldName, fieldType));
-    }
-}
+
+/**
+ * Worker for the {@link org.apache.tapestry.annotations.Inject} annotation.
+ */
+public class InjectWorker implements ComponentClassTransformWorker
+{
+    private final ObjectProvider _objectProvider;
+
+    private final ServiceLocator _locator;
+
+    // Really, a chain of command
+
+    private final InjectionProvider _injectionProvider;
+
+    public InjectWorker(ObjectProvider objectProvider, ServiceLocator locator,
+            InjectionProvider injectionProvider)
+    {
+        _objectProvider = objectProvider;
+        _locator = locator;
+        _injectionProvider = injectionProvider;
+    }
+
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    {
+        for (String fieldName : transformation.findFieldsWithAnnotation(Inject.class))
+        {
+            Inject annotation = transformation.getFieldAnnotation(fieldName, Inject.class);
+
+            String value = annotation.value();
+
+            if (InternalUtils.isBlank(value))
+                injectAnnonymous(fieldName, transformation, model);
+            else
+                injectNamed(fieldName, value, transformation, model);
+
+            transformation.claimField(fieldName, annotation);
+        }
+
+    }
+
+    @SuppressWarnings("unchecked")
+    private void injectNamed(String fieldName, String value, ClassTransformation transformation,
+            MutableComponentModel model)
+    {
+        String fieldType = transformation.getFieldType(fieldName);
+
+        Class type = transformation.toClass(fieldType);
+
+        Object inject = _objectProvider.provide(value, type, _locator);
+
+        transformation.injectField(fieldName, inject);
+    }
+
+    private void injectAnnonymous(String fieldName, ClassTransformation transformation,
+            MutableComponentModel model)
+    {
+        String fieldType = transformation.getFieldType(fieldName);
+
+        boolean result = _injectionProvider.provideInjection(
+                fieldName,
+                fieldType,
+                _locator,
+                transformation,
+                model);
+
+        if (!result)
+            throw new RuntimeException(ServicesMessages.noInjectionFound(transformation
+                    .getClassName(), fieldName, fieldType));
+    }
+}

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=476940&r1=476939&r2=476940
==============================================================================
--- 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 Sun Nov 19 13:59:56 2006
@@ -102,6 +102,8 @@
     // Key is field name, value is expression used to replace read access
     private Map<String, String> _fieldWriteTransforms;
 
+    private Set<String> _removedFieldNames;
+
     /** Contains the assembled Javassist code for the class' default constructor. */
     private StringBuilder _constructor = new StringBuilder();
 
@@ -210,6 +212,7 @@
         _methodSignatures = null;
         _fieldReadTransforms = null;
         _fieldWriteTransforms = null;
+        _removedFieldNames = null;
         _constructor = null;
         _formatter = null;
         _loader = null;
@@ -1064,7 +1067,7 @@
         addConstructor();
 
         verifyFields();
-        
+
         freeze();
     }
 
@@ -1272,6 +1275,19 @@
         replaceWriteAccess(fieldName, methodName);
     }
 
+    public void removeField(String fieldName)
+    {
+        _formatter.format("remove field %s;\n\n", fieldName);
+
+        // TODO: We could check that there's an existing field read and field write transform ...
+
+        if (_removedFieldNames == null)
+            _removedFieldNames = newSet();
+
+        _removedFieldNames.add(fieldName);
+
+    }
+
     public void replaceReadAccess(String fieldName, String methodName)
     {
         String body = String.format("$_ = %s();", methodName);
@@ -1305,9 +1321,28 @@
         // If no field transformations have been requested, then we can save ourselves some
         // trouble!
 
-        if (_fieldReadTransforms == null && _fieldWriteTransforms == null)
-            return;
+        if (_fieldReadTransforms != null || _fieldWriteTransforms != null)
+            replaceFieldAccess();
 
+        if (_removedFieldNames != null)
+        {
+            for (String fieldName : _removedFieldNames)
+            {
+                try
+                {
+                    CtField field = _ctClass.getDeclaredField(fieldName);
+                    _ctClass.removeField(field);
+                }
+                catch (NotFoundException ex)
+                {
+                    throw new RuntimeException(ex);
+                }
+            }
+        }
+    }
+
+    private void replaceFieldAccess()
+    {
         // Provide empty maps here, to make the code in the inner class a tad
         // easier.
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java Sun Nov 19 13:59:56 2006
@@ -121,7 +121,7 @@
         }
 
         if (isNonVoid)
-            builder.addln(")) return;");
+            builder.addln("))) return true;");
         else
             builder.addln(");");
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StringEventHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StringEventHandler.java?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StringEventHandler.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StringEventHandler.java Sun Nov 19 13:59:56 2006
@@ -0,0 +1,27 @@
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.ComponentEventHandler;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.runtime.Component;
+
+/**
+ * Used when a component event handler returns a string value. The value is interpreted as the
+ * logical name of a page to activate (and render the response).
+ */
+public class StringEventHandler implements ComponentEventHandler<String>
+{
+    private final RequestPageCache _requestPageCache;
+
+    public StringEventHandler(final RequestPageCache requestPageCache)
+    {
+        _requestPageCache = requestPageCache;
+    }
+
+    public void handleResult(String result, Component component, String methodDescription)
+    {
+        Page page = _requestPageCache.get(result);
+
+        _requestPageCache.setActive(page);
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java Sun Nov 19 13:59:56 2006
@@ -237,7 +237,7 @@
     {
         ComponentPageElement containerElement = _element.getContainerElement();
 
-        return _element == null ? null : containerElement.getComponent();
+        return containerElement == null ? null : containerElement.getComponent();
     }
 
 }

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=476940&r1=476939&r2=476940
==============================================================================
--- 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 Sun Nov 19 13:59:56 2006
@@ -12,272 +12,282 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-
-/**
- * Contains class-specific information used when transforming an raw class into an executable class.
- * Much of this information is somewhat like ordinary reflection, but applies to a class that has
- * not yet been loaded.
- * <p>
- * Transformation is primarily about identifying annotations on fields and on methods and changing
- * the class, adding new interfaces, fields and methods, and deleting some existing fields.
- * <p>
- * A ClassTransformation contains all the state data specific to a particular class being
- * transformed. A number of <em>workers</em> will operate upon the ClassTransformation to effect
- * the desired changes before the true class is loaded into memory.
- * <p>
- * Instances of this class are not designed to be thread safe, access to an instance should be
- * restricted to a single thread. In fact, the design of this type is to allow stateless singletons
- * in multiple threads to work on thread-specific data (within the ClassTransformation). *
- * <p>
- * The majority of methods concern the <em>declared</em> members (field and methods) of a specific
- * class, rather than any fields or methods inherited from a base class.
- */
-public interface ClassTransformation
-{
-
-    /**
-     * Returns the name of the class being transformed.
-     */
-
-    String getClassName();
-
-    /**
-     * Returns the name of a new member (field or method). Ensures that the resulting name does not
-     * conflict with any existing member (declared by the underlying class, or inherited from a base
-     * class).
-     * <p>
-     * TODO: This method may be removed (see {@link #addField(int, String, String)})
-     * 
-     * @param suggested
-     *            the suggested value for the member
-     * @return a unique name for the member
-     */
-    String newMemberName(String suggested);
-
-    /**
-     * 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);
-
-    /**
-     * Finds all methods defined in the class that are marked with the provided annotation.
-     * 
-     * @param annotationClass
-     * @return a list of method signature (which may be empty) in ascending order
-     */
-    List<MethodSignature> findMethodsWithAnnotation(Class<? extends Annotation> annotationClass);
-
-    /**
-     * Finds an annotation for the class itself, including any annotations inherited from parent
-     * classes.
-     * 
-     * @param <T>
-     * @param annotationClass
-     *            the type of annotation to access
-     * @return the annotation if present, or null otherwise
-     */
-    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
-
-    /**
-     * Finds an annotation on a declared instance field.
-     * 
-     * @param <T>
-     *            constrains parameter and return value to Annotation types
-     * @param fieldName
-     *            the name of the field, which must exist
-     * @param annotationClass
-     *            the type of annotation to access
-     * @return the annotation if present, or null otherwise
-     * @throws IllegalArgumentException
-     *             if the fieldName does not correspond to a declared field
-     */
-    <T extends Annotation> T getFieldAnnotation(String fieldName, Class<T> annotationClass);
-
-    /**
-     * Finds an annotation on a declared method.
-     * 
-     * @param <T>
-     *            constrains parameter and return value to Annotation types
-     * @param method
-     *            the method signature to search
-     * @param annotationClass
-     *            the type of annotation to access
-     * @return the annotation if present, or null otherwise
-     * @throws IllegalArgumentException
-     *             if the method signature does not correspond to a declared method
-     */
-    <T extends Annotation> T getMethodAnnotation(MethodSignature method, Class<T> annotationClass);
-
-    /**
-     * Claims a field so as to ensure that only a single annotation is applied to any single field.
-     * When a transformation occurs (driven by a field annotation), the first thing that occurs is
-     * to claim the field, on behalf of the annotation.
-     * 
-     * @param fieldName
-     *            the name of the field that is being claimed
-     * @param tag
-     *            a non-null object that represents why the field is being tagged (this is typically
-     *            a specific annotation on the field)
-     * @throws IllegalArgumentException
-     *             if the fieldName does not correspond to a declared instance field
-     * @throws IllegalStateException
-     *             if the field is already claimed for some other tag
-     */
-    void claimField(String fieldName, Object tag);
-
-    /**
-     * Changes the field to be read only. Any existing code that changes the field will cause a
-     * runtime exception.
-     * 
-     * @param fieldName
-     *            name of field to so change
-     */
-    void makeReadOnly(String fieldName);
-
-    /**
-     * Finds any declared <em>instance</em> fields that have not been claimed (via
-     * {@link #claimField(String, Object)}) and returns the names of those fields. May return an
-     * empty array.
-     */
-    String[] findUnclaimedFields();
-
-    /**
-     * Obtains the type of a declared instance field.
-     * 
-     * @param fieldName
-     * @return the type of the field, as a string
-     * @throws IllegalArgumentException
-     *             if the fieldName does not correspond to a declared instance field
-     */
-    String getFieldType(String fieldName);
-
-    /**
-     * Defines a new declared field for the class. The suggestedName may be modified to ensure
-     * uniqueness.
-     * 
-     * @param modifiers
-     *            modifiers for the field (typically, {@link java.lang.reflect.Modifier#PRIVATE})
-     * @param type
-     *            the type for the field, as a string
-     * @param suggestedName
-     *            the desired name for the field, which may be modified (for uniqueness) when
-     *            returned
-     * @return the (uniqued) name for the field
-     */
-    String addField(int modifiers, String type, String suggestedName);
-
-    /**
-     * Defines a new <strong>protected</strong> instance variable whose initial value is provided
-     * statically, via a constructor parameter. The transformation caches the result, so calling
-     * this method repeatedly with the same type and value will return the same field name. Caching
-     * extends to the parent transformation, so that a value injected into a parent class will be
-     * available (via the protected instance variable) to subclasses.
-     * 
-     * @param type
-     *            the type of object to inject
-     * @param suggestedName
-     *            the suggested name for the new field
-     * @param value
-     *            to be injected. This value is retained.
-     * @return the actual name of the injected field
-     */
-    String addInjectedField(Class type, String suggestedName, Object value);
-
-    /**
-     * Converts the field into a read only field whose value is the provided value. This is used
-     * when converting an existing field into a read-only injected value.
-     * 
-     * @param fieldName
-     *            name of field to convert
-     * @param value
-     *            the value provided by the field
-     */
-    void injectField(String fieldName, Object value);
-
-    /**
-     * Transforms the class to implement the indicated interface. If the class (or its super class)
-     * does not already implement the interface, then the interface is added, and default
-     * implementations of any methods of the interface are added.
-     * <p>
-     * TODO: Checking that the names of methods in the interface do not conflict with the names of
-     * methods present in the (unmodified) class.
-     * 
-     * @param interfaceClass
-     *            the interface to be implemented by the class
-     * @throws IllegalArgumentException
-     *             if the interfaceClass argument does not represent an interface
-     */
-    void addImplementedInterface(Class interfaceClass);
-
-    /**
-     * Extends an existing method. The provided method body is inserted at the end of the existing
-     * method (i.e. {@link javassist.CtBehavior#insertAfter(java.lang.String)}). To access or
-     * change the return value, use the <code>$_</code> pseudo variable.
-     * <p>
-     * The method may be declared in the class, or may be inherited from a super-class. For
-     * inherited methods, a method is added that first invokes the super implementation. Use
-     * {@link #addMethod(MethodSignature, String)} when it is necessary to control when the
-     * super-class method is invoked.
-     * 
-     * @param signature
-     *            the signature of the method to extend
-     * @param methodBody
-     *            the body of code
-     * @throws IllegalArgumentException
-     *             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. Replaces any existing method declared for the
-     * class. When overriding a super-class method, you should use
-     * {@link #extendMethod(MethodSignature, String)}, or you should remember to invoke the super
-     * class implemetation explicitly. Use this method to control when the super-class
-     * implementation is invoked.
-     */
-    void addMethod(MethodSignature signature, String methodBody);
-
-    /**
-     * Replaces all read-references to the specified field with invocations of the specified method
-     * name. Replacements do not occur in methods added via
-     * {@link #addMethod(MethodSignature, String)} or {@link #extendMethod(MethodSignature, String)}.
-     */
-    void replaceReadAccess(String fieldName, String methodName);
-
-    /**
-     * Replaces all write accesses to the specified field with invocations of the specified method
-     * name. The method should take a single parameter of the same type as the field. Replacements
-     * do not occur in methods added via {@link #addMethod(MethodSignature, String)} or
-     * {@link #extendMethod(MethodSignature, String)}.
-     */
-    void replaceWriteAccess(String fieldName, String methodName);
-
-    /**
-     * Converts a type name into a corresponding class (possibly, a transformed class). Primitive
-     * type names are returned as wrapper types.
-     */
-
-    Class toClass(String type);
-
-    /**
-     * Returns a log, based on the class name being transformed, to which warnings or errors
-     * concerning the class being transformed may be logged.
-     */
-    Log getLog();
-}
+package org.apache.tapestry.services;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Contains class-specific information used when transforming an raw class into an executable class.
+ * Much of this information is somewhat like ordinary reflection, but applies to a class that has
+ * not yet been loaded.
+ * <p>
+ * Transformation is primarily about identifying annotations on fields and on methods and changing
+ * the class, adding new interfaces, fields and methods, and deleting some existing fields.
+ * <p>
+ * A ClassTransformation contains all the state data specific to a particular class being
+ * transformed. A number of <em>workers</em> will operate upon the ClassTransformation to effect
+ * the desired changes before the true class is loaded into memory.
+ * <p>
+ * Instances of this class are not designed to be thread safe, access to an instance should be
+ * restricted to a single thread. In fact, the design of this type is to allow stateless singletons
+ * in multiple threads to work on thread-specific data (within the ClassTransformation). *
+ * <p>
+ * The majority of methods concern the <em>declared</em> members (field and methods) of a specific
+ * class, rather than any fields or methods inherited from a base class.
+ */
+public interface ClassTransformation
+{
+
+    /**
+     * Returns the name of the class being transformed.
+     */
+    String getClassName();
+
+    /**
+     * Returns the name of a new member (field or method). Ensures that the resulting name does not
+     * conflict with any existing member (declared by the underlying class, or inherited from a base
+     * class).
+     * <p>
+     * TODO: This method may be removed (see {@link #addField(int, String, String)})
+     * 
+     * @param suggested
+     *            the suggested value for the member
+     * @return a unique name for the member
+     */
+    String newMemberName(String suggested);
+
+    /**
+     * 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);
+
+    /**
+     * Finds all methods defined in the class that are marked with the provided annotation.
+     * 
+     * @param annotationClass
+     * @return a list of method signature (which may be empty) in ascending order
+     */
+    List<MethodSignature> findMethodsWithAnnotation(Class<? extends Annotation> annotationClass);
+
+    /**
+     * Finds an annotation for the class itself, including any annotations inherited from parent
+     * classes.
+     * 
+     * @param <T>
+     * @param annotationClass
+     *            the type of annotation to access
+     * @return the annotation if present, or null otherwise
+     */
+    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+
+    /**
+     * Finds an annotation on a declared instance field.
+     * 
+     * @param <T>
+     *            constrains parameter and return value to Annotation types
+     * @param fieldName
+     *            the name of the field, which must exist
+     * @param annotationClass
+     *            the type of annotation to access
+     * @return the annotation if present, or null otherwise
+     * @throws IllegalArgumentException
+     *             if the fieldName does not correspond to a declared field
+     */
+    <T extends Annotation> T getFieldAnnotation(String fieldName, Class<T> annotationClass);
+
+    /**
+     * Finds an annotation on a declared method.
+     * 
+     * @param <T>
+     *            constrains parameter and return value to Annotation types
+     * @param method
+     *            the method signature to search
+     * @param annotationClass
+     *            the type of annotation to access
+     * @return the annotation if present, or null otherwise
+     * @throws IllegalArgumentException
+     *             if the method signature does not correspond to a declared method
+     */
+    <T extends Annotation> T getMethodAnnotation(MethodSignature method, Class<T> annotationClass);
+
+    /**
+     * Claims a field so as to ensure that only a single annotation is applied to any single field.
+     * When a transformation occurs (driven by a field annotation), the first thing that occurs is
+     * to claim the field, on behalf of the annotation.
+     * 
+     * @param fieldName
+     *            the name of the field that is being claimed
+     * @param tag
+     *            a non-null object that represents why the field is being tagged (this is typically
+     *            a specific annotation on the field)
+     * @throws IllegalArgumentException
+     *             if the fieldName does not correspond to a declared instance field
+     * @throws IllegalStateException
+     *             if the field is already claimed for some other tag
+     */
+    void claimField(String fieldName, Object tag);
+
+    /**
+     * Changes the field to be read only. Any existing code that changes the field will cause a
+     * runtime exception.
+     * 
+     * @param fieldName
+     *            name of field to so change
+     */
+    void makeReadOnly(String fieldName);
+
+    /**
+     * Finds any declared <em>instance</em> fields that have not been claimed (via
+     * {@link #claimField(String, Object)}) and returns the names of those fields. May return an
+     * empty array.
+     */
+    String[] findUnclaimedFields();
+
+    /**
+     * Obtains the type of a declared instance field.
+     * 
+     * @param fieldName
+     * @return the type of the field, as a string
+     * @throws IllegalArgumentException
+     *             if the fieldName does not correspond to a declared instance field
+     */
+    String getFieldType(String fieldName);
+
+    /**
+     * Defines a new declared field for the class. The suggestedName may be modified to ensure
+     * uniqueness.
+     * 
+     * @param modifiers
+     *            modifiers for the field (typically, {@link java.lang.reflect.Modifier#PRIVATE})
+     * @param type
+     *            the type for the field, as a string
+     * @param suggestedName
+     *            the desired name for the field, which may be modified (for uniqueness) when
+     *            returned
+     * @return the (uniqued) name for the field
+     */
+    String addField(int modifiers, String type, String suggestedName);
+
+    /**
+     * Defines a new <strong>protected</strong> instance variable whose initial value is provided
+     * statically, via a constructor parameter. The transformation caches the result, so calling
+     * this method repeatedly with the same type and value will return the same field name. Caching
+     * extends to the parent transformation, so that a value injected into a parent class will be
+     * available (via the protected instance variable) to subclasses.
+     * 
+     * @param type
+     *            the type of object to inject
+     * @param suggestedName
+     *            the suggested name for the new field
+     * @param value
+     *            to be injected. This value is retained.
+     * @return the actual name of the injected field
+     */
+    String addInjectedField(Class type, String suggestedName, Object value);
+
+    /**
+     * Converts the field into a read only field whose value is the provided value. This is used
+     * when converting an existing field into a read-only injected value.
+     * 
+     * @param fieldName
+     *            name of field to convert
+     * @param value
+     *            the value provided by the field
+     */
+    void injectField(String fieldName, Object value);
+
+    /**
+     * Transforms the class to implement the indicated interface. If the class (or its super class)
+     * does not already implement the interface, then the interface is added, and default
+     * implementations of any methods of the interface are added.
+     * <p>
+     * TODO: Checking that the names of methods in the interface do not conflict with the names of
+     * methods present in the (unmodified) class.
+     * 
+     * @param interfaceClass
+     *            the interface to be implemented by the class
+     * @throws IllegalArgumentException
+     *             if the interfaceClass argument does not represent an interface
+     */
+    void addImplementedInterface(Class interfaceClass);
+
+    /**
+     * Extends an existing method. The provided method body is inserted at the end of the existing
+     * method (i.e. {@link javassist.CtBehavior#insertAfter(java.lang.String)}). To access or
+     * change the return value, use the <code>$_</code> pseudo variable.
+     * <p>
+     * The method may be declared in the class, or may be inherited from a super-class. For
+     * inherited methods, a method is added that first invokes the super implementation. Use
+     * {@link #addMethod(MethodSignature, String)} when it is necessary to control when the
+     * super-class method is invoked.
+     * 
+     * @param signature
+     *            the signature of the method to extend
+     * @param methodBody
+     *            the body of code
+     * @throws IllegalArgumentException
+     *             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. Replaces any existing method declared for the
+     * class. When overriding a super-class method, you should use
+     * {@link #extendMethod(MethodSignature, String)}, or you should remember to invoke the super
+     * class implemetation explicitly. Use this method to control when the super-class
+     * implementation is invoked.
+     */
+    void addMethod(MethodSignature signature, String methodBody);
+
+    /**
+     * Replaces all read-references to the specified field with invocations of the specified method
+     * name. Replacements do not occur in methods added via
+     * {@link #addMethod(MethodSignature, String)} or {@link #extendMethod(MethodSignature, String)}.
+     */
+    void replaceReadAccess(String fieldName, String methodName);
+
+    /**
+     * Replaces all write accesses to the specified field with invocations of the specified method
+     * name. The method should take a single parameter of the same type as the field. Replacements
+     * do not occur in methods added via {@link #addMethod(MethodSignature, String)} or
+     * {@link #extendMethod(MethodSignature, String)}.
+     */
+    void replaceWriteAccess(String fieldName, String methodName);
+
+    /**
+     * Removes a field entirely; this is useful for fields that are replaced entirely by computed
+     * values.
+     * 
+     * @param fieldName
+     *            the name of the field to remove
+     * @see #replaceReadAccess(String, String)
+     * @see #replaceWriteAccess(String, String)
+     */
+    void removeField(String fieldName);
+
+    /**
+     * Converts a type name into a corresponding class (possibly, a transformed class). Primitive
+     * type names are returned as wrapper types.
+     */
+
+    Class toClass(String type);
+
+    /**
+     * Returns a log, based on the class name being transformed, to which warnings or errors
+     * concerning the class being transformed may be logged.
+     */
+    Log getLog();
+}

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=476940&r1=476939&r2=476940
==============================================================================
--- 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 Sun Nov 19 13:59:56 2006
@@ -35,6 +35,7 @@
 import org.apache.tapestry.annotations.BeforeRenderTemplate;
 import org.apache.tapestry.annotations.BeginRender;
 import org.apache.tapestry.annotations.CleanupRender;
+import org.apache.tapestry.annotations.InjectPage;
 import org.apache.tapestry.annotations.PostBeginRender;
 import org.apache.tapestry.annotations.PreBeginRender;
 import org.apache.tapestry.annotations.SetupRender;
@@ -58,6 +59,7 @@
 import org.apache.tapestry.internal.services.HeartbeatImpl;
 import org.apache.tapestry.internal.services.InfrastructureImpl;
 import org.apache.tapestry.internal.services.InfrastructureManagerImpl;
+import org.apache.tapestry.internal.services.InjectPageWorker;
 import org.apache.tapestry.internal.services.InjectWorker;
 import org.apache.tapestry.internal.services.InternalModule;
 import org.apache.tapestry.internal.services.LinkFactory;
@@ -75,6 +77,7 @@
 import org.apache.tapestry.internal.services.RetainWorker;
 import org.apache.tapestry.internal.services.SessionPersistentFieldStrategy;
 import org.apache.tapestry.internal.services.StaticFilesFilter;
+import org.apache.tapestry.internal.services.StringEventHandler;
 import org.apache.tapestry.internal.services.SupportsInformalParametersWorker;
 import org.apache.tapestry.internal.services.UnclaimedFieldWorker;
 import org.apache.tapestry.internal.services.WebContextImpl;
@@ -510,6 +513,8 @@
      * <li>Mixin -- adds a mixin as part of a component's implementation</li>
      * <li>Environment -- allows fields to contain values extracted from the {@link Environment}
      * service</li>
+     * <li>InjectPage -- adds code to allow access to other pages via the {@link InjectPage} field
+     * annotation</li>
      * <li>SupportsInformalParameters -- checks for the annotation</li>
      * <li>UnclaimedField -- identifies unclaimed fields and resets them to null/0/false at the end
      * of the request</li>
@@ -522,7 +527,8 @@
             ObjectProvider objectProvider, @InjectService("InjectionProvider")
             InjectionProvider injectionProvider, @InjectService("Environment")
             Environment environment, @InjectService("tapestry.ComponentClassResolver")
-            ComponentClassResolver resolver)
+            ComponentClassResolver resolver, @InjectService("tapestry.internal.RequestPageCache")
+            RequestPageCache requestPageCache)
     {
         // TODO: Proper scheduling of all of this. Since a given field or method should
         // only have a single annotation, the order doesn't matter so much, as long as
@@ -535,6 +541,7 @@
         configuration.add("Mixin", new MixinWorker(resolver));
         configuration.add("OnEvent", new OnEventWorker());
         configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker());
+        configuration.add("InjectPage", new InjectPageWorker(requestPageCache));
 
         // Workers for the component rendering state machine methods; this is in typical
         // execution order.
@@ -700,12 +707,14 @@
         return _strategyBuilder.build(registry);
     }
 
+    /** Contributes handlers for type Component and type String. */
     public void contributeComponentEventHandler(
             MappedConfiguration<Class, ComponentEventHandler> configuration,
             @InjectService("ComponentInstanceEventHandler")
             ComponentEventHandler componentInstanceEventHandler)
     {
         configuration.add(Component.class, componentInstanceEventHandler);
+        configuration.add(String.class, new StringEventHandler(_requestPageCache));
     }
 
     public ComponentEventHandler buildComponentInstanceEventHandler(Log log)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt Sun Nov 19 13:59:56 2006
@@ -56,6 +56,8 @@
   
   * It has converted the context value from a string to an integer and passed it into the method.
   
+  []
+  
   The OnEvent annotation allows events to be selected based on the originating component,
   or on the type of event.
   
@@ -84,12 +86,31 @@
   
 Event Handler Returns Types
 
-  To be determined.  For the moment, the return type of event handler methods is <<ignored>>.
+  An event handler may return a number of different types:
+  
+  * A page component, via the {{{../apidocs/org/apache/tapestry/annotations/InjectPage.html}InjectPage}} annotation
+  
+  * A string, the <logical> name of a page (not the fully qualified class name)
+
+  * <More types to be determined>
+  
+  []
+  
+  Returning a page will abort the event and direct Tapestry to render the returned page.  It's completely acceptible to invoke
+  methods on the page before returning it (often to inform it about what it should display), but remember that rendering of the page
+  <<will occur in a subsequent request>>, which often requires that you store information persistently between requests.
+  
+  Returning a string is much the same, except that the string is used to locate the page to be activated. This is easy to use
+  when there is no need to invoke methods on the page before returning it.
+  
+  <TODO: Describe differences between client-originating events and flow-of-control events from components.>
   
 End of Action Request
 
   The default behavior at the end of an action request is to set up the page containing
-  the component to render.
+  the component to render.  This is normally the page that contains the component, but the active page
+  (the page that renders the response) may be altered based on the value returned from an component event
+  handler method.
   
   <<This is very important:>> The rendering occurs in a <<new>> request. The normal response
   to an action request is a client-side redirect to re-render the page. Thus an action is <<two>>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt Sun Nov 19 13:59:56 2006
@@ -91,11 +91,15 @@
   when the form is submitted:
   
 +----+
+@Persist
 private String _userId;
+
 private String _password;
+
+@Persist
 private String _errorMessage;
 
-@Inject
+@InjectPage
 private Start _startPage;
 
 @Inject
@@ -131,4 +135,10 @@
     
   In many cases, additional information about the event is available, and can be passed
   into the method by adding parameters to the method. Again, Tapestry will adapt
-  to your parameters, in whatever order you supply them.
\ No newline at end of file
+  to your parameters, in whatever order you supply them.
+  
+  Finally, Tapestry 5 explicitly seperates actions (requests that change things) and rendering (requests that
+  render pages) into two seperate requests.  Performing an action, such as clicking a link or submitting a form,
+  results in a <client side redirect> to the new page. This is often called "redirect after post". This helps ensure
+  that URLs in the browser are book-markable ... but also requires that more information be stored in the session
+  between requests (using the @Persist annotation).  
\ No newline at end of file

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=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html Sun Nov 19 13:59:56 2006
@@ -14,7 +14,7 @@
                     <a href="MerryChristmas.html">Count Page</a>
                 </li>
                 <li>
-                    <a href="InjectPage.html">Inject Page</a>
+                    <a href="InjectDemo.html">Inject Demo</a>
                 </li>
                 <li>
                     <a href="Countdown.html">Countdown Page</a>

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=476940&r1=476939&r2=476940
==============================================================================
--- 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 Sun Nov 19 13:59:56 2006
@@ -119,16 +119,37 @@
     {
         _selenium.open(BASE_URL);
 
-        clickAndWait("link=Inject Page");
+        clickAndWait("link=Inject Demo");
 
         // This is a test for a named @Inject:
         assertTextPresent("<Proxy for tapestry.WebRequest(org.apache.tapestry.services.WebRequest)>");
 
         // This is a test for an annonymous @Inject and ComponentResourcesInjectionProvider
-        assertTextPresent("ComponentResources[org.apache.tapestry.integration.app1.pages.InjectPage]");
+        assertTextPresent("ComponentResources[org.apache.tapestry.integration.app1.pages.InjectDemo]");
 
         // Another test, DefaultInjectionProvider
         assertTextPresent("<Proxy for tapestry.BindingSource(org.apache.tapestry.services.BindingSource)>");
+    }
+
+    @Test
+    public void app1_page_injection() throws Exception
+    {
+        _selenium.open(BASE_URL);
+
+        clickAndWait("link=Inject Demo");
+
+        clickAndWait("link=Fred");
+
+        assertTextPresent("You clicked Fred.");
+
+        clickAndWait("link=Back");
+        clickAndWait("link=Barney");
+
+        assertTextPresent("You clicked Barney.");
+        
+        clickAndWait("link=Back");
+        clickAndWait("link=Wilma");
+        assertTextPresent("You clicked Wilma.");
     }
 
     @Test

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Barney.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Barney.java?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Barney.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Barney.java Sun Nov 19 13:59:56 2006
@@ -0,0 +1,26 @@
+// Copyright 2006 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;
+
+@ComponentClass
+public class Barney implements Runnable
+{
+    public void run()
+    {
+
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Fred.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Fred.java?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Fred.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Fred.java Sun Nov 19 13:59:56 2006
@@ -0,0 +1,23 @@
+// Copyright 2006 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;
+
+@ComponentClass
+public class Fred
+{
+
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectDemo.java (from r476234, tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectDemo.java?view=diff&rev=476940&p1=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java&r1=476234&p2=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectDemo.java&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectDemo.java Sun Nov 19 13:59:56 2006
@@ -12,42 +12,68 @@
 // 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.ComponentResources;
-import org.apache.tapestry.annotations.ComponentClass;
-import org.apache.tapestry.annotations.Inject;
-import org.apache.tapestry.services.BindingSource;
-import org.apache.tapestry.services.WebRequest;
-
-@ComponentClass
-public class InjectPage
-{
-    // Named
-    @Inject("infrastructure:request")
-    private WebRequest _request;
-
-    // Via ComponentResourcesInjectionProvider
-    @Inject
-    private ComponentResources _resources;
-
-    // Via DefaultInjectionProvider -- have to ensure that BindingSource
-    // stays unique.
-    @Inject
-    private BindingSource _bindingSource;
-
-    public BindingSource getBindingSource()
-    {
-        return _bindingSource;
-    }
-
-    public WebRequest getRequest()
-    {
-        return _request;
-    }
-
-    public ComponentResources getResources()
-    {
-        return _resources;
-    }
-}
+package org.apache.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Inject;
+import org.apache.tapestry.annotations.InjectPage;
+import org.apache.tapestry.annotations.OnEvent;
+import org.apache.tapestry.services.BindingSource;
+import org.apache.tapestry.services.WebRequest;
+
+@ComponentClass
+public class InjectDemo
+{
+    // Named
+    @Inject("infrastructure:request")
+    private WebRequest _request;
+
+    // Via ComponentResourcesInjectionProvider
+    @Inject
+    private ComponentResources _resources;
+
+    // Via DefaultInjectionProvider -- have to ensure that BindingSource
+    // stays unique.
+    @Inject
+    private BindingSource _bindingSource;
+
+    @InjectPage
+    private Fred _fred;
+
+    @InjectPage("Barney")
+    private Runnable _barney;
+
+    public BindingSource getBindingSource()
+    {
+        return _bindingSource;
+    }
+
+    public WebRequest getRequest()
+    {
+        return _request;
+    }
+
+    public ComponentResources getResources()
+    {
+        return _resources;
+    }
+
+    @OnEvent(component = "fred")
+    Object clickFred()
+    {
+        return _fred;
+    }
+
+    @OnEvent(component = "barney")
+    Object clickBarney()
+    {
+        return _barney;
+    }
+
+    @OnEvent(component = "wilma")
+    String clickWilma()
+    {
+        return "Wilma";
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Wilma.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Wilma.java?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Wilma.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Wilma.java Sun Nov 19 13:59:56 2006
@@ -0,0 +1,9 @@
+package org.apache.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+
+@ComponentClass
+public class Wilma
+{
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandlerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandlerTest.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandlerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstanceEventHandlerTest.java Sun Nov 19 13:59:56 2006
@@ -1,3 +1,17 @@
+// Copyright 2006 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 org.apache.commons.logging.Log;

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldRemoval.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldRemoval.java?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldRemoval.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldRemoval.java Sun Nov 19 13:59:56 2006
@@ -0,0 +1,24 @@
+// Copyright 2006 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 org.apache.tapestry.annotations.ComponentClass;
+
+@ComponentClass
+public class FieldRemoval
+{
+    @SuppressWarnings("unused")
+    private int _fieldToRemove;
+}

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=476940&r1=476939&r2=476940
==============================================================================
--- 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 Sun Nov 19 13:59:56 2006
@@ -19,6 +19,7 @@
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.Target;
+import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.List;
@@ -878,6 +879,33 @@
             assertEquals(
                     ex.getMessage(),
                     "Class org.apache.tapestry.internal.transform.pages.ParentClass does not declare method 'public void foo()'.");
+        }
+
+        verify();
+    }
+
+    @Test
+    public void remove_field() throws Exception
+    {
+        Log log = newLog();
+
+        replay();
+
+        CtClass targetObjectCtClass = findCtClass(FieldRemoval.class);
+
+        InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass,
+                _contextClassLoader, log, null);
+
+        ct.removeField("_fieldToRemove");
+
+        ct.finish();
+
+        Class transformed = _classPool.toClass(targetObjectCtClass, _loader);
+
+        for (Field f : transformed.getDeclaredFields())
+        {
+            if (f.getName().equals("_fieldToRemove"))
+                throw new AssertionError("_fieldToRemove still in transformed class.");
         }
 
         verify();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java Sun Nov 19 13:59:56 2006
@@ -264,7 +264,7 @@
                 BOILERPLATE_1,
                 BOILERPLATE_2,
                 "$1.setSource(this, \"foo.Bar.foo()\");",
-                "if ($1.storeResult(foo()) return;",
+                "if ($1.storeResult(foo())) return true;",
                 "}");
 
         replay();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/log4j.properties?view=diff&rev=476940&r1=476939&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/log4j.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/log4j.properties Sun Nov 19 13:59:56 2006
@@ -27,5 +27,5 @@
 log4j.category.tapestry.ioc.ClassFactory=error
 
 log4j.category.app=info
-log4j.category.org.apache.tapestry.integration.app1=error
+log4j.category.org.apache.tapestry.integration.app1=debug
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Barney.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Barney.html?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Barney.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Barney.html Sun Nov 19 13:59:56 2006
@@ -0,0 +1,14 @@
+<t:comp type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+    <p>
+        You clicked Barney.
+    </p>
+    
+    <p>
+        In this case, @InjectPage determined the target page via the value attribute of the annotation.
+    </p>
+    
+    <p>
+        [<a href="/InjectDemo.html">Back</a>]
+    </p>
+</t:comp>

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Fred.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Fred.html?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Fred.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Fred.html Sun Nov 19 13:59:56 2006
@@ -0,0 +1,14 @@
+<t:comp type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+    <p>
+        You clicked Fred.
+    </p>
+    
+    <p>
+        In this case, @InjectPage determined the target page via the field type.
+    </p>
+    
+    <p>
+[<a href="/InjectDemo.html">Back</a>]
+    </p>
+</t:comp>

Copied: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectDemo.html (from r476234, tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectDemo.html?view=diff&rev=476940&p1=tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html&r1=476234&p2=tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectDemo.html&r2=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectDemo.html Sun Nov 19 13:59:56 2006
@@ -2,5 +2,14 @@
     <p> Demonstrates the use of the @Inject annotation. </p>
     <p>WebRequest: ${request}</p>
     <p>ComponentResources: ${resources}</p>
-    <p>BindingSource: ${bindingSource}</p>
+    <p>BindingSource: ${bindingSource}</p>
+    
+    
+    <p>
+        ActionLinks used to demonstrate the use of @InjectPage:
+    </p>
+    
+    <p><t:comp id="fred" type="ActionLink">Fred</t:comp></p>
+    <p><t:comp id="barney" type="ActionLink">Barney</t:comp></p>
+    <p><t:comp id="wilma" type="ActionLink">Wilma</t:comp></p>
 </t:comp>

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Wilma.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Wilma.html?view=auto&rev=476940
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Wilma.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Wilma.html Sun Nov 19 13:59:56 2006
@@ -0,0 +1,14 @@
+<t:comp type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    
+    <p>
+        You clicked Wilma.
+    </p>
+    
+    <p>
+        In this case the component event handler method returned the name of the page to activate, as a String.
+    </p>
+    
+    <p>
+        [<a href="/InjectDemo.html">Back</a>]
+    </p>
+</t:comp>