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 2005/06/19 18:06:29 UTC
cvs commit: jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance TestInjectPageWorker.java
hlship 2005/06/19 09:06:29
Modified: framework/src/java/org/apache/tapestry/enhance
EnhanceMessages.java EnhanceStrings.properties
. status.xml
framework/src/descriptor/META-INF tapestry.enhance.xml
src/documentation/content/xdocs/UsersGuide injection.xml
listenermethods.xml
Added: framework/src/java/org/apache/tapestry/enhance
InjectPageWorker.java
framework/src/test/org/apache/tapestry/enhance
TestInjectPageWorker.java
Log:
Add injection of pages.
Revision Changes Path
1.17 +6 -0 jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhanceMessages.java
Index: EnhanceMessages.java
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhanceMessages.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- EnhanceMessages.java 16 Jun 2005 12:03:17 -0000 1.16
+++ EnhanceMessages.java 19 Jun 2005 16:06:29 -0000 1.17
@@ -112,4 +112,10 @@
.getJavaClassName(propertyType), ClassFabUtils.getJavaClassName(requiredType));
}
+ public static String wrongTypeForPageInjection(String propertyName, Class propertyType)
+ {
+ return _formatter.format("wrong-type-for-page-injection", propertyName, ClassFabUtils
+ .getJavaClassName(propertyType));
+ }
+
}
\ No newline at end of file
1.14 +2 -1 jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhanceStrings.properties
Index: EnhanceStrings.properties
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhanceStrings.properties,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- EnhanceStrings.properties 16 Jun 2005 12:03:17 -0000 1.13
+++ EnhanceStrings.properties 19 Jun 2005 16:06:29 -0000 1.14
@@ -23,4 +23,5 @@
incompatible-inject-type=The value obtained using locator ''{0}'' ({1}) is not compatible with the existing property (of type {2}).
initial-value-for-property=initial value for property {0}
unknown-inject-type=Unable to create injected property {0}: injection type ''{1}'' is not defined.
-wrong-type-for-property=Property {0} is type {1}, which is not compatible with {2}.
\ No newline at end of file
+wrong-type-for-property=Property {0} is type {1}, which is not compatible with {2}.
+wrong-type-for-page-injection=Property {0} is type {1}, which is not compatible with injection. The property type should be Object, IPage, or a specific page class.
\ No newline at end of file
1.1 jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/InjectPageWorker.java
Index: InjectPageWorker.java
===================================================================
// Copyright 2005 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.enhance;
import java.lang.reflect.Modifier;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.Location;
import org.apache.hivemind.service.BodyBuilder;
import org.apache.hivemind.service.MethodSignature;
import org.apache.tapestry.IPage;
import org.apache.tapestry.spec.InjectSpecification;
/**
* Injects code to access a named page within the application.
*
* @author Howard Lewis Ship
* @since 4.0
*/
public class InjectPageWorker implements InjectEnhancementWorker
{
public void performEnhancement(EnhancementOperation op, InjectSpecification spec)
{
performEnhancement(op, spec.getObject(), spec.getProperty(), spec.getLocation());
}
public void performEnhancement(EnhancementOperation op, String pageName, String propertyName,
Location location)
{
Class propertyType = op.getPropertyType(propertyName);
if (propertyType == null)
propertyType = Object.class;
else if (propertyType.isPrimitive())
throw new ApplicationRuntimeException(EnhanceMessages.wrongTypeForPageInjection(
propertyName,
propertyType), null, location, null);
op.claimProperty(propertyName);
MethodSignature sig = new MethodSignature(propertyType, op
.getAccessorMethodName(propertyName), null, null);
BodyBuilder builder = new BodyBuilder();
builder.add("return ");
// If the property type is not IPage or a superclass of IPage then a cast
// is needed.
if (!propertyType.isAssignableFrom(IPage.class))
builder.add("({0})", propertyType.getName());
builder.add("getPage().getRequestCycle().getPage(\"{0}\");", pageName);
op.addMethod(Modifier.PUBLIC, sig, builder.toString());
}
}
1.137 +1 -0 jakarta-tapestry/status.xml
Index: status.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/status.xml,v
retrieving revision 1.136
retrieving revision 1.137
diff -u -r1.136 -r1.137
--- status.xml 19 Jun 2005 15:00:45 -0000 1.136
+++ status.xml 19 Jun 2005 16:06:29 -0000 1.137
@@ -85,6 +85,7 @@
<action type="add" dev="HLS">Add translator binding prefix.</action>
<action type="add" dev="HLS">Add cancel and refresh listener parameters to Form.</action>
<action type="add" dev="HLS">Listener methods may now return a page name, or a page instance, to activate and render the response.</action>
+ <action type="add" dev="HLS">Add injection of pages.</action>
</release>
<release version="4.0-alpha-3" date="May 16 2005">
<action type="add" dev="HLS">Add initial support for the validator: binding prefix.</action>
1.21 +1 -0 jakarta-tapestry/framework/src/descriptor/META-INF/tapestry.enhance.xml
Index: tapestry.enhance.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/descriptor/META-INF/tapestry.enhance.xml,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- tapestry.enhance.xml 9 Jun 2005 18:33:44 -0000 1.20
+++ tapestry.enhance.xml 19 Jun 2005 16:06:29 -0000 1.21
@@ -114,6 +114,7 @@
<worker type="state" object="service:InjectStateWorker"/>
<worker type="meta" object="service:InjectMetaWorker"/>
<worker type="script" object="service:InjectScriptWorker"/>
+ <worker type="page" object="instance:InjectPageWorker"/>
</contribution>
<service-point id="DispatchToInjectWorker" interface="EnhancementWorker">
1.2 +84 -24 jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/injection.xml
Index: injection.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/injection.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- injection.xml 15 May 2005 22:56:37 -0000 1.1
+++ injection.xml 19 Jun 2005 16:06:29 -0000 1.2
@@ -31,7 +31,8 @@
<p>
Tapestry 4.0 introduces an entirely new concept into Tapestry application development: property injection.
By use of the &spec.inject; element in page and component specifications, it is possible
-to add new properties to pages or components.
+to add new properties to pages or components, using the &spec.inject; element in the page
+or component specification.
</p>
<p>
@@ -40,35 +41,28 @@
</p>
<p>
-There are four types of property injection built into Tapestry. These types correspond to the
-type attribute of the &spec.inject; element:
+There are different <em>types</em> of injected properties, defined by the type attribute of the &spec.inject;
+element. The type determines how the object attribute is interpreted, and otherwise guides how code
+for the property is generated at runtime. The default type is <strong>object</strong>.
</p>
-<dl>
- <dt>object</dt>
- <dd>
- Injects <link href="hivemind.html">objects defined by the HiveMind Registry</link>.
- </dd>
- <dt>state</dt>
- <dd>
- Creates a property providing access to an &aso;.
- </dd>
- <dt>meta</dt>
- <dd>
- Creates properties that allow access to component meta-data properties, and can automatically
- convert values from strings to other types.
- </dd>
- <dt>script</dt>
- <dd>
- Creates a property containing a parsed &IScript;, ready to execute.
- </dd>
-</dl>
+<p>
+Like so much in Tapestry, this list is open to extension. The
+<link href="&hivedoc;/config/tapestry.enhance.InjectWorkers.html">tapestry.enhance.InjectWorkers</link> configuration point
+defines the available types of injection.
+The <link href="&hivedoc;/config/tapestry.enhance.EnhancementWorkers.html">tapestry.enhance.EnhancementWorkers</link> configuration
+point defines an entire pipeline used to perform runtime code enhancement (of which property injection
+is a critical phase).
+</p>
<p>
-Like so much in Tapestry, this list is open to extension. The tapestry.enhance.InjectWorkers configuration point
-defines new types, and the HiveMind services that implement those types.
+In addition, many other elements support a property attribute; this is the name of a property to create
+that holds the corresponding object. For example, the &spec.bean; element's property allows access
+to a managed bean; the bean is <em>still</em> created on first reference. Components and assets
+may also be injected in this way.
</p>
+
<section id="injection.meta">
<title>meta injection</title>
@@ -115,6 +109,62 @@
</section> <!-- injection.meta -->
+<section id="injection.object">
+ <title>object injection</title>
+
+<p>
+The most common kind of injection, because "object" is the default injection type. The object is a HiveMind object.
+The <link href="hivemind.html">HiveMind integration documentation</link> covers this type
+of injection in more detail.
+</p>
+
+<p>
+
+</p>
+
+</section> <!-- injection.object -->
+
+<section id="injection.page">
+ <title>page injection</title>
+
+<p>
+Page injection allows a page to be injected into another page (or component). Beneather the covers,
+the logic simply accesses the &IRequestCycle; object and obtains the page from it, and adds a
+cast if necessary.
+</p>
+
+<p>
+The property type can be Object, &IPage;, or any type assignable to &IPage;.
+</p>
+
+<p>
+ This is often used with &listener-method;s. For example:
+</p>
+
+<source><![CDATA[
+ <inject property="detailsPage" type="page" object="Details"/>
+]]></source>
+
+<source>
+ public abstract Details getDetailsPage();
+
+ public IPage doShowDetails(long productId)
+ {
+ Details details = getDetailsPage();
+
+ details.setProductId(productId);
+
+ return details;
+ }
+</source>
+
+<p>
+This is a common idiom: getting a page and casting it to its real type, invoking methods upon it,
+then returning it (from the listener method), so that it is activated to render the response.
+</p>
+
+</section> <!-- injection.page -->
+
<section id="injection.script">
<title>script injection</title>
@@ -151,6 +201,16 @@
getScript().execute(cycle, pageRenderSupport, _symbols);
</source>
+</section> <!-- injection.script -->
+
+<section id="injection.state">
+ <title>state injection</title>
+
+<p>
+This style of injection allows easy access to <link href="state.html#state.aso">Application State Objects</link>,
+objects which store various kinds of global information (information needed on many pages).
+</p>
+
</section>
</body>
1.6 +33 -7 jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/listenermethods.xml
Index: listenermethods.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/listenermethods.xml,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- listenermethods.xml 19 Jun 2005 15:00:45 -0000 1.5
+++ listenermethods.xml 19 Jun 2005 16:06:29 -0000 1.6
@@ -50,15 +50,34 @@
</note>
<p>
-A listener method is a public method. It may take parameters, or may not ... the rules are discussed below.
-A simple listener method take no parameters, or takes a single parameter of type &IRequestCycle;.
-A listener method may return void, return a string (the name of a page), or return &IPage; (or an object
-assignable to &IPage;). In
-the latter two cases, the returned page will be <em>activated</em> to render the response. This means that
-in the vast majority of cases, you can write listener methods <em>without</em> the &IRequestCycle; object.
+A listener method is always a public instance method. It may take parameters, or not, and may
+return void or certain other types.
+</p>
+
+<section id="listenermethods.return">
+ <title>Return Type</title>
+
+<p>
+A listener method may return void, may return a string, or may return an object that implements &IPage;.
+The last two options are used to change the <em>active page</em>, the page which will render
+the response. Returning null will not change the active page (it defaults to the page containing the
+link or form components which invoked the listener method).
</p>
<p>
+This control over the returned page, especially when combined with
+<link href="injection.html#injection.page">page injection</link>, means that you will rarely
+need to access the &IRequestCycle; object.
+</p>
+
+</section> <!-- listenermethods.return -->
+
+
+
+<section id="listenermethods.parameters">
+ <title>Listener Method Parameters</title>
+
+<p>
When using the &DirectLink; component, you may specify additional <em>listener parameters</em>. The listener parameters
are encoded into the URL and will be available in a later request, when the listener is triggered.
</p>
@@ -141,12 +160,18 @@
the parameter values (so you can use <code>int</code> and <code>java.lang.Integer</code> interchangeably).
</p>
+</section> <!-- listenermethods.parameters -->
+
+<section id="listenermethods.invoking">
+ <title>Invoking Listener Methods</title>
+
<p>
When creating components that accept a listener as a parameter, you should not invoke the
&IActionListener; directly, instead, you should inject the infrastructure:ListenerInvoker service
into your component, and have it invoke the listener. The ListenerInvoker is extensible, and
-application logic may depend on ListenerInvoker's behavior.
+application logic may depend on ListenerInvoker's behavior (commonly, it is used to mark
+transactions boundaries).
</p>
<p>
@@ -181,5 +206,6 @@
when the listener is an optional parameter.
</p>
+</section> <!-- listenermethods.invoking -->
</body>
</document>
1.1 jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestInjectPageWorker.java
Index: TestInjectPageWorker.java
===================================================================
// Copyright 2005 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.enhance;
import java.lang.reflect.Modifier;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.Location;
import org.apache.hivemind.service.MethodSignature;
import org.apache.hivemind.test.HiveMindTestCase;
import org.apache.tapestry.html.BasePage;
import org.apache.tapestry.spec.InjectSpecification;
import org.apache.tapestry.spec.InjectSpecificationImpl;
import org.easymock.MockControl;
/**
* Tests for {@link org.apache.tapestry.enhance.InjectPageWorker}.
*
* @author Howard Lewis Ship
* @since 4.0
*/
public class TestInjectPageWorker extends HiveMindTestCase
{
public void testPrimitivePropertyType()
{
Location l = newLocation();
MockControl opc = newControl(EnhancementOperation.class);
EnhancementOperation op = (EnhancementOperation) opc.getMock();
op.getPropertyType("somePage");
opc.setReturnValue(int.class);
replayControls();
InjectSpecification is = new InjectSpecificationImpl();
is.setProperty("somePage");
is.setObject("SomePage");
is.setLocation(l);
try
{
new InjectPageWorker().performEnhancement(op, is);
unreachable();
}
catch (ApplicationRuntimeException ex)
{
assertEquals(
"Property somePage is type int, which is not compatible with injection. The property type should be Object, IPage, or a specific page class.",
ex.getMessage());
assertSame(l, ex.getLocation());
}
verifyControls();
}
/**
* Test for when there's no existing property.
*/
public void testNoPropertyType()
{
MockControl opc = newControl(EnhancementOperation.class);
EnhancementOperation op = (EnhancementOperation) opc.getMock();
op.getPropertyType("somePage");
opc.setReturnValue(null);
op.claimProperty("somePage");
op.getAccessorMethodName("somePage");
opc.setReturnValue("getSomePage");
MethodSignature sig = new MethodSignature(Object.class, "getSomePage", null, null);
op.addMethod(
Modifier.PUBLIC,
sig,
"return getPage().getRequestCycle().getPage(\"SomePage\");");
replayControls();
InjectSpecification is = new InjectSpecificationImpl();
is.setProperty("somePage");
is.setObject("SomePage");
new InjectPageWorker().performEnhancement(op, is);
verifyControls();
}
public void testExistingPropertyType()
{
MockControl opc = newControl(EnhancementOperation.class);
EnhancementOperation op = (EnhancementOperation) opc.getMock();
op.getPropertyType("somePage");
opc.setReturnValue(BasePage.class);
op.claimProperty("somePage");
op.getAccessorMethodName("somePage");
opc.setReturnValue("getSomePage");
MethodSignature sig = new MethodSignature(BasePage.class, "getSomePage", null, null);
// BasePage is too specific (the getPage() method returns IPage),
// so we see a cast.
op
.addMethod(
Modifier.PUBLIC,
sig,
"return (org.apache.tapestry.html.BasePage)getPage().getRequestCycle().getPage(\"SomePage\");");
replayControls();
InjectSpecification is = new InjectSpecificationImpl();
is.setProperty("somePage");
is.setObject("SomePage");
new InjectPageWorker().performEnhancement(op, is);
verifyControls();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org