You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by jd...@apache.org on 2008/12/23 20:52:48 UTC
svn commit: r729078 - in /wicket/trunk/wicket/src:
main/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategy.java
test/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategyTest.java
Author: jdonnerstag
Date: Tue Dec 23 11:52:47 2008
New Revision: 729078
URL: http://svn.apache.org/viewvc?rev=729078&view=rev
Log:
wicket-1666 fixed: provide indexed urls for shared resources (with optional query string parameters
Added:
wicket/trunk/wicket/src/main/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategy.java
wicket/trunk/wicket/src/test/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategyTest.java
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategy.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategy.java?rev=729078&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategy.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategy.java Tue Dec 23 11:52:47 2008
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.target.coding;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.wicket.IRequestTarget;
+import org.apache.wicket.request.RequestParameters;
+import org.apache.wicket.request.target.resource.ISharedResourceRequestTarget;
+import org.apache.wicket.request.target.resource.SharedResourceRequestTarget;
+import org.apache.wicket.util.string.AppendingStringBuffer;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.value.ValueMap;
+
+/**
+ * Indexed url encoding for shared resources with optional query parameters
+ * <p/>
+ * for example, with this url
+ *
+ * <pre>
+ * /mountpath/foo/bar/baz?name=joe&languages=java&languages=scala
+ * </pre>
+ *
+ * the parameters value map will be
+ * <p/>
+ * <table border="1" cellpadding="4px">
+ * <thead>
+ * <tr>
+ * <th>Key</th>
+ * <th>Value</th>
+ * </tr>
+ * </thead> <tbody>
+ * <tr>
+ * <td>"0"</th>
+ * <td>"foo"</td>
+ * </tr>
+ * <tr>
+ * <td>"1"</th>
+ * <td>"bar"</td>
+ * </tr>
+ * <tr>
+ * <td>"2"</th>
+ * <td>"baz"</td>
+ * </tr>
+ * <tr>
+ * <td>"name"</th>
+ * <td>"joe"</td>
+ * </tr>
+ * <tr>
+ * <td>"languages"</th>
+ * <td>String[] { "java", "scala" }</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * so you can have urls like these
+ * <code>/images/{imagename}.{format} /blog/2008/05/12/47-test-blog-entry.html</code> with
+ * absolutely no effort.
+ * <p/>
+ * Can be used in WebApplication like this:
+ * <code>mount(new IndexedSharedResourceCodingStrategy(path, sharedResourceKey);</code>
+ * <p/>
+ * The greatest benefit is that shared resource urls look like static resources for the browser.
+ * This comes especially handy when utilizing browser caching. Also, the user will not realize the
+ * resources are served dynamically and bookmarking is easy.
+ *
+ */
+public class IndexedSharedResourceCodingStrategy extends AbstractRequestTargetUrlCodingStrategy
+{
+ // resource key of of resource we map to
+ private final String resourceKey;
+
+ /**
+ * mount resource with specified key under indexed path
+ *
+ * @param mountPath
+ * path the resource will be mounted to
+ * @param resourceKey
+ * key of the resource
+ */
+ public IndexedSharedResourceCodingStrategy(String mountPath, String resourceKey)
+ {
+ super(mountPath);
+
+ if (resourceKey == null)
+ {
+ throw new IllegalArgumentException("resource key must not be null");
+ }
+ this.resourceKey = resourceKey;
+ }
+
+ /**
+ *
+ * @see org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#encode(org.apache.wicket.IRequestTarget)
+ */
+ public CharSequence encode(final IRequestTarget requestTarget)
+ {
+ if (!(requestTarget instanceof ISharedResourceRequestTarget))
+ {
+ throw new IllegalArgumentException("This encoder can only be used with instances of " +
+ ISharedResourceRequestTarget.class.getName());
+ }
+
+ final ISharedResourceRequestTarget target = (ISharedResourceRequestTarget)requestTarget;
+
+ // create url to shared resource
+ final AppendingStringBuffer url = new AppendingStringBuffer();
+ url.append(getMountPath());
+
+ final RequestParameters requestParameters = target.getRequestParameters();
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> params = requestParameters.getParameters();
+
+ if (params != null)
+ {
+ params = new HashMap<String, Object>(params);
+
+ int index = 0;
+
+ // append indexed parameters to url:
+ // these parameters are enumerated with the keys "0", "1", ...
+ while (!params.isEmpty())
+ {
+ final String key = Integer.toString(index++);
+ final Object value = params.get(key);
+
+ // no more indexed parameters?
+ if (value == null)
+ {
+ break;
+ }
+
+ // indexed parameters may not contain arrays
+ if (value instanceof String[])
+ {
+ throw new IllegalArgumentException(
+ "indexed parameter value must not be an array");
+ }
+
+ // remove indexed parameters from rest of parameters
+ params.remove(key);
+
+ // append indexed parameter to url
+ url.append('/').append(urlEncodePathComponent(value.toString()));
+ }
+
+ // create query string from remaining parameters
+ if (!params.isEmpty())
+ {
+ boolean first = true;
+
+ // go through remaining parameters
+ for (Map.Entry<String, Object> arg : params.entrySet())
+ {
+ final String key = urlEncodeQueryComponent(arg.getKey());
+ final Object obj = arg.getValue();
+
+ // for string arrays, create multiple query string parameters with all the
+ // values
+ if (obj instanceof String[])
+ {
+ for (String value : (String[])obj)
+ {
+ appendToQueryString(url, first, key, value);
+ first = false;
+ }
+ }
+ else
+ {
+ // for single query string value, just append it to url
+ appendToQueryString(url, first, key, obj.toString());
+ first = false;
+ }
+ }
+ }
+ }
+ return url;
+ }
+
+ /**
+ * helper
+ *
+ * @param url
+ * @param first
+ * @param key
+ * @param value
+ */
+ private void appendToQueryString(AppendingStringBuffer url, boolean first, final String key,
+ final String value)
+ {
+ url.append(first ? '?' : '&');
+ url.append(key);
+ url.append('=');
+ url.append(urlEncodeQueryComponent(value));
+ }
+
+ /**
+ *
+ * @see org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#decode(org.apache.wicket.request.RequestParameters)
+ */
+ public IRequestTarget decode(final RequestParameters requestParameters)
+ {
+ if (requestParameters == null)
+ {
+ throw new IllegalArgumentException("request parameters must not be null");
+ }
+
+ // get resource path
+ String path = requestParameters.getPath().substring(getMountPath().length());
+
+ // cut away query string
+ int startOfQueryString = path.indexOf("?");
+ if (startOfQueryString != -1)
+ {
+ path = path.substring(0, startOfQueryString);
+ }
+
+ final ValueMap parameters = decodeParameters(path, requestParameters.getParameters());
+
+ requestParameters.setParameters(parameters);
+ requestParameters.setResourceKey(resourceKey);
+ return new SharedResourceRequestTarget(requestParameters);
+ }
+
+ /**
+ *
+ * @see org.apache.wicket.request.target.coding.AbstractRequestTargetUrlCodingStrategy#decodeParameters(java.lang.String,
+ * java.util.Map)
+ */
+ @Override
+ protected ValueMap decodeParameters(String path, Map<String, Object> queryParameters)
+ {
+ final ValueMap parameters = new ValueMap(queryParameters);
+
+ // add indexed parameters to parameters map
+ if (!Strings.isEmpty(path))
+ {
+ final StringTokenizer tokens = new StringTokenizer(path, "/");
+
+ int index = 0;
+ while (tokens.hasMoreTokens())
+ {
+ parameters.add(Integer.toString(index++), tokens.nextToken());
+ }
+ }
+ return parameters;
+ }
+
+ /**
+ *
+ * @see org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#matches(org.apache.wicket.IRequestTarget)
+ */
+ public boolean matches(final IRequestTarget requestTarget)
+ {
+ if (!(requestTarget instanceof ISharedResourceRequestTarget))
+ {
+ return false;
+ }
+
+ final ISharedResourceRequestTarget target = (ISharedResourceRequestTarget)requestTarget;
+ return resourceKey.equals(target.getRequestParameters().getResourceKey());
+ }
+}
Added: wicket/trunk/wicket/src/test/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategyTest.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategyTest.java?rev=729078&view=auto
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategyTest.java (added)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/request/target/coding/IndexedSharedResourceCodingStrategyTest.java Tue Dec 23 11:52:47 2008
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.target.coding;
+
+import java.io.OutputStream;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.Resource;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.WicketTestCase;
+import org.apache.wicket.protocol.http.WebRequestCycle;
+import org.apache.wicket.util.resource.AbstractResourceStreamWriter;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.apache.wicket.util.value.ValueMap;
+
+/**
+ *
+ * @author
+ */
+public class IndexedSharedResourceCodingStrategyTest extends WicketTestCase
+{
+ private static final String URL_PREFIX = "/WicketTester$DummyWebApplication/WicketTester$DummyWebApplication/";
+ private static final String RESOURCE_NAME = "test";
+
+ private TestResource resource;
+
+ /**
+ *
+ * @see org.apache.wicket.WicketTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ resource = new TestResource();
+ tester.getApplication().getSharedResources().add(RESOURCE_NAME, resource);
+ final String key = new ResourceReference(RESOURCE_NAME).getSharedResourceKey();
+ tester.getApplication().mount(new IndexedSharedResourceCodingStrategy("/test", key));
+ }
+
+ /**
+ *
+ */
+ public void testEmptyRequest()
+ {
+ final WebRequestCycle cycle = tester.setupRequestAndResponse();
+ final String url = cycle.urlFor(new ResourceReference(RESOURCE_NAME)).toString();
+ assertEquals("test", url);
+ tester.getServletRequest().setURL(URL_PREFIX + url);
+ tester.processRequestCycle(cycle);
+ assertTrue(resource.params.isEmpty());
+ }
+
+ /**
+ *
+ */
+ public void testRequestWithIndexedParams()
+ {
+ final WebRequestCycle cycle = tester.setupRequestAndResponse();
+ final ValueMap params = new ValueMap();
+ params.add("0", "foo");
+ params.add("1", "bar");
+ final String url = cycle.urlFor(new ResourceReference(RESOURCE_NAME), params).toString();
+ assertEquals("test/foo/bar", url);
+ tester.getServletRequest().setURL(URL_PREFIX + url);
+ tester.processRequestCycle(cycle);
+ assertEquals(2, resource.params.size());
+ assertEquals("foo", resource.params.getString("0"));
+ assertEquals("bar", resource.params.getString("1"));
+ }
+
+ /**
+ *
+ */
+ public void testRequestWithIndexedParamsAndQueryString()
+ {
+ final WebRequestCycle cycle = tester.setupRequestAndResponse();
+ final PageParameters params = new PageParameters();
+
+ params.add("0", "param0");
+ params.add("1", "param1");
+ params.put("test", new String[] { "testval1", "testval2" });
+ params.add("foo", "fooval");
+ final String url = cycle.urlFor(new ResourceReference(RESOURCE_NAME), params).toString();
+ assertEquals("test/param0/param1?test=testval1&test=testval2&foo=fooval", url);
+ tester.getServletRequest().setURL(URL_PREFIX + url);
+ tester.processRequestCycle(cycle);
+ assertEquals(4, resource.params.size());
+ assertEquals("fooval", resource.params.getString("foo"));
+
+ final String[] arr = resource.params.getStringArray("test");
+ assertEquals(2, arr.length);
+ assertEquals("testval1", arr[0]);
+ assertEquals("testval2", arr[1]);
+
+ assertEquals("param0", resource.params.getString("0"));
+ assertEquals("param1", resource.params.getString("1"));
+ }
+
+ /**
+ *
+ */
+ private static class TestResource extends Resource
+ {
+ private static final long serialVersionUID = 6033856371536194742L;
+
+ public ValueMap params;
+
+ /**
+ *
+ * @see org.apache.wicket.Resource#getResourceStream()
+ */
+ @Override
+ public IResourceStream getResourceStream()
+ {
+ params = getParameters();
+
+ return new AbstractResourceStreamWriter()
+ {
+ private static final long serialVersionUID = 1680545160545385303L;
+
+ public void write(final OutputStream output)
+ {
+ // nada
+ }
+
+ public String getContentType()
+ {
+ return "text/plain";
+ }
+ };
+ }
+ }
+}