I am about to run out the house for the Labor Day weekend, quickie post on my new coding url strategy.

MixedParamHybridUrlCodingStrategy lets you keep stateful multi-pagemap URLs clean while using mixed parameters.

Example…


mount(new MixedParamHybridUrlCodingStrategy("/questions",QuestionsPage.class,false,new String[]{"cat"}));

This will mount “/questions/stupid-category” and convert it to…

new PageParameters("cat","stupid-category");

package com.base.target.coding;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.wicket.IRequestTarget;
import org.apache.wicket.PageParameters;
import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy;
import org.apache.wicket.request.target.coding.HybridUrlCodingStrategy;
import org.apache.wicket.util.string.AppendingStringBuffer;
import org.apache.wicket.util.value.ValueMap;

public class MixedParamHybridUrlCodingStrategy extends HybridUrlCodingStrategy {
	private final String[] parameterNames;

	public MixedParamHybridUrlCodingStrategy(final String mountPath, final Class pageClass) {
		super(mountPath, pageClass);
		this.parameterNames = new String[] {};
	}

	public MixedParamHybridUrlCodingStrategy(final String mountPath, final Class pageClass,final boolean refresh) {
		super(mountPath,pageClass,refresh);
		this.parameterNames = new String[] {};
	}

	public MixedParamHybridUrlCodingStrategy(final String mountPath, final Class pageClass,final String[] params) {
		super(mountPath,pageClass,false);
		this.parameterNames = params;
	}

	public MixedParamHybridUrlCodingStrategy(final String mountPath, final Class pageClass,final boolean refresh,final String[] params) {
		super(mountPath,pageClass,refresh);
		this.parameterNames = params;
	}

	@Override
	protected void appendParameters(final AppendingStringBuffer url, final Map parameters)
	{

		Set parameterNamesToAdd = new HashSet(parameters.keySet());
		// Find index of last specified parameter
		boolean foundParameter = false;
		int lastSpecifiedParameter = parameterNames.length;
		while (lastSpecifiedParameter != 0 && !foundParameter)
		{
			foundParameter = parameters.containsKey(parameterNames[--lastSpecifiedParameter]);
		}

		if (foundParameter)
		{
			for (int i = 0; i <= lastSpecifiedParameter; i++)
			{
				String parameterName = parameterNames[i];
				final Object param = parameters.get(parameterName);
				String value = param instanceof String[] ? ((String[])param)[0] : (String)param;
				if (value == null)
				{
					value = "";
				}
				if (!url.endsWith("/"))
				{
					url.append("/");
				}
				url.append(urlEncodePathComponent(value));
				parameterNamesToAdd.remove(parameterName);
			}
		}

		if (!parameterNamesToAdd.isEmpty())
		{
			boolean first = true;
			final Iterator iterator = parameterNamesToAdd.iterator();
			while (iterator.hasNext())
			{
				url.append(first ? '?' : '&');
				String parameterName = (String)iterator.next();
				final Object param = parameters.get(parameterName);
				String value = param instanceof String[] ? ((String[])param)[0] : (String)param;
				url.append(urlEncodeQueryComponent(parameterName)).append("=").append(
						urlEncodeQueryComponent(value));
				first = false;
			}
		}


		String pageMap = (String)parameters.get(WebRequestCodingStrategy.PAGEMAP);
		if (pageMap != null)
		{
			pageMap = WebRequestCodingStrategy.encodePageMapName(pageMap);
			if (!url.endsWith("/"))
			{
				url.append("/");
			}
			url.append(WebRequestCodingStrategy.PAGEMAP).append("/").append(
					urlEncodePathComponent(pageMap));
		}
	}

	@Override
	public CharSequence encode(final IRequestTarget requestTarget) {
		String url = String.valueOf(super.encode(requestTarget));
		if(url.contains(".wicket")) {
			// Rewrite URL from..  /foo?bar=5.wicket-xxx to /foo.wicket-xxx?bar=5
			return url.replaceAll("(.*)\\?(.*)\\.(wicket-[0-9]+)$", "$1.$3?$2");
		}
		return url;
	}

	@Override
	protected ValueMap decodeParameters(final String urlFragment, final Map urlParameters)
	{

		PageParameters params = new PageParameters();
		if(urlFragment == null) {
			return params;
		}

		// Add all url parameters and normalize
		for(Iterator itr = urlParameters.entrySet().iterator();itr.hasNext();) {
			Map.Entry e = itr.next();
			if(e.getValue() != null) {
				String val = (e.getValue())[0];
				if(val != null) {
					if(val.contains(".wicket")) {
						val = val.substring(0,val.indexOf(".wicket"));
						urlParameters.put(e.getKey(), val);
					}
				}
			}
		}
		params.putAll(urlParameters);

		String urlPath = urlFragment;
		if (urlPath.startsWith("/"))
		{
			urlPath = urlPath.substring(1);
		}

		if (urlPath.length() > 0)
		{
			String[] pathParts = urlPath.split("/");
			if (pathParts.length > parameterNames.length)
			{
				throw new IllegalArgumentException(
				"Too many path parts, please provide sufficient number of path parameter names");
			}

			for (int i = 0; i < pathParts.length; i++)
			{
				if(pathParts[i].contains(".wicket")) {
					pathParts[i].substring(0,pathParts[i].indexOf(".wicket"));
				}
				if (WebRequestCodingStrategy.PAGEMAP.equals(pathParts[i]))
				{
					params.put(WebRequestCodingStrategy.PAGEMAP,
							WebRequestCodingStrategy.decodePageMapName(urlDecodePathComponent(pathParts[i])));
				}
				params.put(parameterNames[i], urlDecodePathComponent(pathParts[i]));
			}

		}
		return params;
	}

}