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<Map.Entry> itr = urlParameters.entrySet().iterator();itr.hasNext();) {
                        Map.Entry<String,String[]> 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;
        }

}