001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package org.restlet.data;
020:
021: import java.util.Date;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.restlet.resource.Variant;
026: import org.restlet.util.DateUtils;
027:
028: /**
029: * Set of conditions applying to a request. This is equivalent to the HTTP
030: * conditional headers.
031: *
032: * @see <a
033: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24">If-Match</a>
034: * @see <a
035: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25">If-Modified-Since</a>
036: * @see <a
037: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26">If-None-Match</a>
038: * @see <a
039: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.28">If-Unmodified-Since</a>
040: *
041: * @author Jerome Louvel (contact@noelios.com)
042: */
043: public final class Conditions {
044: /** The "if-modified-since" condition */
045: private Date modifiedSince;
046:
047: /** The "if-unmodified-since" condition */
048: private Date unmodifiedSince;
049:
050: /** The "if-match" condition */
051: private List<Tag> match;
052:
053: /** The "if-none-match" condition */
054: private List<Tag> noneMatch;
055:
056: /**
057: * Constructor.
058: */
059: public Conditions() {
060: }
061:
062: /**
063: * Returns the "if-match" condition.
064: *
065: * @return The "if-match" condition.
066: */
067: public List<Tag> getMatch() {
068: return this .match;
069: }
070:
071: /**
072: * Returns the "if-modified-since" condition.
073: *
074: * @return The "if-modified-since" condition.
075: */
076: public Date getModifiedSince() {
077: return this .modifiedSince;
078: }
079:
080: /**
081: * Returns the "if-none-match" condition.
082: *
083: * @return The "if-none-match" condition.
084: */
085: public List<Tag> getNoneMatch() {
086: return this .noneMatch;
087: }
088:
089: /**
090: * Returns the conditional status of a variant using a given method.
091: *
092: * @param method
093: * The request method.
094: * @param variant
095: * The representation whose entity tag or date of
096: * modification will be tested
097: * @return Null if the requested method can be performed, the status of the
098: * response otherwise.
099: */
100: public Status getStatus(Method method, Variant variant) {
101: Status result = null;
102:
103: // Is the "if-Match" rule followed or not?
104: if (getMatch() != null && getMatch().size() != 0) {
105: boolean matched = false;
106: boolean failed = false;
107: boolean all = getMatch().get(0).equals(Tag.ALL);
108:
109: if (variant != null) {
110: // If a tag exists
111: if (!all && variant.getTag() != null) {
112: // Check if it matches one of the representations already
113: // cached by the client
114: Tag tag;
115:
116: for (Iterator<Tag> iter = getMatch().iterator(); !matched
117: && iter.hasNext();) {
118: tag = iter.next();
119: matched = tag.equals(variant.getTag(), false);
120: }
121: } else {
122: matched = all;
123: }
124: } else {
125: // see
126: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24
127: // If none of the entity tags match, or if "*" is given and no
128: // current entity exists, the server MUST NOT perform the
129: // requested method
130: failed = all;
131: }
132:
133: failed = failed || !matched;
134:
135: if (failed) {
136: result = Status.CLIENT_ERROR_PRECONDITION_FAILED;
137: }
138: }
139:
140: // Is the "if-None-Match" rule followed or not?
141: if (result == null && getNoneMatch() != null
142: && getNoneMatch().size() != 0) {
143: boolean matched = false;
144:
145: if (variant != null) {
146: // If a tag exists
147: if (variant.getTag() != null) {
148: // Check if it matches one of the representations
149: // already cached by the client
150: Tag tag;
151:
152: for (Iterator<Tag> iter = getNoneMatch().iterator(); !matched
153: && iter.hasNext();) {
154: tag = iter.next();
155: matched = tag
156: .equals(variant.getTag(), (Method.GET
157: .equals(method) || Method.HEAD
158: .equals(method)));
159: }
160:
161: // The current representation matches one of those already
162: // cached by the client
163: if (matched) {
164: // Check if the current representation has been updated
165: // since the "if-modified-since" date. In this case, the
166: // rule is followed.
167: Date modifiedSince = getModifiedSince();
168: boolean isModifiedSince = (modifiedSince != null)
169: && (DateUtils.after(new Date(),
170: modifiedSince)
171: || (variant
172: .getModificationDate() == null) || DateUtils
173: .after(modifiedSince, variant
174: .getModificationDate()));
175: matched = !isModifiedSince;
176: }
177: }
178: } else {
179: matched = getNoneMatch().get(0).equals(Tag.ALL);
180: }
181:
182: if (matched) {
183: if (Method.GET.equals(method)
184: || Method.HEAD.equals(method)) {
185: result = Status.REDIRECTION_NOT_MODIFIED;
186: } else {
187: result = Status.CLIENT_ERROR_PRECONDITION_FAILED;
188: }
189: }
190: }
191:
192: // Is the "if-Modified-Since" rule followed or not?
193: if (result == null && getModifiedSince() != null) {
194: if (variant != null) {
195: Date modifiedSince = getModifiedSince();
196: boolean isModifiedSince = (DateUtils.after(new Date(),
197: modifiedSince)
198: || (variant.getModificationDate() == null) || DateUtils
199: .after(modifiedSince, variant
200: .getModificationDate()));
201:
202: if (!isModifiedSince) {
203: result = Status.REDIRECTION_NOT_MODIFIED;
204: }
205: }
206: }
207:
208: // Is the "if-Unmodified-Since" rule followed or not?
209: if (result == null && getUnmodifiedSince() != null) {
210: if (variant != null) {
211: Date unModifiedSince = getUnmodifiedSince();
212:
213: boolean isUnModifiedSince = ((unModifiedSince == null)
214: || (variant.getModificationDate() == null) || DateUtils
215: .after(variant.getModificationDate(),
216: unModifiedSince));
217:
218: if (!isUnModifiedSince) {
219: result = Status.CLIENT_ERROR_PRECONDITION_FAILED;
220: }
221: }
222: }
223:
224: return result;
225: }
226:
227: /**
228: * Returns the "if-unmodified-since" condition.
229: *
230: * @return The "if-unmodified-since" condition.
231: */
232: public Date getUnmodifiedSince() {
233: return this .unmodifiedSince;
234: }
235:
236: /**
237: * Indicates if there are some conditions set.
238: *
239: * @return True if there are some conditions set.
240: */
241: public boolean hasSome() {
242: return ((getMatch() != null && !getMatch().isEmpty())
243: || (getNoneMatch() != null && !getNoneMatch().isEmpty())
244: || (getModifiedSince() != null) || (getUnmodifiedSince() != null));
245: }
246:
247: /**
248: * Sets the "if-match" condition.
249: *
250: * @param tags
251: * The "if-match" condition.
252: */
253: public void setMatch(List<Tag> tags) {
254: this .match = tags;
255: }
256:
257: /**
258: * Sets the "if-modified-since" condition.
259: *
260: * @param date
261: * The "if-modified-since" condition.
262: */
263: public void setModifiedSince(Date date) {
264: this .modifiedSince = DateUtils.unmodifiable(date);
265: }
266:
267: /**
268: * Sets the "if-none-match" condition.
269: *
270: * @param tags
271: * The "if-none-match" condition.
272: */
273: public void setNoneMatch(List<Tag> tags) {
274: this .noneMatch = tags;
275: }
276:
277: /**
278: * Sets the "if-unmodified-since" condition.
279: *
280: * @param date
281: * The "if-unmodified-since" condition.
282: */
283: public void setUnmodifiedSince(Date date) {
284: this.unmodifiedSince = DateUtils.unmodifiable(date);
285: }
286:
287: }
|