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 */
017package org.apache.wicket.request.resource.caching;
018
019import org.apache.wicket.request.cycle.RequestCycle;
020import org.apache.wicket.request.http.WebResponse;
021import org.apache.wicket.request.mapper.parameter.INamedParameters;
022import org.apache.wicket.request.resource.AbstractResource;
023import org.apache.wicket.request.resource.caching.version.CachingResourceVersion;
024import org.apache.wicket.request.resource.caching.version.IResourceVersion;
025import org.apache.wicket.util.lang.Args;
026import org.apache.wicket.util.string.StringValue;
027
028/**
029 * resource caching strategy that adds a version string to the query parameters of the resource
030 * (this is similar to how wicket 1.4 does it when enabling timestamps on resources). You should
031 * preferably use {@link FilenameWithVersionResourceCachingStrategy} since it is more reliable. 
032 * 
033 * @author Peter Ertl
034 *
035 * @see FilenameWithVersionResourceCachingStrategy
036 * 
037 * @since 1.5
038 */
039public class QueryStringWithVersionResourceCachingStrategy implements IResourceCachingStrategy
040{
041        /**
042         * default query parameter for version information
043         */
044        private static final String DEFAULT_VERSION_PARAMETER = "ver";
045
046        /**
047         * query string parameter name that contains the version string for the resource
048         */
049        private final String versionParameter;
050
051        /**
052         * resource version provider
053         */
054        private final IResourceVersion resourceVersion;
055
056        /**
057         * create query string resource caching strategy
058         * <p/>
059         * it will use a query parameter named <code>{@value #DEFAULT_VERSION_PARAMETER}</code>
060         * for storing the version information.
061         * 
062         * @param resourceVersion
063         *                resource version provider
064         */
065        public QueryStringWithVersionResourceCachingStrategy(IResourceVersion resourceVersion)
066        {
067                this(DEFAULT_VERSION_PARAMETER, resourceVersion);
068        }
069
070        /**
071         * create query string resource caching strategy
072         * <p/>
073         * it will use a query parameter with name specified by 
074         * parameter <code>resourceVersion</code> for storing the version information.
075         *
076         * @param versionParameter
077         *            name of version parameter which will be added to query string
078         *            containing the resource version
079         * @param resourceVersion
080         *                resource version provider
081         */
082        public QueryStringWithVersionResourceCachingStrategy(String versionParameter, 
083                                                             IResourceVersion resourceVersion)
084        {
085                this.versionParameter = Args.notEmpty(versionParameter, "versionParameter");
086                this.resourceVersion = Args.notNull(resourceVersion, "resourceVersion");
087        }
088
089        /**
090         * @return name of version parameter which will be added to query string
091         */
092        public final String getVersionParameter()
093        {
094                return versionParameter;
095        }
096
097        @Override
098        public void decorateUrl(ResourceUrl url, final IStaticCacheableResource resource)
099        {
100                String version = resourceVersion.getVersion(resource);
101
102                if (version != null)
103                {
104                        url.getParameters().set(versionParameter, version, INamedParameters.Type.MANUAL);
105                }
106        }
107
108        @Override
109        public void undecorateUrl(ResourceUrl url)
110        {
111                final INamedParameters parameters = url.getParameters();
112                
113                if (parameters != null)
114                {
115                        // store the version in the request cycle
116                        StringValue versionValue = parameters.get(versionParameter);
117                        RequestCycle requestCycle = RequestCycle.get();
118                        if (versionValue.isEmpty() == false && requestCycle != null)
119                        {
120                                requestCycle.setMetaData(URL_VERSION, versionValue.toString());
121                        }
122
123                        // undecorate
124                        parameters.remove(versionParameter);
125                }
126        }
127
128        @Override
129        public void decorateResponse(AbstractResource.ResourceResponse response, IStaticCacheableResource resource)
130        {
131                String requestedVersion = RequestCycle.get().getMetaData(URL_VERSION);
132                String calculatedVersion = this.resourceVersion.getVersion(resource);
133                if (calculatedVersion != null && calculatedVersion.equals(requestedVersion))
134                {
135                        response.setCacheDurationToMaximum();
136                        response.setCacheScope(WebResponse.CacheScope.PUBLIC);
137                }
138        }
139
140        @Override
141        public void clearCache()
142        {
143                if (resourceVersion instanceof CachingResourceVersion)
144                {
145                        ((CachingResourceVersion) resourceVersion).invalidateAll();
146                }
147        }
148}