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 2008/10/25 20:34:09 UTC
svn commit: r707887 [1/2] - in /tapestry/tapestry5/trunk:
tapestry-core/src/main/java/org/apache/tapestry5/internal/
tapestry-core/src/main/java/org/apache/tapestry5/internal/services/
tapestry-core/src/main/java/org/apache/tapestry5/internal/structure...
Author: hlship
Date: Sat Oct 25 11:34:08 2008
New Revision: 707887
URL: http://svn.apache.org/viewvc?rev=707887&view=rev
Log:
TAP5-302: URL encoded strings that contain symbols such as %2f (encoded "/") are decoded incorrectly in some environments
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventTarget.java
- copied, changed from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ActionLinkTarget.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextPathEncoderImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollector.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollectorImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderTarget.java
- copied, changed from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageLinkTarget.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/URLEncoderImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ComponentEventInvoker.java
- copied, changed from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ActionLinkInvoker.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageRenderInvoker.java
- copied, changed from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageLinkInvoker.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ContextPathEncoder.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentInvocationImplTest.java (contents, props changed)
- copied, changed from r704144, tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentInvocationTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PageActivationContextCollectorImplTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/URLEncoderImplTest.java
Removed:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ActionLinkTarget.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageLinkTarget.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ActionLinkInvoker.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageLinkInvoker.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentInvocationTest.java
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/URLEventContext.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStrategy.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocation.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocationImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InvocationTarget.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactory.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryListener.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderDispatcher.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.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/test/PageTester.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Target.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/corelib/base/AbstractLinkTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/AdditionalIntegrationTests.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/TapestryInternalUtilsTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/LinkFactoryImplTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/LinkImplTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PageRenderDispatcherTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java Sat Oct 25 11:34:08 2008
@@ -14,18 +14,13 @@
package org.apache.tapestry5.internal;
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.net.URLCodec;
import org.apache.tapestry5.OptionModel;
import org.apache.tapestry5.SelectModel;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newList;
import org.apache.tapestry5.ioc.internal.util.Defense;
-import static org.apache.tapestry5.ioc.internal.util.Defense.notNull;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
@@ -35,30 +30,12 @@
*/
public class TapestryInternalUtils
{
- private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
-
- private static final URLCodec CODEC = new URLCodec()
- {
+ private static final String SLASH = "/";
- private BitSet contextSafe = (BitSet) WWW_FORM_URL.clone();
+ private static final Pattern SLASH_PATTERN = Pattern.compile(SLASH);
- {
- // Servlet container does not decode '+' in path to ' ',
- // so we encode ' ' to %20, not to '+'.
- contextSafe.clear(' ');
- }
+ private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
- @Override
- public byte[] encode(byte[] bytes)
- {
- return encodeUrl(contextSafe, bytes);
- }
- };
-
- private TapestryInternalUtils()
- {
- // Prevent instantiation.
- }
/**
* Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
@@ -150,7 +127,7 @@
{
Defense.notNull(input, "input");
- List<OptionModel> result = newList();
+ List<OptionModel> result = CollectionFactory.newList();
for (String term : input.split(","))
result.add(toOptionModel(term.trim()));
@@ -179,7 +156,7 @@
*/
public static OptionModel toOptionModel(Map.Entry input)
{
- notNull(input, "input");
+ Defense.notNull(input, "input");
String label = input.getValue() != null ? String.valueOf(input.getValue()) : "";
@@ -196,7 +173,7 @@
{
Defense.notNull(input, "input");
- List<OptionModel> result = newList();
+ List<OptionModel> result = CollectionFactory.newList();
for (Map.Entry entry : input.entrySet())
result.add(toOptionModel(entry));
@@ -240,7 +217,7 @@
{
Defense.notNull(input, "input");
- List<OptionModel> result = newList();
+ List<OptionModel> result = CollectionFactory.newList();
for (E element : input)
result.add(toOptionModel(element));
@@ -365,60 +342,6 @@
return getLabelForEnum(messages, prefix, value);
}
- /**
- * Encodes a string for inclusion in a URL. Slashes and percents are converted to "%25" and "%2F" respectively,
- * then the entire string is URL encoded.
- *
- * @param input string to include, may not be blank
- * @return encoded input
- */
- public static String encodeContext(String input)
- {
- Defense.notBlank(input, "input");
-
- try
- {
- return CODEC.encode(escapePercentAndSlash(input));
- }
- catch (EncoderException ex)
- {
- throw new RuntimeException(ex);
- }
- }
-
- private static final String PERCENT = "%";
- private static final Pattern PERCENT_PATTERN = Pattern.compile(PERCENT);
- private static final String ENCODED_PERCENT = "%25";
- private static final Pattern ENCODED_PERCENT_PATTERN = Pattern.compile(ENCODED_PERCENT);
-
- private static final String SLASH = "/";
- private static final Pattern SLASH_PATTERN = Pattern.compile(SLASH);
- private static final String ENCODED_SLASH = "%2F";
- private static final Pattern ENCODED_SLASH_PATTERN = Pattern.compile(ENCODED_SLASH, Pattern.CASE_INSENSITIVE);
-
- /**
- * Encodes percent and slash characters in the string for later decoding via {@link
- * #unescapePercentAndSlash(String)}.
- *
- * @param input string to encode
- * @return modified string
- */
- public static String escapePercentAndSlash(String input)
- {
- return replace(replace(input, PERCENT_PATTERN, ENCODED_PERCENT), SLASH_PATTERN, ENCODED_SLASH);
- }
-
- /**
- * Used to decode certain escaped characters that are replaced when using {@link #encodeContext(String)}}.
- *
- * @param input a previously encoded string
- * @return the string with slash and percent characters restored
- */
- public static String unescapePercentAndSlash(String input)
- {
- return replace(replace(input, ENCODED_SLASH_PATTERN, SLASH), ENCODED_PERCENT_PATTERN, PERCENT);
- }
-
private static String replace(String input, Pattern pattern, String replacement)
{
return pattern.matcher(input).replaceAll(replacement);
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/URLEventContext.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/URLEventContext.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/URLEventContext.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/URLEventContext.java Sat Oct 25 11:34:08 2008
@@ -35,7 +35,7 @@
public int getCount()
{
- return values.length;
+ return values == null ? 0 : values.length;
}
public <T> T get(Class<T> desiredType, int index)
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStrategy.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStrategy.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStrategy.java Sat Oct 25 11:34:08 2008
@@ -44,7 +44,7 @@
storage.postChange(pageName, componentId, fieldName, newValue);
}
- public void createComponentEventLink(Link link)
+ public void createdComponentEventLink(Link link)
{
storage.updateLink(link);
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java Sat Oct 25 11:34:08 2008
@@ -16,10 +16,7 @@
import org.apache.tapestry5.EventConstants;
import org.apache.tapestry5.EventContext;
-import org.apache.tapestry5.internal.EmptyEventContext;
import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
-import org.apache.tapestry5.internal.URLEventContext;
import org.apache.tapestry5.services.*;
import java.io.IOException;
@@ -50,9 +47,7 @@
private final ComponentEventRequestHandler componentEventRequestHandler;
- private final ContextValueEncoder contextValueEncoder;
-
- private final EventContext emptyContext = new EmptyEventContext();
+ private final ContextPathEncoder contextPathEncoder;
public ComponentEventDispatcher(
@Traditional
@@ -60,11 +55,11 @@
ComponentClassResolver componentClassResolver,
- ContextValueEncoder contextValueEncoder)
+ ContextPathEncoder contextPathEncoder)
{
this.componentEventRequestHandler = componentEventRequestHandler;
this.componentClassResolver = componentClassResolver;
- this.contextValueEncoder = contextValueEncoder;
+ this.contextPathEncoder = contextPathEncoder;
}
// A beast that recognizes all the elements of a path in a single go.
@@ -108,9 +103,10 @@
if (!componentClassResolver.isPageName(activePageName)) return false;
- EventContext eventContext = decodeContext(matcher.group(CONTEXT));
+ EventContext eventContext = contextPathEncoder.decodePath(matcher.group(CONTEXT));
- EventContext activationContext = decodeContext(request.getParameter(InternalConstants.PAGE_CONTEXT_NAME));
+ EventContext activationContext = contextPathEncoder.decodePath(
+ request.getParameter(InternalConstants.PAGE_CONTEXT_NAME));
// The event type is often omitted, and defaults to "action".
@@ -132,20 +128,4 @@
return true;
}
-
-
- private EventContext decodeContext(String input)
- {
- if (input == null) return emptyContext;
-
- String[] values = TapestryInternalUtils.splitPath(input);
-
- for (int i = 0; i < values.length; i++)
- {
- values[i] = TapestryInternalUtils.unescapePercentAndSlash(values[i]);
- }
-
- return new URLEventContext(contextValueEncoder, values);
- }
-
}
Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventTarget.java (from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ActionLinkTarget.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventTarget.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventTarget.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ActionLinkTarget.java&r1=704144&r2=707887&rev=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ActionLinkTarget.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventTarget.java Sat Oct 25 11:34:08 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -18,9 +18,9 @@
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
/**
- * It represents an invocation target for an action link.
+ * It represents an invocation target for any kind of component event.
*/
-public class ActionLinkTarget implements InvocationTarget
+public class ComponentEventTarget implements InvocationTarget
{
private final String eventType;
@@ -28,12 +28,11 @@
private final String componentNestedId;
- public ActionLinkTarget(String eventType, String pageName, String componentNestedId)
+ public ComponentEventTarget(String eventType, String pageName, String componentNestedId)
{
this.eventType = eventType;
this.pageName = pageName;
this.componentNestedId = componentNestedId;
-
}
public String getPath()
@@ -78,5 +77,4 @@
{
return pageName;
}
-
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocation.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocation.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocation.java Sat Oct 25 11:34:08 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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,26 +14,55 @@
package org.apache.tapestry5.internal.services;
+import org.apache.tapestry5.EventContext;
+
import java.util.List;
+/**
+ * Represents an invocation of a page (to render) or a component (to handle an event). This is the core of the {@link
+ * org.apache.tapestry5.Link} implementation, and is seperated out to faciliate the {@link
+ * org.apache.tapestry5.test.PageTester}.
+ */
public interface ComponentInvocation
{
/**
- * @return A path taking the format <em>target-path</em>/e1/e2?&q1=v1&q2=v2. where the <em>target-path</em> is the
- * path provided by the invocation target; e1 and e2 are elements of the context; q1 and q2 are the
- * parameters.
+ * Constructs the URI for the component invocation. This may include the event context or page activation context.
+ * If the invocation was constructed for a form, then parameters will be omitted (such that they can be rendered as
+ * individual hidden fields within the form) ... otherwise, the URI will include query parameters.
*/
- String buildURI(boolean isForm);
+ String buildURI();
- String[] getContext();
+ /**
+ * Returns the event context associated with the component event. This will be an empty event context for a page
+ * render request.
+ */
+ EventContext getEventContext();
- String[] getActivationContext();
+ /**
+ * Returns the page activation context for the page referenced in a page render or component event request.
+ */
+ EventContext getPageActivationContext();
+ /**
+ * Adds an additional parameter to be encoded into the URL.
+ *
+ * @param parameterName name of parameter
+ * @param value parameter value (should be URL safe)
+ */
void addParameter(String parameterName, String value);
+ /**
+ * Returns sorted list of parameter names.
+ */
List<String> getParameterNames();
+ /**
+ * Returns value for a parameter.
+ */
String getParameterValue(String name);
+ /**
+ * Returns the target of the invocation (this is used by {@link org.apache.tapestry5.test.PageTester}).
+ */
InvocationTarget getTarget();
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocationImpl.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocationImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInvocationImpl.java Sat Oct 25 11:34:08 2008
@@ -14,51 +14,63 @@
package org.apache.tapestry5.internal.services;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
+import org.apache.tapestry5.EventContext;
+import org.apache.tapestry5.internal.InternalConstants;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import static org.apache.tapestry5.ioc.internal.util.Defense.notBlank;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.test.PageTester;
+import org.apache.tapestry5.services.ContextPathEncoder;
import java.util.List;
import java.util.Map;
/**
- * Represents an invocation for a page or a component in the current application. This information is extracted from
- * incoming URLs for a running application (or created by the {@link PageTester}. Each invocation may provide a context
- * (Object[]) and parameters to the invocation target.
+ * Represents an invocation for a page render or a component event, in the current application.
*/
public class ComponentInvocationImpl implements ComponentInvocation
{
- private final String[] context;
+ private final ContextPathEncoder encoder;
+
+ private final String eventContextPath;
private final InvocationTarget target;
- private final String[] activationContext;
+ private final String pageActivationContextPath;
+
+ private final boolean forForm;
private Map<String, String> parameters;
/**
- * @param target identifies the target of the event: a component with a page
- * @param context context information supplied by the component to be provided back when the event on the
- * component is triggered, or contains the activation context when the invocation is for a
- * page render request
- * @param activationContext page activation context for the page containing the component, supplied via a passivate
- * event to the page's root component (used when an action component invocation is for a
- * page with an activation context)
+ * @param encoder
+ * @param target identifies the target of the event: a component with a page
+ * @param eventContext event activation context (or null for a page render invocation)
+ * @param pageActivationContext page activation context (may be null)
+ * @param forForm if true, the URL is rendered for a form
*/
- public ComponentInvocationImpl(InvocationTarget target, String[] context, String[] activationContext)
+ public ComponentInvocationImpl(ContextPathEncoder encoder, InvocationTarget target, Object[] eventContext,
+ Object[] pageActivationContext,
+ boolean forForm)
{
+ this.encoder = encoder;
this.target = target;
- this.context = context;
- this.activationContext = activationContext;
+ this.forForm = forForm;
+ this.eventContextPath = eventContext == null ? null : encoder.encodeIntoPath(eventContext);
+ this.pageActivationContextPath = encoder.encodeIntoPath(pageActivationContext);
+
+ // For component events, the page activation context (if it exists) is a query parameter
+ // not path info.
+
+ if (eventContext != null && !InternalUtils.isBlank(this.pageActivationContextPath))
+ addParameter(InternalConstants.PAGE_CONTEXT_NAME, this.pageActivationContextPath);
}
- public String buildURI(boolean isForm)
+ public String buildURI()
{
String path = getPath();
- if (isForm || parameters == null) return path;
+
+ if (forForm || parameters == null) return path;
StringBuilder builder = new StringBuilder();
@@ -86,31 +98,34 @@
}
/**
- * @return Just like the return value of {@link #buildURI(boolean)} except that parameters are not included.
+ * Return the path which identifies the page (and perhaps component) plus the event or page activation context. This
+ * is the {@linkplain InvocationTarget#getPath() target path} plus any extra path info.
*/
private String getPath()
{
- StringBuilder builder = new StringBuilder();
- builder.append(target.getPath());
+ // For component event requests, the extra path info the the event context. For page render requests,
+ // the extra path info is the page activation context.
- for (String id : context)
- {
- if (builder.length() > 0) builder.append("/");
+ String extraPath =
+ eventContextPath != null ? eventContextPath : pageActivationContextPath;
- builder.append(TapestryInternalUtils.encodeContext(id));
- }
+ String targetPath = target.getPath();
- return builder.toString();
+ if (InternalUtils.isBlank(extraPath)) return targetPath;
+
+ if (targetPath.length() == 0) return extraPath;
+
+ return targetPath + "/" + extraPath;
}
- public String[] getContext()
+ public EventContext getEventContext()
{
- return context;
+ return encoder.decodePath(eventContextPath);
}
- public String[] getActivationContext()
+ public EventContext getPageActivationContext()
{
- return activationContext;
+ return encoder.decodePath(pageActivationContextPath);
}
public void addParameter(String parameterName, String value)
@@ -118,7 +133,7 @@
notBlank(parameterName, "parameterName");
notBlank(value, "value");
- if (parameters == null) parameters = newMap();
+ if (parameters == null) parameters = CollectionFactory.newMap();
if (parameters.containsKey(parameterName)) throw new IllegalArgumentException(
ServicesMessages.parameterNameMustBeUnique(parameterName, parameters.get(parameterName)));
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextPathEncoderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextPathEncoderImpl.java?rev=707887&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextPathEncoderImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextPathEncoderImpl.java Sat Oct 25 11:34:08 2008
@@ -0,0 +1,75 @@
+// Copyright 2008 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.internal.services;
+
+import org.apache.tapestry5.EventContext;
+import org.apache.tapestry5.internal.EmptyEventContext;
+import org.apache.tapestry5.internal.TapestryInternalUtils;
+import org.apache.tapestry5.internal.URLEventContext;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.services.ContextPathEncoder;
+import org.apache.tapestry5.services.ContextValueEncoder;
+import org.apache.tapestry5.services.URLEncoder;
+
+public class ContextPathEncoderImpl implements ContextPathEncoder
+{
+ private static final int BUFFER_SIZE = 100;
+
+ private final ContextValueEncoder valueEncoder;
+
+ private final URLEncoder urlEncoder;
+
+ private final EventContext EMPTY = new EmptyEventContext();
+
+ public ContextPathEncoderImpl(ContextValueEncoder valueEncoder, URLEncoder urlEncoder)
+ {
+ this.valueEncoder = valueEncoder;
+ this.urlEncoder = urlEncoder;
+ }
+
+ public String encodeIntoPath(Object[] context)
+ {
+ if (context == null || context.length == 0) return "";
+
+ StringBuilder output = new StringBuilder(BUFFER_SIZE);
+
+ for (int i = 0; i < context.length; i++)
+ {
+ Object raw = context[i];
+ String valueEncoded = raw == null ? null : valueEncoder.toClient(raw);
+ String urlEncoded = urlEncoder.encode(valueEncoded);
+
+ if (i > 0) output.append("/");
+
+ output.append(urlEncoded);
+ }
+
+ return output.toString();
+ }
+
+ public EventContext decodePath(String path)
+ {
+ if (InternalUtils.isBlank(path)) return EMPTY;
+
+ String[] split = TapestryInternalUtils.splitPath(path);
+
+ for (int i = 0; i < split.length; i++)
+ {
+ split[i] = urlEncoder.decode(split[i]);
+ }
+
+ return new URLEventContext(valueEncoder, split);
+ }
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java Sat Oct 25 11:34:08 2008
@@ -84,6 +84,7 @@
binder.bind(RequestSecurityManager.class, RequestSecurityManagerImpl.class);
binder.bind(InternalRequestGlobals.class, InternalRequestGlobalsImpl.class);
binder.bind(EndOfRequestListenerHub.class);
+ binder.bind(PageActivationContextCollector.class);
}
/**
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InvocationTarget.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InvocationTarget.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InvocationTarget.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InvocationTarget.java Sat Oct 25 11:34:08 2008
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2008 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.
@@ -17,8 +17,14 @@
/**
* It represents target for a {@link org.apache.tapestry5.internal.services.ComponentInvocation}. For example, it may be
* a page or an action for a component within a page.
+ *
+ * @see org.apache.tapestry5.services.Dispatcher
*/
public interface InvocationTarget
{
+ /**
+ * Represents the invocation as a path, part of a larger URI. The path will come after the context path and before
+ * extra path info (converted from event or page activation context values).
+ */
String getPath();
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactory.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactory.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactory.java Sat Oct 25 11:34:08 2008
@@ -64,7 +64,7 @@
* @param context activation context for the page
* @return
*/
- Link createPageLink(String logicalPageName, boolean override, Object... context);
+ Link createPageRenderLink(String logicalPageName, boolean override, Object... context);
/**
* Adds a listener, to be notified any time an action or render link is created; this allows the listener to modify
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryImpl.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryImpl.java Sat Oct 25 11:34:08 2008
@@ -14,26 +14,16 @@
package org.apache.tapestry5.internal.services;
-import org.apache.tapestry5.ComponentEventCallback;
-import org.apache.tapestry5.EventConstants;
import org.apache.tapestry5.Link;
import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
-import org.apache.tapestry5.internal.structure.ComponentPageElement;
import org.apache.tapestry5.internal.structure.Page;
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.*;
-import static org.apache.tapestry5.ioc.internal.util.Defense.notBlank;
-import static org.apache.tapestry5.ioc.internal.util.Defense.notNull;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.util.StrategyRegistry;
-import org.apache.tapestry5.services.ContextValueEncoder;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.Defense;
+import org.apache.tapestry5.services.ContextPathEncoder;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.Response;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.List;
-import java.util.Map;
public class LinkFactoryImpl implements LinkFactory
{
@@ -45,23 +35,18 @@
private final RequestPageCache pageCache;
- private final ContextValueEncoder contextValueEncoder;
-
private final RequestPathOptimizer optimizer;
private final PageRenderQueue pageRenderQueue;
private final RequestSecurityManager requestSecurityManager;
- private final List<LinkFactoryListener> listeners = newThreadSafeList();
+ private final ContextPathEncoder contextPathEncoder;
- private final StrategyRegistry<PassivateContextHandler> registry;
+ private final PageActivationContextCollector contextCollector;
+ private final List<LinkFactoryListener> listeners = CollectionFactory.newThreadSafeList();
- private interface PassivateContextHandler<T>
- {
- void handle(T result, List context);
- }
public LinkFactoryImpl(Request request,
Response response,
@@ -69,8 +54,9 @@
RequestPageCache pageCache,
RequestPathOptimizer optimizer,
PageRenderQueue pageRenderQueue,
- ContextValueEncoder contextValueEncoder,
- RequestSecurityManager requestSecurityManager)
+ RequestSecurityManager requestSecurityManager,
+ ContextPathEncoder contextPathEncoder,
+ PageActivationContextCollector contextCollector)
{
this.request = request;
this.response = response;
@@ -78,40 +64,9 @@
this.pageCache = pageCache;
this.optimizer = optimizer;
this.pageRenderQueue = pageRenderQueue;
- this.contextValueEncoder = contextValueEncoder;
this.requestSecurityManager = requestSecurityManager;
-
- Map<Class, PassivateContextHandler> registrations = newMap();
-
- registrations.put(Object.class, new PassivateContextHandler()
- {
- @SuppressWarnings("unchecked")
- public void handle(Object result, List context)
- {
- context.add(result);
- }
- });
-
- registrations.put(Object[].class, new PassivateContextHandler<Object[]>()
- {
-
- @SuppressWarnings("unchecked")
- public void handle(Object[] result, List context)
- {
- context.addAll(Arrays.asList(result));
- }
- });
-
- registrations.put(Collection.class, new PassivateContextHandler<Collection>()
- {
- @SuppressWarnings("unchecked")
- public void handle(Collection result, List context)
- {
- context.addAll(result);
- }
- });
-
- registry = StrategyRegistry.newInstance(PassivateContextHandler.class, registrations);
+ this.contextPathEncoder = contextPathEncoder;
+ this.contextCollector = contextCollector;
}
public void addListener(LinkFactoryListener listener)
@@ -120,27 +75,26 @@
}
public Link createComponentEventLink(Page page, String nestedId, String eventType, boolean forForm,
- Object... context)
+ Object... eventContext)
{
- notNull(page, "page");
- notBlank(eventType, "action");
+ Defense.notNull(page, "page");
+ Defense.notBlank(eventType, "action");
Page activePage = pageRenderQueue.getRenderingPage();
// See TAPESTRY-2184
if (activePage == null) activePage = page;
- ActionLinkTarget target = new ActionLinkTarget(eventType, activePage.getLogicalName(), nestedId);
-
- String[] contextStrings = toContextStrings(context);
+ ComponentEventTarget target = new ComponentEventTarget(eventType, activePage.getLogicalName(), nestedId);
- String[] activationContext = collectActivationContextForPage(activePage);
+ Object[] pageActivationContext = contextCollector.collectPageActivationContext(activePage);
- ComponentInvocation invocation = new ComponentInvocationImpl(target, contextStrings, activationContext);
+ ComponentInvocation invocation = new ComponentInvocationImpl(contextPathEncoder, target, eventContext,
+ pageActivationContext, forForm);
String baseURL = requestSecurityManager.getBaseURL(activePage);
- Link link = new LinkImpl(response, optimizer, baseURL, request.getContextPath(), invocation, forForm);
+ Link link = new LinkImpl(response, optimizer, baseURL, request.getContextPath(), invocation);
// TAPESTRY-2044: Sometimes the active page drags in components from another page and we
// need to differentiate that.
@@ -148,46 +102,29 @@
if (activePage != page)
link.addParameter(InternalConstants.CONTAINER_PAGE_NAME, page.getLogicalName().toLowerCase());
- // Now see if the page has an activation context.
-
- addActivationContextToLink(link, activationContext, forForm);
+ // This is a hook used for testing; we can relate the link to an invocation so that we can simulate
+ // the clicking of the link (or submitting of the form).
componentInvocationMap.store(link, invocation);
for (LinkFactoryListener listener : listeners)
- listener.createComponentEventLink(link);
+ listener.createdComponentEventLink(link);
return link;
}
- private void addActivationContextToLink(Link link, String[] activationContext, boolean forForm)
- {
- if (activationContext.length == 0) return;
-
- StringBuilder builder = new StringBuilder();
-
- for (int i = 0; i < activationContext.length; i++)
- {
- if (i > 0) builder.append("/");
-
- builder.append(forForm
- ? TapestryInternalUtils.escapePercentAndSlash(activationContext[i])
- : TapestryInternalUtils.encodeContext(activationContext[i]));
- }
-
- link.addParameter(InternalConstants.PAGE_CONTEXT_NAME, builder.toString());
- }
- public Link createPageRenderLink(Page page, boolean override, Object... activationContext)
+ public Link createPageRenderLink(Page page, boolean override, Object... pageActivationContext)
{
- notNull(page, "page");
+ Defense.notNull(page, "page");
String logicalPageName = page.getLogicalName();
// When override is true, we use the activation context even if empty.
- String[] context = (override || activationContext.length != 0) ? toContextStrings(
- activationContext) : collectActivationContextForPage(page);
+ Object[] context = (override || pageActivationContext.length != 0)
+ ? pageActivationContext
+ : contextCollector.collectPageActivationContext(page);
// Strip a trailing "/index" from the path.
@@ -202,13 +139,13 @@
logicalPageName = lastSlashx < 0 ? "" : logicalPageName.substring(0, lastSlashx);
}
- PageLinkTarget target = new PageLinkTarget(logicalPageName);
+ PageRenderTarget target = new PageRenderTarget(logicalPageName);
- ComponentInvocation invocation = new ComponentInvocationImpl(target, context, null);
+ ComponentInvocation invocation = new ComponentInvocationImpl(contextPathEncoder, target, null, context, false);
String baseURL = requestSecurityManager.getBaseURL(page);
- Link link = new LinkImpl(response, optimizer, baseURL, request.getContextPath(), invocation, false);
+ Link link = new LinkImpl(response, optimizer, baseURL, request.getContextPath(), invocation);
componentInvocationMap.store(link, invocation);
@@ -218,57 +155,7 @@
return link;
}
- /**
- * Returns a list of objects acquired by invoking triggering the passivate event on the page's root element. May
- * return an empty list.
- */
- private String[] collectActivationContextForPage(final Page page)
- {
- final List context = newList();
-
- ComponentEventCallback callback = new ComponentEventCallback()
- {
- @SuppressWarnings("unchecked")
- public boolean handleResult(Object result)
- {
- PassivateContextHandler contextHandler = registry.getByInstance(result);
-
- contextHandler.handle(result, context);
-
- return true;
- }
- };
-
- ComponentPageElement rootElement = page.getRootElement();
-
- rootElement.triggerEvent(EventConstants.PASSIVATE, null, callback);
-
- return toContextStrings(context.toArray());
- }
-
- private String[] toContextStrings(Object[] context)
- {
- if (context == null) return new String[0];
-
- String[] result = new String[context.length];
-
- for (int i = 0; i < context.length; i++)
- {
-
- Object value = context[i];
-
- String encoded = value == null ? null : contextValueEncoder.toClient(value);
-
- if (InternalUtils.isBlank(encoded))
- throw new RuntimeException(ServicesMessages.contextValueMayNotBeNull());
-
- result[i] = encoded;
- }
-
- return result;
- }
-
- public Link createPageLink(String logicalPageName, boolean override, Object... context)
+ public Link createPageRenderLink(String logicalPageName, boolean override, Object... context)
{
// This verifies that the page name is valid.
Page page = pageCache.get(logicalPageName);
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryListener.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryListener.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryListener.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkFactoryListener.java Sat Oct 25 11:34:08 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -35,5 +35,5 @@
*
* @param link the newly created link
*/
- void createComponentEventLink(Link link);
+ void createdComponentEventLink(Link link);
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java Sat Oct 25 11:34:08 2008
@@ -37,21 +37,8 @@
private final ComponentInvocation invocation;
- private final boolean forForm;
-
private String anchor;
- LinkImpl(Response response, RequestPathOptimizer optimizer, String contextPath, String targetPath)
- {
- this(response, optimizer, contextPath, targetPath, false);
- }
-
- LinkImpl(Response response, RequestPathOptimizer optimizer, String contextPath, String targetPath, boolean forForm)
- {
- this(response, optimizer, null, contextPath,
- new ComponentInvocationImpl(new OpaqueConstantTarget(targetPath), new String[0], null), forForm);
- }
-
/**
* Creates a new Link. Links may be full or optimized; optimization involves creating a relative URI from the
* request's URI to the Link's URI.
@@ -61,17 +48,15 @@
* @param baseURL base URL prefix (before the context path), used when switching between secure and non-secure
* @param contextPath path for the context {@link org.apache.tapestry5.services.Request#getContextPath()}
* @param invocation abstraction around the type of link (needed by {@link org.apache.tapestry5.test.PageTester})
- * @param forForm if true, then a Form has requested the Link, in which case, the link should not generated
*/
public LinkImpl(Response response, RequestPathOptimizer optimizer, String baseURL, String contextPath,
- ComponentInvocation invocation, boolean forForm)
+ ComponentInvocation invocation)
{
this.response = response;
this.optimizer = optimizer;
this.baseURL = baseURL;
this.contextPath = contextPath;
this.invocation = invocation;
- this.forForm = forForm;
}
public void addParameter(String parameterName, String value)
@@ -108,8 +93,15 @@
if (baseURL != null) builder.append(baseURL);
builder.append(contextPath);
- builder.append("/");
- builder.append(invocation.buildURI(forForm));
+
+ String invocationURI = invocation.buildURI();
+
+ if (invocationURI.length() > 0)
+ {
+ builder.append("/");
+
+ builder.append(invocationURI);
+ }
if (InternalUtils.isNonBlank(anchor))
{
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollector.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollector.java?rev=707887&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollector.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollector.java Sat Oct 25 11:34:08 2008
@@ -0,0 +1,33 @@
+// Copyright 2008 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.internal.services;
+
+import org.apache.tapestry5.internal.structure.Page;
+
+/**
+ * Fires the {@link org.apache.tapestry5.EventConstants#PASSIVATE} event on a page, and collects the result, converting
+ * it to an array of objects.
+ */
+public interface PageActivationContextCollector
+{
+ /**
+ * Fires the passivate event and collects the response, which is coerced to an object array. A page that does not
+ * have an event handler for the passivate event will return an empty array.
+ *
+ * @param page to collect context from
+ * @return the activation context, or an empty array of the page does not provide a context
+ */
+ Object[] collectPageActivationContext(Page page);
+}
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollectorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollectorImpl.java?rev=707887&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollectorImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageActivationContextCollectorImpl.java Sat Oct 25 11:34:08 2008
@@ -0,0 +1,59 @@
+// Copyright 2008 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.internal.services;
+
+import org.apache.tapestry5.ComponentEventCallback;
+import org.apache.tapestry5.EventConstants;
+import org.apache.tapestry5.internal.structure.ComponentPageElement;
+import org.apache.tapestry5.internal.structure.Page;
+import org.apache.tapestry5.internal.util.Holder;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+public class PageActivationContextCollectorImpl implements PageActivationContextCollector
+{
+ private final Object[] EMPTY = new Object[0];
+
+ private final TypeCoercer typeCoercer;
+
+ public PageActivationContextCollectorImpl(TypeCoercer typeCoercer)
+ {
+ this.typeCoercer = typeCoercer;
+ }
+
+ public Object[] collectPageActivationContext(Page page)
+ {
+ ComponentPageElement element = page.getRootElement();
+
+ final Holder<Object[]> holder = Holder.create();
+
+ ComponentEventCallback callback = new ComponentEventCallback()
+ {
+ public boolean handleResult(Object result)
+ {
+ holder.put(typeCoercer.coerce(result, Object[].class));
+
+ // We've got the value, stop the event.
+
+ return true;
+ }
+ };
+
+ element.triggerEvent(EventConstants.PASSIVATE, null, callback);
+
+ if (!holder.hasValue()) return EMPTY;
+
+ return holder.get();
+ }
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderDispatcher.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderDispatcher.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderDispatcher.java Sat Oct 25 11:34:08 2008
@@ -15,8 +15,6 @@
package org.apache.tapestry5.internal.services;
import org.apache.tapestry5.EventContext;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
-import org.apache.tapestry5.internal.URLEventContext;
import org.apache.tapestry5.services.*;
import java.io.IOException;
@@ -32,14 +30,14 @@
private final PageRenderRequestHandler handler;
- private final ContextValueEncoder contextValueEncoder;
+ private final ContextPathEncoder contextPathEncoder;
public PageRenderDispatcher(ComponentClassResolver componentClassResolver, PageRenderRequestHandler handler,
- ContextValueEncoder contextValueEncoder)
+ ContextPathEncoder contextPathEncoder)
{
this.componentClassResolver = componentClassResolver;
this.handler = handler;
- this.contextValueEncoder = contextValueEncoder;
+ this.contextPathEncoder = contextPathEncoder;
}
public boolean dispatch(Request request, final Response response) throws IOException
@@ -87,10 +85,7 @@
{
if (!componentClassResolver.isPageName(pageName)) return false;
- String[] values = convertActivationContext(pageActivationContext);
-
- EventContext activationContext
- = new URLEventContext(contextValueEncoder, values);
+ EventContext activationContext = contextPathEncoder.decodePath(pageActivationContext);
PageRenderRequestParameters parameters = new PageRenderRequestParameters(pageName, activationContext);
@@ -98,23 +93,4 @@
return true;
}
-
- /**
- * Converts the "extra path", the portion after the page name (and after the slash seperating the page name from the
- * activation context) into an array of strings. LinkFactory and friends URL encode each value, so we URL decode the
- * value (we assume that page names are "URL safe").
- */
- private String[] convertActivationContext(String extraPath)
- {
- if (extraPath.length() == 0) return new String[0];
-
- String[] context = TapestryInternalUtils.splitPath(extraPath);
-
- for (int i = 0; i < context.length; i++)
- {
- context[i] = TapestryInternalUtils.unescapePercentAndSlash(context[i]);
- }
-
- return context;
- }
}
Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderTarget.java (from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageLinkTarget.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderTarget.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderTarget.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageLinkTarget.java&r1=704144&r2=707887&rev=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageLinkTarget.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderTarget.java Sat Oct 25 11:34:08 2008
@@ -20,14 +20,13 @@
* and the real Tapestry code {@link org.apache.tapestry5.internal.services.PageRenderDispatcher} in order to invoke a
* page link.
*/
-public class PageLinkTarget implements InvocationTarget
+public class PageRenderTarget implements InvocationTarget
{
private final String pageName;
- public PageLinkTarget(String pageName)
+ public PageRenderTarget(String pageName)
{
this.pageName = pageName;
-
}
public String getPath()
@@ -39,5 +38,4 @@
{
return pageName;
}
-
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java Sat Oct 25 11:34:08 2008
@@ -405,11 +405,6 @@
return MESSAGES.format("no-such-method", ClassFabUtils.toJavaClassName(clazz), methodName);
}
- static String contextValueMayNotBeNull()
- {
- return MESSAGES.get("context-value-may-not-be-null");
- }
-
static String forbidInstantiateComponentClass(String className)
{
return MESSAGES.format("forbid-instantiate-component-class", className);
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/URLEncoderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/URLEncoderImpl.java?rev=707887&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/URLEncoderImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/URLEncoderImpl.java Sat Oct 25 11:34:08 2008
@@ -0,0 +1,153 @@
+// Copyright 2008 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.internal.services;
+
+import org.apache.tapestry5.ioc.internal.util.Defense;
+import org.apache.tapestry5.services.URLEncoder;
+
+import java.util.BitSet;
+
+public class URLEncoderImpl implements URLEncoder
+{
+ static final String ENCODED_NULL = "$N";
+ static final String ENCODED_BLANK = "$B";
+
+ /**
+ * Bit set indicating which character are safe to pass through (when encoding or decoding) as-is. All other
+ * characters are encoded as a kind of unicode escape.
+ */
+ private final BitSet safe = new BitSet(128);
+
+ {
+ markSafe("abcdefghijklmnopqrstuvwxyz");
+ markSafe("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ markSafe("01234567890-_.:");
+ }
+
+ private void markSafe(String s)
+ {
+ for (char ch : s.toCharArray())
+ {
+ safe.set((int) ch);
+ }
+ }
+
+
+ public String encode(String input)
+ {
+ if (input == null) return ENCODED_NULL;
+
+ if (input.equals("")) return ENCODED_BLANK;
+
+ boolean dirty = false;
+
+ int length = input.length();
+
+ StringBuilder output = new StringBuilder(length * 2);
+
+ for (int i = 0; i < length; i++)
+ {
+ char ch = input.charAt(i);
+
+ if (ch == '$')
+ {
+ output.append("$$");
+ dirty = true;
+ continue;
+ }
+
+ int chAsInt = (int) ch;
+
+ if (safe.get(chAsInt))
+ {
+ output.append(ch);
+ continue;
+ }
+
+ output.append(String.format("$%04x", chAsInt));
+ dirty = true;
+ }
+
+ return dirty ? output.toString() : input;
+ }
+
+ public String decode(String input)
+ {
+ Defense.notNull(input, "input");
+
+ if (input.equals(ENCODED_NULL)) return null;
+
+ if (input.equals(ENCODED_BLANK)) return "";
+
+ boolean dirty = false;
+
+ int length = input.length();
+
+ StringBuilder output = new StringBuilder(length * 2);
+
+ for (int i = 0; i < length; i++)
+ {
+ char ch = input.charAt(i);
+
+ if (ch == '$')
+ {
+ dirty = true;
+
+ if (i + 1 < length && input.charAt(i + 1) == '$')
+ {
+ output.append('$');
+ i++;
+
+ dirty = true;
+ continue;
+ }
+
+ if (i + 4 < length)
+ {
+ String hex = input.substring(i + 1, i + 5);
+
+ try
+ {
+ int unicode = Integer.parseInt(hex, 16);
+
+ output.append((char) unicode);
+ i += 4;
+ dirty = true;
+ continue;
+ }
+ catch (NumberFormatException ex)
+ {
+ // Ignore.
+ }
+ }
+
+ throw new IllegalArgumentException(String.format(
+ "Input string '%s' is not valid; the '$' character at position %d should be followed by another '$' or a four digit hex number (a unicode value).",
+ input, i + 1));
+ }
+
+ if (!safe.get((int) ch))
+ {
+ throw new IllegalArgumentException(
+ String.format("Input string '%s' is not valid; the character '%s' at position %d is not valid.",
+ input, ch, i + 1));
+ }
+
+ output.append(ch);
+ }
+
+ return dirty ? output.toString() : input;
+ }
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java Sat Oct 25 11:34:08 2008
@@ -163,7 +163,7 @@
public Link createPageRenderLink(String pageName, boolean override, Object... context)
{
- return linkFactory.createPageLink(pageName, override, context);
+ return linkFactory.createPageRenderLink(pageName, override, context);
}
public Link createPageRenderLink(Class pageClass, boolean override, Object... context)
@@ -172,7 +172,7 @@
String pageName = componentClassResolver.resolvePageClassNameToPageName(pageClass.getName());
- return linkFactory.createPageLink(pageName, override, context);
+ return linkFactory.createPageRenderLink(pageName, override, context);
}
public void persistFieldChange(ComponentResources resources, String fieldName, Object newValue)
Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ComponentEventInvoker.java (from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ActionLinkInvoker.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ComponentEventInvoker.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ComponentEventInvoker.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ActionLinkInvoker.java&r1=704144&r2=707887&rev=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ActionLinkInvoker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/ComponentEventInvoker.java Sat Oct 25 11:34:08 2008
@@ -16,8 +16,7 @@
import org.apache.tapestry5.Link;
import org.apache.tapestry5.dom.Document;
-import org.apache.tapestry5.internal.URLEventContext;
-import org.apache.tapestry5.internal.services.ActionLinkTarget;
+import org.apache.tapestry5.internal.services.ComponentEventTarget;
import org.apache.tapestry5.internal.services.ComponentInvocation;
import org.apache.tapestry5.internal.services.ComponentInvocationMap;
import org.apache.tapestry5.internal.services.InvocationTarget;
@@ -25,14 +24,13 @@
import org.apache.tapestry5.ioc.internal.util.Defense;
import org.apache.tapestry5.services.ComponentEventRequestHandler;
import org.apache.tapestry5.services.ComponentEventRequestParameters;
-import org.apache.tapestry5.services.ContextValueEncoder;
import java.io.IOException;
/**
- * Simulates a click on an action link.
+ * Simulates a click on an component event invocation link.
*/
-public class ActionLinkInvoker implements ComponentInvoker
+public class ComponentEventInvoker implements ComponentInvoker
{
private final Registry registry;
@@ -44,21 +42,17 @@
private final TestableResponse response;
- private final ContextValueEncoder contextValueEncoder;
-
- public ActionLinkInvoker(Registry registry, ComponentInvoker followupInvoker,
- ComponentInvocationMap componentInvocationMap)
+ public ComponentEventInvoker(Registry registry, ComponentInvoker followupInvoker,
+ ComponentInvocationMap componentInvocationMap)
{
this.registry = registry;
this.followupInvoker = followupInvoker;
- componentEventRequestHandler = this.registry.getService("ComponentEventRequestHandler",
- ComponentEventRequestHandler.class);
-
- response = this.registry.getObject(TestableResponse.class, null);
-
this.componentInvocationMap = componentInvocationMap;
- contextValueEncoder = this.registry.getService(ContextValueEncoder.class);
+ componentEventRequestHandler = registry.getService("ComponentEventRequestHandler",
+ ComponentEventRequestHandler.class);
+
+ response = registry.getObject(TestableResponse.class, null);
}
/**
@@ -90,20 +84,20 @@
{
InvocationTarget target = invocation.getTarget();
- ActionLinkTarget actionLinkTarget = Defense.cast(target, ActionLinkTarget.class, "target");
+ ComponentEventTarget componentEventTarget = Defense.cast(target, ComponentEventTarget.class, "target");
ComponentEventRequestParameters parameters = new ComponentEventRequestParameters(
- actionLinkTarget.getPageName(),
+ componentEventTarget.getPageName(),
- actionLinkTarget.getPageName(),
+ componentEventTarget.getPageName(),
- actionLinkTarget.getComponentNestedId(),
+ componentEventTarget.getComponentNestedId(),
- actionLinkTarget.getEventType(),
+ componentEventTarget.getEventType(),
- new URLEventContext(contextValueEncoder, invocation.getActivationContext()),
+ invocation.getPageActivationContext(),
- new URLEventContext(contextValueEncoder, invocation.getContext()));
+ invocation.getEventContext());
componentEventRequestHandler.handle(parameters);
}
Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageRenderInvoker.java (from r704144, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageLinkInvoker.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageRenderInvoker.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageRenderInvoker.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageLinkInvoker.java&r1=704144&r2=707887&rev=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageLinkInvoker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/PageRenderInvoker.java Sat Oct 25 11:34:08 2008
@@ -14,14 +14,11 @@
package org.apache.tapestry5.internal.test;
-import org.apache.tapestry5.EventContext;
import org.apache.tapestry5.dom.Document;
-import org.apache.tapestry5.internal.URLEventContext;
import org.apache.tapestry5.internal.services.ComponentInvocation;
import org.apache.tapestry5.internal.services.InvocationTarget;
-import org.apache.tapestry5.internal.services.PageLinkTarget;
+import org.apache.tapestry5.internal.services.PageRenderTarget;
import org.apache.tapestry5.ioc.Registry;
-import org.apache.tapestry5.services.ContextValueEncoder;
import org.apache.tapestry5.services.PageRenderRequestHandler;
import org.apache.tapestry5.services.PageRenderRequestParameters;
@@ -30,7 +27,7 @@
/**
* Simulates a click on a page link.
*/
-public class PageLinkInvoker implements ComponentInvoker
+public class PageRenderInvoker implements ComponentInvoker
{
private final Registry registry;
@@ -40,16 +37,13 @@
private final TestableResponse response;
- private final ContextValueEncoder contextValueEncoder;
-
- public PageLinkInvoker(Registry registry)
+ public PageRenderInvoker(Registry registry)
{
this.registry = registry;
pageRenderRequestHandler = this.registry.getService(PageRenderRequestHandler.class);
markupWriterFactory = this.registry.getService(TestableMarkupWriterFactory.class);
response = this.registry.getService(TestableResponse.class);
- contextValueEncoder = this.registry.getService(ContextValueEncoder.class);
}
/**
@@ -64,12 +58,10 @@
{
InvocationTarget target = invocation.getTarget();
- PageLinkTarget pageLinkTarget = (PageLinkTarget) target;
+ PageRenderTarget pageRenderTarget = (PageRenderTarget) target;
- EventContext activationContext
- = new URLEventContext(contextValueEncoder, invocation.getContext());
- PageRenderRequestParameters parameters = new PageRenderRequestParameters(pageLinkTarget.getPageName(),
- activationContext);
+ PageRenderRequestParameters parameters = new PageRenderRequestParameters(pageRenderTarget.getPageName(),
+ invocation.getPageActivationContext());
pageRenderRequestHandler.handle(parameters);
@@ -85,7 +77,5 @@
registry.cleanupThread();
}
-
}
-
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ContextPathEncoder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ContextPathEncoder.java?rev=707887&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ContextPathEncoder.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ContextPathEncoder.java Sat Oct 25 11:34:08 2008
@@ -0,0 +1,44 @@
+// Copyright 2008 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.services;
+
+import org.apache.tapestry5.EventContext;
+
+/**
+ * A service to provide utilities needed for event context encoding and decoding to and from (partial) URL paths. This
+ * is used for both component event contexts and page activation contexts.
+ */
+public interface ContextPathEncoder
+{
+ /**
+ * Encodes the context values into a path string. Each context value (if non-null) is first value encoded into a
+ * string via the {@link org.apache.tapestry5.services.ContextValueEncoder} service. Those values are then encoded,
+ * via {@link URLEncoder#encode(String)} into URL-safe strings. The URL-safe strings are then concatinated
+ * together, seperated with "/" characters.
+ *
+ * @param context an array of objects to encode as the context (may be null)
+ * @return the path-encoded context, or the blank string if the context is empty
+ */
+ String encodeIntoPath(Object[] context);
+
+ /**
+ * Inverse of {@link #encodeIntoPath(Object[])}; the path is split into strings, and the string are decoded and
+ * constructed into an {@link org.apache.tapestry5.EventContext}.
+ *
+ * @param path to decode, possibly empty or null
+ * @return corresponding event context
+ */
+ EventContext decodePath(String path);
+}
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=707887&r1=707886&r2=707887&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 Sat Oct 25 11:34:08 2008
@@ -195,6 +195,8 @@
binder.bind(BindingFactory.class, AssetBindingFactory.class).withId("AssetBindingFactory");
binder.bind(BindingFactory.class, NullFieldStrategyBindingFactory.class).withId(
"NullFieldStrategyBindingFactory");
+ binder.bind(URLEncoder.class, URLEncoderImpl.class);
+ binder.bind(ContextPathEncoder.class, ContextPathEncoderImpl.class);
}
// ========================================================================
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java?rev=707887&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java Sat Oct 25 11:34:08 2008
@@ -0,0 +1,41 @@
+// Copyright 2008 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.services;
+
+/**
+ * Service used to encode or decode strings that are placed into URLs. This is used as an alternative to UUEncoding.
+ * Alphabetics, numbers and some punctuation ("-", "_", ".", ":") are passed through as is, the "$" character is an
+ * escape, followed by either another "$", or by a four digit hex unicode number. A null input (not a blank input, but
+ * actual null) has a special encoding, "$N". Likewise, the blank string has the special encoding "$B".
+ */
+public interface URLEncoder
+{
+ /**
+ * Given an input value containing any characters, returns the input string, or an encoded version of the string (as
+ * outlined above).
+ *
+ * @param input string to be encoded, which may be null
+ * @return encoded version of input
+ */
+ String encode(String input);
+
+ /**
+ * Given a previously encoded string, returns the original input.
+ *
+ * @param input encoded string (may not be null)
+ * @return decoded input
+ */
+ String decode(String input);
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java Sat Oct 25 11:34:08 2008
@@ -29,6 +29,7 @@
import org.apache.tapestry5.ioc.services.SymbolProvider;
import org.apache.tapestry5.ioc.util.StrategyRegistry;
import org.apache.tapestry5.services.ApplicationGlobals;
+import org.apache.tapestry5.services.ContextPathEncoder;
import java.util.Locale;
import java.util.Map;
@@ -49,10 +50,12 @@
private final StrategyRegistry<ComponentInvoker> invokerRegistry;
- private Locale preferedLanguage;
-
private final LocalizationSetter localizationSetter;
+ private final ContextPathEncoder contextPathEncoder;
+
+ private Locale preferedLanguage;
+
public static final String DEFAULT_CONTEXT_PATH = "src/main/webapp";
private static final String DEFAULT_SUBMIT_VALUE_ATTRIBUTE = "Submit Query";
@@ -104,10 +107,12 @@
globals.storeContext(new PageTesterContext(contextPath));
Map<Class, ComponentInvoker> map = newMap();
- map.put(PageLinkTarget.class, new PageLinkInvoker(registry));
- map.put(ActionLinkTarget.class, new ActionLinkInvoker(registry, this, invocationMap));
+ map.put(PageRenderTarget.class, new PageRenderInvoker(registry));
+ map.put(ComponentEventTarget.class, new ComponentEventInvoker(registry, this, invocationMap));
invokerRegistry = StrategyRegistry.newInstance(ComponentInvoker.class, map);
+
+ contextPathEncoder = registry.getService(ContextPathEncoder.class);
}
/**
@@ -156,7 +161,8 @@
*/
public Document renderPage(String pageName)
{
- return invoke(new ComponentInvocationImpl(new PageLinkTarget(pageName), new String[0], null));
+ return invoke(
+ new ComponentInvocationImpl(contextPathEncoder, new PageRenderTarget(pageName), null, null, false));
}
/**
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java Sat Oct 25 11:34:08 2008
@@ -1154,4 +1154,9 @@
{
expect(ts.findByType(propertyType)).andReturn(translator);
}
+
+ protected final void train_toURI(Link link, String URI)
+ {
+ expect(link.toURI()).andReturn(URI);
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties Sat Oct 25 11:34:08 2008
@@ -91,6 +91,5 @@
no-translator-for-type=No translator is defined for type %s. Registered types: %s.
parameter-binding-must-not-be-empty=Parameter '%s' must have a non-empty binding.
no-such-method=Class %s does not contain a method named '%s()'.
-context-value-may-not-be-null=Context values (which are added to the request URL) may not be null or blank.
forbid-instantiate-component-class=Component class %s may not be instantiated directly. You should use an @InjectPage or @InjectComponent annotation instead.
event-not-handled=Request event '%s' (on component %s) was not handled; you must provide a matching event handler method in the component or in one of its containers.
\ No newline at end of file
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Target.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Target.tml?rev=707887&r1=707886&r2=707887&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Target.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Target.tml Sat Oct 25 11:34:08 2008
@@ -4,7 +4,9 @@
<t:if test="activationContext">
<ul>
- <li t:type="loop" source="activationContext" value="object">${object}</li>
+ <li t:type="loop" source="activationContext" value="object">
+ <t:if test="object" else="NULL">${object}</t:if>
+ </li>
</ul>
<t:parameter name="else">No activation context.</t:parameter>
</t:if>
@@ -15,19 +17,19 @@
<li t:type="loop" source="componentContext" value="object">${object}</li>
</ul>
- <t:parameter name="else"> No component context. </t:parameter>
+ <t:parameter name="else">No component context.</t:parameter>
</t:if>
- <h2>Setup Component Context</h2> [<a t:type="actionlink" context="contextToEncode">go</a>]
-
+ <h2>Setup Component Context</h2>
+ [<a t:type="actionlink" context="contextToEncode">go</a>]
+
<h2>Navigation</h2>
-
- <p>[<a t:type="pagelink" page="pagelinkcontext">PageLink Context Demo</a>]</p>
-
- <p>
- [<t:pagelink t:id="nocontext" page="target" context="null">Target base, no context</t:pagelink>]
- </p>
-
-
-
-
- </html>
+
+ <p>[<a t:type="pagelink" page="pagelinkcontext">PageLink Context Demo</a>]
+ </p>
+
+ <p>
+ [<t:pagelink t:id="nocontext" page="target" context="null">Target base, no context</t:pagelink>]
+ </p>
+
+
+</html>