package ca.carleton.gcrc.couch.client.impl;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.sf.json.JSON;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONTokener;
import ca.carleton.gcrc.couch.client.CouchContext;
public class ConnectionUtils {
static public JSON getJsonFromInputStream(InputStream contentStream, String encoding) throws Exception {
if( null == encoding ) {
encoding = "UTF-8";
}
InputStreamReader isr = new InputStreamReader(contentStream, encoding);
StringWriter sw = new StringWriter();
int b = isr.read();
while( b >= 0 ) {
sw.write((char)b);
b = isr.read();
}
sw.flush();
JSONTokener jsonTokener = new JSONTokener(sw.toString());
JSON json = null;
Object obj = jsonTokener.nextValue();
if( obj instanceof JSON ) {
json = (JSON)obj;
} else {
throw new Exception("Unexpected returned object type: "+obj.getClass().getSimpleName());
}
return json;
}
static public <T> T getJsonFromInputStream(InputStream contentStream, String encoding, Class<T> clazz) throws Exception {
JSON json = getJsonFromInputStream(contentStream, encoding);
if( clazz.isAssignableFrom(json.getClass()) ) {
T result = clazz.cast(json);
return result;
}
throw new Exception("Unexpected returned object type: "+json.getClass().getSimpleName());
}
static public URL computeUrlWithParameter(URL url, UrlParameter parameter) throws Exception {
List<UrlParameter> parameters = new ArrayList<UrlParameter>(1);
parameters.add(parameter);
return computeUrlWithParameters(url, parameters);
}
static public URL computeUrlWithParameters(URL url, List<UrlParameter> parameters) throws Exception {
StringWriter sw = new StringWriter();
sw.write(url.toExternalForm());
boolean first = true;
for(UrlParameter parameter : parameters) {
if( first ) {
sw.write("?");
first = false;
} else {
sw.write("&");
}
sw.write( URLEncoder.encode(parameter.getKey(), "UTF-8") );
sw.write("=");
sw.write( URLEncoder.encode(parameter.getValue(), "UTF-8") );
}
sw.flush();
return new URL( sw.toString() );
}
static public <T> T getJsonResource(CouchContext ctxt, URL url, Class<T> clazz) throws Exception {
CouchContextBase context = CouchContextBase.getBase(ctxt);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
context.adjustConnection(conn);
conn.setDoOutput(false);
conn.setDoInput(true);
conn.connect();
updateContextFromHeaderFields(ctxt,conn.getHeaderFields());
String contentEncoding = conn.getContentEncoding();
InputStream contentStream = conn.getInputStream();
T result = getJsonFromInputStream(contentStream, contentEncoding, clazz);
contentStream.close();
conn.disconnect();
return result;
}
static public JSONObject getJsonResource(CouchContext ctxt, URL url) throws Exception {
return getJsonResource(ctxt, url, JSONObject.class);
}
static public JSONObject putJsonResource(CouchContext ctxt, URL url, JSONObject jsonObj) throws Exception {
CouchContextBase context = CouchContextBase.getBase(ctxt);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("PUT");
context.adjustConnection(conn);
conn.setDoInput(true);
if( null == jsonObj ) {
conn.setDoOutput(false);
} else {
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
OutputStream os = conn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
jsonObj.write(osw);
osw.flush();
os.close();
}
conn.connect();
updateContextFromHeaderFields(ctxt,conn.getHeaderFields());
String contentEncoding = conn.getContentEncoding();
InputStream contentStream = conn.getInputStream();
JSONObject result = getJsonFromInputStream(contentStream, contentEncoding, JSONObject.class);
contentStream.close();
conn.disconnect();
return result;
}
static public JSONObject postJsonResource(CouchContext ctxt, URL url, JSONObject jsonObj) throws Exception {
CouchContextBase context = CouchContextBase.getBase(ctxt);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
context.adjustConnection(conn);
conn.setDoInput(true);
if( null == jsonObj ) {
conn.setDoOutput(false);
} else {
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
OutputStream os = conn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
jsonObj.write(osw);
osw.flush();
os.close();
}
conn.connect();
updateContextFromHeaderFields(ctxt,conn.getHeaderFields());
String contentEncoding = conn.getContentEncoding();
InputStream contentStream = conn.getInputStream();
JSONObject result = getJsonFromInputStream(contentStream, contentEncoding, JSONObject.class);
contentStream.close();
conn.disconnect();
return result;
}
static public JSONObject postForm(CouchContext ctxt, URL url, Map<String,String> form) throws Exception {
CouchContextBase context = CouchContextBase.getBase(ctxt);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
context.adjustConnection(conn);
conn.setDoInput(true);
if( null == form ) {
conn.setDoOutput(false);
} else {
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
OutputStream os = conn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
boolean first = true;
for(String key : form.keySet()){
String value = form.get(key);
if( first ) {
first = false;
} else {
osw.write("&");
}
osw.write( URLEncoder.encode(key, "UTF-8") );
osw.write("=");
osw.write( URLEncoder.encode(value, "UTF-8") );
}
osw.flush();
os.close();
}
conn.connect();
updateContextFromHeaderFields(ctxt,conn.getHeaderFields());
String contentEncoding = conn.getContentEncoding();
InputStream contentStream = conn.getInputStream();
JSONObject result = getJsonFromInputStream(contentStream, contentEncoding, JSONObject.class);
contentStream.close();
conn.disconnect();
return result;
}
static public JSONObject deleteJsonResource(CouchContext ctxt, URL url) throws Exception {
CouchContextBase context = CouchContextBase.getBase(ctxt);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("DELETE");
context.adjustConnection(conn);
conn.setDoOutput(false);
conn.setDoInput(true);
conn.connect();
updateContextFromHeaderFields(ctxt,conn.getHeaderFields());
String contentEncoding = conn.getContentEncoding();
InputStream contentStream = conn.getInputStream();
JSONObject result = getJsonFromInputStream(contentStream, contentEncoding, JSONObject.class);
contentStream.close();
conn.disconnect();
return result;
}
static public JSONObject putStreamResource(CouchContext ctxt, URL url, InputStream is, String contentType, long size) throws Exception {
CouchContextBase context = CouchContextBase.getBase(ctxt);
if( null == contentType ) {
contentType = "application/binary";
}
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("PUT");
context.adjustConnection(conn);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", contentType);
OutputStream os = conn.getOutputStream();
int b = is.read();
while( b >= 0 ) {
os.write(b);
b = is.read();
}
os.flush();
os.close();
conn.connect();
updateContextFromHeaderFields(ctxt,conn.getHeaderFields());
String contentEncoding = conn.getContentEncoding();
InputStream contentStream = conn.getInputStream();
JSONObject result = getJsonFromInputStream(contentStream, contentEncoding, JSONObject.class);
contentStream.close();
conn.disconnect();
return result;
}
static public String getStreamResource(CouchContext ctxt, URL url, OutputStream outputStream) throws Exception {
CouchContextBase context = CouchContextBase.getBase(ctxt);
String contentType = null;
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
context.adjustConnection(conn);
conn.setDoInput(true);
conn.setDoOutput(false);
conn.connect();
updateContextFromHeaderFields(ctxt,conn.getHeaderFields());
contentType = conn.getContentType();
//String contentEncoding = conn.getContentEncoding();
InputStream contentStream = conn.getInputStream();
int b = contentStream.read();
while( b >= 0 ) {
outputStream.write(b);
b = contentStream.read();
}
outputStream.flush();
outputStream.close();
contentStream.close();
conn.disconnect();
return contentType;
}
/**
* Analyze a CouchDb response and raises an exception if an error was returned
* in the response.
* @param response JSON response sent by server
* @param errorMessage Message of top exception
* @throws Exception If error is returned in response
*/
static public void captureReponseErrors(Object response, String errorMessage) throws Exception {
if( null == response ) {
throw new Exception("Capturing errors from null response");
}
if( false == (response instanceof JSONObject) ) {
// Not an error
return;
}
JSONObject obj = (JSONObject)response;
if( obj.containsKey("error") ) {
String serverMessage;
try {
serverMessage = obj.getString("error");
} catch (Exception e) {
serverMessage = "Unable to parse error response";
}
if( null == errorMessage ) {
errorMessage = "Error returned by database: ";
}
throw new Exception(errorMessage+serverMessage);
}
}
static public void updateContextFromHeaderFields(CouchContext context, Map<String,List<String>> headerFields){
// Cookies
if( headerFields.containsKey("Set-Cookie")
&& context instanceof AcceptsCookies ) {
AcceptsCookies acceptsCookies = (AcceptsCookies)context;
List<String> cookies = headerFields.get("Set-Cookie");
for(String cookie : cookies){
String[] cookieComponents = cookie.split(";");
if( cookieComponents.length > 0 ) {
String[] cookieKeyValue = cookieComponents[0].split("=");
if( cookieKeyValue.length >= 2 ) {
acceptsCookies.setCookie(cookieKeyValue[0].trim(), cookieKeyValue[1].trim());
};
};
}
}
}
}