package aQute.bnd.http;
import java.io.File;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import org.osgi.util.promise.Deferred;
import org.osgi.util.promise.Promise;
import aQute.bnd.osgi.Processor;
import aQute.bnd.service.url.TaggedData;
import aQute.lib.converter.TypeReference;
import aQute.service.reporter.Reporter;
/**
* Builds up a request
*
* @param <T>
*/
@SuppressWarnings("unchecked")
public class HttpRequest<T> {
String verb = "GET";
Object upload;
Type download;
Map<String,String> headers = new HashMap<>();
long timeout = -1;
HttpClient client;
String ifNoneMatch;
long ifModifiedSince;
long ifUnmodifiedSince;
URL url;
int redirects = 10;
String ifMatch;
boolean cached;
long maxStale;
Reporter reporter;
File useCacheFile;
boolean updateTag;
HttpRequest(HttpClient client) {
this.client = client;
}
/**
* Convert the result to a specific type
*/
public <X> HttpRequest<X> get(Class<X> type) {
this.download = type;
return (HttpRequest<X>) this;
}
/**
* Convert the result to a specific type
*/
public <X> HttpRequest<X> get(TypeReference<X> type) {
this.download = type.getType();
return (HttpRequest<X>) this;
}
/**
* Convert the result to a specific type
*/
public HttpRequest<Object> get(Type type) {
this.download = type;
return (HttpRequest<Object>) this;
}
/**
* Set the HTTP verb
*/
public HttpRequest<T> verb(String verb) {
this.verb = verb;
return this;
}
/**
* Set the verb/method to put
*/
public HttpRequest<T> put() {
this.verb = "PUT";
return this;
}
/**
* Set the verb/method to head
*/
public HttpRequest<T> head() {
this.verb = "HEAD";
return this;
}
/**
* Set the verb/method to get
*/
public HttpRequest<T> get() {
this.verb = "GET";
return this;
}
/**
* Set the verb/method to post
*/
public HttpRequest<T> post() {
this.verb = "POST";
return this;
}
/**
* Set the verb/method to option
*/
public HttpRequest<T> option() {
this.verb = "OPTION";
return this;
}
/**
* Set the verb/method to delete
*/
public HttpRequest<T> delete() {
this.verb = "DELETE";
return this;
}
/**
* Set the object to upload. Can be of several types:
* <ul>
* <li>InputStream – copied verbatim
* <li>String – content sent
* <li>byte[] – content sent
* <li>File – content sent
* <li>Otherwise assumes DTO and encodes in JSON
* </ul>
*/
public HttpRequest<T> upload(Object upload) {
this.upload = upload;
return this;
}
/**
* Add headers to request
*/
public HttpRequest<T> headers(Map<String,String> map) {
headers.putAll(map);
return this;
}
/**
* Add header to request
*/
public HttpRequest<T> headers(String key, String value) {
headers.put(key, value);
return this;
}
/**
* Set timeout in ms
*/
public HttpRequest<T> timeout(long timeoutInMs) {
this.timeout = timeoutInMs;
return this;
}
public HttpRequest<T> ifNoneMatch(String etag) {
this.ifNoneMatch = etag;
return this;
}
public HttpRequest<T> ifModifiedSince(long epochTime) {
this.ifModifiedSince = epochTime;
return this;
}
public HttpRequest<T> maxRedirects(int n) {
this.redirects = n;
return this;
}
public T go(URL url) throws Exception {
this.url = url;
return (T) client.send(this);
}
public T go(URI url) throws Exception {
this.url = url.toURL();
return (T) client.send(this);
}
public HttpRequest<T> age(int n, TimeUnit tu) {
this.headers.put("Age", "" + tu.toSeconds(n));
return this;
}
public Promise<T> async(final URL url) throws InterruptedException {
this.url = url;
final Deferred<T> deferred = new Deferred<>();
Executor e = Processor.getExecutor();
e.execute(new Runnable() {
@Override
public void run() {
try {
T result = (T) client.send(HttpRequest.this);
deferred.resolve(result);
} catch (Throwable t) {
deferred.fail(t);
}
}
});
return deferred.getPromise();
}
public Promise<T> async(URI uri) throws MalformedURLException, InterruptedException {
return async(uri.toURL());
}
@Override
public String toString() {
return "HttpRequest [verb=" + verb + ", upload=" + upload + ", download=" + download + ", headers=" + headers
+ ", timeout=" + timeout + ", client=" + client + ", url=" + url + "]";
}
public HttpRequest<T> ifUnmodifiedSince(long ifNotModifiedSince) {
this.ifUnmodifiedSince = ifNotModifiedSince;
return this;
}
public HttpRequest<T> ifMatch(String etag) {
this.ifMatch = etag;
return this;
}
public HttpRequest<TaggedData> asTag() {
return get(TaggedData.class);
}
public HttpRequest<String> asString() {
return get(String.class);
}
public boolean isCache() {
return ("GET".equalsIgnoreCase(verb) && cached) || download == File.class;
}
public HttpRequest<File> useCache(long maxStale) {
this.maxStale = maxStale;
this.cached = true;
download = File.class;
return (HttpRequest<File>) this;
}
public HttpRequest<File> useCache() {
return useCache(-1);
}
public HttpRequest<File> useCache(File file) {
this.useCacheFile = file;
return useCache(-1);
}
public HttpRequest<File> useCache(File file, long maxStale) {
this.useCacheFile = file;
return useCache(maxStale);
}
public HttpRequest<T> report(Reporter reporter) {
this.reporter = reporter;
return this;
}
// TODO
public HttpRequest<T> timeout(long timeout, TimeUnit unit) {
this.timeout = timeout;
return this;
}
public boolean isTagResult() {
return download == null || download == TaggedData.class;
}
public HttpRequest<T> updateTag() {
updateTag = true;
return this;
}
}