View Javadoc

1   /**
2    * Licensed to jclouds, Inc. (jclouds) under one or more
3    * contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  jclouds licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.jclouds.blobstore.options;
20  
21  import static com.google.common.base.Preconditions.checkArgument;
22  import static com.google.common.base.Preconditions.checkNotNull;
23  
24  import java.io.UnsupportedEncodingException;
25  import java.util.ArrayList;
26  import java.util.Date;
27  import java.util.List;
28  
29  /**
30   * Contains options supported for HTTP GET operations. <h2>
31   * Usage</h2> The recommended way to instantiate a {@link GetOptions} object is to statically import
32   * GetOptions.Builder.* and invoke a static creation method followed by an instance mutator (if
33   * needed):
34   * <p/>
35   * <code>
36   * import static org.jclouds.blobstore.options.GetOptions.Builder.*
37   * 
38   * 
39   * // this will get the first megabyte of an blob, provided it wasn't modified since yesterday
40   * blob = blobStore.getBlob("container, "blobName",range(0,1024).ifUnmodifiedSince(new Date().minusDays(1)));
41   * <code>
42   * 
43   * @author Adrian Cole
44   * 
45   */
46  public class GetOptions {
47  
48     public static final GetOptions NONE = new GetOptions();
49  
50     private final List<String> ranges = new ArrayList<String>();
51     private Date ifModifiedSince;
52     private Date ifUnmodifiedSince;
53     private String ifMatch;
54     private String ifNoneMatch;
55  
56     /**
57      * download the specified range of the object.
58      * @param start first offset included in the response
59      * @param end last offset included in the response (inclusive).
60      * @return itself to enable daisy-chaining of expressions
61      */
62     public GetOptions range(long start, long end) {
63        checkArgument(start >= 0, "start must be >= 0");
64        checkArgument(end >= 0, "end must be >= 0");
65        getRanges().add(String.format("%d-%d", start, end));
66        return this;
67     }
68  
69     /**
70      * download the specified range of the object.
71      */
72     public GetOptions startAt(long start) {
73        checkArgument(start >= 0, "start must be >= 0");
74        getRanges().add(String.format("%d-", start));
75        return this;
76     }
77  
78  
79     /**
80      * download the specified range of the object starting from the end of the object.
81      */
82     public GetOptions tail(long length) {
83        checkArgument(length >= 0, "length must be >= 0");
84        getRanges().add(String.format("-%d", length));
85        return this;
86     }
87  
88     /**
89      * Only return the object if it has changed since this time.
90      * <p />
91      * Not compatible with {@link #ifETagMatches(String)} or {@link #ifUnmodifiedSince(Date)}
92      */
93     public GetOptions ifModifiedSince(Date ifModifiedSince) {
94        checkArgument(getIfMatch() == null, "ifETagMatches() is not compatible with ifModifiedSince()");
95        checkArgument(getIfUnmodifiedSince() == null, "ifUnmodifiedSince() is not compatible with ifModifiedSince()");
96        this.ifModifiedSince = checkNotNull(ifModifiedSince, "ifModifiedSince");
97        return this;
98     }
99  
100    /**
101     * For use in the header If-Modified-Since
102     * <p />
103     * Return the object only if it has been modified since the specified time, otherwise return a
104     * 304 (not modified).
105     * 
106     * @see GetOptions#ifModifiedSince(Date)
107     */
108    public Date getIfModifiedSince() {
109       return this.ifModifiedSince;
110    }
111 
112    /**
113     * Only return the object if it hasn't changed since this time.
114     * <p />
115     * Not compatible with {@link #ifETagDoesntMatch(String)} or {@link #ifModifiedSince(Date)}
116     */
117    public GetOptions ifUnmodifiedSince(Date ifUnmodifiedSince) {
118       checkArgument(getIfNoneMatch() == null, "ifETagDoesntMatch() is not compatible with ifUnmodifiedSince()");
119       checkArgument(getIfModifiedSince() == null, "ifModifiedSince() is not compatible with ifUnmodifiedSince()");
120       this.ifUnmodifiedSince = checkNotNull(ifUnmodifiedSince, "ifUnmodifiedSince");
121       return this;
122    }
123 
124    /**
125     * For use in the header If-Unmodified-Since
126     * <p />
127     * Return the object only if it has not been modified since the specified time, otherwise return
128     * a 412 (precondition failed).
129     * 
130     * @see GetOptions#ifUnmodifiedSince(Date)
131     */
132    public Date getIfUnmodifiedSince() {
133       return this.ifUnmodifiedSince;
134    }
135 
136    /**
137     * The object's eTag hash should match the parameter <code>eTag</code>.
138     * 
139     * <p />
140     * Not compatible with {@link #ifETagDoesntMatch(String)} or {@link #ifModifiedSince(Date)}
141     * 
142     * @param eTag
143     *           hash representing the payload
144     */
145    public GetOptions ifETagMatches(String eTag) {
146       checkArgument(getIfNoneMatch() == null, "ifETagDoesntMatch() is not compatible with ifETagMatches()");
147       checkArgument(getIfModifiedSince() == null, "ifModifiedSince() is not compatible with ifETagMatches()");
148       this.ifMatch = checkNotNull(eTag, "eTag");
149       return this;
150    }
151 
152    /**
153     * For use in the request header: If-Match
154     * <p />
155     * Return the object only if its payload tag (ETag) is the same as the eTag specified, otherwise
156     * return a 412 (precondition failed).
157     * 
158     * @see GetOptions#ifETagMatches(String)
159     */
160    public String getIfMatch() {
161       return this.ifMatch;
162    }
163 
164    /**
165     * The object should not have a eTag hash corresponding with the parameter <code>eTag</code>.
166     * <p />
167     * Not compatible with {@link #ifETagMatches(String)} or {@link #ifUnmodifiedSince(Date)}
168     * 
169     * @param eTag
170     *           hash representing the payload
171     */
172    public GetOptions ifETagDoesntMatch(String eTag) {
173       checkArgument(getIfMatch() == null, "ifETagMatches() is not compatible with ifETagDoesntMatch()");
174       checkArgument(getIfUnmodifiedSince() == null, "ifUnmodifiedSince() is not compatible with ifETagDoesntMatch()");
175       this.ifNoneMatch = checkNotNull(eTag, "eTag");
176       return this;
177    }
178 
179    /**
180     * For use in the request header: If-None-Match
181     * <p />
182     * Return the object only if its payload tag (ETag) is different from the one specified,
183     * otherwise return a 304 (not modified).
184     * 
185     * @see GetOptions#ifETagDoesntMatch(String)
186     */
187    public String getIfNoneMatch() {
188       return this.ifNoneMatch;
189    }
190 
191    public List<String> getRanges() {
192       return ranges;
193    }
194 
195    public static class Builder {
196 
197       /**
198        * @see GetOptions#range(long, long)
199        */
200       public static GetOptions range(long start, long end) {
201          GetOptions options = new GetOptions();
202          return options.range(start, end);
203       }
204 
205       /**
206        * @see GetOptions#getIfModifiedSince()
207        */
208       public static GetOptions ifModifiedSince(Date ifModifiedSince) {
209          GetOptions options = new GetOptions();
210          return options.ifModifiedSince(ifModifiedSince);
211       }
212 
213       /**
214        * @see GetOptions#ifUnmodifiedSince(Date)
215        */
216       public static GetOptions ifUnmodifiedSince(Date ifUnmodifiedSince) {
217          GetOptions options = new GetOptions();
218          return options.ifUnmodifiedSince(ifUnmodifiedSince);
219       }
220 
221       /**
222        * @see GetOptions#ifETagMatches(String)
223        */
224       public static GetOptions ifETagMatches(String eTag) throws UnsupportedEncodingException {
225          GetOptions options = new GetOptions();
226          return options.ifETagMatches(eTag);
227       }
228 
229       /**
230        * @see GetOptions#ifETagDoesntMatch(String)
231        */
232       public static GetOptions ifETagDoesntMatch(String eTag) throws UnsupportedEncodingException {
233          GetOptions options = new GetOptions();
234          return options.ifETagDoesntMatch(eTag);
235       }
236 
237    }
238 
239    @Override
240    public int hashCode() {
241       final int prime = 31;
242       int result = 1;
243       result = prime * result + ((ifMatch == null) ? 0 : ifMatch.hashCode());
244       result = prime * result + ((ifModifiedSince == null) ? 0 : ifModifiedSince.hashCode());
245       result = prime * result + ((ifNoneMatch == null) ? 0 : ifNoneMatch.hashCode());
246       result = prime * result + ((ifUnmodifiedSince == null) ? 0 : ifUnmodifiedSince.hashCode());
247       result = prime * result + ((ranges == null) ? 0 : ranges.hashCode());
248       return result;
249    }
250 
251    @Override
252    public boolean equals(Object obj) {
253       if (this == obj)
254          return true;
255       if (obj == null)
256          return false;
257       if (getClass() != obj.getClass())
258          return false;
259       GetOptions other = (GetOptions) obj;
260       if (ifMatch == null) {
261          if (other.ifMatch != null)
262             return false;
263       } else if (!ifMatch.equals(other.ifMatch))
264          return false;
265       if (ifModifiedSince == null) {
266          if (other.ifModifiedSince != null)
267             return false;
268       } else if (!ifModifiedSince.equals(other.ifModifiedSince))
269          return false;
270       if (ifNoneMatch == null) {
271          if (other.ifNoneMatch != null)
272             return false;
273       } else if (!ifNoneMatch.equals(other.ifNoneMatch))
274          return false;
275       if (ifUnmodifiedSince == null) {
276          if (other.ifUnmodifiedSince != null)
277             return false;
278       } else if (!ifUnmodifiedSince.equals(other.ifUnmodifiedSince))
279          return false;
280       if (ranges == null) {
281          if (other.ranges != null)
282             return false;
283       } else if (!ranges.equals(other.ranges))
284          return false;
285       return true;
286    }
287 
288    @Override
289    public String toString() {
290       return "[ranges=" + ranges + ", ifModifiedSince=" + ifModifiedSince + ", ifUnmodifiedSince=" + ifUnmodifiedSince
291                + ", ifMatch=" + ifMatch + ", ifNoneMatch=" + ifNoneMatch + "]";
292    }
293 
294 }