org.apache.wicket.portlet.WicketPortlet.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.wicket.portlet.WicketPortlet.java

Source

/*
 * 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.portlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.MimeResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.servlet.RequestDispatcher;

import org.apache.commons.fileupload.portlet.PortletRequestContext;
import org.apache.wicket.protocol.http.WicketFilter;
import org.apache.wicket.util.file.File;
import org.apache.wicket.util.string.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Adapter between the Portlet world requests and the internal Wicket engine.
 * I.e. simulates the web/servlet environment for Wicket, while it's actually
 * running as a Portlet.
 * 
 * <p>
 * It receives a portlet request and dispatches to a a Wicket filter; wrapping
 * the servlet context, request and response objects; intercepts response
 * writing (especially urls and redirects) and rewrites and adapts the output to
 * accommodate the portlet requirements.
 * 
 * <p>
 * The WicketPortlet is configured (using an initParameter) against a specific
 * filter path, e.g. Wicket WebApplication. The WicketPortlet maintains a
 * parameter for the current Wicket page URL being requested as a URL parameter,
 * based against the filter path (e.g. fully qualified to the context path).
 * When a request (action, render or direct resource/ajax call) is received by
 * the WicketPortlet, it dispatches it to Wicket core as a filter request using
 * the provided Wicket page URL parameter.
 * 
 * @see WicketPortlet#WICKET_URL_PORTLET_PARAMETER
 * @see WicketFilter
 * 
 * @author Ate Douma
 * @author <a href="http://sebthom.de/">Sebastian Thomschke</a>
 * @author Peter Pastrnak
 * @author Konstantinos Karavitis
 */
public class WicketPortlet extends GenericPortlet {
    private static final Pattern PROTECTED_RESOURCES = Pattern.compile("\\A\\s*[/\\\\]*\\s*(WEB|META)[-]INF(.*)",
            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

    private static final Pattern ABSOLUTE_URI_PATTERN = Pattern.compile("([a-z][a-z0-9]*://|/).*");

    public static enum PageType {
        ACTION("actionPage"), //
        CUSTOM("customPage"), //
        EDIT("editPage"), //
        HELP("helpPage"), //
        VIEW("viewPage");

        public static PageType getByInitParameterName(final String initParameterName) {
            for (final PageType p : PageType.values())
                if (p.initParameterName.equals(initParameterName))
                    return p;
            return null;
        }

        public final String initParameterName;

        PageType(final String initParameterName) {
            this.initParameterName = initParameterName;
        }
    }

    private static final Logger LOG = LoggerFactory.getLogger(WicketPortlet.class);

    /**
     * FIXME javadoc
     * 
     * <p>
     * The prefix for the parameter name for storing Wicket URLs.
     * 
     * <p>
     * The actual Wicket URLs generated by Wicket are passed around in portal
     * URLs, encoded by the portal (as a URL parameter of this name). The Wicket
     * URL is later decoded on subsequent requests, from the portal URL, so that
     * we know where to route the request, once it's passed out of the 'portal'
     * realm and into the 'Wicket' realm.
     * 
     * <p>
     * This is also used in generating links by {@link PortletRequestContext} in
     * generating links, as the links have to be portal encoded links, but must
     * also still contain the original wicket url for use by Wicket (e.g.
     * {@link PortletRequestContext#encodeActionURL}).
     * 
     * <p>
     * The default/buildin name of the parameter which stores the name of the
     * wicket url is stored under {@link #WICKET_URL_PORTLET_PARAMETER}. It will
     * be stored suffixed with the current portlet mode (e.g. view), so that
     * render requests know what mode to render.
     * 
     * @see PortletRequestContext
     */
    public static final String WICKET_URL_PORTLET_PARAMETER = "_wu";

    /**
     * FIXME javadoc
     */
    public static final String WICKET_FILTER_PATH_PARAM = "wicketFilterPath";
    /**
     * FIXME javadoc
     */
    public static final String RESPONSE_BUFFER_FOLDER_PARAM = "responseBufferFolder";
    /**
     * FIXME javadoc
     */
    public static final String CONFIG_PARAM_PREFIX = WicketPortlet.class.getName() + ".";
    /**
     * Marker used as key for the ResponseState object stored as a request
     * attribute.
     */
    public static final String RESPONSE_STATE_ATTR = ResponseState.class.getName();
    /** FIXME javadoc */
    public static final String WICKET_PORTLET_PROPERTIES = WicketPortlet.class.getName().replace('.', '/')
            + ".properties";

    /** FIXME javadoc */
    private String wicketFilterPath;

    /** FIXME javadoc */
    private File responseBufferFolder;

    /**
     * A collection of the default URL's for the different view modes of the
     * portlet - e.g. VIEW, EDIT, HELP etc...
     */
    private final HashMap<PageType, String> defaultPages = new HashMap<PageType, String>();

    protected String buildWicketFilterPath(String filterPath) {
        if (filterPath == null || filterPath.length() == 0)
            return "/";

        if (!filterPath.startsWith("/"))
            filterPath = "/" + filterPath;
        if (filterPath.endsWith("*"))
            filterPath = filterPath.substring(0, filterPath.length() - 1);
        if (!filterPath.endsWith("/"))
            filterPath += "/";

        return filterPath;
    }

    /**
     * Delegates to
     * {@link #processRequest(PortletRequest, PortletResponse, String, String)}.
     * 
     * @see #processRequest(PortletRequest, PortletResponse, String, String)
     */
    protected void doCustom(final RenderRequest request, final RenderResponse response)
            throws PortletException, IOException {
        processRequest(request, response, PageType.CUSTOM);
    }

    /**
     * Delegates to
     * {@link #processRequest(PortletRequest, PortletResponse, String, String)}.
     * 
     * @see #processRequest(PortletRequest, PortletResponse, String, String)
     */
    @Override
    protected void doEdit(final RenderRequest request, final RenderResponse response)
            throws PortletException, IOException {
        processRequest(request, response, PageType.EDIT);
    }

    /**
     * Delegates to
     * {@link #processRequest(PortletRequest, PortletResponse, String, String)}.
     * 
     * @see #processRequest(PortletRequest, PortletResponse, String, String)
     */
    @Override
    protected void doHelp(final RenderRequest request, final RenderResponse response)
            throws PortletException, IOException {
        processRequest(request, response, PageType.HELP);
    }

    /**
     * Delegates to
     * {@link #processRequest(PortletRequest, PortletResponse, String, String)}.
     * 
     * @see #processRequest(PortletRequest, PortletResponse, String, String)
     */
    @Override
    protected void doView(final RenderRequest request, final RenderResponse response)
            throws PortletException, IOException {
        processRequest(request, response, PageType.VIEW);
    }

    /**
     * @param pageType
     *            the mode of the portlet page, e.g. VIEW, EDIT etc...
     * @return the default page name for the given pate type.
     */
    protected String getDefaultPage(final PageType pageType) {
        return defaultPages.get(pageType);
    }

    /**
     * Loads the Wicket Portlet properties file off the class path.
     * 
     * FIXME javadoc - check properties
     * 
     * @param properties
     *            appends the portlet properties to
     * @return Wicket portlet properties. Returns an empty or unchanged
     *         properties object if Wicket Portlet properties could not be found
     * @throws PortletException
     *             if loading the properties fails
     */
    protected Properties getWicketPortletProperties(Properties properties) throws PortletException {
        if (properties == null)
            properties = new Properties();
        final InputStream is = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream(WICKET_PORTLET_PROPERTIES);
        if (is != null)
            try {
                properties.load(is);
            } catch (final IOException e) {
                throw new PortletException("Failed to load WicketPortlet.properties from classpath", e);
            }
        return properties;
    }

    /**
     * Retrieves the Wicket URL from the request object as a request parameter,
     * or if none exists returns the default URL. The name of the request
     * parameter is stored as a request attribute.
     * 
     * <p>
     * This url is then used to pass on to the matching {@link WicketFilter} to
     * process, by way of {@link RequestDispatcher} via the filters context
     * path.
     * 
     * <p>
     * A "parameter" is a form field name/value pair passed from the HTML side
     * of the world. Its value is a String.
     * 
     * <p>
     * An "attribute" is a Java object name/value pair passed only through the
     * internal JavaServer processes. (I.e. it can come from a JSP or servlet
     * but not an HTML page.) Its value is an Object.
     * 
     * @see PortletRequestContext#getLastEncodedPath()
     * @param request
     * @param pageType
     * @param defaultPage
     *            url of the default page
     * @return the Wicket URL from within the specified request
     */
    protected String getWicketURL(final PortletRequest request, final PageType pageType, final String defaultPage) {
        String wicketURL = null;
        if (request instanceof ActionRequest)
            // try to lookup the passed in wicket url parameter
            wicketURL = request.getParameter(WICKET_URL_PORTLET_PARAMETER);
        else if (request instanceof ResourceRequest)
            wicketURL = ((ResourceRequest) request).getResourceID();
        else {
            // try to lookup the passed in wicket url parameter, suffixed with
            // the portlet mode
            String redirectUrlKey = WICKET_URL_PORTLET_PARAMETER + request.getPortletMode().toString();
            String redirectUrl = request.getParameter(redirectUrlKey);
            // if the wicket url is not in request parameters try to lookup into the action scoped
            // attributes.
            wicketURL = redirectUrl == null ? (String) request.getAttribute(redirectUrlKey) : redirectUrl;
        }

        // if the wicketURL could not be retrieved, return the url for the
        // default page
        if (wicketURL == null)
            wicketURL = defaultPage;
        return wicketURL;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void init(final PortletConfig config) throws PortletException {
        // enable action-scoped request attributes support (see JSR286 specification PLT.10.4.4)
        config.getContainerRuntimeOptions().put("javax.portlet.actionScopedRequestAttributes",
                new String[] { "true", "numberOfCachedScopes", "10" });
        super.init(config);

        wicketFilterPath = buildWicketFilterPath(config.getInitParameter(WICKET_FILTER_PATH_PARAM));
        String responseBufferFolderPath = config.getInitParameter(RESPONSE_BUFFER_FOLDER_PARAM);
        if ((responseBufferFolderPath != null) && (!Strings.isEmpty(responseBufferFolderPath))) {
            responseBufferFolder = new File(responseBufferFolderPath);
        }

        for (final PageType p : PageType.values()) {
            defaultPages.put(p, config.getInitParameter(p.initParameterName));
        }

        validateDefaultPages(defaultPages);
    }

    /**
     * Delegates to
     * {@link #processRequest(PortletRequest, PortletResponse, String, String)}.
     * 
     * <p>
     * Stores the {@link ActionResponse} so that
     * {@link PortletEventService#broadcast} can send events using
     * {@link ActionResponse#setEvent}
     * 
     * @see PortletEventService#broadcastToPortletListeners
     * @see #processRequest(PortletRequest, PortletResponse, String, String)
     */
    @Override
    public void processAction(final ActionRequest request, final ActionResponse response)
            throws PortletException, IOException {
        processRequest(request, response, PageType.ACTION);
    }

    /**
     * Handles redirects set from processing the action. Checks the response
     * state after the action has been processed by Wicket for the presence of a
     * redirect URL, and if present, 'portletifies' the URL. If the URL is a
     * redirect to within the scope of this portlet, leaves it to be handled in
     * a subsequent render call, or if not, sends the redirect to the client.
     * The recorded url is then used in by wicket in the subsequnt 'VIEW'
     * requests by the portal, to render the correct Page.
     * 
     * @see IRequestCycleSettings#REDIRECT_TO_RENDER
     * @param wicketURL
     * @param request
     * @param response
     * @param responseState
     * @throws PortletException
     * @throws IOException
     */
    protected void processActionResponseState(String wicketURL, final PortletRequest request,
            final ActionResponse response, final ResponseState responseState) throws PortletException, IOException {
        // write out Cookies to ActionResponse
        responseState.flushAndClose();
        String redirectLocationUrl = responseState.getRedirectLocation();
        if (LOG.isDebugEnabled())
            LOG.debug("redirectURL after include:" + redirectLocationUrl);
        if (redirectLocationUrl != null && !redirectLocationUrl.isEmpty()) {
            redirectLocationUrl = fixWicketUrl(wicketURL, redirectLocationUrl);
            if (redirectLocationUrl.startsWith(wicketFilterPath)) {
                final String portletMode = request.getPortletMode().toString();
                final String redirectUrlKey = WICKET_URL_PORTLET_PARAMETER + portletMode;
                // put the redirect location into the "_wuview" action scoped request attribute
                request.setAttribute(redirectUrlKey, redirectLocationUrl);
            } else
                response.sendRedirect(redirectLocationUrl);
        }
    }

    /**
     * Loops until wicket processing does not result in a redirect (redirects
     * have to be caught, and fed back into Wicket as we only want the portlet
     * redirected, not the entire page of course).
     * 
     * @param request
     * @param response
     * @param requestType
     * @param wicketURL
     * @param responseState
     * @throws PortletException
     * @throws IOException
     */
    private void processMimeResponseRequest(String wicketURL, final PortletRequest request,
            final MimeResponse response, final ResponseState responseState) throws PortletException, IOException {
        PortletRequestDispatcher rd = null;
        String previousURL = null;
        // FIXME portal comment: explain while loop
        // keep looping until wicket processing does not result in a redirect
        // (redirects have to
        // be caught, and fed back into Wicket as we only want the portlet
        // redirected, not the
        // entire page of course.
        while (true) {
            rd = getPortletContext().getRequestDispatcher(wicketURL);
            if (rd != null) {
                // Need to use RequestDispatcher.include here otherwise
                // internally rewinding on a
                // redirect
                // won't be allowed (calling forward will close the response)
                rd.include(request, response);

                // process _other_ response states - check for redirects as a
                // result of wicket
                // processing the request

                String redirectLocation = responseState.getRedirectLocation();
                String ajaxRedirectLocation = responseState.getAjaxRedirectLocation();
                if (ajaxRedirectLocation != null) {
                    // Ajax redirect
                    ajaxRedirectLocation = fixWicketUrl(wicketURL, ajaxRedirectLocation);
                    responseState.clear();
                    responseState.setDateHeader("Date", System.currentTimeMillis());
                    responseState.setDateHeader("Expires", 0);
                    responseState.setHeader("Pragma", "no-cache");
                    responseState.setHeader("Cache-Control", "no-cache, no-store");
                    //client side javascript needs the Ajax-Location header see wicket-ajax-jquery.js line 771
                    responseState.setHeader("Ajax-Location", ajaxRedirectLocation);//
                    responseState.setContentType("text/xml;charset=UTF-8");
                    responseState.getWriter().write("<ajax-response><redirect><![CDATA[" + ajaxRedirectLocation
                            + "]]></redirect></ajax-response>");
                    responseState.flushAndClose();
                } else if (redirectLocation != null) {
                    // TODO: check if its redirect to wicket page (find _wu or
                    // _wuPortletMode or resourceId parameter)

                    redirectLocation = fixWicketUrl(wicketURL, redirectLocation);

                    final boolean validWicketUrl = redirectLocation.startsWith(wicketFilterPath);
                    if (validWicketUrl) {
                        if (previousURL == null || previousURL != redirectLocation) {
                            previousURL = wicketURL;
                            wicketURL = redirectLocation;
                            ((RenderResponse) response).reset();
                            responseState.clear();
                            continue;
                        } else {
                            // internal Wicket redirection loop: unsure yet what
                            // to send out from
                            // here
                            // TODO: determine what kind of error (message or
                            // page) should be
                            // written out
                            // for now: no output available/written :(
                            responseState.clear();
                            break;
                        }
                    } else {
                        responseState.clear();
                        if (responseState.isResourceResponse()) {
                            // Formally, the Portlet 2.0 Spec doesn't support
                            // directly redirecting
                            // from serveResource. However, it is possible to
                            // write response headers
                            // to the ResourceResponse (using setProperty),
                            // which means the
                            // technical implementation of a response.redirect
                            // call might be
                            // "simulated" by writing out:

                            // a) setting response.setStatus(SC_FOUND)
                            // b) setting header "Location" to the
                            // redirectLocation

                            // Caveat 1:
                            // ResourceResponse.setStatus isn't supported
                            // either, but this can be
                            // done by setting the header property
                            // ResourceResponse.HTTP_STATUS_CODE

                            // Caveat 2: Actual handling of Response headers as
                            // set through
                            // PortletResponse.setProperty is completely
                            // optional by the Portlet
                            // Spec so it really depends on the portlet
                            // container implementation
                            // (and environment, e.g. consider using WSRP
                            // here...) if this will
                            // work.

                            // On Apache Pluto/Jetspeed-2, the above descibed
                            // handling *will* be
                            // implemented as expected!

                            // HttpServletResponse.SC_FOUND == 302, defined by
                            // Servlet API >= 2.4
                            response.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(302));
                            response.setProperty("Location", redirectLocation);
                        } else {
                            response.reset();
                            response.setProperty("expiration-cache", "0");

                            PrintWriter writer = response.getWriter();
                            writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
                            writer.append(
                                    "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">");
                            writer.append("<html><head><meta http-equiv=\"refresh\" content=\"0; url=")
                                    .append(redirectLocation).append("\"/></head></html>");
                            writer.close();
                            break;
                        }
                    }
                } else {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("ajax redirect url after inclusion:" + redirectLocation);
                    }
                    // write response state out to the PortletResponse
                    responseState.flushAndClose();
                }
            }
            break;
        }
    }

    /**
     * Consumes and processes all portlet requests. All the doX methods delegate
     * to this method, including processAction and serveResource.
     * 
     * @param request
     * @param response
     * @param requestType
     * @param pageType
     * @throws PortletException
     * @throws IOException
     */
    protected void processRequest(final PortletRequest request, final PortletResponse response,
            final PageType pageType) throws PortletException, IOException {
        String wicketURL = null;

        // get the actual wicketURL for this request, to be passed onto Wicket
        // core for processing
        wicketURL = getWicketURL(request, pageType, getDefaultPage(pageType));

        if (LOG.isDebugEnabled())
            LOG.debug("Portlet \"" + request.getAttribute(PortletRequest.LIFECYCLE_PHASE) + "\" for wicket url:"
                    + wicketURL);

        // store the response state and request type in the request object, so
        // they can be looked up
        // from a different context
        final ResponseState responseState = new ResponseState(request, response, responseBufferFolder);
        request.setAttribute(RESPONSE_STATE_ATTR, responseState);

        // need to record the effective wicket url of the rendered result, so
        // that the subsequent
        // portlet 'view' requests can delegate to wicket to render the correct
        // location/wicket url.
        if (responseState.isActionResponse()) {
            // create the request dispatcher, to delegate the request to the
            // wicket filter
            final PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(wicketURL);

            if (rd != null) {
                // delegate to wicket filter - this is where the magic happens
                rd.include(request, response);
                // String newWicketURL = getWicketURL(request, pageType,
                // getDefaultPage(pageType));
                LOG.debug("wicket filter inclusion complete");
                processActionResponseState(wicketURL, request, (ActionResponse) response, responseState);
            } else {
                // FIXME - throw exception?
                // no-op for now
            }
        } else if (responseState.isMimeResponse())
            processMimeResponseRequest(wicketURL, request, (MimeResponse) response, responseState);
        else
            LOG.warn("Unsupported Portlet lifecycle: {}", request.getAttribute(PortletRequest.LIFECYCLE_PHASE));
        if (LOG.isDebugEnabled()) {
            wicketURL = getWicketURL(request, pageType, getDefaultPage(pageType));
            LOG.debug("end of request, wicket url: " + wicketURL);
        }
    }

    /**
     * Delegates to
     * {@link #processRequest(PortletRequest, PortletResponse, String, String)}.
     * 
     * @see #processRequest(PortletRequest, PortletResponse, String, String)
     */
    @Override
    public void serveResource(final ResourceRequest request, final ResourceResponse response)
            throws PortletException, IOException {
        String resourceId = request.getResourceID();
        if (resourceId != null) {
            if (PROTECTED_RESOURCES.matcher(resourceId).matches()) {
                response.setProperty(ResourceResponse.HTTP_STATUS_CODE, "404");
            }
            processRequest(request, response, PageType.VIEW);
        }
    }

    /**
     * FIXME javadoc
     * 
     * <p>
     * Corrects the incoming URL if the old home page style, or if it's missing
     * the filter path prefix.
     * 
     * @param url
     *            the URL to fix
     * @return the corrected URL
     */
    protected String fixWicketUrl(final String url) {
        if (url == null)
            return wicketFilterPath;

        if (!url.startsWith(wicketFilterPath)) {
            if (url.startsWith("..?")) {
                return wicketFilterPath + url.substring(2);
            }
            if ((url + "/").equals(wicketFilterPath)) {
                // hack around "old" style wicket home url's without trailing
                // '/' which would lead
                // to a redirect to the real home path anyway
                return wicketFilterPath;
            }
        }
        return url;
    }

    /**
     * FIXME javadoc
     * 
     * <p>
     * Corrects the incoming URL if the old home page style, or if it's missing
     * the filter path prefix.
     * 
     * @param requestUrl
     *            the original request URL
     * @param url
     *            the URL to fix
     * @return the corrected URL
     */
    protected String fixWicketUrl(final String requestUrl, final String url) {
        if ((url != null) && (requestUrl != null) && (!ABSOLUTE_URI_PATTERN.matcher(url).matches())) {
            try {
                if (!requestUrl.startsWith("http")) {
                    URL fixedUrl = new URL("http:" + url);
                    String query = fixedUrl.getQuery();
                    if (query != null) {
                        String wuViewParam = "_wuview=";
                        for (String queryParamValuePair : query.split("&")) {
                            if (queryParamValuePair.startsWith(wuViewParam)) {
                                return URLDecoder.decode(queryParamValuePair.replace(wuViewParam, ""), "UTF-8")
                                        + "?" + query;
                            }
                        }
                    }

                    return new URL(new URL("http:" + wicketFilterPath), url).toString().substring(5);
                } else {
                    return new URL(new URL(wicketFilterPath), url).getPath();
                }
            } catch (Exception e) {
            }
        }
        return fixWicketUrl(url);
    }

    /**
     * FIXME javadoc
     * 
     * <p>
     * Registers the default pages and their URLs for the different
     * {@link PortletMode}s. Also corrects and slightly incorrect URLs (see
     * {@link #fixWicketUrl(String)}).
     * 
     * <p>
     * If no specific page was specified for a given portlet mode (VIEW, EDIT
     * etc) then the page for that mode is set to be the same page as that of
     * the VIEW mode.
     * 
     * @see PortletMode
     * @see #fixWicketUrl(String)
     * @param defaultPages
     */
    protected void validateDefaultPages(final Map<PageType, String> defaultPages) {
        final String viewPage = fixWicketUrl(defaultPages.get(PageType.VIEW));
        defaultPages.put(PageType.VIEW, viewPage.startsWith(wicketFilterPath) ? viewPage : wicketFilterPath);

        String defaultPage = defaultPages.get(PageType.ACTION);
        if (defaultPage == null)
            defaultPages.put(PageType.ACTION, viewPage);
        else {
            defaultPage = fixWicketUrl(defaultPage);
            defaultPages.put(PageType.ACTION, defaultPage.startsWith(wicketFilterPath) ? defaultPage : viewPage);
        }

        defaultPage = defaultPages.get(PageType.CUSTOM);
        if (defaultPage == null)
            defaultPages.put(PageType.CUSTOM, viewPage);
        else {
            defaultPage = fixWicketUrl(defaultPage);
            defaultPages.put(PageType.CUSTOM, defaultPage.startsWith(wicketFilterPath) ? defaultPage : viewPage);
        }

        defaultPage = defaultPages.get(PageType.HELP);
        if (defaultPage == null)
            defaultPages.put(PageType.HELP, viewPage);
        else {
            defaultPage = fixWicketUrl(defaultPage);
            defaultPages.put(PageType.HELP, defaultPage.startsWith(wicketFilterPath) ? defaultPage : viewPage);
        }

        defaultPage = defaultPages.get(PageType.EDIT);
        if (defaultPage == null)
            defaultPages.put(PageType.EDIT, viewPage);
        else {
            defaultPage = fixWicketUrl(defaultPage);
            defaultPages.put(PageType.EDIT, defaultPage.startsWith(wicketFilterPath) ? defaultPage : viewPage);
        }
    }
}