All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.httpcache4j.Conditionals Maven / Gradle / Ivy

There is a newer version: 5.1.1
Show newest version
/*
 * Copyright (c) 2008, The Codehaus. All Rights Reserved.
 *
 *   Licensed 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.codehaus.httpcache4j;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Represents the different conditional types that an HTTP request may have.
 * This are basically 4 things:
 * 
    *
  • If-Match
  • *
  • If-None-Match
  • *
  • If-Unmodified-Since
  • *
  • If-Modified-Since
  • *
* * Combinations of these conditionals are possible with the following exceptions
* * * * * * * * * * * * * * * * * * * *
ConditionalCan be combined withUnspecified
If-MatchIf-Unmodified-SinceIf-None-Match, If-Modified-Since
If-None-MatchIf-Modified-SinceIf-Match, If-Unmodified-Since
If-Unmodified-SinceIf-MatchIf-None-Match, If-Modified-Since
If-Modified-SinceIf-None-MatchIf-Match, If-Unmodified-Since
* * @author Erlend Hamnaberg */ public final class Conditionals { private final List match; private final List noneMatch; private final DateTime modifiedSince; private final DateTime unModifiedSince; private static final String ERROR_MESSAGE = "The combination of %s and %s is undefined by the HTTP specification"; public Conditionals() { this(empty(), empty(), null, null); } private static List empty() { return Collections.emptyList(); } public Conditionals(List match, List noneMatch, DateTime modifiedSince, DateTime unModifiedSince) { this.match = match; this.noneMatch = noneMatch; this.modifiedSince = modifiedSince; this.unModifiedSince = unModifiedSince; } /** * Adds tags to the If-Match header. * * @param tag the tag to add, may be null. This means the same as adding {@link Tag#ALL} * @throws IllegalArgumentException if ALL is supplied more than once, or you add a null tag more than once. * @return a new Conditionals object with the If-Match tag added. */ public Conditionals addIfMatch(Tag tag) { Preconditions.checkArgument(modifiedSince == null, String.format(ERROR_MESSAGE, HeaderConstants.IF_MATCH, HeaderConstants.IF_MODIFIED_SINCE)); Preconditions.checkArgument(noneMatch.isEmpty(), String.format(ERROR_MESSAGE, HeaderConstants.IF_MATCH, HeaderConstants.IF_NONE_MATCH)); List match = new ArrayList(this.match); if (tag == null) { tag = Tag.ALL; } if (Tag.ALL.equals(tag)) { match.clear(); } if (!match.contains(Tag.ALL)) { if (!match.contains(tag)) { match.add(tag); } } else { throw new IllegalArgumentException("Tag ALL already in the list"); } return new Conditionals(Collections.unmodifiableList(match), empty(), null, unModifiedSince); } /** * Adds tags to the If-None-Match header. * * The meaning of "If-None-Match: *" is that the method MUST NOT be performed if the representation selected by * the origin server (or by a cache, possibly using the Vary mechanism, see section 14.44) exists, * and SHOULD be performed if the representation does not exist. * This feature is intended to be useful in preventing races between PUT operations. * * @param tag the tag to add, may be null. This means the same as adding {@link Tag#ALL} * @throws IllegalArgumentException if ALL is supplied more than once, or you add a null tag more than once. * @return a new Conditionals object with the If-None-Match tag added. */ public Conditionals addIfNoneMatch(Tag tag) { Preconditions.checkArgument(unModifiedSince == null, String.format(ERROR_MESSAGE, HeaderConstants.IF_NONE_MATCH, HeaderConstants.IF_UNMODIFIED_SINCE)); Preconditions.checkArgument(match.isEmpty(), String.format(ERROR_MESSAGE, HeaderConstants.IF_NONE_MATCH, HeaderConstants.IF_MATCH)); List noneMatch = new ArrayList(this.noneMatch); if (tag == null) { tag = Tag.ALL; } if (Tag.ALL.equals(tag)) { noneMatch.clear(); } if (!noneMatch.contains(Tag.ALL)) { if (!noneMatch.contains(tag)) { noneMatch.add(tag); } } else { throw new IllegalArgumentException("Tag ALL already in the list"); } return new Conditionals(empty(), Collections.unmodifiableList(noneMatch), modifiedSince, null); } /** * You should use the server's time here. Otherwise you might get unexpected results. * The typical use case is:
*
     *   HTTPResponse response = ....
     *   HTTPRequest request = createRequest();
     *   request = request.conditionals(new Conditionals().ifModifiedSince(response.getLastModified());
     * 
* * @param time the time to check. * @return the conditionals with the If-Modified-Since date set. */ public Conditionals ifModifiedSince(DateTime time) { Preconditions.checkArgument(match.isEmpty(), String.format(ERROR_MESSAGE, HeaderConstants.IF_MODIFIED_SINCE, HeaderConstants.IF_MATCH)); Preconditions.checkArgument(unModifiedSince == null, String.format(ERROR_MESSAGE, HeaderConstants.IF_MODIFIED_SINCE, HeaderConstants.IF_UNMODIFIED_SINCE)); time = time.toDateTime(DateTimeZone.forID("UTC")); time = time.withMillisOfSecond(0); return new Conditionals(empty(), noneMatch, time, null); } /** * You should use the server's time here. Otherwise you might get unexpected results. * The typical use case is:
*
     *   HTTPResponse response = ....
     *   HTTPRequest request = createRequest();
     *   request = request.conditionals(new Conditionals().ifUnModifiedSince(response.getLastModified());
     * 
* * @param time the time to check. * @return the conditionals with the If-Unmodified-Since date set. */ public Conditionals ifUnModifiedSince(DateTime time) { Preconditions.checkArgument(noneMatch.isEmpty(), String.format(ERROR_MESSAGE, HeaderConstants.IF_UNMODIFIED_SINCE, HeaderConstants.IF_NONE_MATCH)); Preconditions.checkArgument(modifiedSince == null, String.format(ERROR_MESSAGE, HeaderConstants.IF_UNMODIFIED_SINCE, HeaderConstants.IF_MODIFIED_SINCE)); time = time.toDateTime(DateTimeZone.forID("UTC")); time = time.withMillisOfSecond(0); return new Conditionals(match, empty(), null, time); } public List getMatch() { return Collections.unmodifiableList(match); } public List getNoneMatch() { return Collections.unmodifiableList(noneMatch); } public DateTime getModifiedSince() { return modifiedSince; } public DateTime getUnModifiedSince() { return unModifiedSince; } /** * * @return {@code true} if the Conditionals represents a unconditional request. */ public boolean isUnconditional() { return noneMatch.contains(Tag.ALL) || match.contains(Tag.ALL) || (match.isEmpty() && unModifiedSince == null) || (noneMatch.isEmpty() && modifiedSince == null) ; } /** * Converts the Conditionals into real headers. */ public Headers toHeaders() { Headers headers = new Headers(); if (!getMatch().isEmpty()) { headers = headers.add(new Header(HeaderConstants.IF_MATCH, buildTagHeaderValue(getMatch()))); } if (!getNoneMatch().isEmpty()) { headers = headers.add(new Header(HeaderConstants.IF_NONE_MATCH, buildTagHeaderValue(getNoneMatch()))); } if (modifiedSince != null) { headers = headers.set(HeaderUtils.toHttpDate(HeaderConstants.IF_MODIFIED_SINCE, modifiedSince)); } if (unModifiedSince != null) { headers = headers.set(HeaderUtils.toHttpDate(HeaderConstants.IF_UNMODIFIED_SINCE, unModifiedSince)); } return headers; } public static Conditionals valueOf(Headers headers) { ImmutableList ifMatch = makeTags(headers.getFirstHeaderValue(HeaderConstants.IF_MATCH)); ImmutableList ifNoneMatch = makeTags(headers.getFirstHeaderValue(HeaderConstants.IF_NONE_MATCH)); DateTime modifiedSince = HeaderUtils.fromHttpDate(headers.getFirstHeader(HeaderConstants.IF_MODIFIED_SINCE)); DateTime unModifiedSince = HeaderUtils.fromHttpDate(headers.getFirstHeader(HeaderConstants.IF_UNMODIFIED_SINCE)); return new Conditionals(ifMatch, ifNoneMatch, modifiedSince, unModifiedSince); } private static ImmutableList makeTags(String ifMatch) { if (ifMatch == null) { return ImmutableList.of(); } return ImmutableList.copyOf(Iterables.transform(Splitter.on(",").omitEmptyStrings().trimResults().split(ifMatch), tagFunction)); } private String buildTagHeaderValue(List match) { return Joiner.on(",").join(Collections2.transform(match, new Function() { @Override public String apply(Tag input) { return input.format(); } })); } public static Function tagFunction = new Function() { @Override public Tag apply(String input) { return Tag.parse(input); } }; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy