package com.couchbase.lite.ektorp;
import android.util.Log;
import com.couchbase.lite.Database;
import com.couchbase.lite.Manager;
import com.couchbase.lite.router.Router;
import com.couchbase.lite.router.URLConnection;
import org.apache.http.HttpEntity;
import org.ektorp.http.HttpClient;
import org.ektorp.http.HttpResponse;
import org.ektorp.util.Exceptions;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
public class CBLiteHttpClient implements HttpClient {
private Manager manager;
public CBLiteHttpClient(Manager manager) {
this.manager = manager;
}
protected URL urlFromUri(String uri) {
URL url = null;
try {
url = new URL(String.format("cblite://%s", uri));
} catch (MalformedURLException e) {
Log.w(Database.TAG, "Unable to build CBLite URL", e);
throw Exceptions.propagate(e);
}
return url;
}
protected URLConnection connectionFromUri(String uri) {
URLConnection conn = null;
URL url = urlFromUri(uri);
try {
conn = (URLConnection) url.openConnection();
conn.setDoOutput(true);
} catch (IOException e) {
Exceptions.propagate(e);
}
return conn;
}
@Override
public HttpResponse delete(String uri) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("DELETE");
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse get(String uri) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("GET");
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse get(String uri, Map<String, String> headers) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("GET");
if( headers != null && !headers.isEmpty()) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
}
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse getUncached(String uri) {
return get(uri);
}
@Override
public HttpResponse head(String uri) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("HEAD");
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse post(String uri, String content) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("POST");
if (content != null) {
conn.setDoInput(true);
conn.setRequestInputStream(new ByteArrayInputStream(content
.getBytes()));
}
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse post(String uri, InputStream contentStream) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("POST");
if (contentStream != null) {
conn.setDoInput(true);
conn.setRequestInputStream(contentStream);
}
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse post(String uri, HttpEntity httpEntity) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("POST");
InputStream contentStream = httpEntity.getContent();
if (contentStream != null) {
conn.setDoInput(true);
conn.setRequestInputStream(contentStream);
}
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
} catch (IOException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse postUncached(String uri, String content) {
return post(uri, content);
}
@Override
public HttpResponse copy(String sourceUri, String destination) {
URLConnection conn = connectionFromUri(sourceUri);
try {
conn.setRequestMethod("POST");
conn.setRequestProperty("Destination", destination);
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse put(String uri) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("PUT");
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse put(String uri, String content) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("PUT");
if (content != null) {
conn.setDoInput(true);
conn.setRequestInputStream(new ByteArrayInputStream(content
.getBytes()));
}
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse put(String uri, InputStream contentStream,
String contentType, long contentLength) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("PUT");
if (contentStream != null) {
conn.setDoInput(true);
conn.setRequestProperty("content-type", contentType);
conn.setRequestInputStream(contentStream);
}
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public HttpResponse put(String uri, HttpEntity httpEntity) {
URLConnection conn = connectionFromUri(uri);
try {
conn.setRequestMethod("PUT");
return executeRequest(conn);
} catch (ProtocolException e) {
throw Exceptions.propagate(e);
}
}
@Override
public void shutdown() {
}
protected HttpResponse executeRequest(URLConnection conn) {
final Router router = new Router(manager, conn);
CBLiteHttpResponse response;
try {
response = CBLiteHttpResponse.of(conn, router);
} catch (IOException e) {
throw Exceptions.propagate(e);
}
router.setCallbackBlock(response);
ScheduledExecutorService workExecutor = manager.getWorkExecutor();
Future<?> routerFuture = workExecutor.submit(new Runnable() {
@Override
public void run() {
router.start();
}
});
try {
routerFuture.get();
} catch (InterruptedException e) {
throw Exceptions.propagate(e);
} catch (ExecutionException e) {
throw Exceptions.propagate(e);
}
return response;
}
}