001    /*
002     * The contents of this file are subject to the terms
003     * of the Common Development and Distribution License
004     * (the "License").  You may not use this file except
005     * in compliance with the License.
006     * 
007     * You can obtain a copy of the license at
008     * http://www.opensource.org/licenses/cddl1.php
009     * See the License for the specific language governing
010     * permissions and limitations under the License.
011     */
012    
013    /*
014     * CacheControl.java
015     *
016     * Created on March 5, 2007, 3:36 PM
017     */
018    
019    package javax.ws.rs.core;
020    
021    import java.util.ArrayList;
022    import java.util.HashMap;
023    import java.util.List;
024    import java.util.Map;
025    import javax.ws.rs.ext.RuntimeDelegate;
026    import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
027    
028    /**
029     * An abstraction for the value of a HTTP Cache-Control response header.
030     * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9">HTTP/1.1 section 14.9</a>
031     */
032    public class CacheControl {
033        private boolean _private;
034        private List<String> privateFields;
035        private boolean noCache;
036        private List<String> noCacheFields;
037        private boolean noStore;
038        private boolean noTransform;
039        private boolean mustRevalidate;
040        private boolean proxyRevalidate;
041        private int maxAge = -1;
042        private int sMaxAge = -1;
043        private Map<String, String> cacheExtension;
044        
045        private static final HeaderDelegate<CacheControl> delegate = 
046                RuntimeDelegate.getInstance().createHeaderDelegate(CacheControl.class);
047    
048        
049        /**
050         * Create a new instance of CacheControl. The new instance will have the 
051         * following default settings:
052         *
053         * <ul>
054         * <li>private = false</li>
055         * <li>noCache = false</li>
056         * <li>noStore = false</li>
057         * <li>noTransform = true</li>
058         * <li>mustRevalidate = false</li>
059         * <li>proxyRevalidate = false</li>
060         * <li>An empty list of private fields</li>
061         * <li>An empty list of no-cache fields</li>
062         * <li>An empty map of cache extensions</li>
063         * </ul>
064         */
065        public CacheControl() {
066            _private = false;
067            noCache = false;
068            noStore = false;
069            noTransform = true;
070            mustRevalidate = false;
071            proxyRevalidate = false;
072        }
073    
074        /**
075         * Creates a new instance of CacheControl by parsing the supplied string.
076         * @param value the cache control string
077         * @return the newly created CacheControl
078         * @throws IllegalArgumentException if the supplied string cannot be parsed
079         * or is null
080         */
081        public static CacheControl valueOf(String value) throws IllegalArgumentException {
082            return delegate.fromString(value);
083        }
084        
085        /**
086         * Corresponds to the must-revalidate cache control directive.
087         * @return true if the must-revalidate cache control directive will be included in the
088         * response, false otherwise.
089         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4">HTTP/1.1 section 14.9.4</a>
090         */
091        public boolean isMustRevalidate() {
092            return mustRevalidate;
093        }
094    
095        /**
096         * Corresponds to the must-revalidate cache control directive.
097         * @param mustRevalidate true if the must-revalidate cache control directive should be included in the
098         * response, false otherwise.
099         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4">HTTP/1.1 section 14.9.4</a>
100         */
101        public void setMustRevalidate(boolean mustRevalidate) {
102            this.mustRevalidate = mustRevalidate;
103        }
104    
105        /**
106         * Corresponds to the proxy-revalidate cache control directive.
107         * @return true if the proxy-revalidate cache control directive will be included in the
108         * response, false otherwise.
109         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4">HTTP/1.1 section 14.9.4</a>
110         */
111        public boolean isProxyRevalidate() {
112            return proxyRevalidate;
113        }
114    
115        /**
116         * Corresponds to the must-revalidate cache control directive.
117         * @param proxyRevalidate true if the proxy-revalidate cache control directive should be included in the
118         * response, false otherwise.
119         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4">HTTP/1.1 section 14.9.4</a>
120         */
121        public void setProxyRevalidate(boolean proxyRevalidate) {
122            this.proxyRevalidate = proxyRevalidate;
123        }
124    
125        /**
126         * Corresponds to the max-age cache control directive.
127         * @return the value of the max-age cache control directive, -1 if the directive is disabled.
128         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3">HTTP/1.1 section 14.9.3</a>
129         */
130        public int getMaxAge() {
131            return maxAge;
132        }
133    
134        /**
135         * Corresponds to the max-age cache control directive.
136         * @param maxAge the value of the max-age cache control directive, a value of -1 will disable the directive.
137         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3">HTTP/1.1 section 14.9.3</a>
138         */
139        public void setMaxAge(int maxAge) {
140            this.maxAge = maxAge;
141        }
142    
143        /**
144         * Corresponds to the s-maxage cache control directive.
145         * @return the value of the s-maxage cache control directive, -1 if the directive is disabled.
146         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3">HTTP/1.1 section 14.9.3</a>
147         */
148        public int getSMaxAge() {
149            return sMaxAge;
150        }
151    
152        /**
153         * Corresponds to the s-maxage cache control directive.
154         * @param sMaxAge the value of the s-maxage cache control directive, a value of -1 will disable the directive.
155         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3">HTTP/1.1 section 14.9.3</a>
156         */
157        public void setSMaxAge(int sMaxAge) {
158            this.sMaxAge = sMaxAge;
159        }
160    
161        /**
162         * Corresponds to the value of the no-cache cache control directive.
163         * @return a mutable list of field-names that will form the value of the no-cache cache control directive.
164         * An empty list results in a bare no-cache directive.
165         * @see #isNoCache
166         * @see #setNoCache
167         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1">HTTP/1.1 section 14.9.1</a>
168         */
169        public List<String> getNoCacheFields() {
170            if (noCacheFields == null)
171                noCacheFields = new ArrayList<String>();
172            return noCacheFields;
173        }
174    
175        /**
176         * Corresponds to the no-cache cache control directive.
177         * @param noCache true if the no-cache cache control directive should be included in the
178         * response, false otherwise.
179         * @see #getNoCacheFields
180         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1">HTTP/1.1 section 14.9.1</a>
181         */
182        public void setNoCache(boolean noCache) {
183            this.noCache = noCache;
184        }
185    
186        /**
187         * Corresponds to the no-cache cache control directive.
188         * @return true if the no-cache cache control directive will be included in the
189         * response, false otherwise.
190         * @see #getNoCacheFields
191         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1">HTTP/1.1 section 14.9.1</a>
192         */
193        public boolean isNoCache() {
194            return noCache;
195        }
196    
197        /**
198         * Corresponds to the private cache control directive.
199         * @return true if the private cache control directive will be included in the
200         * response, false otherwise.
201         * @see #getPrivateFields
202         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1">HTTP/1.1 section 14.9.1</a>
203         */
204        public boolean isPrivate() {
205            return _private;
206        }
207    
208        /**
209         * Corresponds to the value of the private cache control directive.
210         * @return a mutable list of field-names that will form the value of the private cache control directive.
211         * An empty list results in a bare no-cache directive.
212         * @see #isPrivate
213         * @see #setPrivate
214         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1">HTTP/1.1 section 14.9.1</a>
215         */
216        public List<String> getPrivateFields() {
217            if (privateFields == null)
218                privateFields = new ArrayList<String>();
219            return privateFields;
220        }
221    
222        /**
223         * Corresponds to the private cache control directive.
224         * @param _private true if the private cache control directive should be included in the
225         * response, false otherwise.
226         * @see #getPrivateFields
227         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1">HTTP/1.1 section 14.9.1</a>
228         */
229        public void setPrivate(boolean _private) {
230            this._private = _private;
231        }
232    
233        /**
234         * Corresponds to the no-transform cache control directive.
235         * @return true if the no-transform cache control directive will be included in the
236         * response, false otherwise.
237         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5">HTTP/1.1 section 14.9.5</a>
238         */
239        public boolean isNoTransform() {
240            return noTransform;
241        }
242    
243        /**
244         * Corresponds to the no-transform cache control directive.
245         * @param noTransform true if the no-transform cache control directive should be included in the
246         * response, false otherwise.
247         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5">HTTP/1.1 section 14.9.5</a>
248         */
249        public void setNoTransform(boolean noTransform) {
250            this.noTransform = noTransform;
251        }
252    
253        /**
254         * Corresponds to the no-store cache control directive.
255         * @return true if the no-store cache control directive will be included in the
256         * response, false otherwise.
257         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2">HTTP/1.1 section 14.9.2</a>
258         */
259        public boolean isNoStore() {
260            return noStore;
261        }
262    
263        /**
264         * Corresponds to the no-store cache control directive.
265         * @param noStore true if the no-store cache control directive should be included in the
266         * response, false otherwise.
267         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2">HTTP/1.1 section 14.9.2</a>
268         */
269        public void setNoStore(boolean noStore) {
270            this.noStore = noStore;
271        }
272    
273        /**
274         * Corresponds to a set of extension cache control directives.
275         * @return a mutable map of cache control extension names and their values.
276         * If a key has a null value, it will appear as a bare directive. If a key has
277         * a value that contains no whitespace then the directive will appear as
278         * a simple name=value pair. If a key has a value that contains whitespace 
279         * then the directive will appear as a quoted name="value" pair.
280         * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.6">HTTP/1.1 section 14.9.6</a>
281         */
282        public Map<String, String> getCacheExtension() {
283            if (cacheExtension == null)
284                cacheExtension = new HashMap<String, String>();
285            return cacheExtension;
286        }
287    
288        /**
289         * Convert the cache control to a string suitable for use as the value of the
290         * corresponding HTTP header.
291         * @return a stringified cache control
292         */
293        @Override
294        public String toString() {
295            return delegate.toString(this);
296        }
297    
298        /**
299         * Generate hash code from cache control properties.
300         * @return the hashCode
301         */
302        @Override
303        public int hashCode() {
304            int hash = 7;
305            hash = 41 * hash + (this._private ? 1 : 0);
306            hash = 41 * hash + (this.privateFields != null ? this.privateFields.hashCode() : 0);
307            hash = 41 * hash + (this.noCache ? 1 : 0);
308            hash = 41 * hash + (this.noCacheFields != null ? this.noCacheFields.hashCode() : 0);
309            hash = 41 * hash + (this.noStore ? 1 : 0);
310            hash = 41 * hash + (this.noTransform ? 1 : 0);
311            hash = 41 * hash + (this.mustRevalidate ? 1 : 0);
312            hash = 41 * hash + (this.proxyRevalidate ? 1 : 0);
313            hash = 41 * hash + this.maxAge;
314            hash = 41 * hash + this.sMaxAge;
315            hash = 41 * hash + (this.cacheExtension != null ? this.cacheExtension.hashCode() : 0);
316            return hash;
317        }
318    
319        /**
320         * Compares obj to this cache control to see if they are the same 
321         * considering all property values.
322         * @param obj the object to compare to
323         * @return true if the two cache controls are the same, false otherwise.
324         */
325        @Override
326        public boolean equals(Object obj) {
327            if (obj == null) {
328                return false;
329            }
330            if (getClass() != obj.getClass()) {
331                return false;
332            }
333            final CacheControl other = (CacheControl) obj;
334            if (this._private != other._private) {
335                return false;
336            }
337            if (this.privateFields != other.privateFields && (this.privateFields == null || !this.privateFields.equals(other.privateFields))) {
338                return false;
339            }
340            if (this.noCache != other.noCache) {
341                return false;
342            }
343            if (this.noCacheFields != other.noCacheFields && (this.noCacheFields == null || !this.noCacheFields.equals(other.noCacheFields))) {
344                return false;
345            }
346            if (this.noStore != other.noStore) {
347                return false;
348            }
349            if (this.noTransform != other.noTransform) {
350                return false;
351            }
352            if (this.mustRevalidate != other.mustRevalidate) {
353                return false;
354            }
355            if (this.proxyRevalidate != other.proxyRevalidate) {
356                return false;
357            }
358            if (this.maxAge != other.maxAge) {
359                return false;
360            }
361            if (this.sMaxAge != other.sMaxAge) {
362                return false;
363            }
364            if (this.cacheExtension != other.cacheExtension && (this.cacheExtension == null || !this.cacheExtension.equals(other.cacheExtension))) {
365                return false;
366            }
367            return true;
368        }
369        
370    }