org.apache.wicket.core.request.mapper.ResourceMapper.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.wicket.core.request.mapper.ResourceMapper.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.core.request.mapper;

import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.wicket.Application;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.IRequestMapper;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
import org.apache.wicket.request.http.flow.AbortWithHttpErrorCodeException;
import org.apache.wicket.request.mapper.parameter.INamedParameters;
import org.apache.wicket.request.mapper.parameter.IPageParametersEncoder;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
import org.apache.wicket.request.resource.IResource;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
import org.apache.wicket.request.resource.caching.IStaticCacheableResource;
import org.apache.wicket.request.resource.caching.ResourceUrl;
import org.apache.wicket.resource.ResourceUtil;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.string.Strings;

/**
 * A {@link IRequestMapper} to mount resources to a custom mount path
 * <ul>
 * <li>maps indexed parameters to path segments</li>
 * <li>maps named parameters to query string arguments or placeholder path segments</li>
 * </ul>
 *
 * <strong>sample structure of url</strong>
 *
 * <pre>
 *    /myresources/${category}/images/[indexed-param-0]/[indexed-param-1]?[named-param-1=value]&[named-param-2=value2]
 * </pre>
 *
 * <h4>sample usage</h4>
 *
 * in your wicket application's init() method use a statement like this
 * <p/>
 *
 * <pre>
 * mountResource(&quot;/images&quot;, new ImagesResourceReference()));
 * </pre>
 *
 * Note: Mounted this way the resource reference has application scope, i.e. it is shared between
 * all users of the application. It is recommended to not keep any state in it.
 *
 * @see org.apache.wicket.protocol.http.WebApplication#mountResource(String,
 *      org.apache.wicket.request.resource.ResourceReference)
 *
 * @author Peter Ertl
 */
public class ResourceMapper extends AbstractBookmarkableMapper {
    // encode page parameters into url + decode page parameters from url
    private final IPageParametersEncoder parametersEncoder;

    // mount path (= segments) the resource is bound to
    private final String[] mountSegments;

    // resource that the mapper links to
    private final ResourceReference resourceReference;

    /**
     * create a resource mapper for a resource
     *
     * @param path
     *            mount path for the resource
     * @param resourceReference
     *            resource reference that should be linked to the mount path
     *
     * @see #ResourceMapper(String, org.apache.wicket.request.resource.ResourceReference,
     *      org.apache.wicket.request.mapper.parameter.IPageParametersEncoder)
     */
    public ResourceMapper(String path, ResourceReference resourceReference) {
        this(path, resourceReference, new PageParametersEncoder());
    }

    /**
     * create a resource mapper for a resource
     *
     * @param path
     *            mount path for the resource
     * @param resourceReference
     *            resource reference that should be linked to the mount path
     * @param encoder
     *            encoder for url parameters
     */
    public ResourceMapper(String path, ResourceReference resourceReference, IPageParametersEncoder encoder) {
        super(path, encoder);
        Args.notNull(resourceReference, "resourceReference");

        this.resourceReference = resourceReference;
        mountSegments = getMountSegments(path);
        parametersEncoder = encoder;
    }

    @Override
    public IRequestHandler mapRequest(final Request request) {
        final Url url = new Url(request.getUrl());

        // now extract the page parameters from the request url
        PageParameters parameters = extractPageParameters(request, mountSegments.length, parametersEncoder);
        if (parameters != null) {
            parameters.setLocale(resolveLocale());
        }

        // remove caching information from current request
        removeCachingDecoration(url, parameters);

        // check if url matches mount path
        if (urlStartsWith(url, mountSegments) == false) {
            return null;
        }

        // check if there are placeholders in mount segments
        for (int index = 0; index < mountSegments.length; ++index) {
            String placeholder = getPlaceholder(mountSegments[index]);

            if (placeholder != null) {
                // extract the parameter from URL
                if (parameters == null) {
                    parameters = newPageParameters();
                }
                parameters.add(placeholder, url.getSegments().get(index), INamedParameters.Type.PATH);
            }
        }
        return new ResourceReferenceRequestHandler(resourceReference, parameters);
    }

    @Override
    protected final UrlInfo parseRequest(final Request request) {
        throw new UnsupportedOperationException();
    }

    @Override
    protected final Url buildUrl(final UrlInfo info) {
        throw new UnsupportedOperationException();
    }

    @Override
    protected final boolean pageMustHaveBeenCreatedBookmarkable() {
        throw new UnsupportedOperationException();
    }

    @Override
    public int getCompatibilityScore(Request request) {
        Url originalUrl = new Url(request.getUrl());
        PageParameters parameters = extractPageParameters(request, mountSegments.length, parametersEncoder);
        if (parameters != null) {
            parameters.setLocale(resolveLocale());
        }
        removeCachingDecoration(originalUrl, parameters);
        Request requestWithoutDecoration = request.cloneWithUrl(originalUrl);

        int score = super.getCompatibilityScore(requestWithoutDecoration);
        if (score > 0) {
            score--; // pages always have priority over resources
        } else {
            score = -1;
        }
        return score;
    }

    @Override
    public Url mapHandler(IRequestHandler requestHandler) {
        if ((requestHandler instanceof ResourceReferenceRequestHandler) == false) {
            return null;
        }

        ResourceReferenceRequestHandler handler = (ResourceReferenceRequestHandler) requestHandler;

        // see if request handler addresses the resource reference we serve
        if (resourceReference.equals(handler.getResourceReference()) == false) {
            return null;
        }

        Url url = new Url();

        // add mount path segments
        for (String segment : mountSegments) {
            url.getSegments().add(segment);
        }

        // replace placeholder parameters
        PageParameters parameters = newPageParameters();
        parameters.mergeWith(handler.getPageParameters());

        for (int index = 0; index < mountSegments.length; ++index) {
            String placeholder = getPlaceholder(mountSegments[index]);

            if (placeholder != null) {
                url.getSegments().set(index, parameters.get(placeholder).toString(""));
                parameters.remove(placeholder);
            }
        }

        // add caching information
        addCachingDecoration(url, parameters);

        ResourceUtil.encodeResourceReferenceAttributes(url, resourceReference);
        // create url
        return encodePageParameters(url, parameters, parametersEncoder);
    }

    protected IResourceCachingStrategy getCachingStrategy() {
        return Application.get().getResourceSettings().getCachingStrategy();
    }

    protected void addCachingDecoration(Url url, PageParameters parameters) {
        final List<String> segments = url.getSegments();
        final int lastSegmentAt = segments.size() - 1;
        final String filename = segments.get(lastSegmentAt);

        if (Strings.isEmpty(filename) == false) {
            final IResource resource = resourceReference.getResource();

            if (resource instanceof IStaticCacheableResource) {
                final IStaticCacheableResource cacheable = (IStaticCacheableResource) resource;

                if (cacheable.isCachingEnabled()) {
                    final ResourceUrl cacheUrl = new ResourceUrl(filename, parameters);

                    getCachingStrategy().decorateUrl(cacheUrl, cacheable);

                    if (Strings.isEmpty(cacheUrl.getFileName())) {
                        if (Application.exists() && Application.get().usesDeploymentConfig()) {
                            throw new AbortWithHttpErrorCodeException(HttpServletResponse.SC_NOT_FOUND,
                                    "caching strategy returned empty name for " + resource);
                        } else {
                            throw new IllegalStateException("caching strategy returned empty name for " + resource);
                        }
                    }
                    segments.set(lastSegmentAt, cacheUrl.getFileName());
                }
            }
        }
    }

    protected void removeCachingDecoration(Url url, PageParameters parameters) {
        final List<String> segments = url.getSegments();

        if (segments.isEmpty() == false) {
            // get filename (the last segment)
            final int lastSegmentAt = segments.size() - 1;
            String filename = segments.get(lastSegmentAt);

            // ignore requests with empty filename
            if (Strings.isEmpty(filename)) {
                return;
            }

            // create resource url from filename and query parameters
            final ResourceUrl resourceUrl = new ResourceUrl(filename, parameters);

            // remove caching information from request
            getCachingStrategy().undecorateUrl(resourceUrl);

            // check for broken caching strategy (this must never happen)
            if (Strings.isEmpty(resourceUrl.getFileName())) {
                throw new IllegalStateException("caching strategy returned empty name for " + resourceUrl);
            }

            segments.set(lastSegmentAt, resourceUrl.getFileName());
        }
    }
}