001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.request.target.coding;
018:
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.Map;
022: import java.util.Set;
023: import java.util.TreeSet;
024:
025: import org.apache.wicket.PageMap;
026: import org.apache.wicket.PageParameters;
027: import org.apache.wicket.protocol.http.UnitTestSettings;
028: import org.apache.wicket.util.string.AppendingStringBuffer;
029: import org.apache.wicket.util.value.ValueMap;
030:
031: /**
032: *
033: * Url coding strategy for bookmarkable pages that encodes a set of given
034: * parameters
035: *
036: * in the url's path path and the rest in the querystring.
037: *
038: * <p>
039: * Strategy looks for path-parameters whose name is read from an array of
040: *
041: * names e.g. ["param0", "param1"]. Found parameters will be appended to the url
042: * in
043: *
044: * the form <code>/mount-path/paramvalue0/paramvalue1</code>.
045: * </p>
046: *
047: * <p>
048: * All other parameters are added as parameter in the form:
049: *
050: * <code>/mount-path/paramvalue0?otherparam0=otherparamvalue0&otherparam1=otherparamvalue1</code>.
051: * </p>
052: *
053: * <p>
054: * Decode is symmetric except for when a path parameter that is not at the end
055: * has no value during encode.
056: *
057: * For example, the names for the path parameters are: "a", "b" and "c". When
058: * "b" is
059: *
060: * not specified upon encoding, but "c" is, upon a decode "b" will get the empty
061: * string
062: *
063: * as value. When both "b" and "c" are missing on encode, the will not get a
064: * value during decode.
065: * </p>
066: *
067: * @author erik.van.oosten
068: */
069: public class MixedParamUrlCodingStrategy extends
070: BookmarkablePageRequestTargetUrlCodingStrategy {
071: private final String[] parameterNames;
072:
073: /**
074: * Construct.
075: *
076: * @param mountPath
077: * mount path
078: * @param bookmarkablePageClass
079: * class of mounted page
080: * @param pageMapName
081: * name of pagemap
082: * @param parameterNames
083: * the parameter names (not null)
084: */
085: public MixedParamUrlCodingStrategy(String mountPath,
086: Class bookmarkablePageClass, String pageMapName,
087: String[] parameterNames) {
088: super (mountPath, bookmarkablePageClass, pageMapName);
089: this .parameterNames = parameterNames;
090: }
091:
092: /**
093: * Construct.
094: *
095: * @param mountPath
096: * mount path (not empty)
097: * @param bookmarkablePageClass
098: * class of mounted page (not null)
099: * @param parameterNames
100: * the parameter names (not null)
101: */
102: public MixedParamUrlCodingStrategy(String mountPath,
103: Class bookmarkablePageClass, String[] parameterNames) {
104: super (mountPath, bookmarkablePageClass, PageMap.DEFAULT_NAME);
105: this .parameterNames = parameterNames;
106: }
107:
108: /** {@inheritDoc} */
109: protected void appendParameters(AppendingStringBuffer url,
110: Map parameters) {
111: if (!url.endsWith("/")) {
112: url.append("/");
113: }
114:
115: Set parameterNamesToAdd = new HashSet(parameters.keySet());
116: // Find index of last specified parameter
117: boolean foundParameter = false;
118: int lastSpecifiedParameter = parameterNames.length;
119: while (lastSpecifiedParameter != 0 && !foundParameter) {
120: foundParameter = parameters
121: .containsKey(parameterNames[--lastSpecifiedParameter]);
122: }
123:
124: if (foundParameter) {
125: for (int i = 0; i <= lastSpecifiedParameter; i++) {
126: String parameterName = parameterNames[i];
127: String value = (String) parameters.get(parameterName);
128: if (value == null) {
129: value = "";
130: }
131: url.append(urlEncode(value)).append("/");
132: parameterNamesToAdd.remove(parameterName);
133: }
134: }
135:
136: if (!parameterNamesToAdd.isEmpty()) {
137: boolean first = true;
138: final Iterator iterator;
139: if (UnitTestSettings.getSortUrlParameters()) {
140: iterator = new TreeSet(parameterNamesToAdd).iterator();
141: } else {
142: iterator = parameterNamesToAdd.iterator();
143: }
144: while (iterator.hasNext()) {
145: url.append(first ? '?' : '&');
146: String parameterName = (String) iterator.next();
147: String value = (String) parameters.get(parameterName);
148: url.append(urlEncode(parameterName)).append("=")
149: .append(urlEncode(value));
150: first = false;
151: }
152: }
153: }
154:
155: /** {@inheritDoc} */
156: protected ValueMap decodeParameters(String urlFragment,
157: Map urlParameters) {
158: PageParameters params = new PageParameters();
159: // Add all url parameters
160: params.putAll(urlParameters);
161: String urlPath = urlFragment;
162: if (urlPath.startsWith("/")) {
163: urlPath = urlPath.substring(1);
164: }
165:
166: if (urlPath.length() > 0) {
167: String[] pathParts = urlPath.split("/");
168: if (pathParts.length > parameterNames.length) {
169: throw new IllegalArgumentException(
170: "Too many path parts, please provide sufficient number of path parameter names");
171: }
172:
173: for (int i = 0; i < pathParts.length; i++) {
174: params.put(parameterNames[i], urlDecode(pathParts[i]));
175: }
176: }
177:
178: return params;
179: }
180: }
|