Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. 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. For additional information regarding * copyright in this work, please see the NOTICE file in the top level * directory of this distribution. */ package org.apache.abdera2.common.protocol; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.activation.MimeType; import org.apache.abdera2.common.Localizer; import org.apache.abdera2.common.lang.Lang; import org.apache.abdera2.common.misc.ExceptionHelper; import org.apache.abdera2.common.misc.MoreFunctions; import org.apache.abdera2.common.selector.AbstractSelector; import org.apache.abdera2.common.selector.Selector; import org.apache.abdera2.common.text.Codec; import org.apache.abdera2.common.text.UrlEncoding; import org.apache.abdera2.common.text.CharUtils.Profile; import org.apache.abdera2.common.date.DateTimes; import org.apache.abdera2.common.http.Authentication; import org.apache.abdera2.common.http.CacheControl; import org.apache.abdera2.common.http.EntityTag; import org.apache.abdera2.common.http.Preference; import org.apache.abdera2.common.http.WebLink; import org.apache.http.impl.cookie.DateParseException; import org.apache.http.impl.cookie.DateUtils; import org.joda.time.DateTime; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; /** * The RequestOptions class allows a variety of options affecting the execution of the request to be modified. */ public class RequestOptions extends AbstractRequest implements Request { public static Builder make() { return new Builder(); } public static Builder make(DateTime ifModifiedSince) { return make().ifModifiedSince(ifModifiedSince); } public static Builder make(String ifNoneMatch) { return make().ifNoneMatch(ifNoneMatch); } public static Builder make(String etag, String... ifNoneMatch) { return make().ifNoneMatch(etag, ifNoneMatch); } public static Builder make(DateTime ifModifiedSince, String ifNoneMatch) { return make().ifModifiedSince(ifModifiedSince).ifNoneMatch(ifNoneMatch); } public static Builder make(DateTime ifModifiedSince, String etag, String... ifNoneMatch) { return make().ifModifiedSince(ifModifiedSince).ifNoneMatch(etag, ifNoneMatch); } public static Builder make(boolean no_cache) { return make().cacheControl(CacheControl.NOCACHE()); } public Builder template() { return new Builder(this); } public Builder template(Selector<Map.Entry<String, Set<String>>> filter) { return new Builder(this, filter); } public static Selector<Map.Entry<String, Set<String>>> withAllHeaders() { return new AbstractSelector<Map.Entry<String, Set<String>>>() { public boolean select(Object item) { return true; } }; } public static Selector<Map.Entry<String, Set<String>>> withNoHeaders() { return new AbstractSelector<Map.Entry<String, Set<String>>>() { public boolean select(Object item) { return false; } }; } @SuppressWarnings("unchecked") public static Selector<Map.Entry<String, Set<String>>> withHeaders(String... names) { final ImmutableSet<String> set = ImmutableSet.copyOf(names); return new AbstractSelector<Map.Entry<String, Set<String>>>() { public boolean select(Object item) { Map.Entry<String, Set<String>> entry = (Entry<String, Set<String>>) item; return set.contains(entry.getKey()); } }; } @SuppressWarnings("unchecked") public static Selector<Map.Entry<String, Set<String>>> withoutHeaders(String... names) { final ImmutableSet<String> set = ImmutableSet.copyOf(names); return new AbstractSelector<Map.Entry<String, Set<String>>>() { public boolean select(Object item) { Map.Entry<String, Set<String>> entry = (Entry<String, Set<String>>) item; return !set.contains(entry.getKey()); } }; } public static class Builder implements Supplier<RequestOptions> { boolean revalidateAuth = false; boolean useChunked = false; boolean usePostOverride = false; boolean requestException4xx = false; boolean requestException5xx = false; boolean useExpectContinue = true; boolean useConditional = true; boolean followRedirects = true; CacheControl cacheControl = null; int waitForContinue = -1; final Map<String, ImmutableSet.Builder<String>> headers = Maps.newHashMap(); public Builder() { } Builder(RequestOptions template) { this(template, null); } Builder(RequestOptions template, Selector<Map.Entry<String, Set<String>>> filter) { this.revalidateAuth = template.revalidateAuth; this.followRedirects = template.followRedirects; this.cacheControl = template.cacheControl; this.useChunked = template.useChunked; this.usePostOverride = template.usePostOverride; this.requestException4xx = template.requestException4xx; this.requestException5xx = template.requestException5xx; this.useExpectContinue = template.useExpectContinue; this.useConditional = template.useConditional; this.waitForContinue = template.waitForContinue; for (Map.Entry<String, Set<String>> header : template.headers.entrySet()) { if (filter == null || filter.apply(header)) { ImmutableSet.Builder<String> builder = ImmutableSet.builder(); builder.addAll(header.getValue()); this.headers.put(header.getKey(), builder); } } } public Builder revalidateAuth() { this.revalidateAuth = true; return this; } public Builder useChunked() { this.useChunked = true; return this; } public Builder usePostOverride() { this.usePostOverride = true; return this; } public Builder requestException4xx() { this.requestException4xx = true; return this; } public Builder requestException5xx() { this.requestException5xx = true; return this; } public Builder doNotUseExpectContinue() { this.useExpectContinue = false; return this; } public Builder waitForContinue(int millis) { this.waitForContinue = millis; return this; } public Builder doNotFollowRedirects() { this.followRedirects = false; return this; } public Builder contentType(String value) { return header("Content-Type", value); } public Builder contentType(MimeType value) { return header("Content-Type", value.toString()); } public Builder contentLocation(String iri) { return header("Content-Location", iri); } public Builder setAuthorization(String auth) { return header("Authorization", auth); } public Builder setAuthorization(Authentication auth) { return header("Authorization", auth.toString()); } public Builder encodedHeader(String header, String charset, String value) { return header(header, Codec.encode(value, charset)); } public Builder encodedHeader(String header, String charset, String... values) { if (values != null && values.length > 0) { ImmutableSet.Builder<String> vals = headers.get(header); if (vals == null) { vals = ImmutableSet.builder(); headers.put(header, vals); } for (String value : values) vals.add(Codec.encode(value, charset)); } return this; } public Builder header(String header, String value) { if (value != null) header(header, MoreFunctions.array(value)); return this; } public Builder header(String header, String... values) { if (values != null && values.length > 0) { ImmutableSet.Builder<String> vals = headers.get(header); if (vals == null) { vals = ImmutableSet.builder(); headers.put(header, vals); } vals.add(combine(values)); } return this; } public Builder dateHeader(String header, DateTime value) { if (value != null) header(header, DateUtils.formatDate(value.toDate())); return this; } private String combine(String... values) { StringBuilder v = new StringBuilder(); for (String val : values) { if (v.length() > 0) v.append(", "); v.append(val); } return v.toString(); } public Builder ifMatch(EntityTag entity_tag) { return header("If-Match", entity_tag.toString()); } /** * Sets the value of the HTTP If-Match header */ public Builder ifMatch(EntityTag tag, EntityTag... entity_tags) { return header("If-Match", EntityTag.toString(tag, entity_tags)); } /** * Sets the value of the HTTP If-Match header */ public Builder ifMatch(String etag, String... entity_tags) { return header("If-Match", EntityTag.toString(etag, entity_tags)); } /** * Sets the value of the HTTP If-None-Match header */ public Builder ifNoneMatch(String entity_tag) { return ifNoneMatch(new EntityTag(entity_tag)); } /** * Sets the value of the HTTP If-None-Match header */ public Builder ifNoneMatch(EntityTag entity_tag) { return header("If-None-Match", entity_tag.toString()); } /** * Sets the value of the HTTP If-None-Match header */ public Builder ifNoneMatch(EntityTag etag, EntityTag... entity_tags) { return header("If-None-Match", EntityTag.toString(etag, entity_tags)); } /** * Sets the value of the HTTP If-None-Match header */ public Builder ifNoneMatch(String etag, String... entity_tags) { return header("If-None-Match", EntityTag.toString(etag, entity_tags)); } /** * Sets the value of the HTTP If-Modified-Since header */ public Builder ifModifiedSince(DateTime date) { return dateHeader("If-Modified-Since", date); } public Builder ifModifiedSinceNow() { return ifModifiedSince(DateTimes.now()); } /** * Sets the value of the HTTP If-Unmodified-Since header */ public Builder ifUnmodifiedSince(DateTime date) { return dateHeader("If-Unmodified-Since", date); } /** * Sets the value of the HTTP Accept header */ public Builder accept(String accept) { return accept(new String[] { accept }); } /** * Sets the value of the HTTP Accept header */ public Builder accept(String... accept) { return header("Accept", combine(accept)); } public Builder acceptLanguage(Locale locale) { return acceptLanguage(Lang.fromLocale(locale)); } public Builder acceptLanguage(Locale... locales) { String[] langs = new String[locales.length]; for (int n = 0; n < locales.length; n++) langs[n] = Lang.fromLocale(locales[n]); acceptLanguage(langs); return this; } /** * Sets the value of the HTTP Accept-Language header */ public Builder acceptLanguage(String accept) { return acceptLanguage(new String[] { accept }); } /** * Sets the value of the HTTP Accept-Language header */ public Builder acceptLanguage(String... accept) { return header("Accept-Language", combine(accept)); } /** * Sets the value of the HTTP Accept-Charset header */ public Builder acceptCharset(String accept) { return acceptCharset(new String[] { accept }); } /** * Sets the value of the HTTP Accept-Charset header */ public Builder acceptCharset(String... accept) { return header("Accept-Charset", combine(accept)); } /** * Sets the value of the HTTP Accept-Encoding header */ public Builder acceptEncoding(String accept) { return acceptEncoding(new String[] { accept }); } /** * Sets the value of the HTTP Accept-Encoding header */ public Builder acceptEncoding(String... accept) { return header("Accept-Encoding", combine(accept)); } /** * Sets the value of the Atom Publishing Protocol Slug header */ public Builder slug(String slug) { if (slug.indexOf((char) 10) > -1 || slug.indexOf((char) 13) > -1) throw new IllegalArgumentException(Localizer.get("SLUG.BAD.CHARACTERS")); return header("Slug", UrlEncoding.encode(slug, Profile.PATHNODELIMS)); } public Builder cacheControl(String cc) { this.cacheControl = CacheControl.parse(cc); return this; } public Builder cacheControl(CacheControl cc) { this.cacheControl = cc; return this; } public Builder ifMatch(String entity_tag) { return ifMatch(new EntityTag(entity_tag)); } public Builder webLinks(WebLink weblink, WebLink... links) { header("Link", WebLink.toString(weblink, links)); return this; } public Builder prefer(Preference pref, Preference... prefs) { header("Prefer", Preference.toString(pref, prefs)); return this; } public RequestOptions get() { ImmutableMap.Builder<String, Set<String>> actuals = ImmutableMap.builder(); for (Map.Entry<String, ImmutableSet.Builder<String>> header : headers.entrySet()) actuals.put(header.getKey(), header.getValue().build()); return new RequestOptions(this, actuals.build()); } } final boolean revalidateAuth; final boolean useChunked; final boolean usePostOverride; final boolean requestException4xx; final boolean requestException5xx; final boolean useExpectContinue; final boolean useConditional; final boolean followRedirects; final CacheControl cacheControl; final ImmutableMap<String, Set<String>> headers; final int waitForContinue; RequestOptions(Builder builder, ImmutableMap<String, Set<String>> headers) { this.revalidateAuth = builder.revalidateAuth; this.useChunked = builder.useChunked; this.usePostOverride = builder.usePostOverride; this.requestException4xx = builder.requestException4xx; this.requestException5xx = builder.requestException5xx; this.useConditional = builder.useConditional; this.useExpectContinue = builder.useExpectContinue; this.followRedirects = builder.followRedirects; this.cacheControl = builder.cacheControl; this.headers = headers; this.waitForContinue = builder.waitForContinue; } private Map<String, Set<String>> getHeaders() { return headers; } /** * Returns the text value of the specified header */ public String getHeader(String header) { Set<String> list = getHeaders().get(header); return list.size() > 0 ? list.iterator().next() : null; } /** * Return a listing of text values for the specified header */ public Iterable<Object> getHeaders(String header) { return ImmutableSet.<Object>copyOf(getHeaders().get(header)); } /** * Returns the date value of the specified header */ public DateTime getDateHeader(String header) { String val = getHeader(header); try { return (val != null) ? new DateTime(DateUtils.parseDate(val)) : null; } catch (DateParseException e) { throw ExceptionHelper.propogate(e); } } /** * Returns a listing of header names */ public Iterable<String> getHeaderNames() { return getHeaders().keySet(); } /** * Return the value of the Cache-Control header */ public CacheControl getCacheControl() { return cacheControl; } /** * Configure the AbderaClient Side cache to revalidate when using Authorization */ public boolean getRevalidateWithAuth() { return revalidateAuth; } /** * Should the request use chunked encoding? */ public boolean isUseChunked() { return useChunked; } /** * Return whether the request should use the X-HTTP-Method-Override option */ public boolean isUsePostOverride() { return this.usePostOverride; } /** * Return true if a RequestException should be thrown on 4xx responses */ public boolean is4xxRequestException() { return this.requestException4xx; } /** * Return true if a RequestException should be thrown on 5xx responses */ public boolean is5xxRequestException() { return this.requestException5xx; } /** * Return true if Expect-Continue should be used */ public boolean isUseExpectContinue() { return this.useExpectContinue; } /** * True if HTTP Conditional Requests should be used automatically. This only has an effect when putting a Document * that has an ETag or Last-Modified date present */ public boolean isConditionalPut() { return this.useConditional; } /** * True if the client should follow redirects automatically */ public boolean isFollowRedirects() { return followRedirects; } public boolean has(String header) { return headers.containsKey(header); } public int getWaitForContinue() { return waitForContinue; } }