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.http;
20  
21  import static com.google.common.base.Preconditions.checkArgument;
22  import static com.google.common.base.Preconditions.checkNotNull;
23  
24  import java.net.URI;
25  import java.util.Arrays;
26  import java.util.List;
27  
28  import org.jclouds.javax.annotation.Nullable;
29  
30  import org.jclouds.io.Payload;
31  
32  import com.google.common.collect.ImmutableList;
33  import com.google.common.collect.ImmutableMultimap;
34  import com.google.common.collect.Multimap;
35  
36  /**
37   * Represents a request that can be executed within {@link HttpCommandExecutorService}
38   * 
39   * @author Adrian Cole
40   */
41  public class HttpRequest extends HttpMessage {
42     public static Builder<? extends HttpRequest> builder() {
43        return new Builder<HttpRequest>();
44     }
45  
46     public static class Builder<T extends HttpRequest> extends HttpMessage.Builder<T> {
47        protected String method;
48        protected URI endpoint;
49        protected char[] skips = new char[] {};
50        protected List<HttpRequestFilter> requestFilters = ImmutableList.of();
51  
52        public Builder<T> filters(List<HttpRequestFilter> requestFilters) {
53           this.requestFilters = ImmutableList.copyOf(checkNotNull(requestFilters, "requestFilters"));
54           return this;
55        }
56  
57        public Builder<T> method(String method) {
58           this.method = checkNotNull(method, "method");
59           return this;
60        }
61  
62        public Builder<T> endpoint(URI endpoint) {
63           this.endpoint = checkNotNull(endpoint, "endpoint");
64           return this;
65        }
66  
67        public Builder<T> skips(char[] skips) {
68           char[] retval = new char[checkNotNull(skips, "skips").length];
69           System.arraycopy(skips, 0, retval, 0, skips.length);
70           this.skips = retval;
71           return this;
72        }
73  
74        @Override
75        public Builder<T> payload(Payload payload) {
76           return (Builder<T>) super.payload(payload);
77        }
78  
79        @Override
80        public Builder<T> headers(Multimap<String, String> headers) {
81           return (Builder<T>) super.headers(headers);
82        }
83  
84        @Override
85        @SuppressWarnings("unchecked")
86        public T build() {
87           return (T) new HttpRequest(method, endpoint, skips, requestFilters, payload, headers);
88        }
89  
90        public static <X extends HttpRequest> Builder<X> from(X input) {
91           return new Builder<X>().method(input.getMethod()).endpoint(input.getEndpoint()).skips(input.getSkips())
92                    .filters(input.getFilters()).payload(input.getPayload()).headers(input.getHeaders());
93        }
94  
95     }
96  
97     private final List<HttpRequestFilter> requestFilters;
98     private final String method;
99     private final URI endpoint;
100    private final char[] skips;
101 
102    /**
103     * 
104     * @param endpoint
105     *           This may change over the life of the request due to redirects.
106     * @param method
107     *           If the request is HEAD, this may change to GET due to redirects
108     */
109    public HttpRequest(String method, URI endpoint) {
110       this(method, endpoint, new char[] {});
111    }
112 
113    public HttpRequest(String method, URI endpoint, char[] skips) {
114       this(method, endpoint, skips, ImmutableList.<HttpRequestFilter> of());
115    }
116 
117    public HttpRequest(String method, URI endpoint, char[] skips, List<HttpRequestFilter> requestFilters) {
118       this(method, endpoint, skips, requestFilters, null);
119    }
120 
121    public HttpRequest(String method, URI endpoint, char[] skips, List<HttpRequestFilter> requestFilters,
122             @Nullable Payload payload) {
123       this(method, endpoint, skips, requestFilters, payload, ImmutableMultimap.<String, String> of());
124    }
125 
126    /**
127     * 
128     * @param endpoint
129     *           This may change over the life of the request due to redirects.
130     * @param method
131     *           If the request is HEAD, this may change to GET due to redirects
132     */
133    public HttpRequest(String method, URI endpoint, Multimap<String, String> headers) {
134       this(method, endpoint, new char[] {}, ImmutableList.<HttpRequestFilter> of(), null, headers);
135    }
136 
137    public HttpRequest(String method, URI endpoint, char[] skips, List<HttpRequestFilter> requestFilters,
138             @Nullable Payload payload, Multimap<String, String> headers) {
139       super(payload, headers);
140       this.method = checkNotNull(method, "method");
141       this.endpoint = checkNotNull(endpoint, "endpoint");
142       checkArgument(endpoint.getHost() != null, String.format("endpoint.getHost() is null for %s", endpoint));
143       this.skips = checkNotNull(skips, "skips");
144       this.requestFilters = ImmutableList.<HttpRequestFilter> copyOf(checkNotNull(requestFilters, "requestFilters"));
145    }
146 
147    /**
148     * 
149     * @param endpoint
150     *           This may change over the life of the request due to redirects.
151     * @param method
152     *           If the request is HEAD, this may change to GET due to redirects
153     */
154    protected HttpRequest(String method, URI endpoint, Multimap<String, String> headers, @Nullable Payload payload) {
155       this(method, endpoint, new char[] {}, ImmutableList.<HttpRequestFilter> of(), payload, headers);
156    }
157 
158    public String getRequestLine() {
159       return String.format("%s %s HTTP/1.1", getMethod(), getEndpoint().toASCIIString());
160    }
161 
162    /**
163     * We cannot return an enum, as per specification custom methods are allowed. Enums are not
164     * extensible.
165     * 
166     * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1" >rfc2616</a>
167     */
168    public String getMethod() {
169       return method;
170    }
171 
172    /**
173     * characters to skip encoding on.
174     */
175    public char[] getSkips() {
176       return skips;
177    }
178 
179    public URI getEndpoint() {
180       return endpoint;
181    }
182 
183    public void addFilter(HttpRequestFilter filter) {
184       requestFilters.add(filter);
185    }
186 
187    public List<HttpRequestFilter> getFilters() {
188       return requestFilters;
189    }
190 
191    @Override
192    public Builder<? extends HttpRequest> toBuilder() {
193       return Builder.from(this);
194    }
195 
196    @Override
197    public int hashCode() {
198       final int prime = 31;
199       int result = super.hashCode();
200       result = prime * result + ((endpoint == null) ? 0 : endpoint.hashCode());
201       result = prime * result + ((method == null) ? 0 : method.hashCode());
202       result = prime * result + ((payload == null) ? 0 : payload.hashCode());
203       result = prime * result + ((headers == null) ? 0 : headers.hashCode());
204       result = prime * result + ((requestFilters == null) ? 0 : requestFilters.hashCode());
205       result = prime * result + Arrays.hashCode(skips);
206       return result;
207    }
208 
209    @Override
210    public boolean equals(Object obj) {
211       if (this == obj)
212          return true;
213       if (!super.equals(obj))
214          return false;
215       if (getClass() != obj.getClass())
216          return false;
217       HttpRequest other = (HttpRequest) obj;
218       if (endpoint == null) {
219          if (other.endpoint != null)
220             return false;
221       } else if (!endpoint.equals(other.endpoint))
222          return false;
223       if (method == null) {
224          if (other.method != null)
225             return false;
226       } else if (!method.equals(other.method))
227          return false;
228       if (payload == null) {
229          if (other.payload != null)
230             return false;
231       } else if (!payload.equals(other.payload))
232          return false;
233       if (headers == null) {
234          if (other.headers != null)
235             return false;
236       } else if (!headers.equals(other.headers))
237          return false;
238       if (requestFilters == null) {
239          if (other.requestFilters != null)
240             return false;
241       } else if (!requestFilters.equals(other.requestFilters))
242          return false;
243       if (!Arrays.equals(skips, other.skips))
244          return false;
245       return true;
246    }
247 
248    @Override
249    public String toString() {
250       return String.format("[method=%s, endpoint=%s, headers=%s, payload=%s]", method, endpoint, headers, payload);
251    }
252 
253 }