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>