You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/03/03 02:42:37 UTC
svn commit: r918301 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/annotations/
main/java/org/apache/tapestry5/corelib/components/
main/java/org/apache/tapestry5/corelib/mixins/
main/java/org/apache/tapestry5/internal/...
Author: hlship
Date: Wed Mar 3 01:42:37 2010
New Revision: 918301
URL: http://svn.apache.org/viewvc?rev=918301&view=rev
Log:
TAP5-156: Add a @QueryParameter annotation for parameters to event handler method
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/QueryParameter.java (with props)
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/QueryParameterDemo.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/QueryParameterTests.java (with props)
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/QueryParameterDemo.java (with props)
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/QueryParameter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/QueryParameter.java?rev=918301&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/QueryParameter.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/QueryParameter.java Wed Mar 3 01:42:37 2010
@@ -0,0 +1,57 @@
+// Copyright 2010 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.tapestry5.annotations;
+
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.COMPONENT;
+import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.MIXIN;
+import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.PAGE;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.apache.tapestry5.ioc.annotations.UseWith;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.services.Request;
+
+/**
+ * Annotation that may be placed on parameters of event handler methods.
+ * Annotated parameters will be {@linkplain Request#getParameter(String) extracted from the request},
+ * then {@linkplain TypeCoercer coerced} to the type of the parameter. Such parameters are seperate
+ * from ordinary context parameters (extracted from the Request path). Typically, this is used when
+ * client-side JavaScript adds a query parameter to a request to communicate some information from the client
+ * side to the server side.
+ *
+ * @since 5.2.0
+ */
+@Target(
+{ PARAMETER })
+@Retention(RUNTIME)
+@Documented
+@UseWith(
+{ COMPONENT, MIXIN, PAGE })
+public @interface QueryParameter
+{
+ /** The name of the query parameter to extract from the request. */
+ String value();
+
+ /**
+ * If false (the default), then an exception is thrown when the query parameter is read, if it is blank (null or an
+ * empty string). If true, then blank values are allowed.
+ */
+ boolean allowBlank() default false;
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/QueryParameter.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java Wed Mar 3 01:42:37 2010
@@ -1,10 +1,10 @@
-// Copyright 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2007, 2008, 2009, 2010 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
+// 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,
@@ -14,8 +14,21 @@
package org.apache.tapestry5.corelib.components;
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
import org.apache.tapestry5.*;
-import org.apache.tapestry5.annotations.*;
+import org.apache.tapestry5.annotations.Environmental;
+import org.apache.tapestry5.annotations.Events;
+import org.apache.tapestry5.annotations.IncludeJavaScriptLibrary;
+import org.apache.tapestry5.annotations.IncludeStylesheet;
+import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.QueryParameter;
import org.apache.tapestry5.corelib.base.AbstractField;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
@@ -25,30 +38,21 @@
import org.apache.tapestry5.services.ComponentDefaultProvider;
import org.apache.tapestry5.services.Request;
-import java.text.DateFormat;
-import java.text.DateFormatSymbols;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-
/**
* A component used to collect a provided date from the user using a client-side JavaScript calendar. Non-JavaScript
* clients can simply type into a text field.
* <p/>
* One wierd aspect here is that, because client-side JavaScript formatting and parsing is so limited, we (currently)
* use Ajax to send the user's input to the server for parsing (before raising the popup) and formatting (after closing
- * the popup). Wierd and inefficient, but easier than writing client-side JavaScript for that purpose.
+ * the popup). Wierd and inefficient, but easier than writing client-side JavaScript for that purpose.
* <p/>
- * Tapestry's DateField component is a wrapper around <a href="http://webfx.eae.net/dhtml/datepicker/datepicker.html">WebFX
- * DatePicker</a>.
+ * Tapestry's DateField component is a wrapper around <a
+ * href="http://webfx.eae.net/dhtml/datepicker/datepicker.html">WebFX DatePicker</a>.
*/
// TODO: More testing; see https://issues.apache.org/jira/browse/TAPESTRY-1844
@IncludeStylesheet("${tapestry.datepicker}/css/datepicker.css")
-@IncludeJavaScriptLibrary({ "${tapestry.datepicker}/js/datepicker.js",
- "datefield.js"
-})
+@IncludeJavaScriptLibrary(
+{ "${tapestry.datepicker}/js/datepicker.js", "datefield.js" })
@Events(EventConstants.VALIDATE)
public class DateField extends AbstractField
{
@@ -59,7 +63,7 @@
private Date value;
/**
- * Request attribute set to true if localization for the client-side DatePicker has been configured. Used to ensure
+ * Request attribute set to true if localization for the client-side DatePicker has been configured. Used to ensure
* that this only occurs once, regardless of how many DateFields are on the page.
*/
static final String LOCALIZATION_CONFIGURED_FLAG = "tapestry.DateField.localization-configured";
@@ -73,7 +77,7 @@
private DateFormat format;
/**
- * If true, then the text field will be hidden, and only the icon for the date picker will be visible. The default
+ * If true, then the text field will be hidden, and only the icon for the date picker will be visible. The default
* is false.
*/
@Parameter
@@ -124,7 +128,6 @@
private static final String ERROR = "error";
private static final String INPUT_PARAMETER = "input";
-
DateFormat defaultFormat()
{
DateFormat shortDateFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale);
@@ -154,12 +157,12 @@
/**
* Ajax event handler, used when initiating the popup. The client sends the input value form the field to the server
* to parse it according to the server-side format. The response contains a "result" key of the formatted date in a
- * format acceptable to the JavaScript Date() constructor. Alternately, an "error" key indicates the the input was
+ * format acceptable to the JavaScript Date() constructor. Alternately, an "error" key indicates the the input was
* not formatted correct.
*/
- JSONObject onParse()
+ JSONObject onParse(@QueryParameter(INPUT_PARAMETER)
+ String input)
{
- String input = request.getParameter(INPUT_PARAMETER);
JSONObject response = new JSONObject();
try
@@ -181,10 +184,9 @@
* milliseconds since the epoch, to the server, which reformats it according to the server side format and returns
* the result.
*/
- JSONObject onFormat()
+ JSONObject onFormat(@QueryParameter(INPUT_PARAMETER)
+ String input)
{
- String input = request.getParameter(INPUT_PARAMETER);
-
JSONObject response = new JSONObject();
try
@@ -207,27 +209,28 @@
{
String value = tracker.getInput(this);
- if (value == null) value = formatCurrentValue();
+ if (value == null)
+ value = formatCurrentValue();
String clientId = getClientId();
String triggerId = clientId + "-trigger";
writer.element("input",
- "type", hideTextField ? "hidden" : "text",
+ "type", hideTextField ? "hidden" : "text",
- "name", getControlName(),
+ "name", getControlName(),
- "id", clientId,
+ "id", clientId,
- "value", value);
+ "value", value);
writeDisabled(writer);
-
+
putPropertyNameIntoBeanValidationContext("value");
validate.render(writer);
-
+
removePropertyNameFromBeanValidationContext();
resources.renderInformalParameters(writer);
@@ -240,13 +243,13 @@
writer.element("img",
- "id", triggerId,
+ "id", triggerId,
- "class", "t-calendar-trigger",
+ "class", "t-calendar-trigger",
- "src", icon.toClientURL(),
+ "src", icon.toClientURL(),
- "alt", "[Show]");
+ "alt", "[Show]");
writer.end(); // img
JSONObject setup = new JSONObject();
@@ -298,13 +301,14 @@
private void writeDisabled(MarkupWriter writer)
{
- if (isDisabled()) writer.attributes("disabled", "disabled");
+ if (isDisabled())
+ writer.attributes("disabled", "disabled");
}
-
private String formatCurrentValue()
{
- if (value == null) return "";
+ if (value == null)
+ return "";
return format.format(value);
}
@@ -340,7 +344,7 @@
{
tracker.recordError(this, ex.getMessage());
}
-
+
removePropertyNameFromBeanValidationContext();
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java Wed Mar 3 01:42:37 2010
@@ -1,10 +1,10 @@
-// Copyright 2008, 2009 The Apache Software Foundation
+// Copyright 2008, 2009, 2010 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
+// 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,
@@ -14,7 +14,13 @@
package org.apache.tapestry5.corelib.components;
-import org.apache.tapestry5.*;
+import org.apache.tapestry5.BindingConstants;
+import org.apache.tapestry5.CSSClassConstants;
+import org.apache.tapestry5.ClientElement;
+import org.apache.tapestry5.ComponentAction;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.RenderSupport;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.SupportsInformalParameters;
@@ -23,31 +29,44 @@
import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.services.ClientBehaviorSupport;
+import org.apache.tapestry5.services.ClientDataEncoder;
+import org.apache.tapestry5.services.Environment;
+import org.apache.tapestry5.services.FormSupport;
+import org.apache.tapestry5.services.HiddenFieldLocationRules;
import org.slf4j.Logger;
/**
- * A FormFragment is a portion of a Form that may be selectively displayed. Form elements inside a FormFragment will
- * automatically bypass validation when the fragment is invisible. The trick is to also bypass server-side form
- * processing for such fields when the form is submitted; client-side logic "removes" the {@link
- * org.apache.tapestry5.corelib.components.Form#FORM_DATA form data} for the fragment if it is invisible when the form
+ * A FormFragment is a portion of a Form that may be selectively displayed. Form elements inside a FormFragment will
+ * automatically bypass validation when the fragment is invisible. The trick is to also bypass server-side form
+ * processing for such fields when the form is submitted; client-side logic "removes" the
+ * {@link org.apache.tapestry5.corelib.components.Form#FORM_DATA form data} for the fragment if it is invisible when the
+ * form
* is submitted; alternately, client-side logic can simply remove the form fragment element (including its visible and
* hidden fields) to prevent server-side processing.
* <p/>
- * The client-side element has a new property, formFragment, added to it. The formFragment object has new methods to
- * control the client-side behavior of the fragment: <dl> <dt>hide()</dt> <dd>Hides the element, using the configured
- * client-side animation effect.</dd> <dt>hideAndRemove()</dt> <dd>As with hide(), but the element is removed from the
- * DOM after being hidden.</dd> <dt>show()</dt> <dd>Makes the element visible, using the configured client-side
- * animation effect.</dd> <dt>toggle()</dt> <dd>Invokes hide() or show() as necessary.</dd> <dt>setVisible()</dt>
- * <dd>Passed a boolean parameter, invokes hide() or show() as necessary.</dd> </dl>
- *
+ * The client-side element has a new property, formFragment, added to it. The formFragment object has new methods to
+ * control the client-side behavior of the fragment:
+ * <dl>
+ * <dt>hide()</dt>
+ * <dd>Hides the element, using the configured client-side animation effect.</dd>
+ * <dt>hideAndRemove()</dt>
+ * <dd>As with hide(), but the element is removed from the DOM after being hidden.</dd>
+ * <dt>show()</dt>
+ * <dd>Makes the element visible, using the configured client-side animation effect.</dd>
+ * <dt>toggle()</dt>
+ * <dd>Invokes hide() or show() as necessary.</dd>
+ * <dt>setVisible()</dt>
+ * <dd>Passed a boolean parameter, invokes hide() or show() as necessary.</dd>
+ * </dl>
+ *
* @see org.apache.tapestry5.corelib.mixins.TriggerFragment
*/
@SupportsInformalParameters
public class FormFragment implements ClientElement
{
/**
- * Determines if the fragment is intially visible or initially invisible (the default). This is only used when
+ * Determines if the fragment is initially visible or initially invisible (the default). This is only used when
* rendering; when the form is submitted, the hidden field value is used to determine whether the elements within
* the fragment should be processed (or ignored if still invisible).
*/
@@ -82,7 +101,6 @@
@Parameter(name = "id", defaultPrefix = BindingConstants.LITERAL)
private String idParameter;
-
@Inject
private Environment environment;
@@ -90,9 +108,6 @@
private RenderSupport renderSupport;
@Inject
- private ComponentSource componentSource;
-
- @Inject
private ComponentResources resources;
@Environmental
@@ -103,9 +118,6 @@
private ComponentActionSink componentActions;
@Inject
- private Request request;
-
- @Inject
private Logger logger;
@Inject
@@ -166,7 +178,7 @@
}
};
- // Tada! Now all the enclosed components will use our override of FormSupport,
+ // Tada! Now all the enclosed components will use our override of FormSupport,
// until we pop it off.
environment.push(FormSupport.class, override);
@@ -176,20 +188,18 @@
/**
* Closes the <div> tag and pops off the {@link org.apache.tapestry5.services.FormSupport} environmental
* override.
- *
+ *
* @param writer
*/
void afterRender(MarkupWriter writer)
{
- hiddenFieldPositioner.getElement().attributes(
- "type", "hidden",
+ hiddenFieldPositioner.getElement().attributes("type", "hidden",
- "name", Form.FORM_DATA,
+ "name", Form.FORM_DATA,
- "id", clientId + "-hidden",
+ "id", clientId + "-hidden",
- "value", componentActions.getClientData()
- );
+ "value", componentActions.getClientData());
writer.end(); // div
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java Wed Mar 3 01:42:37 2010
@@ -1,4 +1,4 @@
-// Copyright 2008, 2009 The Apache Software Foundation
+// Copyright 2008, 2009, 2010 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.
@@ -14,27 +14,34 @@
package org.apache.tapestry5.corelib.components;
+import java.io.IOException;
+
import org.apache.tapestry5.*;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Events;
import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.QueryParameter;
import org.apache.tapestry5.annotations.SupportsInformalParameters;
import org.apache.tapestry5.corelib.data.InsertPosition;
import org.apache.tapestry5.corelib.internal.ComponentActionSink;
import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
import org.apache.tapestry5.corelib.internal.InternalFormSupport;
import org.apache.tapestry5.dom.Element;
-import org.apache.tapestry5.internal.services.ComponentResultProcessorWrapper;
import org.apache.tapestry5.internal.services.PageRenderQueue;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.internal.util.IdAllocator;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.json.JSONObject;
-import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.services.ClientBehaviorSupport;
+import org.apache.tapestry5.services.ClientDataEncoder;
+import org.apache.tapestry5.services.ComponentSource;
+import org.apache.tapestry5.services.Environment;
+import org.apache.tapestry5.services.FormSupport;
+import org.apache.tapestry5.services.Heartbeat;
+import org.apache.tapestry5.services.HiddenFieldLocationRules;
+import org.apache.tapestry5.services.PartialMarkupRenderer;
+import org.apache.tapestry5.services.PartialMarkupRendererFilter;
import org.slf4j.Logger;
-import java.io.IOException;
-
/**
* A way to add new content to an existing Form. The FormInjector emulates its tag from the template (or uses a
* <div>). When triggered, new content is obtained from the application and is injected before or after the
@@ -104,9 +111,6 @@
private ComponentResources resources;
@Inject
- private Request request;
-
- @Inject
private Environment environment;
@Inject
@@ -175,7 +179,13 @@
* event notification is what will ultimately render (typically, its a Block). However, we do a <em>lot</em> of
* tricks to provide the desired FormSupport around the what renders.
*/
- void onInject(EventContext context) throws IOException
+ void onInject(EventContext context,
+
+ @QueryParameter(FORM_CLIENTID_PARAMETER)
+ final String formClientId,
+
+ @QueryParameter(FORM_COMPONENTID_PARAMETER)
+ String formComponentId) throws IOException
{
resources.triggerContextEvent(EventConstants.ACTION, context, eventCallback);
@@ -184,10 +194,6 @@
// Here's where it gets very, very tricky.
- final String formClientId = readParameterValue(FORM_CLIENTID_PARAMETER);
-
- String formComponentId = request.getParameter(FORM_COMPONENTID_PARAMETER);
-
final Form form = (Form) componentSource.getComponent(formComponentId);
final ComponentActionSink actionSink = new ComponentActionSink(logger, clientDataEncoder);
@@ -238,15 +244,4 @@
pageRenderQueue.addPartialMarkupRendererFilter(filter);
}
-
- private String readParameterValue(String parameterName)
- {
- String value = request.getParameter(parameterName);
-
- if (InternalUtils.isBlank(value))
- throw new RuntimeException(String.format(
- "Query parameter '%s' was blank, but should have been specified in the request.", parameterName));
-
- return value;
- }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java Wed Mar 3 01:42:37 2010
@@ -243,12 +243,14 @@
}
}
- Object onChange()
- {
- final String formId = this.request.getParameter(FORM_COMPONENTID_PARAMETER);
+ Object onChange(
- final String changedValue = this.request.getParameter("t:selectvalue");
+ @QueryParameter(FORM_COMPONENTID_PARAMETER)
+ final String formId,
+ @QueryParameter(value = "t:selectvalue", allowBlank = true)
+ final String changedValue)
+ {
final Object newValue = toValue(changedValue);
final Holder<Object> holder = Holder.create();
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java Wed Mar 3 01:42:37 2010
@@ -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,
@@ -41,10 +41,11 @@
* Multiple selection on the client is enabled by binding the tokens parameter (however, the mixin doesn't help split
* multiple selections up on the server, that is still your code's responsibility).
* <p/>
- * The container is responsible for providing an event handler for event "providecompletions". The context will be the
- * partial input string sent from the client. The return value should be an array or list of completions, in
- * presentation order. I.e.
+ * The container is responsible for providing an event handler for event "providecompletions". The context will be the
+ * partial input string sent from the client. The return value should be an array or list of completions, in
+ * presentation order. I.e.
* <p/>
+ *
* <pre>
* String[] onProvideCompletionsFromMyField(String input)
* {
@@ -52,7 +53,8 @@
* }
* </pre>
*/
-@IncludeJavaScriptLibrary({ "${tapestry.scriptaculous}/controls.js", "autocomplete.js" })
+@IncludeJavaScriptLibrary(
+{ "${tapestry.scriptaculous}/controls.js", "autocomplete.js" })
@Events(EventConstants.PROVIDE_COMPLETIONS)
public class Autocomplete
{
@@ -73,9 +75,6 @@
private RenderSupport renderSupport;
@Inject
- private Request request;
-
- @Inject
private TypeCoercer coercer;
@Inject
@@ -94,7 +93,6 @@
@Inject
private ResponseRenderer responseRenderer;
-
/**
* Overrides the default check frequency for determining whether to send a server request. The default is .4
* seconds.
@@ -112,7 +110,7 @@
/**
* Mixin afterRender phrase occurs after the component itself. This is where we write the <div> element and
* the JavaScript.
- *
+ *
* @param writer
*/
void afterRender(MarkupWriter writer)
@@ -127,32 +125,33 @@
writer.element("img",
- "src", spacerImage.toClientURL(),
+ "src", spacerImage.toClientURL(),
- "class", "t-autoloader-icon " + CSSClassConstants.INVISIBLE,
+ "class", "t-autoloader-icon " + CSSClassConstants.INVISIBLE,
- "alt", "",
+ "alt", "",
- "id", loaderId);
+ "id", loaderId);
writer.end();
writer.element("div",
- "id", menuId,
+ "id", menuId,
- "class", "t-autocomplete-menu");
+ "class", "t-autocomplete-menu");
writer.end();
Link link = resources.createEventLink(EVENT_NAME);
-
JSONObject config = new JSONObject();
config.put("paramName", PARAM_NAME);
config.put("indicator", loaderId);
- if (resources.isBound("minChars")) config.put("minChars", minChars);
+ if (resources.isBound("minChars"))
+ config.put("minChars", minChars);
- if (resources.isBound("frequency")) config.put("frequency", frequency);
+ if (resources.isBound("frequency"))
+ config.put("frequency", frequency);
if (resources.isBound("tokens"))
{
@@ -168,10 +167,9 @@
renderSupport.addInit("autocompleter", new JSONArray(id, menuId, link.toAbsoluteURI(), config));
}
- Object onAutocomplete()
+ Object onAutocomplete(@QueryParameter(PARAM_NAME)
+ String input)
{
- String input = request.getParameter(PARAM_NAME);
-
final Holder<List> matchesHolder = Holder.create();
// Default it to an empty list.
@@ -190,7 +188,8 @@
}
};
- resources.triggerEvent(EventConstants.PROVIDE_COMPLETIONS, new Object[] { input }, callback);
+ resources.triggerEvent(EventConstants.PROVIDE_COMPLETIONS, new Object[]
+ { input }, callback);
ContentType contentType = responseRenderer.findContentType(this);
@@ -208,8 +207,9 @@
* <p/>
* <p/>
* This implementation does nothing.
- *
- * @param config parameters object
+ *
+ * @param config
+ * parameters object
*/
protected void configure(JSONObject config)
{
@@ -219,9 +219,11 @@
* Generates the markup response that will be returned to the client; this should be an <ul> element with
* nested <li> elements. Subclasses may override this to produce more involved markup (including images and
* CSS class attributes).
- *
- * @param writer to write the list to
- * @param matches list of matching objects, each should be converted to a string
+ *
+ * @param writer
+ * to write the list to
+ * @param matches
+ * list of matching objects, each should be converted to a string
*/
protected void generateResponseMarkup(MarkupWriter writer, List matches)
{
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java Wed Mar 3 01:42:37 2010
@@ -98,6 +98,8 @@
private Boolean override;
+ private List<List<Annotation>> parameterAnnotations;
+
TransformMethodImpl(CtMethod method, boolean added)
{
this.method = method;
@@ -125,6 +127,39 @@
return findAnnotationInList(annotationClass, annotations);
}
+ public <A extends Annotation> A getParameterAnnotation(int index, Class<A> annotationType)
+ {
+ if (parameterAnnotations == null)
+ extractParameterAnnotations();
+
+ return findAnnotationInList(annotationType, parameterAnnotations.get(index));
+ }
+
+ private void extractParameterAnnotations()
+ {
+ int count = sig.getParameterTypes().length;
+
+ parameterAnnotations = CollectionFactory.newList();
+
+ for (int parameterIndex = 0; parameterIndex < count; parameterIndex++)
+ {
+ List<Annotation> annotations = extractAnnotationsForParameter(parameterIndex);
+
+ parameterAnnotations.add(annotations);
+ }
+ }
+
+ private List<Annotation> extractAnnotationsForParameter(int parameterIndex)
+ {
+ List<Annotation> result = CollectionFactory.newList();
+
+ Object[] parameterAnnotations = method.getAvailableParameterAnnotations()[parameterIndex];
+
+ addAnnotationsToList(result, parameterAnnotations, false);
+
+ return result;
+ }
+
public TransformMethodSignature getSignature()
{
return sig;
@@ -317,7 +352,6 @@
return methodName;
}
-
public String getMethodIdentifier()
{
if (identifier == null)
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java Wed Mar 3 01:42:37 2010
@@ -20,16 +20,22 @@
import org.apache.tapestry5.EventContext;
import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.QueryParameter;
+import org.apache.tapestry5.internal.services.ComponentClassCache;
import org.apache.tapestry5.ioc.Predicate;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.model.MutableComponentModel;
import org.apache.tapestry5.runtime.ComponentEvent;
import org.apache.tapestry5.services.ClassTransformation;
import org.apache.tapestry5.services.ComponentClassTransformWorker;
import org.apache.tapestry5.services.ComponentMethodAdvice;
import org.apache.tapestry5.services.ComponentMethodInvocation;
+import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.TransformConstants;
import org.apache.tapestry5.services.TransformMethod;
+import org.apache.tapestry5.services.TransformMethodSignature;
/**
* Provides implementations of the
@@ -38,6 +44,13 @@
*/
public class OnEventWorker implements ComponentClassTransformWorker
{
+
+ private final Request request;
+
+ private final TypeCoercer typeCoercer;
+
+ private final ComponentClassCache classCache;
+
/**
* Stores a couple of special parameter type mappings that are used when matching the entire event context
* (either as Object[] or EventContext).
@@ -77,6 +90,13 @@
});
}
+ public OnEventWorker(Request request, TypeCoercer typeCoercer, ComponentClassCache classCache)
+ {
+ this.request = request;
+ this.typeCoercer = typeCoercer;
+ this.classCache = classCache;
+ }
+
public void transform(ClassTransformation transformation, MutableComponentModel model)
{
List<TransformMethod> methods = matchEventHandlerMethods(transformation);
@@ -84,7 +104,7 @@
if (methods.isEmpty())
return;
- List<EventHandlerMethodInvoker> invokers = toInvokers(methods);
+ List<EventHandlerMethodInvoker> invokers = toInvokers(transformation.getClassName(), methods);
updateModelWithHandledEvents(model, invokers);
@@ -175,19 +195,19 @@
});
}
- private List<EventHandlerMethodInvoker> toInvokers(List<TransformMethod> methods)
+ private List<EventHandlerMethodInvoker> toInvokers(String componentClassName, List<TransformMethod> methods)
{
List<EventHandlerMethodInvoker> result = CollectionFactory.newList();
for (TransformMethod method : methods)
{
- result.add(toInvoker(method));
+ result.add(toInvoker(componentClassName, method));
}
return result;
}
- private EventHandlerMethodInvoker toInvoker(TransformMethod method)
+ private EventHandlerMethodInvoker toInvoker(final String componentClassName, TransformMethod method)
{
OnEvent annotation = method.getAnnotation(OnEvent.class);
@@ -196,7 +216,9 @@
String eventType = extractEventType(methodName, annotation);
String componentId = extractComponentId(methodName, annotation);
- String[] parameterTypes = method.getSignature().getParameterTypes();
+ final TransformMethodSignature signature = method.getSignature();
+
+ String[] parameterTypes = signature.getParameterTypes();
if (parameterTypes.length == 0)
return new BaseEventHandlerMethodInvoker(method, eventType, componentId);
@@ -206,16 +228,27 @@
// I'd refactor a bit more of this if Java had covariant return types.
int contextIndex = 0;
- boolean catchAll = false;
- for (final String type : parameterTypes)
+ for (int i = 0; i < parameterTypes.length; i++)
{
+ String type = parameterTypes[i];
+
EventHandlerMethodParameterSource source = parameterTypeToSource.get(type);
if (source != null)
{
sources.add(source);
- catchAll = true;
+ continue;
+ }
+
+ QueryParameter parameterAnnotation = method.getParameterAnnotation(i, QueryParameter.class);
+
+ if (parameterAnnotation != null)
+ {
+ String parameterName = parameterAnnotation.value();
+
+ sources.add(createQueryParameterSource(componentClassName, signature, i, parameterName, type,
+ parameterAnnotation.allowBlank()));
continue;
}
@@ -224,12 +257,54 @@
final int parameterIndex = contextIndex++;
- sources.add(createParameterSource(type, parameterIndex));
+ sources.add(createEventContextSource(type, parameterIndex));
}
- int minContextCount = catchAll ? 0 : contextIndex;
+ return createInvoker(method, eventType, componentId, contextIndex, sources);
+ }
+
+ private EventHandlerMethodParameterSource createQueryParameterSource(final String componentClassName,
+ final TransformMethodSignature signature, final int parameterIndex, final String parameterName,
+ final String parameterTypeName, final boolean allowBlank)
+ {
+ return new EventHandlerMethodParameterSource()
+ {
+ @SuppressWarnings("unchecked")
+ public Object valueForEventHandlerMethodParameter(ComponentEvent event)
+ {
+ try
+ {
+ String parameterValue = request.getParameter(parameterName);
+
+ if (!allowBlank && InternalUtils.isBlank(parameterValue))
+ throw new RuntimeException(String.format(
+ "The value for query parameter '%s' was blank, but a non-blank value is needed.",
+ parameterName));
- return createInvoker(method, eventType, componentId, minContextCount, sources);
+ Class parameterType = classCache.forName(parameterTypeName);
+
+ Object coerced = typeCoercer.coerce(parameterValue, parameterType);
+
+ if (parameterType.isPrimitive() && coerced == null)
+ throw new RuntimeException(
+ String
+ .format(
+ "Query parameter '%s' evaluates to null, but the event method parameter is type %s, a primitive.",
+ parameterName, parameterType.getName()));
+
+ return coerced;
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException(
+ String
+ .format(
+ "Unable process query parameter '%s' as parameter #%d of event handler method %s (in class %s): %s",
+ parameterName, parameterIndex + 1, signature, componentClassName,
+ InternalUtils.toMessage(ex)), ex);
+ }
+ }
+ };
}
private EventHandlerMethodInvoker createInvoker(TransformMethod method, String eventType, String componentId,
@@ -260,7 +335,7 @@
};
}
- private EventHandlerMethodParameterSource createParameterSource(final String type, final int parameterIndex)
+ private EventHandlerMethodParameterSource createEventContextSource(final String type, final int parameterIndex)
{
return new EventHandlerMethodParameterSource()
{
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Wed Mar 3 01:42:37 2010
@@ -555,7 +555,7 @@
configuration.add("MixinAfter", new MixinAfterWorker());
configuration.add("Component", new ComponentWorker(resolver));
configuration.add("Mixin", new MixinWorker(resolver));
- configuration.add("OnEvent", new OnEventWorker());
+ configuration.addInstance("OnEvent", OnEventWorker.class);
configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker());
configuration.addInstance("InjectPage", InjectPageWorker.class);
configuration.addInstance("InjectContainer", InjectContainerWorker.class);
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java Wed Mar 3 01:42:37 2010
@@ -14,6 +14,8 @@
package org.apache.tapestry5.services;
+import java.lang.annotation.Annotation;
+
import org.apache.tapestry5.ioc.AnnotationProvider;
/**
@@ -71,4 +73,14 @@
*/
boolean isOverride();
+ /**
+ * Gets an annotation on a parameter of the method.
+ *
+ * @param index
+ * index of parameter
+ * @param annotationType
+ * type of annotation to check for
+ * @return the annotation, if found, or null
+ */
+ <A extends Annotation> A getParameterAnnotation(int index, Class<A> annotationType);
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/QueryParameterDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/QueryParameterDemo.tml?rev=918301&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/QueryParameterDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/QueryParameterDemo.tml Wed Mar 3 01:42:37 2010
@@ -0,0 +1,25 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+ <h1>QueryParameter Annotation Demo</h1>
+
+ <p>
+ The current value is:
+ <span id="current">${value}</span>
+ .
+ </p>
+
+ <ul>
+ <li>
+ <a href="${workingLink}">Working Link</a>
+ </li>
+ <li>
+ <a href="${brokenLink}">Broken Link</a>
+ </li>
+ <li>
+ <a href="${nullLink}">Null Link</a>
+ </li>
+ <li>
+ <a href="${nullAllowedLink}">Null Allowed Link</a>
+ </li>
+ </ul>
+</html>
\ No newline at end of file
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/QueryParameterTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/QueryParameterTests.java?rev=918301&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/QueryParameterTests.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/QueryParameterTests.java Wed Mar 3 01:42:37 2010
@@ -0,0 +1,59 @@
+// Copyright 2010 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.tapestry5.integration.app1;
+
+import org.apache.tapestry5.integration.TapestryCoreTestCase;
+import org.testng.annotations.Test;
+
+public class QueryParameterTests extends TapestryCoreTestCase
+{
+ @Test
+ public void successful_use_of_query_parameter_annotation()
+ {
+ clickThru("QueryParameter Annotation Demo", "Working Link");
+
+ assertText("id=current", "97");
+ }
+
+ @Test
+ public void null_value_when_not_allowed()
+ {
+ clickThru("QueryParameter Annotation Demo", "Null Link");
+
+ assertTextPresent(
+ "Unable process query parameter 'gnip' as parameter #1 of event handler method void onFrob(int) (in class org.apache.tapestry5.integration.app1.pages.QueryParameterDemo)",
+ "The value for query parameter 'gnip' was blank, but a non-blank value is needed.");
+ }
+
+ @Test
+ public void null_for_primitive_when_allowed()
+ {
+ clickThru("QueryParameter Annotation Demo", "Null Allowed Link");
+
+ assertTextPresent(
+ "Unable process query parameter 'gnip' as parameter #1 of event handler method void onFrobNullAllowed(int) (in class org.apache.tapestry5.integration.app1.pages.QueryParameterDemo)",
+ "Query parameter 'gnip' evaluates to null, but the event method parameter is type int, a primitive.");
+ }
+
+ @Test
+ public void type_mismatch_for_method_parameter()
+ {
+ clickThru("QueryParameter Annotation Demo", "Broken Link");
+
+ assertTextPresent(
+ "Unable process query parameter 'gnip' as parameter #1 of event handler method void onFrob(int) (in class org.apache.tapestry5.integration.app1.pages.QueryParameterDemo)",
+ "Coercion of frodo to type java.lang.Integer");
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/QueryParameterTests.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java?rev=918301&r1=918300&r2=918301&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java Wed Mar 3 01:42:37 2010
@@ -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,
@@ -66,7 +66,10 @@
private static final List<Item> ITEMS = CollectionFactory
.newList(
-
+
+ new Item("QueryParameterDemo", "QueryParameter Annotation Demo",
+ "Use of @QueryParameter annotation on event handler method parameters"),
+
new Item("CancelDemo", "Cancel Demo", "Use of the cancel option with Submit"),
new Item("PageResetDemo", "PageReset Annotation Demo",
@@ -85,11 +88,9 @@
new Item("FormZoneDemo", "Form Zone Demo", "Use a form to update a zone."),
- new Item("ZoneUpdateNamespace", "Zone/Namespace Interaction",
- "Prove that TAP5-573 is fixed"),
+ new Item("ZoneUpdateNamespace", "Zone/Namespace Interaction", "Prove that TAP5-573 is fixed"),
- new Item("AbstractComponentDemo", "Abstract Component Demo",
- "Error when a component is abstract"),
+ new Item("AbstractComponentDemo", "Abstract Component Demo", "Error when a component is abstract"),
new Item("TemplateOverrideDemo", "Template Override Demo",
"Child component extends and overrides parent template."),
@@ -103,8 +104,7 @@
new Item("SlowAjaxDemo", "Slow Ajax Demo",
"Handling of client-side Ajax before the page is fully loaded"),
- new Item("ProgressiveDemo", "ProgressiveDisplay Demo",
- "Progressive Enhancement via a component"),
+ new Item("ProgressiveDemo", "ProgressiveDisplay Demo", "Progressive Enhancement via a component"),
new Item("ClientNumericValidationDemo", "Client-Side Numeric Validation",
"Client-side locale-specific validation"),
@@ -114,16 +114,13 @@
new Item("LinkSubmitDemo", "LinkSubmit Demo", "JavaScript LinkSubmit component"),
- new Item(
- "LinkSubmitWithoutValidatorDemo",
- "LinkSubmit Without Validator Demo",
+ new Item("LinkSubmitWithoutValidatorDemo", "LinkSubmit Without Validator Demo",
"Demonstrates that the LinkSubmit component is working without a validator on any of fields in the form"),
new Item("PerFormValidationMessageDemo", "Per-Form Validation Messages",
"Per-form configuration of validation messages and constraints."),
- new Item("EmptyLoopDemo", "Empty Loop Demo",
- "Use of empty parameter with the Loop component."),
+ new Item("EmptyLoopDemo", "Empty Loop Demo", "Use of empty parameter with the Loop component."),
new Item("BlankPasswordDemo", "Blank Password Demo",
"Show that a blank value in a PasswordField does not update the server side value."),
@@ -134,8 +131,7 @@
new Item("DateFieldAjaxFormLoop", "DateField inside AjaxFormLoop",
"Show that DateField component works correctly inside AjaxFormLoop"),
- new Item("NestedForm", "Nested Form Demo",
- "Error when a Form is nested inside another Form."),
+ new Item("NestedForm", "Nested Form Demo", "Error when a Form is nested inside another Form."),
new Item("UnhandledEventDemo", "Unhandled Event Demo",
"Events that don't have matching event handlers cause exceptions"),
@@ -143,52 +139,42 @@
new Item("PrimitiveDefaultDemo", "Primitive Default Demo",
"Primitive value returned from parameter default method"),
- new Item("ValidateFormValidationExceptionDemo",
- "ValidationForm ValidationException Demo",
+ new Item("ValidateFormValidationExceptionDemo", "ValidationForm ValidationException Demo",
"Throwing a ValidationException from the validateForm event handler."),
- new Item("ClientFormatDemo", "Client Format Validation",
- "Client-side input format validation"),
+ new Item("ClientFormatDemo", "Client Format Validation", "Client-side input format validation"),
new Item("ShortGrid", "Short Grid",
"Grid where the number of claimed rows is less than the number of actual rows"),
- new Item("NullParameterDemo", "Null Parameter Demo",
- "Binding a not-null parameter to null."),
+ new Item("NullParameterDemo", "Null Parameter Demo", "Binding a not-null parameter to null."),
new Item("nestedbeaneditor", "Nested BeanEditor",
"BeanEditor as override for property editor in BeanEditForm"),
new Item("actionpage", "Action Page", "tests fixture for ActionLink component"),
- new Item("cleancachedemo", "Clean Cache Demo",
- "cache cleared properly during Ajax calls"),
+ new Item("cleancachedemo", "Clean Cache Demo", "cache cleared properly during Ajax calls"),
new Item("numberbeaneditordemo", "Number BeanEditor Demo",
"use of nulls and wrapper types with BeanEditor"),
- new Item("forminjectordemo", "FormInjector Demo",
- "extending a form dynamically via Ajax"),
+ new Item("forminjectordemo", "FormInjector Demo", "extending a form dynamically via Ajax"),
new Item("music", "Music Page", "demo handling of edge cases of page naming"),
- new Item("PersistentDemo", "Persistent Demo",
- "storing and clearing persistent properties"),
+ new Item("PersistentDemo", "Persistent Demo", "storing and clearing persistent properties"),
- new Item("ActionViaLinkDemo", "Action via Link Demo",
- "tests creating an action link explicitly"),
+ new Item("ActionViaLinkDemo", "Action via Link Demo", "tests creating an action link explicitly"),
- new Item("FormFragmentDemo", "Form Fragment Demo",
- "page with dynamic form sections"),
+ new Item("FormFragmentDemo", "Form Fragment Demo", "page with dynamic form sections"),
new Item("BooleanDemo", "Boolean Property Demo",
"demo boolean properties using both is and get prefixes"),
- new Item("DeleteFromGridDemo", "Delete From Grid",
- "demo deleting items form a Grid"),
+ new Item("DeleteFromGridDemo", "Delete From Grid", "demo deleting items form a Grid"),
- new Item("RenderErrorDemo", "Render Error Demo",
- "reporting of errors while rendering"),
+ new Item("RenderErrorDemo", "Render Error Demo", "reporting of errors while rendering"),
new Item("nested/AssetDemo", "AssetDemo", "declaring an image using Assets"),
@@ -197,13 +183,11 @@
new Item("blockdemo", "BlockDemo", "use of blocks to control rendering"),
- new Item("countdown", "Countdown Page",
- "defining component using @Component annotation"),
+ new Item("countdown", "Countdown Page", "defining component using @Component annotation"),
new Item("injectdemo", "Inject Demo", "use of various kinds of injection"),
- new Item("instancemixin", "InstanceMixin",
- "mixin added to a particular component instance"),
+ new Item("instancemixin", "InstanceMixin", "mixin added to a particular component instance"),
new Item("TextFieldWrapperTypeDemo", "TextField Wrapper Types",
"use of TextField to edit numeric wrapper types (not primitives) "),
@@ -216,19 +200,16 @@
new Item("ExpansionSubclass", "ExpansionSubclass",
"components can inherit templates from base classes"),
- new Item("Localization", "Localization",
- "access localized messages from the component catalog"),
+ new Item("Localization", "Localization", "access localized messages from the component catalog"),
new Item("NumberSelect", "NumberSelect", "passivate/activate page context demo"),
new Item("ParameterConflict", "Template Overridden by Class Page",
"Parameters in the class override those in the template"),
- new Item("ParameterDefault", "ParameterDefault",
- "defaulter methods for component parameters"),
+ new Item("ParameterDefault", "ParameterDefault", "defaulter methods for component parameters"),
- new Item("passwordfielddemo", "PasswordFieldDemo",
- "test for the PasswordField component"),
+ new Item("passwordfielddemo", "PasswordFieldDemo", "test for the PasswordField component"),
new Item("rendercomponentdemo", "RenderComponentDemo",
"components that \"nominate\" other components to render"),
@@ -236,29 +217,24 @@
new Item("renderphaseorder", "RenderPhaseOrder",
"order of operations when invoking render phase methods"),
- new Item("simpleform", "SimpleForm",
- "first pass at writing Form and TextField components"),
+ new Item("simpleform", "SimpleForm", "first pass at writing Form and TextField components"),
new Item("validform", "ValidForm", "server-side input validation"),
- new Item("ToDoListVolatile", "ToDo List (Volatile)",
- "Loops and Submit inside Form, volatile mode"),
+ new Item("ToDoListVolatile", "ToDo List (Volatile)", "Loops and Submit inside Form, volatile mode"),
new Item("MissingTemplate", "Missing Template Demo",
"Demo for what happens when a template is not found for a page"),
new Item("nested/zonedemo", "Zone Demo", "dynamic updates within a page"),
- new Item("todolist", "ToDo List",
- "Loops and Submit inside Form using primary key encoder"),
+ new Item("todolist", "ToDo List", "Loops and Submit inside Form using primary key encoder"),
new Item("flashdemo", "FlashDemo", "demonstrate 'flash' persistence"),
- new Item("beaneditordemo", "BeanEditor Demo",
- "demonstrate the BeanEditor mega-component"),
+ new Item("beaneditordemo", "BeanEditor Demo", "demonstrate the BeanEditor mega-component"),
- new Item("pageloadeddemo", "PageLoaded Demo",
- "shows that page lifecycle methods are invoked"),
+ new Item("pageloadeddemo", "PageLoaded Demo", "shows that page lifecycle methods are invoked"),
new Item("griddemo", "Grid Demo", "default Grid component"),
@@ -274,8 +250,7 @@
new Item("protected", "Protected Page",
"Demonstrate result of non-void return from a page's activate method"),
- new Item("Kicker", "Kicker",
- "demos complex page and component context in links"),
+ new Item("Kicker", "Kicker", "demos complex page and component context in links"),
new Item("simpletrackgriddemo", "SimpleTrack Grid Demo",
"customizing the model for a Grid around an interface"),
@@ -283,14 +258,11 @@
new Item("pagelinkcontext", "PageLink Context Demo",
"passing explicit context in a page render link"),
- new Item("pagecontextinform", "Page Context in Form",
- "passivate/activate page context in Form"),
+ new Item("pagecontextinform", "Page Context in Form", "passivate/activate page context in Form"),
- new Item("ValidBeanEditorDemo", "Client Validation Demo",
- "BeanEditor with validation enabled"),
+ new Item("ValidBeanEditorDemo", "Client Validation Demo", "BeanEditor with validation enabled"),
- new Item("Unreachable", "Unreachable Page",
- "page not reachable due to IgnoredPathsFilter"),
+ new Item("Unreachable", "Unreachable Page", "page not reachable due to IgnoredPathsFilter"),
new Item("renderabledemo", "Renderable Demo",
"shows that render phase methods can return a Renderable"),
@@ -306,8 +278,7 @@
new Item("PaletteDemo", "Palette Demo", "multiple selection component"),
- new Item("ReturnTypes", "Return Types",
- "tests various event handler return types"),
+ new Item("ReturnTypes", "Return Types", "tests various event handler return types"),
new Item("FormEncodingType", "Form Encoding Type",
"Test ability to set an encoding type for a Form"),
@@ -324,8 +295,7 @@
new Item("GridFormDemo", "Grid Form Demo", "Grid operating inside a Form"),
- new Item("DateFieldDemo", "DateField Demo",
- "using DateField by itself on a page"),
+ new Item("DateFieldDemo", "DateField Demo", "using DateField by itself on a page"),
new Item("BeanEditDateDemo", "BeanEditor / Date Demo",
"Use of date properties inside BeanEditor and BeanDisplay"),
@@ -342,21 +312,15 @@
new Item("inheritinformalsdemo", "Inherit Informal Parameters Demo",
"Demo a component which inherits informal parameters from its container"),
- new Item(
- "disabledfields",
- "Disabled Fields",
+ new Item("disabledfields", "Disabled Fields",
"Demonstrate a bunch of disabled fields, to verify that the RenderDisabled mixin works and is being used properly"),
- new Item(
- "BeanEditorOverride",
- "BeanEditor Override",
+ new Item("BeanEditorOverride", "BeanEditor Override",
"Property editor overrides work for the BeanEditor component itself (not just the BeanEditForm component)"),
new Item("varbindingdemo", "Var Binding Demo", "use of the var: binding prefix"),
- new Item(
- "leangriddemo",
- "Lean Grid Demo",
+ new Item("leangriddemo", "Lean Grid Demo",
"Grid component with lean parameter turned on, to eliminate CSS class attributes in TD and TH elements"),
new Item("blockcaller", "Action Links off of Active Page",
@@ -367,23 +331,19 @@
new Item("MagicValueEncoder", "Magic ValueEncoder Demo",
"Automatic creation of ValueEncoder using the TypeCoercer"),
- new Item("NullStrategyDemo", "Null Field Strategy Demo",
- "use of the nulls parameter of TextField"),
+ new Item("NullStrategyDemo", "Null Field Strategy Demo", "use of the nulls parameter of TextField"),
new Item("OverrideValidationDecorator", "Override Validation Decorator",
"override the default validation decorator"),
- new Item("ExceptionEventDemo", "Exception Event Demo",
- "handling component event exceptions"),
+ new Item("ExceptionEventDemo", "Exception Event Demo", "handling component event exceptions"),
- new Item("AddedGridColumnsDemo", "Added Grid Columns Demo",
- "programatically adding grid columns"),
+ new Item("AddedGridColumnsDemo", "Added Grid Columns Demo", "programatically adding grid columns"),
new Item("PrimitiveArrayParameterDemo", "Primitive Array Parameter Demo",
"use primitive array as parameter type"),
- new Item("RenderPhaseMethodExceptionDemo",
- "Render Phase Method Exception Demo",
+ new Item("RenderPhaseMethodExceptionDemo", "Render Phase Method Exception Demo",
"render phase methods may throw checked exceptions"),
new Item("TrackEditor", "Generic Page Class Demo",
@@ -392,22 +352,17 @@
new Item("IndirectProtectedFields", "Protected Fields Demo",
"demo exception when component class contains protected fields"),
- new Item("injectcomponentdemo", "Inject Component Demo",
- "inject component defined in template"),
+ new Item("injectcomponentdemo", "Inject Component Demo", "inject component defined in template"),
new Item("cachedpage", "Cached Annotation", "Caching method return values"),
- new Item("cachedpage2", "Cached Annotation2",
- "Caching method return values w/ inheritence"),
+ new Item("cachedpage2", "Cached Annotation2", "Caching method return values w/ inheritence"),
- new Item("inplacegriddemo", "In-Place Grid Demo",
- "Grid that updates in-place using Ajax"),
+ new Item("inplacegriddemo", "In-Place Grid Demo", "Grid that updates in-place using Ajax"),
- new Item("methodadvicedemo", "Method Advice Demo",
- "Advising component methods."),
+ new Item("methodadvicedemo", "Method Advice Demo", "Advising component methods."),
- new Item("HasBodyDemo", "Has Body Demo",
- "Verify the hasBody() method of ComponentResources"),
+ new Item("HasBodyDemo", "Has Body Demo", "Verify the hasBody() method of ComponentResources"),
new Item("BeanEditorBeanEditContext", "BeanEditor BeanEditContext",
"BeanEditContext is pushed into enviroment by BeanEditor."),
@@ -418,11 +373,9 @@
new Item("FormFieldOutsideForm", "Form Field Outside Form",
"Nice exception message for common problem of form fields outside forms"),
- new Item("SubmitWithContext", "Submit With Context",
- "Providing a context for Submit component"),
+ new Item("SubmitWithContext", "Submit With Context", "Providing a context for Submit component"),
- new Item("MessageConstraintGeneratorDemo",
- "Validation Constraints From Messages",
+ new Item("MessageConstraintGeneratorDemo", "Validation Constraints From Messages",
"Providing validators to apply from a properties file"),
new Item("RenderClientIdDemo", "RenderClientId Mixin",
@@ -437,8 +390,7 @@
new Item("BindParameterOnComponent", "BindParameter on component",
"Verify that BindParameter can only be used on mixin fields"),
- new Item("MixinOrderingDemo", "Mixin Ordering Demo",
- "Various mixin-ordering scenarios"),
+ new Item("MixinOrderingDemo", "Mixin Ordering Demo", "Various mixin-ordering scenarios"),
new Item(
"MissingComponentClassException",
@@ -456,12 +408,11 @@
new Item("ImageSubmitDemo", "Submit with an Image Demo",
"Make sure that submit with the image parameter set triggers the 'selected' event."),
- new Item("SelectZoneDemo", "Select Zone Demo",
- "Use a Select component to update a zone."),
+ new Item("SelectZoneDemo", "Select Zone Demo", "Use a Select component to update a zone."),
new Item("AssetProtectionDemo", "Asset Protection Demo",
"AssetProtectionDispatcher is properly contributed and functioning"),
-
+
new Item("BeanDisplayEnumDemo", "BeanDisplay Enum Demo",
"User represenation of enum values is correctly read from messages")
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/QueryParameterDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/QueryParameterDemo.java?rev=918301&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/QueryParameterDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/QueryParameterDemo.java Wed Mar 3 01:42:37 2010
@@ -0,0 +1,74 @@
+// Copyright 2010 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.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.Link;
+import org.apache.tapestry5.annotations.Persist;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.QueryParameter;
+import org.apache.tapestry5.ioc.annotations.Inject;
+
+public class QueryParameterDemo
+{
+ private static final String PARAMETER_NAME = "gnip";
+
+ private static final String EVENT_NAME = "frob";
+
+ @Property
+ @Persist
+ private int value;
+
+ @Inject
+ private ComponentResources resources;
+
+ public Link getWorkingLink()
+ {
+ Link link = resources.createEventLink(EVENT_NAME);
+ link.addParameter(PARAMETER_NAME, "97");
+
+ return link;
+ }
+
+ public Link getBrokenLink()
+ {
+ Link link = resources.createEventLink(EVENT_NAME);
+ link.addParameter(PARAMETER_NAME, "frodo");
+
+ return link;
+ }
+
+ public Link getNullLink()
+ {
+ return resources.createEventLink(EVENT_NAME);
+ }
+
+ public Link getNullAllowedLink()
+ {
+ return resources.createEventLink("frobNullAllowed");
+ }
+
+ void onFrob(@QueryParameter(PARAMETER_NAME)
+ int value)
+ {
+ this.value = value;
+ }
+
+ void onFrobNullAllowed(@QueryParameter(value = PARAMETER_NAME, allowBlank = true)
+ int value)
+ {
+ this.value = value;
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/QueryParameterDemo.java
------------------------------------------------------------------------------
svn:eol-style = native