You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by kn...@apache.org on 2009/03/28 18:53:08 UTC
svn commit: r759525 [3/7] - in
/wicket/sandbox/knopp/experimental/wicket-ng/src: main/java/org/
main/java/org/apache/ main/java/org/apache/wicket/
main/java/org/apache/wicket/behavior/ main/java/org/apache/wicket/markup/
main/java/org/apache/wicket/mar...
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/Url.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/Url.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/Url.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/Url.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,467 @@
+/*
+ * 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;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.wicket.protocol.http.WicketURLDecoder;
+import org.apache.wicket.protocol.http.WicketURLEncoder;
+import org.apache.wicket.util.lang.Objects;
+import org.apache.wicket.util.string.StringValue;
+import org.apache.wicket.util.string.Strings;
+
+ /**
+ * Represents the URL part after Wicket Filter.
+ * <p>
+ * URL consists of segments and query parameters.
+ * <p>
+ * Example URLs:
+ *
+ * <pre>
+ * foo/bar/baz?a=1&b=5 - segments: ["foo","bar,"baz], query parameters: ["a"="1", "b"="5"]
+ * foo/bar//baz?=4&6 - segments: ["foo", "bar", "", "baz"], query parameters: [""="4", "6"=""]
+ * /foo/bar/ - segments: ["", "foo", "bar", ""]
+ * foo/bar// - segments: ["foo", "bar", "", ""]
+ * ?a=b - segments: [ ], query parameters: ["a"="b"]
+ * / - segments: ["", ""] (note that Url represents part after Wicket Filter
+ * - so if Wicket filter is mapped to /* this would be
+ * an additional slash, i.e. //
+ * </pre>
+ *
+ * The Url class takes care of encoding and decoding of the segments and parameters.
+ *
+ * @author Matej Knopp
+ */
+public final class Url implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ private final List<String> segments = new ArrayList<String>();
+
+ private List<QueryParameter> parameters = new ArrayList<QueryParameter>();
+
+ /**
+ * Construct.
+ */
+ public Url()
+ {
+ }
+
+ /**
+ * Construct.
+ *
+ * @param url
+ * url being copied
+ */
+ public Url(Url url)
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("Argument 'url' may not be null.");
+ }
+ segments.addAll(url.getSegments());
+ parameters.addAll(url.getQueryParameters());
+ }
+
+ /**
+ * Construct.
+ *
+ * @param segments
+ * @param parameters
+ */
+ public Url(List<String> segments, List<QueryParameter> parameters)
+ {
+ if (segments == null)
+ {
+ throw new IllegalArgumentException("Argument 'segments' may not be null.");
+ }
+ if (parameters == null)
+ {
+ throw new IllegalArgumentException("Argument 'parameters' may not be null.");
+ }
+ this.segments.addAll(segments);
+ this.parameters.addAll(parameters);
+ }
+
+ /**
+ * Returns segments of the URL. Segments form the part before query string.
+ *
+ * @return mutable list of segments
+ */
+ public List<String> getSegments()
+ {
+ return segments;
+ }
+
+ /**
+ * Returns query parameters of the URL.
+ *
+ * @return mutable list of query parameters
+ */
+ public List<QueryParameter> getQueryParameters()
+ {
+ return parameters;
+ }
+
+ /**
+ * Returns whether the URL is absolute.
+ *
+ * @return <code>true</code> if URL is absolute, <code>false</code> otherwise.
+ */
+ public boolean isAbsolute()
+ {
+ return !getSegments().isEmpty() && Strings.isEmpty(getSegments().get(0));
+ }
+
+ /**
+ * Convenience method that removes all query parameters with given name.
+ *
+ * @param name
+ * query parameter name
+ */
+ public void removeQueryParameters(String name)
+ {
+ for (Iterator<QueryParameter> i = getQueryParameters().iterator(); i.hasNext();)
+ {
+ QueryParameter param = i.next();
+ if (Objects.equal(name, param.getName()))
+ {
+ i.remove();
+ }
+ }
+ }
+
+ /**
+ * Convenience method that removes all query parameters with given name and adds new query
+ * parameter with specified name and value
+ *
+ * @param name
+ * @param value
+ */
+ public void setQueryParameter(String name, Object value)
+ {
+ removeQueryParameters(name);
+ if (value != null)
+ {
+ QueryParameter parameter = new QueryParameter(name, value.toString());
+ getQueryParameters().add(parameter);
+ }
+ }
+
+ /**
+ * Returns first query parameter with specified name or null if such query parameter doesn't
+ * exist.
+ *
+ * @param name
+ * @return query parameter or <code>null</code>
+ */
+ public QueryParameter getQueryParameter(String name)
+ {
+ for (QueryParameter parameter : parameters)
+ {
+ if (Objects.equal(name, parameter.getName()))
+ {
+ return parameter;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the value of first query parameter with specified name. Note that this method never
+ * returns <code>null</code>. Not even if the parameter does not exist.
+ *
+ * @see StringValue#isNull()
+ *
+ * @param name
+ * @return {@link StringValue} instance wrapping the parameter value
+ */
+ public StringValue getQueryParameterValue(String name)
+ {
+ QueryParameter parameter = getQueryParameter(name);
+ if (parameter == null)
+ {
+ return StringValue.valueOf((String)null);
+ }
+ else
+ {
+ return StringValue.valueOf(parameter.getValue());
+ }
+ }
+
+ /**
+ * Represents a single query parameter
+ *
+ * @author Matej Knopp
+ */
+ public final static class QueryParameter
+ {
+ private final String name;
+ private final String value;
+
+ /**
+ * Creates new {@link QueryParameter} instance. The <code>name</code> and
+ * <code>value</code> parameters must not be <code>null</code>, though they can be
+ * empty strings.
+ *
+ * @param name
+ * parameter name
+ * @param value
+ * parameter value
+ */
+ public QueryParameter(String name, String value)
+ {
+ if (name == null)
+ {
+ throw new IllegalArgumentException("Argument 'name' can not be null.");
+ }
+ if (value == null)
+ {
+ throw new IllegalArgumentException("Argument 'value' can not be null.");
+ }
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns query parameter name.
+ *
+ * @return query parameter name
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns query parameter value.
+ *
+ * @return query parameter value
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj instanceof QueryParameter == false)
+ {
+ return false;
+ }
+ QueryParameter rhs = (QueryParameter)obj;
+ return Objects.equal(this.getName(), rhs.getName()) &&
+ Objects.equal(this.getValue(), rhs.getValue());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hashCode(getName(), getValue());
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder result = new StringBuilder();
+ result.append(encodeParameter(getName()));
+ if (!Strings.isEmpty(getValue()))
+ {
+ result.append('=');
+ result.append(encodeParameter(getValue()));
+ }
+ return result.toString();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj instanceof Url == false)
+ {
+ return false;
+ }
+ Url rhs = (Url)obj;
+
+ return getSegments().equals(rhs.getSegments()) &&
+ getQueryParameters().equals(rhs.getQueryParameters());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hashCode(getSegments(), getQueryParameters());
+ }
+
+ private static String encodeSegment(String string)
+ {
+ return WicketURLEncoder.PATH_INSTANCE.encode(string);
+ }
+
+ private static String decodeSegment(String string)
+ {
+ return WicketURLDecoder.PATH_INSTANCE.decode(string);
+ }
+
+ private static String encodeParameter(String string)
+ {
+ return WicketURLEncoder.QUERY_INSTANCE.encode(string);
+ }
+
+ private static String decodeParameter(String string)
+ {
+ return WicketURLDecoder.QUERY_INSTANCE.decode(string);
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder result = new StringBuilder();
+ boolean first = true;
+ for (String s : getSegments())
+ {
+ if (!first)
+ {
+ result.append('/');
+ }
+ first = false;
+ result.append(encodeSegment(s));
+ }
+
+ first = true;
+
+ for (QueryParameter p : getQueryParameters())
+ {
+ if (first)
+ {
+ result.append("?");
+ first = false;
+ }
+ else
+ {
+ result.append("&");
+ }
+ result.append(p.toString());
+ }
+
+ return result.toString();
+ }
+
+ private static QueryParameter parseQueryParameter(String qp)
+ {
+ if (qp.indexOf('=') == -1)
+ {
+ return new QueryParameter(decodeParameter(qp), "");
+ }
+ String parts[] = qp.split("=");
+ if (parts.length == 0)
+ {
+ return new QueryParameter("", "");
+ }
+ else if (parts.length == 1)
+ {
+ return new QueryParameter("", decodeParameter(parts[0]));
+ }
+ else
+ {
+ return new QueryParameter(decodeParameter(parts[0]), decodeParameter(parts[1]));
+ }
+ }
+
+ /**
+ * Parses the given URL string.
+ *
+ * @param url
+ * @return Url object
+ */
+ public static Url parse(String url)
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("Argument 'url' may not be null.");
+ }
+
+ Url result = new Url();
+
+ String segments;
+ String query;
+
+ int qIndex = url.indexOf('?');
+
+ if (qIndex == -1)
+ {
+ segments = url;
+ query = "";
+ }
+ else
+ {
+ segments = url.substring(0, qIndex);
+ query = url.substring(qIndex + 1);
+ }
+
+ if (segments.length() > 0)
+ {
+
+ boolean removeLast = false;
+ if (segments.endsWith("/"))
+ {
+ // we need to append something and remove it after splitting because otherwise the
+ // trailing slashes will be lost
+ segments += "/x";
+ removeLast = true;
+ }
+
+ String segmentArray[] = segments.split("/");
+
+ if (removeLast)
+ {
+ segmentArray[segmentArray.length - 1] = null;
+ }
+
+ for (String s : segmentArray)
+ {
+ if (s != null)
+ {
+ result.segments.add(decodeSegment(s));
+ }
+ }
+ }
+
+ if (query.length() > 0)
+ {
+ String queryArray[] = query.split("&");
+ for (String s : queryArray)
+ {
+ result.parameters.add(parseQueryParameter(s));
+ }
+ }
+
+ return result;
+ };
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/Url.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRenderer.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRenderer.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRenderer.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRenderer.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,131 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Takes care of rendering relative (or in future possibly absolute - depending on configuration)
+ * URLs.
+ * <p>
+ * All Urls are rendered relative to the base Url. Base Url is normally Url of the page being
+ * rendered. However, during Ajax request and redirect to buffer rendering the BaseUrl need to be
+ * adjusted.
+ *
+ * @author Matej Knopp
+ */
+public class UrlRenderer
+{
+ /**
+ * Construct.
+ *
+ * @param base
+ * base Url. All generated Urls will be relative to this Url.
+ */
+ public UrlRenderer(Url base)
+ {
+ if (base == null)
+ {
+ throw new IllegalArgumentException("Argument 'base' may not be null.");
+ }
+ this.baseUrl = base;
+ }
+
+ /**
+ * Sets the base Url. All generated URLs will be relative to this Url.
+ *
+ * @param base
+ * @return original base Url
+ */
+ public Url setBaseUrl(Url base)
+ {
+ if (base == null)
+ {
+ throw new IllegalArgumentException("Argument 'base' may not be null.");
+ }
+ Url original = this.baseUrl;
+ this.baseUrl = base;
+ return original;
+ }
+
+ /**
+ * Returns the base Url.
+ *
+ * @return base Url
+ */
+ public Url getBaseUrl()
+ {
+ return baseUrl;
+ }
+
+ private Url baseUrl;
+
+ /**
+ * Renders the Url relative to currently set Base Url.
+ *
+ * @param url
+ * @return Url rendered as string
+ */
+ public String renderUrl(Url url)
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("Argument 'url' may not be null.");
+ }
+
+ if (url.isAbsolute())
+ {
+ return url.toString();
+ }
+ else
+ {
+ List<String> baseUrlSegments = getBaseUrl().getSegments();
+ List<String> urlSegments = new ArrayList<String>(url.getSegments());
+
+ List<String> newSegments = new ArrayList<String>();
+
+ int common = 0;
+
+ // Remove the last segment. We need at least one segment in the result URL.
+ // This prevents the last segment to be marked as common. Note that the last
+ // segment can also be "" (which means that the URL ends with slash).
+ List<String> baseUrlSegmentsCopy = new ArrayList<String>(baseUrlSegments);
+ if (!baseUrlSegments.isEmpty())
+ {
+ baseUrlSegmentsCopy.remove(baseUrlSegmentsCopy.size() - 1);
+ }
+
+ for (String s : baseUrlSegmentsCopy)
+ {
+ if (!urlSegments.isEmpty() && s.equals(urlSegments.get(0)))
+ {
+ ++common;
+ urlSegments.remove(0);
+ }
+ }
+
+ for (int i = common + 1; i < baseUrlSegments.size(); ++i)
+ {
+ newSegments.add("..");
+ }
+ newSegments.addAll(urlSegments);
+
+ return new Url(newSegments, url.getQueryParameters()).toString();
+ }
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRenderer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRequestParameters.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRequestParameters.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRequestParameters.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRequestParameters.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.wicket.request.Url.QueryParameter;
+import org.apache.wicket.util.lang.Objects;
+import org.apache.wicket.util.string.StringValue;
+
+/**
+ * Utility class that expresses query parameters from {@link Url} as {@link RequestParameters}.
+ *
+ * @author Matej Knopp
+ */
+public class UrlRequestParameters implements RequestParameters
+{
+ private final Url url;
+
+ /**
+ * Construct.
+ * @param url
+ */
+ public UrlRequestParameters(Url url)
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("Argument 'url' may not be null.");
+ }
+ this.url = url;
+ }
+
+ public Set<String> getParameterNames()
+ {
+ Set<String> result = new HashSet<String>();
+ for (QueryParameter parameter : url.getQueryParameters())
+ {
+ result.add(parameter.getName());
+ }
+ return Collections.unmodifiableSet(result);
+ }
+
+ public StringValue getParameterValue(String name)
+ {
+ return url.getQueryParameterValue(name);
+ }
+
+ public List<StringValue> getParameterValues(String name)
+ {
+ List<StringValue> values = null;
+ for (QueryParameter parameter : url.getQueryParameters())
+ {
+ if (Objects.equal(name, parameter.getName()))
+ {
+ if (values == null)
+ {
+ values = new ArrayList<StringValue>();
+ }
+ values.add(StringValue.valueOf(parameter.getValue()));
+ }
+ }
+ return values != null ? Collections.unmodifiableList(values) : null;
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/UrlRequestParameters.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractBookmarkableEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractBookmarkableEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractBookmarkableEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractBookmarkableEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,284 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.IComponent;
+import org.apache.wicket.IPage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.RequestListenerInterface;
+import org.apache.wicket.request.RequestHandler;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.encoder.info.ComponentInfo;
+import org.apache.wicket.request.encoder.info.PageComponentInfo;
+import org.apache.wicket.request.encoder.info.PageInfo;
+import org.apache.wicket.request.handler.impl.BookmarkableListenerInterfaceRequestHandler;
+import org.apache.wicket.request.handler.impl.BookmarkablePageRequestHandler;
+import org.apache.wicket.request.handler.impl.ListenerInterfaceRequestHandler;
+import org.apache.wicket.request.handler.impl.RenderPageRequestHandler;
+import org.apache.wicket.request.request.Request;
+
+/**
+ * Abstract encoder for Bookmarkable, Hybrid and BookmarkableListenerInterface URLs.
+ *
+ * @author Matej Knopp
+ */
+public abstract class AbstractBookmarkableEncoder extends AbstractEncoder
+{
+ /**
+ * Construct.
+ */
+ public AbstractBookmarkableEncoder()
+ {
+ }
+
+ private RequestHandler processBookmarkable(Class<? extends IPage> pageClass,
+ PageParameters pageParameters)
+ {
+ IPage page = newPageInstance(pageClass, pageParameters);
+ return new RenderPageRequestHandler(page);
+ }
+
+ private RequestHandler processHybrid(PageInfo pageInfo, Class<? extends IPage> pageClass,
+ PageParameters pageParameters, Integer renderCount)
+ {
+ IPage page = getPageInstance(pageInfo, pageClass, pageParameters, renderCount);
+ return new RenderPageRequestHandler(page);
+ }
+
+ private RequestHandler processListener(PageComponentInfo pageComponentInfo,
+ Class<? extends IPage> pageClass, PageParameters pageParameters)
+ {
+ PageInfo pageInfo = pageComponentInfo.getPageInfo();
+ ComponentInfo componentInfo = pageComponentInfo.getComponentInfo();
+ Integer renderCount = componentInfo != null ? componentInfo.getRenderCount() : null;
+
+ IPage page = getPageInstance(pageInfo, pageClass, pageParameters, true, renderCount);
+ IComponent component = getComponent(page, componentInfo.getComponentPath());
+ RequestListenerInterface listenerInterface = requestListenerInterfaceFromString(componentInfo.getListenerInterface());
+
+ return new ListenerInterfaceRequestHandler(page, component, listenerInterface,
+ componentInfo.getBehaviorIndex());
+ }
+
+ /**
+ * Represents information stored in URL.
+ *
+ * @author Matej
+ */
+ protected static final class UrlInfo
+ {
+ private final PageComponentInfo pageComponentInfo;
+ private final PageParameters pageParameters;
+ private final Class<? extends IPage> pageClass;
+
+ /**
+ * Construct.
+ *
+ * @param pageComponentInfo
+ * optional parameter providing the page instance and component information
+ * @param pageClass
+ * mandatory parameter
+ * @param pageParameters
+ * optional parameter providing pageParameters
+ */
+ public UrlInfo(PageComponentInfo pageComponentInfo, Class<? extends IPage> pageClass,
+ PageParameters pageParameters)
+ {
+ if (pageClass == null)
+ {
+ throw new IllegalArgumentException("Argument 'pageClass' may not be null.");
+ }
+ this.pageComponentInfo = pageComponentInfo;
+ this.pageParameters = pageParameters != null ? pageParameters : null;
+ this.pageClass = pageClass;
+ }
+
+ /**
+ * @return PageComponentInfo instance or <code>null</code>
+ */
+ public PageComponentInfo getPageComponentInfo()
+ {
+ return pageComponentInfo;
+ }
+
+ /**
+ * @return page class
+ */
+ public Class<? extends IPage> getPageClass()
+ {
+ return pageClass;
+ }
+
+ /**
+ * @return PageParameters instance (never <code>null</code>)
+ */
+ public PageParameters getPageParameters()
+ {
+ return pageParameters;
+ }
+ }
+
+ /**
+ * Parse the given request to an {@link UrlInfo} instance.
+ *
+ * @param request
+ * @return UrlInfo instance or <code>null</code> if this encoder can not handle the request
+ */
+ protected abstract UrlInfo parseRequest(Request request);
+
+ /**
+ * Builds URL for the given {@link UrlInfo} instance. The URL this method produces must be
+ * parseable by the {@link #parseRequest(Request)} method.
+ *
+ * @param info
+ * @return Url result URL
+ */
+ protected abstract Url buildUrl(UrlInfo info);
+
+ public RequestHandler decode(Request request)
+ {
+ UrlInfo urlInfo = parseRequest(request);
+
+ // check if the URL is long enough and starts with the proper segments
+ if (urlInfo != null)
+ {
+ PageComponentInfo info = urlInfo.getPageComponentInfo();
+ Class<? extends IPage> pageClass = urlInfo.getPageClass();
+ PageParameters pageParameters = urlInfo.getPageParameters();
+
+ if (info == null || info.getPageInfo().getPageId() == null)
+ {
+ // if there are is no page instance information (only page map name - optionally)
+ // then this is a simple bookmarkable URL
+ return processBookmarkable(pageClass, pageParameters);
+ }
+ else if (info.getPageInfo().getPageId() != null && info.getComponentInfo() == null)
+ {
+ // if there is page instance information in the URL but no component and listener
+ // interface then this is a hybrid URL - we need to try to reuse existing page
+ // instance
+ return processHybrid(info.getPageInfo(), pageClass, pageParameters, null);
+ }
+ else if (info.getComponentInfo() != null)
+ {
+ // with both page instance and component+listener this is a listener interface URL
+ return processListener(info, pageClass, pageParameters);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Indicates whether hybrid {@link RenderPageRequestHandler} URL for page will be generated only
+ * if page has been created with bookmarkable URL.
+ * <p>
+ * Generic bookmarkable encoders this method should return <code>true</code>. For explicit
+ * (mounted) encoders this method should return <code>false</code>
+ *
+ * @return <code>true</code> if hybrid URL requires page created bookmarkable,
+ * <code>false</code> otherwise.
+ */
+ protected abstract boolean pageMustHaveBeenCreatedBookmarkable();
+
+ public Url encode(RequestHandler requestHandler)
+ {
+ if (requestHandler instanceof BookmarkablePageRequestHandler)
+ {
+ // simple bookmarkable URL with no page instance information
+ BookmarkablePageRequestHandler handler = (BookmarkablePageRequestHandler)requestHandler;
+
+ PageInfo info = new PageInfo();
+ UrlInfo urlInfo = new UrlInfo(new PageComponentInfo(info, null),
+ handler.getPageClass(), handler.getPageParameters());
+
+ return buildUrl(urlInfo);
+ }
+ else if (requestHandler instanceof RenderPageRequestHandler)
+ {
+ // possibly hybrid URL - bookmarkable URL with page instance information
+ // but only allowed if the page was created by bookamarkable URL
+
+ RenderPageRequestHandler handler = (RenderPageRequestHandler)requestHandler;
+ IPage page = handler.getPage();
+
+ if (!pageMustHaveBeenCreatedBookmarkable() || page.wasCreatedBookmarkable())
+ {
+ PageInfo info = null;
+ if (!page.isPageStateless())
+ {
+ info = new PageInfo(page);
+ }
+ PageComponentInfo pageComponentInfo = info != null ? new PageComponentInfo(info,
+ null) : null;
+
+ UrlInfo urlInfo = new UrlInfo(pageComponentInfo, page.getClass(),
+ handler.getPageParameters());
+ return buildUrl(urlInfo);
+ }
+ else
+ {
+ return null;
+ }
+
+ }
+ else if (requestHandler instanceof BookmarkableListenerInterfaceRequestHandler)
+ {
+ // listener interface URL with page class information
+ BookmarkableListenerInterfaceRequestHandler handler = (BookmarkableListenerInterfaceRequestHandler)requestHandler;
+ IPage page = handler.getPage();
+ PageInfo pageInfo = new PageInfo(page);
+ ComponentInfo componentInfo = new ComponentInfo(
+ page.getRenderCount(), requestListenerInterfaceToString(handler.getListenerInterface()),
+ handler.getComponent().getPath(), handler.getBehaviorIndex());
+
+ UrlInfo urlInfo = new UrlInfo(new PageComponentInfo(pageInfo, componentInfo),
+ page.getClass(), handler.getPageParameters());
+ return buildUrl(urlInfo);
+ }
+
+ return null;
+ }
+
+ public abstract int getMachingSegmentsCount(Request request);
+
+ /**
+ * Convenience method for representing mountPath as array of segments
+ *
+ * @param mountPath
+ * @return array of path segments
+ */
+ protected String[] getMountSegments(String mountPath)
+ {
+ if (mountPath.startsWith("/"))
+ {
+ mountPath = mountPath.substring(1);
+ }
+ Url url = Url.parse(mountPath);
+
+ if (url.getSegments().isEmpty())
+ {
+ throw new IllegalArgumentException("Mount path must have at least one segment.");
+ }
+
+ String[] res = new String[url.getSegments().size()];
+ for (int i = 0; i < res.length; ++i)
+ {
+ res[i] = url.getSegments().get(i);
+ }
+ return res;
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractBookmarkableEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,445 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.IComponent;
+import org.apache.wicket.IPage;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.RequestListenerInterface;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.protocol.http.PageExpiredException;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.request.RequestHandlerEncoder;
+import org.apache.wicket.request.RequestParameters;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.Url.QueryParameter;
+import org.apache.wicket.request.encoder.info.PageComponentInfo;
+import org.apache.wicket.request.encoder.info.PageInfo;
+import org.apache.wicket.request.encoder.parameters.PageParametersEncoder;
+import org.apache.wicket.util.lang.Classes;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * Convenience class for implementing page/components related encoders.
+ *
+ * @author Matej Knopp
+ */
+public abstract class AbstractEncoder implements RequestHandlerEncoder
+{
+ protected EncoderContext getContext()
+ {
+ return WebApplication.get().getEncoderContext();
+ }
+
+ /**
+ * Converts the specified listener interface to String.
+ *
+ * @param listenerInterface
+ * @return listenerInterface name as string
+ */
+ protected String requestListenerInterfaceToString(RequestListenerInterface listenerInterface)
+ {
+ if (listenerInterface == null)
+ {
+ throw new IllegalArgumentException("Argument 'listenerInterface' may not be null.");
+ }
+ return getContext().requestListenerInterfaceToString(listenerInterface);
+ }
+
+ /**
+ * Creates listener interface from the specified string
+ *
+ * @param interfaceName
+ * @return listener interface
+ */
+ protected RequestListenerInterface requestListenerInterfaceFromString(String interfaceName)
+ {
+ if (interfaceName == null)
+ {
+ throw new IllegalArgumentException("Argument 'interfaceName' may not be null.");
+ }
+ return getContext().requestListenerInterfaceFromString(interfaceName);
+ }
+
+ protected static String getPlaceholder(String s)
+ {
+ if (s == null || s.length() < 4 || !s.startsWith("${") || !s.endsWith("}"))
+ {
+ return null;
+ }
+ else
+ {
+ return s.substring(2, s.length() - 1);
+ }
+ }
+
+ /**
+ * Returns true if the given url starts with specified segments. Segments that contain
+ * placelhoders are not compared.
+ *
+ * @param url
+ * @param segments
+ * @return <code>true</code> if the URL starts with the specified segments, <code>false</code>
+ * otherwise
+ */
+ protected boolean urlStartsWith(Url url, String... segments)
+ {
+ if (url == null)
+ {
+ return false;
+ }
+ else
+ {
+ if (url.getSegments().size() < segments.length)
+ {
+ return false;
+ }
+ else
+ {
+ for (int i = 0; i < segments.length; ++i)
+ {
+ if (segments[i].equals(url.getSegments().get(i)) == false && getPlaceholder(segments[i]) == null)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Extracts the {@link PageComponentInfo} from the URL. The {@link PageComponentInfo} is encoded
+ * as the very first query parameter and the parameter consists of name only (no value).
+ *
+ * @param url
+ *
+ * @return PageComponentInfo instance if one was encoded in URL, <code>null</code> otherwise.
+ */
+ protected PageComponentInfo getPageComponentInfo(Url url)
+ {
+ if (url == null)
+ {
+ throw new IllegalStateException("Argument 'url' may not be null.");
+ }
+ if (url.getQueryParameters().size() > 0)
+ {
+ QueryParameter param = url.getQueryParameters().get(0);
+ if (Strings.isEmpty(param.getValue()))
+ {
+ return PageComponentInfo.parse(param.getName());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Encodes the {@link PageComponentInfo} instance as the first query string parameter to the
+ * URL.
+ *
+ * @param url
+ * @param info
+ */
+ protected void encodePageComponentInfo(Url url, PageComponentInfo info)
+ {
+ if (url == null)
+ {
+ throw new IllegalStateException("Argument 'url' may not be null.");
+ }
+ if (info != null)
+ {
+ String s = info.toString();
+ if (!Strings.isEmpty(s))
+ {
+ QueryParameter parameter = new QueryParameter(s, "");
+ url.getQueryParameters().add(parameter);
+ }
+ }
+ }
+
+ /**
+ * Returns the page instance specified by the {@link PageInfo} object. When there is no such
+ * page instance this method either throws {@link PageExpiredException} (if the
+ * <code>throwExpiredExceptionIfNotFound</code> parameter is true) or return <code>null>/code>
+ *
+ * @param info
+ * @param throwExpiredExceptionIfNotFound
+ * @param renderCount
+ * @return page instance or <code>null</code>
+ */
+ protected IPage getPageInstance(PageInfo info, boolean throwExpiredExceptionIfNotFound, Integer renderCount)
+ {
+ if (info == null)
+ {
+ throw new IllegalArgumentException("Argument 'info' may not be null.");
+ }
+ IPage page = getContext().getPageInstance(info.getPageId());
+
+ if (page == null && throwExpiredExceptionIfNotFound)
+ {
+ throw new PageExpiredException("Page expired.");
+ }
+
+ if (page != null && renderCount != null && page.getRenderCount() != renderCount)
+ {
+ throw new StalePageException(page);
+ }
+
+ return page;
+ }
+
+ /**
+ * Returns the page instance specified by the {@link PageInfo} object. If there is no such page
+ * instance {@link PageExpiredException} is thrown.
+ *
+ * @param info
+ * @param renderCount
+ * @return page instance
+ */
+ protected IPage getPageInstance(PageInfo info, Integer renderCount)
+ {
+ return getPageInstance(info, true, renderCount);
+ }
+
+ /**
+ * Returns component on page with given path. If the component is not found an exception is
+ * thrown.
+ *
+ * @param page
+ * @param componentPath
+ * @return component instance
+ */
+ protected IComponent getComponent(IPage page, String componentPath)
+ {
+ if (page == null)
+ {
+ throw new IllegalArgumentException("Argument 'page' may not be nul.");
+ }
+ if (componentPath == null)
+ {
+ throw new IllegalArgumentException("Argument 'componentPath' may not be null.");
+ }
+ IComponent component = page.get(componentPath);
+ if (component == null)
+ {
+ throw new WicketRuntimeException("Component with path " + componentPath + " not found in page.");
+ }
+ else
+ {
+ return component;
+ }
+ }
+
+ /**
+ * Loads page class with given name.
+ *
+ * @param name
+ * @return class
+ */
+ protected Class<? extends IPage> getPageClass(String name)
+ {
+ if (name == null)
+ {
+ throw new IllegalArgumentException("Argument 'name' may not be null");
+ }
+ return Classes.resolveClass(name);
+ }
+
+ /**
+ * Extracts {@link PageParameters} from the URL using the given {@link PageParametersEncoder}.
+ *
+ * @param url
+ * @param requestParameters
+ * @param segmentsToSkip
+ * how many URL segments should be skipped because they "belong" to the
+ * {@link RequestHandlerEncoder}
+ * @param encoder
+ * @return PageParameters instance
+ */
+ protected PageParameters extractPageParameters(Url url, RequestParameters requestParameters, int segmentsToSkip,
+ PageParametersEncoder encoder)
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("Argument 'url' may not be null.");
+ }
+ if (encoder == null)
+ {
+ throw new IllegalArgumentException("Argument 'encoder' may not be null.");
+ }
+
+ // strip the segments and first query parameter from URL
+ Url urlCopy = new Url(url);
+ while (segmentsToSkip > 0 && urlCopy.getSegments().isEmpty() == false)
+ {
+ urlCopy.getSegments().remove(0);
+ --segmentsToSkip;
+ }
+
+ if (!urlCopy.getQueryParameters().isEmpty() && Strings.isEmpty(urlCopy.getQueryParameters().get(0).getValue()))
+ {
+ urlCopy.getQueryParameters().remove(0);
+ }
+
+ PageParameters decoded = encoder.decodePageParameters(urlCopy, requestParameters);
+ return decoded != null ? decoded : new PageParameters();
+ }
+
+ /**
+ * Encodes the given {@link PageParameters} to the URL using the given
+ * {@link PageParametersEncoder}. The original URL object is unchanged.
+ *
+ * @param url
+ * @param pageParameters
+ * @param encoder
+ * @return URL with encoded parameters
+ */
+ protected Url encodePageParameters(Url url, PageParameters pageParameters, PageParametersEncoder encoder)
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("Argument 'url' may no be null.");
+ }
+
+ if (pageParameters == null)
+ {
+ pageParameters = new PageParameters();
+ }
+
+ if (encoder == null)
+ {
+ throw new IllegalArgumentException("Argument 'encoder' may not be null.");
+ }
+
+ Url parametersUrl = encoder.encodePageParameters(pageParameters);
+ if (parametersUrl != null)
+ {
+ // copy the url
+ url = new Url(url);
+
+ for (String s : parametersUrl.getSegments())
+ {
+ url.getSegments().add(s);
+ }
+ for (QueryParameter p : parametersUrl.getQueryParameters())
+ {
+ url.getQueryParameters().add(p);
+ }
+ }
+
+ return url;
+ }
+
+ /**
+ * Creates new page instance with the specified attributes.
+ *
+ * @param pageMapName
+ * @param pageClass
+ * @param pageParameters
+ * @return new page instance
+ */
+ protected IPage newPageInstance(Class<? extends IPage> pageClass, PageParameters pageParameters)
+ {
+ IPage page = getContext().newPageInstance(pageClass, pageParameters);
+
+ // the page might have not propagate page parameters from constructor. if that's the case
+ // we force the parameters
+ if (pageParameters != null && page.getPageParameters() != pageParameters)
+ {
+ page.getPageParameters().assign(pageParameters);
+ }
+ return page;
+ }
+
+ /**
+ * Tries to get existing page instance specified by the {@link PageInfo} object. If there is no
+ * such instance or there instance class doesn't match the <code>pageClass</code> argument, new
+ * page instance is created.
+ *
+ * @param pageInfo
+ * @param pageClass
+ * @param pageParameters
+ * @param renderCount
+ *
+ * @return page instance
+ */
+ protected IPage getPageInstance(PageInfo pageInfo, Class<? extends IPage> pageClass, PageParameters pageParameters,
+ Integer renderCount)
+ {
+ return getPageInstance(pageInfo, pageClass, pageParameters, false, renderCount);
+ }
+
+ /**
+ * Tries to get existing page instance specified by the {@link PageInfo} object. If there is no
+ * such instance or there instance class doesn't match the <code>pageClass</code> argument, new
+ * page instance is created.
+ * <p>
+ * If new page was created (no existing page was found) and the the
+ * <code>prepareForRenderNewPage</code> flag is set, <code>page.repareForRender(false)</code> is
+ * called on the page. This is necessary to do when looking on a component on stateless page as
+ * the component hierarchy has to be built.
+ *
+ * @param pageInfo
+ * @param pageClass
+ * @param pageParameters
+ * @param prepareForRenderNewPage
+ * @param renderCount
+ *
+ * @return page instance
+ */
+ protected IPage getPageInstance(PageInfo pageInfo, Class<? extends IPage> pageClass, PageParameters pageParameters,
+ boolean prepareForRenderNewPage, Integer renderCount)
+ {
+ if (pageInfo == null)
+ {
+ throw new IllegalArgumentException("Argument 'pageInfo' may not be null.");
+ }
+ if (pageClass == null)
+ {
+ throw new IllegalArgumentException("Argument 'pageClass' may not be null.");
+ }
+ if (pageParameters == null)
+ {
+ throw new IllegalArgumentException("Argument 'pageParameters' may not be null.");
+ }
+ IPage page = getContext().getPageInstance(pageInfo.getPageId());
+ if (page != null && page.getClass().equals(pageClass) == false)
+ {
+ page = null;
+ }
+ if (page == null)
+ {
+ page = newPageInstance(pageClass, pageParameters);
+
+ // this is required for stateless listeners
+ if (prepareForRenderNewPage && page instanceof Page)
+ {
+ ((Page) page).prepareForRender(false);
+ }
+ }
+ else
+ {
+ if (renderCount != null && page.getRenderCount() != renderCount)
+ {
+ throw new StalePageException(page);
+ }
+ page.getPageParameters().assign(pageParameters);
+ }
+ return page;
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractResourceReferenceEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractResourceReferenceEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractResourceReferenceEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractResourceReferenceEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,133 @@
+/*
+ * 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.encoder;
+
+import java.util.Locale;
+
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.Url.QueryParameter;
+import org.apache.wicket.resource.ResourceReference;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * Base class for encoding and decoding {@link ResourceReference}s
+ *
+ * @author Matej Knopp
+ */
+public abstract class AbstractResourceReferenceEncoder extends AbstractEncoder
+{
+
+ protected static class ResourceReferenceAttributes
+ {
+ protected Locale locale;
+ protected String style;
+ };
+
+ protected static String encodeResourceReferenceAttributes(ResourceReferenceAttributes attributes)
+ {
+ if (attributes == null || (attributes.locale == null && attributes.style == null))
+ {
+ return null;
+ }
+ else
+ {
+ StringBuilder res = new StringBuilder();
+ if (attributes.locale != null)
+ {
+ res.append(attributes.locale.toString());
+ }
+ if (!Strings.isEmpty(attributes.style))
+ {
+ res.append("-");
+ res.append(attributes.style);
+ }
+ return res.toString();
+ }
+ };
+
+ protected static ResourceReferenceAttributes decodeResourceReferenceAttributes(String attributes)
+ {
+ ResourceReferenceAttributes res = new ResourceReferenceAttributes();
+ if (!Strings.isEmpty(attributes))
+ {
+ String split[] = attributes.split("-", 2);
+ res.locale = parseLocale(split[0]);
+ if (split.length == 2)
+ {
+ res.style = split[1];
+ }
+ }
+ return res;
+ }
+
+ private static Locale parseLocale(String locale)
+ {
+ if (Strings.isEmpty(locale))
+ {
+ return null;
+ }
+ else
+ {
+ String parts[] = locale.toLowerCase().split("_", 3);
+ if (parts.length == 1)
+ {
+ return new Locale(parts[0]);
+ }
+ else if (parts.length == 2)
+ {
+ return new Locale(parts[0], parts[1]);
+ }
+ else if (parts.length == 3)
+ {
+ return new Locale(parts[0], parts[1], parts[2]);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ protected void encodeResourceReferenceAttributes(Url url, ResourceReference reference)
+ {
+ ResourceReferenceAttributes attributes = new ResourceReferenceAttributes();
+ attributes.locale = reference.getLocale();
+ attributes.style = reference.getStyle();
+ String encoded = encodeResourceReferenceAttributes(attributes);
+ if (!Strings.isEmpty(encoded))
+ {
+ url.getQueryParameters().add(new Url.QueryParameter(encoded, ""));
+ }
+ }
+
+ protected ResourceReferenceAttributes getResourceReferenceAttributes(Url url)
+ {
+ if (url == null)
+ {
+ throw new IllegalStateException("Argument 'url' may not be null.");
+ }
+ if (url.getQueryParameters().size() > 0)
+ {
+ QueryParameter param = url.getQueryParameters().get(0);
+ if (Strings.isEmpty(param.getValue()))
+ {
+ return decodeResourceReferenceAttributes(param.getName());
+ }
+ }
+ return new ResourceReferenceAttributes();
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/AbstractResourceReferenceEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/BookmarkableEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/BookmarkableEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/BookmarkableEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/BookmarkableEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,126 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.IPage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.encoder.info.PageComponentInfo;
+import org.apache.wicket.request.encoder.parameters.PageParametersEncoder;
+import org.apache.wicket.request.encoder.parameters.SimplePageParametersEncoder;
+import org.apache.wicket.request.request.Request;
+
+/**
+ * Decodes and encodes the following URLs:
+ *
+ * <pre>
+ * Page Class - Render (BookmarkablePageRequestHandler)
+ * /wicket/bookmarkable/org.apache.wicket.MyPage
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?pageMap
+ * (these will redirect to hybrid alternative if page is not stateless)
+ *
+ * Page Instance - Render Hybrid (RenderPageRequestHandler for pages that were created using bookmarkable URLs)
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2.4
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?pageMap.2.4
+ *
+ * Page Instance - Bookmarkable Listener (BookmarkableListenerInterfaceRequestHandler)
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2-click-foo-bar-baz
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2.4-click-foo-bar-baz
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?pageMap.2.4-click-foo-bar-baz
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2.4-click.1-foo-bar-baz (1 is behavior index)
+ * (these will redirect to hybrid if page is not stateless)
+ * </pre>
+ *
+ * @author Matej Knopp
+ */
+public class BookmarkableEncoder extends AbstractBookmarkableEncoder
+{
+ private final PageParametersEncoder pageParametersEncoder;
+
+ /**
+ * Construct.
+ *
+ * @param pageParametersEncoder
+ */
+ public BookmarkableEncoder(PageParametersEncoder pageParametersEncoder)
+ {
+ if (pageParametersEncoder == null)
+ {
+ throw new IllegalArgumentException("Argument 'pageParametersEncoder' may not be null.");
+ }
+ this.pageParametersEncoder = pageParametersEncoder;
+ }
+
+ /**
+ * Construct.
+ */
+ public BookmarkableEncoder()
+ {
+ this(new SimplePageParametersEncoder());
+ }
+
+ @Override
+ protected Url buildUrl(UrlInfo info)
+ {
+ Url url = new Url();
+ url.getSegments().add(getContext().getNamespace());
+ url.getSegments().add(getContext().getBookmarkableIdentifier());
+ url.getSegments().add(info.getPageClass().getName());
+
+ encodePageComponentInfo(url, info.getPageComponentInfo());
+
+ return encodePageParameters(url, info.getPageParameters(), pageParametersEncoder);
+ }
+
+ @Override
+ protected UrlInfo parseRequest(Request request)
+ {
+ Url url = request.getUrl();
+ if (url.getSegments().size() >= 3 &&
+ urlStartsWith(url, getContext().getNamespace(),
+ getContext().getBookmarkableIdentifier()))
+ {
+ // try to extract page and component information from URL
+ PageComponentInfo info = getPageComponentInfo(url);
+
+ // load the page class
+ String className = url.getSegments().get(2);
+ Class<? extends IPage> pageClass = getPageClass(className);
+
+ // extract the PageParameters from URL if there are any
+ PageParameters pageParameters = extractPageParameters(url,
+ request.getRequestParameters(), 3, pageParametersEncoder);
+
+ return new UrlInfo(info, pageClass, pageParameters);
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean pageMustHaveBeenCreatedBookmarkable()
+ {
+ return true;
+ }
+
+ public int getMachingSegmentsCount(Request request)
+ {
+ // always return 0 here so that the mounts have higher priority
+ return 0;
+ }
+
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/BookmarkableEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/EncoderContext.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/EncoderContext.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/EncoderContext.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/EncoderContext.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,98 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.IPage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.RequestListenerInterface;
+import org.apache.wicket.resource.ResourceReferenceRegistry;
+
+/**
+ * Utility interface for providing and creating new page instances.
+ *
+ * @author Matej Knopp
+ */
+public interface EncoderContext
+{
+ /**
+ * Returns existing page instance if the page exists.
+ *
+ * @param pageId
+ * @return page instance or <code>null</code> if the page does not exist.
+ */
+ public IPage getPageInstance(int pageId);
+
+ /**
+ * Creates new page instance of page with given class. The page should be marked as
+ * create bookmarkable, so subsequent calls to {@link IPage#wasCreatedBookmarkable()}
+ * must return <code>true</code>
+ *
+ * @param pageMapName
+ * @param pageClass
+ * @param pageParameters
+ * @return new page instance
+ */
+ public IPage newPageInstance(Class<? extends IPage> pageClass, PageParameters pageParameters);
+
+ /**
+ * @return the namespace for Wicket URLs.
+ */
+ public String getNamespace();
+
+ /**
+ * @return identifier for non bookmarkable URLs
+ */
+ public String getPageIdentifier();
+
+ /**
+ * @return identifier for bookmarkable URLs
+ */
+ public String getBookmarkableIdentifier();
+
+ /**
+ * @return identifier for resources
+ */
+ public String getResourceIdentifier();
+
+ /**
+ * @return {@link ResourceReferenceRegistry}
+ */
+ public ResourceReferenceRegistry getResourceReferenceRegistry();
+
+ /**
+ * Returns the listener interface name as string.
+ *
+ * @param listenerInterface
+ * @return listener interface name as string
+ */
+ public String requestListenerInterfaceToString(RequestListenerInterface listenerInterface);
+
+ /**
+ * Returns listener interface for the name
+ *
+ * @param interfaceName
+ * @return listener interface
+ */
+ public RequestListenerInterface requestListenerInterfaceFromString(String interfaceName);
+
+ /**
+ * Returns the home page class.
+ *
+ * @return home page class
+ */
+ public Class<? extends IPage> getHomePageClass();
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/EncoderContext.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/MountedEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/MountedEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/MountedEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/MountedEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,230 @@
+/*
+ * 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.encoder;
+
+import java.lang.ref.WeakReference;
+
+import org.apache.wicket.IPage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.encoder.info.PageComponentInfo;
+import org.apache.wicket.request.encoder.parameters.PageParametersEncoder;
+import org.apache.wicket.request.encoder.parameters.SimplePageParametersEncoder;
+import org.apache.wicket.request.request.Request;
+
+/**
+ * Encoder for mounted URL. The mount path can contain parameter placeholders, i.e.
+ * <code>/mount/${foo}/path</code>. In that case the appropriate segment from the URL will be
+ * accessible as named parameter "foo" in the {@link PageParameters}. Similarly when the URL is
+ * constructed, the second segment will contain the value of the "foo" named page parameter.
+ * <p>
+ * Decodes and encodes the following URLs:
+ *
+ * <pre>
+ * Page Class - Render (BookmarkablePageRequestHandler for mounted pages)
+ * /mount/point
+ * /mount/point?pageMap
+ * (these will redirect to hybrid alternative if page is not stateless)
+ *
+ * IPage Instance - Render Hybrid (RenderPageRequestHandler for mounted pages)
+ * /mount/point?2
+ * /mount/point?2.4
+ * /mount/point?pageMap.2.4
+ *
+ * IPage Instance - Bookmarkable Listener (BookmarkableListenerInterfaceRequestHandler for mounted pages)
+ * /mount/point?2-click-foo-bar-baz
+ * /mount/point?2.4-click-foo-bar-baz
+ * /mount/point?pageMap.2.4-click-foo-bar-baz
+ * /mount/point?2.4-click.1-foo-bar-baz (1 is behavior index)
+ * (these will redirect to hybrid if page is not stateless)
+ * </pre>
+ *
+ * @author Matej Knopp
+ */
+public class MountedEncoder extends AbstractBookmarkableEncoder
+{
+ private final PageParametersEncoder pageParametersEncoder;
+ private final String[] mountSegments;
+
+ /** bookmarkable page class. */
+ protected final WeakReference<Class<? extends IPage>> pageClass;
+
+
+ /**
+ * Construct.
+ *
+ * @param mountPath
+ * @param pageClass
+ * @param pageParametersEncoder
+ */
+ public MountedEncoder(String mountPath, Class<? extends IPage> pageClass,
+ PageParametersEncoder pageParametersEncoder)
+ {
+ if (pageParametersEncoder == null)
+ {
+ throw new IllegalArgumentException("Argument 'pageParametersEncoder' may not be null.");
+ }
+ if (pageClass == null)
+ {
+ throw new IllegalArgumentException("Argument 'pageClass' may not be null.");
+ }
+ if (mountPath == null)
+ {
+ throw new IllegalArgumentException("Argument 'mountPath' may not be null.");
+ }
+ this.pageParametersEncoder = pageParametersEncoder;
+ this.pageClass = new WeakReference<Class<? extends IPage>>(pageClass);
+ this.mountSegments = getMountSegments(mountPath);
+ }
+
+ /**
+ * Construct.
+ *
+ * @param mountPath
+ * @param pageClass
+ */
+ public MountedEncoder(String mountPath, Class<? extends IPage> pageClass)
+ {
+ this(mountPath, pageClass, new SimplePageParametersEncoder());
+ }
+
+ @Override
+ protected UrlInfo parseRequest(Request request)
+ {
+ Url url = request.getUrl();
+
+ // when redirect to buffer/render is active and redirectFromHomePage returns true
+ // check mounted class against the home page class. if it matches let wicket redirect
+ // to the mounted URL
+ if (redirectFromHomePage() && checkHomePage(url))
+ {
+ UrlInfo info = new UrlInfo(null, getContext().getHomePageClass(), newPageParameters());
+ return info;
+ }
+ // check if the URL is long enough and starts with the proper segments
+ else if (url.getSegments().size() >= mountSegments.length &&
+ urlStartsWith(url, mountSegments))
+ {
+ // try to extract page and component information from URL
+ PageComponentInfo info = getPageComponentInfo(url);
+
+ Class<? extends IPage> pageClass = this.pageClass.get();
+
+ // extract the PageParameters from URL if there are any
+ PageParameters pageParameters = extractPageParameters(url,
+ request.getRequestParameters(), mountSegments.length, pageParametersEncoder);
+
+ // check if there are placeholders in mount segments
+ for (int i = 0; i < mountSegments.length; ++i)
+ {
+ String placeholder = getPlaceholder(mountSegments[i]);
+ if (placeholder != null)
+ {
+ // extract the parameter from URL
+ pageParameters.addNamedParameter(placeholder, url.getSegments().get(i));
+ }
+ }
+
+ return new UrlInfo(info, pageClass, pageParameters);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ protected PageParameters newPageParameters()
+ {
+ return new PageParameters();
+ }
+
+ @Override
+ protected Url buildUrl(UrlInfo info)
+ {
+ Url url = new Url();
+ for (String s : mountSegments)
+ {
+ url.getSegments().add(s);
+ }
+ encodePageComponentInfo(url, info.getPageComponentInfo());
+
+ PageParameters copy = new PageParameters(info.getPageParameters());
+
+ for (int i = 0; i < mountSegments.length; ++i)
+ {
+ String placeholder = getPlaceholder(mountSegments[i]);
+ if (placeholder != null)
+ {
+ url.getSegments().set(i, copy.getNamedParameter(placeholder).toString(""));
+ copy.removeNamedParameter(placeholder);
+ }
+ }
+
+ return encodePageParameters(url, copy, pageParametersEncoder);
+ }
+
+ /**
+ * Check if the URL is for home page and the home page class match mounted class. If so,
+ * redirect to mounted URL.
+ *
+ * @param url
+ * @return request handler or <code>null</code>
+ */
+ private boolean checkHomePage(Url url)
+ {
+ if (url.getSegments().isEmpty() && url.getQueryParameters().isEmpty())
+ {
+ // this is home page
+ if (pageClass.get().equals(getContext().getHomePageClass()) && redirectFromHomePage())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * If this method returns <code>true</code> and application home page class is same as the
+ * class mounted with this encoder, request to home page will result in a redirect to the
+ * mounted path.
+ *
+ * @return whether this encode should respond to home page request when home page class is same
+ * as mounted class.
+ */
+ protected boolean redirectFromHomePage()
+ {
+ return true;
+ }
+
+ @Override
+ protected boolean pageMustHaveBeenCreatedBookmarkable()
+ {
+ return false;
+ }
+
+ public int getMachingSegmentsCount(Request request)
+ {
+ if (urlStartsWith(request.getUrl(), mountSegments))
+ {
+ return mountSegments.length;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/MountedEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/PageInstanceEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/PageInstanceEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/PageInstanceEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/PageInstanceEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,136 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.IComponent;
+import org.apache.wicket.IPage;
+import org.apache.wicket.RequestListenerInterface;
+import org.apache.wicket.request.RequestHandler;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.encoder.info.ComponentInfo;
+import org.apache.wicket.request.encoder.info.PageComponentInfo;
+import org.apache.wicket.request.encoder.info.PageInfo;
+import org.apache.wicket.request.handler.impl.ListenerInterfaceRequestHandler;
+import org.apache.wicket.request.handler.impl.RenderPageRequestHandler;
+import org.apache.wicket.request.request.Request;
+
+/**
+ * Decodes and encodes the following URLs:
+ *
+ * <pre>
+ * Page Instance - Render (RenderPageRequestHandler)
+ * /wicket/page?2
+ * /wicket/page?2.4
+ * /wicket/page?abc.2.4
+ *
+ * Page Instance - Listener (ListenerInterfaceRequestHandler)
+ * /wicket/page?2-click-foo-bar-baz
+ * /wicket/page?2.4-click-foo-bar-baz
+ * /wicket/page?pageMap.2.4-click-foo-bar-bazr-baz
+ * /wicket/page?2.4-click.1-foo-bar-baz (1 is behavior index)
+ * </pre>
+ *
+ * @author Matej Knopp
+ */
+public class PageInstanceEncoder extends AbstractEncoder
+{
+
+ /**
+ * Construct.
+ */
+ public PageInstanceEncoder()
+ {
+ }
+
+
+ public RequestHandler decode(Request request)
+ {
+ Url url = request.getUrl();
+ if (urlStartsWith(url, getContext().getNamespace(), getContext().getPageIdentifier()))
+ {
+ PageComponentInfo info = getPageComponentInfo(url);
+ if (info != null && info.getPageInfo().getPageId() != null)
+ {
+ Integer renderCount = info.getComponentInfo() != null ? info.getComponentInfo().getRenderCount() : null;
+
+ IPage page = getPageInstance(info.getPageInfo(), renderCount);
+
+ if (info.getComponentInfo() == null)
+ {
+ // render page
+ return new RenderPageRequestHandler(page);
+ }
+ else
+ {
+ ComponentInfo componentInfo = info.getComponentInfo();
+ // listener interface
+ IComponent component = getComponent(page, componentInfo.getComponentPath());
+ RequestListenerInterface listenerInterface = requestListenerInterfaceFromString(componentInfo.getListenerInterface());
+
+ return new ListenerInterfaceRequestHandler(page, component, listenerInterface,
+ componentInfo.getBehaviorIndex());
+ }
+ }
+ }
+ return null;
+ }
+
+ public Url encode(RequestHandler requestHandler)
+ {
+ PageComponentInfo info = null;
+
+ if (requestHandler instanceof RenderPageRequestHandler)
+ {
+ IPage page = ((RenderPageRequestHandler)requestHandler).getPage();
+
+ PageInfo i = new PageInfo(page);
+ info = new PageComponentInfo(i, null);
+ }
+ else if (requestHandler instanceof ListenerInterfaceRequestHandler)
+ {
+ ListenerInterfaceRequestHandler handler = (ListenerInterfaceRequestHandler)requestHandler;
+ IPage page = handler.getPage();
+ String componentPath = handler.getComponent().getPath();
+ RequestListenerInterface listenerInterface = handler.getListenerInterface();
+
+ PageInfo pageInfo = new PageInfo(page);
+ ComponentInfo componentInfo = new ComponentInfo(
+ page.getRenderCount(), requestListenerInterfaceToString(listenerInterface), componentPath,
+ handler.getBehaviorIndex());
+ info = new PageComponentInfo(pageInfo, componentInfo);
+ }
+
+ if (info != null)
+ {
+ Url url = new Url();
+ url.getSegments().add(getContext().getNamespace());
+ url.getSegments().add(getContext().getPageIdentifier());
+ encodePageComponentInfo(url, info);
+ return url;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public int getMachingSegmentsCount(Request request)
+ {
+ // always return 0 here so that the mounts have higher priority
+ return 0;
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/PageInstanceEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/ResourceReferenceEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/ResourceReferenceEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/ResourceReferenceEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/ResourceReferenceEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,161 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.request.RequestHandler;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.encoder.parameters.PageParametersEncoder;
+import org.apache.wicket.request.encoder.parameters.SimplePageParametersEncoder;
+import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
+import org.apache.wicket.request.handler.resource.ResourceRequestHandler;
+import org.apache.wicket.request.request.Request;
+import org.apache.wicket.resource.Resource;
+import org.apache.wicket.resource.ResourceReference;
+import org.apache.wicket.util.lang.Classes;
+
+/**
+ * Generic {@link ResourceReference} encoder that encodes and decodes non-mounted
+ * {@link ResourceReference}s.
+ * <p>
+ * Decodes and encodes the following URLs:
+ * <pre>
+ * /wicket/resource/org.apache.wicket.ResourceScope/name
+ * /wicket/resource/org.apache.wicket.ResourceScope/name?en
+ * /wicket/resource/org.apache.wicket.ResourceScope/name?-style
+ * /wicket/resource/org.apache.wicket.ResourceScope/resource/name.xyz?en_EN-style
+ * </pre>
+ *
+ * @author Matej Knopp
+ */
+public class ResourceReferenceEncoder extends AbstractResourceReferenceEncoder
+{
+ private final PageParametersEncoder pageParametersEncoder;
+
+ /**
+ * Construct.
+ *
+ * @param pageParametersEncoder
+ */
+ public ResourceReferenceEncoder(PageParametersEncoder pageParametersEncoder)
+ {
+ this.pageParametersEncoder = pageParametersEncoder;
+ }
+
+ /**
+ * Construct.
+ */
+ public ResourceReferenceEncoder()
+ {
+ this(new SimplePageParametersEncoder());
+ }
+
+ protected EncoderContext getContext()
+ {
+ return null;
+ };
+
+ public RequestHandler decode(Request request)
+ {
+ Url url = request.getUrl();
+ if (url.getSegments().size() >= 4 &&
+ urlStartsWith(url, getContext().getNamespace(), getContext().getResourceIdentifier()))
+ {
+ String className = url.getSegments().get(2);
+ StringBuilder name = new StringBuilder();
+ for (int i = 3; i < url.getSegments().size(); ++i)
+ {
+ if (name.length() > 0)
+ {
+ name.append("/");
+ }
+ name.append(url.getSegments().get(i));
+ }
+
+ ResourceReferenceAttributes attributes = getResourceReferenceAttributes(url);
+
+ // extract the PageParameters from URL if there are any
+ PageParameters pageParameters = extractPageParameters(url,
+ request.getRequestParameters(), url.getSegments().size(), pageParametersEncoder);
+
+ Class<?> scope = resolveClass(className);
+ if (scope != null)
+ {
+ ResourceReference res = getContext().getResourceReferenceRegistry()
+ .getResourceReference(scope, name.toString(), attributes.locale,
+ attributes.style, false);
+ if (res != null)
+ {
+ Resource resource = res.getResource();
+ if (resource != null)
+ {
+ ResourceRequestHandler handler = new ResourceRequestHandler(resource,
+ attributes.locale, attributes.style, pageParameters);
+ return handler;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ protected Class<?> resolveClass(String name)
+ {
+ return Classes.resolveClass(name);
+ }
+
+ protected String getClassName(Class<?> scope)
+ {
+ return scope.getName();
+ }
+
+ public Url encode(RequestHandler requestHandler)
+ {
+ if (requestHandler instanceof ResourceReferenceRequestHandler)
+ {
+ ResourceReferenceRequestHandler referenceRequestHandler = (ResourceReferenceRequestHandler)requestHandler;
+ ResourceReference reference = referenceRequestHandler.getResourceReference();
+ Url url = new Url();
+ url.getSegments().add(getContext().getNamespace());
+ url.getSegments().add(getContext().getResourceIdentifier());
+ url.getSegments().add(getClassName(reference.getScope()));
+ String nameParts[] = reference.getName().split("/");
+ for (String name : nameParts)
+ {
+ url.getSegments().add(name);
+ }
+ encodeResourceReferenceAttributes(url, reference);
+ PageParameters parameters = referenceRequestHandler.getPageParameters();
+ if (parameters != null)
+ {
+ parameters = new PageParameters(parameters);
+ // need to remove indexed parameters otherwise the URL won't be able to decode
+ parameters.clearIndexedParameters();
+ url = encodePageParameters(url, parameters, pageParametersEncoder);
+ }
+ return url;
+ }
+ return null;
+ }
+
+ public int getMachingSegmentsCount(Request request)
+ {
+ // always return 0 here so that the mounts have higher priority
+ return 0;
+ }
+
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/ResourceReferenceEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/StalePageException.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/StalePageException.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/StalePageException.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/StalePageException.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,52 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.IPage;
+import org.apache.wicket.WicketRuntimeException;
+
+/**
+ * Exception invoked when when stale link has been clicked. The page should then be rerendered
+ * with an explanatory error message.
+ *
+ * @author Matej Knopp
+ */
+public class StalePageException extends WicketRuntimeException
+{
+ private static final long serialVersionUID = 1L;
+
+ private final IPage page;
+
+ /**
+ *
+ * Construct.
+ * @param page
+ */
+ public StalePageException(IPage page)
+ {
+ this.page = page;
+ }
+
+ /**
+ *
+ * @return page instance
+ */
+ public IPage getPage()
+ {
+ return page;
+ }
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/StalePageException.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/info/ComponentInfo.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/info/ComponentInfo.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/info/ComponentInfo.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/info/ComponentInfo.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,248 @@
+/*
+ * 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.encoder.info;
+
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * Encodes listener inteface and component path in form of
+ * <listenerInterface>-<componentPath> or
+ * <listenerInterface>.<behaviorIndex>-<componentPath>
+ * <p>
+ * Component path is escaped (':' characters are replaced by '-')
+ *
+ * @author Matej Knopp
+ */
+public class ComponentInfo
+{
+ private final String listenerInterface;
+ private final String componentPath;
+ private final Integer behaviorIndex;
+ private final Integer renderCount;
+
+ private static final char BEHAVIOR_INDEX_SEPARATOR = '.';
+ private static final char SEPARATOR = '-';
+
+ /**
+ * Construct.
+ *
+ * @param renderCount
+ * @param listenerInterface
+ * @param componentPath
+ * @param behaviorIndex
+ */
+ public ComponentInfo(Integer renderCount, String listenerInterface, String componentPath,
+ Integer behaviorIndex)
+ {
+ if (listenerInterface == null)
+ {
+ throw new IllegalArgumentException("Argument 'listenerInterface' may not be null.");
+ }
+ if (componentPath == null)
+ {
+ throw new IllegalArgumentException("Argument 'componentPath' may not be null.");
+ }
+ this.listenerInterface = listenerInterface;
+ this.componentPath = componentPath;
+ this.behaviorIndex = behaviorIndex;
+ this.renderCount = renderCount;
+ }
+
+ /**
+ * @return component path
+ */
+ public String getComponentPath()
+ {
+ return componentPath;
+ }
+
+ /**
+ * @return listener interface name
+ */
+ public String getListenerInterface()
+ {
+ return listenerInterface;
+ }
+
+ /**
+ * @return behavior index
+ */
+ public Integer getBehaviorIndex()
+ {
+ return behaviorIndex;
+ }
+
+ /**
+ *
+ * @return render count
+ */
+ public Integer getRenderCount()
+ {
+ return renderCount;
+ }
+
+ private static final String TMP_PLACEHOLDER = "[[[[[[[WICKET[[TMP]]DASH]]" + Math.random() +
+ "]]]]";
+
+ private static String encodeComponentPath(String path)
+ {
+ if (path != null)
+ {
+ path = path.replace("" + SEPARATOR, TMP_PLACEHOLDER);
+ path = path.replace(':', SEPARATOR);
+ path = path.replace(TMP_PLACEHOLDER, "" + SEPARATOR + SEPARATOR);
+ return path;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private static String decodeComponentPath(String path)
+ {
+ if (path != null)
+ {
+ path = path.replace("" + SEPARATOR + SEPARATOR, TMP_PLACEHOLDER);
+ path = path.replace(SEPARATOR, ':');
+ path = path.replace(TMP_PLACEHOLDER, "" + SEPARATOR);
+ return path;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder result = new StringBuilder();
+
+ if (renderCount != null)
+ {
+ result.append(renderCount);
+ result.append(BEHAVIOR_INDEX_SEPARATOR);
+ }
+
+ result.append(listenerInterface);
+
+ if (behaviorIndex != null)
+ {
+ result.append(BEHAVIOR_INDEX_SEPARATOR);
+ result.append(behaviorIndex);
+ }
+ result.append(SEPARATOR);
+ result.append(encodeComponentPath(componentPath));
+
+ return result.toString();
+ }
+
+ /**
+ * Method that rigidly checks if the string consists of digits only.
+ *
+ * @param string
+ * @return whether the string consists of digits only
+ */
+ private static boolean isNumber(String string)
+ {
+ if (string == null || string.length() == 0)
+ {
+ return false;
+ }
+ for (int i = 0; i < string.length(); ++i)
+ {
+ if (Character.isDigit(string.charAt(i)) == false)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Parses the given string.
+ *
+ * @param string
+ * @return component info or <code>null</code> if the string is not in correct format.
+ */
+ public static ComponentInfo parse(String string)
+ {
+ if (Strings.isEmpty(string))
+ {
+ return null;
+ }
+ int i = string.indexOf(SEPARATOR);
+ if (i == -1)
+ {
+ return null;
+ }
+ else
+ {
+ String listenerInterface = string.substring(0, i);
+ String componentPath = decodeComponentPath(string.substring(i + 1));
+
+ if (Strings.isEmpty(listenerInterface))
+ {
+ return null;
+ }
+ if (Strings.isEmpty(componentPath))
+ {
+ return null;
+ }
+
+ Integer behaviorIndex = null;
+ Integer renderCount = null;
+
+ String listenerParts[] = Strings.split(listenerInterface, BEHAVIOR_INDEX_SEPARATOR);
+ if (listenerParts.length == 2)
+ {
+ if (isNumber(listenerParts[0]))
+ {
+ renderCount = Integer.valueOf(listenerParts[0]);
+ listenerInterface = listenerParts[1];
+ }
+ else if (isNumber(listenerParts[1]))
+ {
+ listenerInterface = listenerParts[0];
+ behaviorIndex = Integer.valueOf(listenerParts[1]);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else if (listenerParts.length == 3)
+ {
+ if (!isNumber(listenerParts[0]) && !isNumber(listenerParts[1]))
+ {
+ return null;
+ }
+ renderCount = Integer.valueOf(listenerParts[0]);
+ listenerInterface = listenerParts[1];
+ behaviorIndex = Integer.valueOf(listenerParts[2]);
+ }
+ else if (listenerParts.length != 1)
+ {
+ return null;
+ }
+
+ return new ComponentInfo(renderCount, listenerInterface, componentPath, behaviorIndex);
+ }
+ }
+
+}
Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/encoder/info/ComponentInfo.java
------------------------------------------------------------------------------
svn:mime-type = text/plain