readComplete = false;
}
- public GatewayRequest send() {
- try {
-
- String postData = compilePostData(service, method);
+ public GatewayRequest send() throws java.io.IOException {
+ String postData = compilePostData(service, method);
- urlConn = (HttpURLConnection) httpConn.url.openConnection();
- urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- urlConn.setDoInput(true);
- urlConn.setDoOutput(true);
+ urlConn = (HttpURLConnection) httpConn.url.openConnection();
+ urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ urlConn.setDoInput(true);
+ urlConn.setDoOutput(true);
- OutputStreamWriter wr = new OutputStreamWriter(urlConn.getOutputStream());
- wr.write(postData);
- wr.flush();
- wr.close();
-
- } catch (java.io.IOException ex) {
- failed = true;
- failure = ex;
- }
+ OutputStreamWriter wr = new OutputStreamWriter(urlConn.getOutputStream());
+ wr.write(postData);
+ wr.flush();
+ wr.close();
return this;
}
- public Object recv() {
+ public Object recv() throws java.io.IOException {
- if (readComplete)
- return nextResponse();
+ if (!readComplete) {
+ readResponses();
+ readComplete = true;
+ }
- try {
+ Object response = nextResponse();
+ if (response == null)
+ complete = true;
+
+ return response;
+ }
+
+ /**
+ * Reads responses from network and populdates responseList.
+ */
+ private void readResponses() throws java.io.IOException {
- InputStream netStream = new BufferedInputStream(urlConn.getInputStream());
- StringBuffer readBuf = new StringBuffer();
+ InputStream netStream = new BufferedInputStream(urlConn.getInputStream());
+ StringBuffer readBuf = new StringBuffer();
- int bytesRead = 0;
- byte[] buffer = new byte[1024];
+ int bytesRead = 0;
+ byte[] buffer = new byte[1024];
- while ((bytesRead = netStream.read(buffer)) != -1) {
- readBuf.append(new String(buffer, 0, bytesRead));
- }
-
- netStream.close();
- urlConn = null;
+ while ((bytesRead = netStream.read(buffer)) != -1)
+ readBuf.append(new String(buffer, 0, bytesRead));
+
+ netStream.close();
+ urlConn = null;
- Map<String,?> result = null;
+ // parse the JSON response
+ Map<String,?> result = null;
- try {
- result = (Map<String, ?>) new JSONReader(readBuf.toString()).readObject();
- } catch (org.opensrf.util.JSONException ex) {
- ex.printStackTrace();
- return null;
- }
+ try {
+ result = (Map<String, ?>) new JSONReader(readBuf.toString()).readObject();
- String status = result.get("status").toString();
- if (!"200".equals(status)) {
- failed = true;
- // failure = <some new exception>
- }
+ } catch (org.opensrf.util.JSONException ex) {
+ // if this happens, something is wrong
+ Logger.error("Gateway returned bad data " + ex.getStackTrace());
+ return;
+ }
- // gateway always returns a wrapper array with the full results set
- responseList = (List) result.get("payload");
+ // extract the gateway status value
+ String status = result.get("status").toString();
- } catch (java.io.IOException ex) {
- failed = true;
- failure = ex;
+ if (!"200".equals(status)) {
+ return;
+ // throw some new exception
}
- readComplete = true;
- return nextResponse();
+ // gateway always returns a wrapper array with the full results set
+ responseList = (List) result.get("payload");
}
private String compilePostData(String service, Method method) {
}
try {
+
// not using URLEncoder because it replaces ' ' with '+'.
uri = new URI("http", "", null, postData.toString(), null);
+
} catch (java.net.URISyntaxException ex) {
- ex.printStackTrace();
+
+ // if this happens, something is wrong
+ Logger.error("Error compiling POST data " + ex.getStackTrace());
+ return null;
}
return uri.getRawQuery();
url = new URL(fullUrl);
}
+ /**
+ * Maximun number of threads allowed to communicate with the server.
+ */
public int getMaxThreads() {
return maxThreads;
}
/**
- * Set the maximum number of actively communicating threads allowed
+ * Set the maximum number of actively communicating (async) threads allowed.
+ *
+ * This has no effect on synchronous communication.
*/
public void setMaxThreads(int max) {
maxThreads = max;
//thread if necessary, then pass the result to the handler
Runnable r = new Runnable() {
public void run() {
-
Object response;
- request.send();
- while ((response = request.recv()) != null) {
- if (request.handler != null)
+ try {
+ request.send();
+ while ((response = request.recv()) != null)
request.handler.onResponse(request, response);
- }
- if (request.handler != null)
request.handler.onComplete(request);
- activeThreads--;
+ } catch (Exception ex) {
+ request.handler.onError(request, ex);
+
+ } finally {
+ // server communication has completed
+ activeThreads--;
+ }
if (activeThreads < maxThreads) {
try {
public abstract class HttpRequest {
+ /** OpenSRF service. */
protected String service;
+ /** OpenSRF method. */
protected Method method;
+ /** Connection to server. */
protected HttpURLConnection urlConn;
+ /** Connection manager. */
protected HttpConnection httpConn;
- protected HttpRequestHandler handler;
+
+ /**
+ * List of responses.
+ *
+ * Responses are not kept after being passed to onResponse .
+ */
protected List<Object> responseList;
- protected Exception failure;
- protected boolean failed;
+
+ /** True if all responses data has been read and delivered */
protected boolean complete;
+ // use a no-op handler by default
+ protected HttpRequestHandler handler = new HttpRequestHandler() {};
+
public HttpRequest() {
- failed = false;
complete = false;
handler = null;
urlConn = null;
}
+ /**
+ * Constructor.
+ *
+ * @param conn Connection
+ * @param service The OpenSRF service.
+ * @param method The method to send to the server.
+ */
public HttpRequest(HttpConnection conn, String service, Method method) {
this();
this.httpConn = conn;
this.method = method;
}
+ /**
+ * Send a request asynchronously (via threads).
+ *
+ * @param handler Manages responses
+ */
public void sendAsync(final HttpRequestHandler handler) {
- this.handler = handler;
+ if (handler != null)
+ this.handler = handler;
httpConn.manageAsyncRequest(this);
}
}
protected Object nextResponse() {
- if (complete || failed) return null;
+ if (complete || responseList == null)
+ return null;
if (responseList.size() > 0)
return responseList.remove(0);
return null;
}
- public Exception getFailure() {
- return failure;
- }
-
- public abstract HttpRequest send();
+ /**
+ * Send a request to the server.
+ */
+ public abstract GatewayRequest send() throws java.io.IOException;
- public abstract Object recv();
+ /**
+ * Receive one response from the server.
+ *
+ * @return The response object
+ */
+ public abstract Object recv() throws java.io.IOException;
}
package org.opensrf.net.http;
+import org.opensrf.util.*;
import java.util.List;
/*
/**
* Called when all responses have been received.
- *
- * If discardResponses() returns true, will be passed null.
*/
public void onComplete(HttpRequest request) {
}
*/
public void onResponse(HttpRequest request, Object response) {
}
+
+ public void onError(HttpRequest request, Exception ex) {
+ Logger.error("HttpRequest Error: " + ex.getStackTrace());
+ }
}
public class TestGateway {
- public static void main(String[] args) throws java.net.MalformedURLException {
+ public static void main(String[] args) {
if (args.length == 0) {
System.err.println("Please provide a gateway URL: e.g. http://example.org/osrf-gateway-v1");
return;
}
- // configure the connection
- HttpConnection conn = new HttpConnection(args[0]);
+ try {
- Method method = new Method("opensrf.system.echo");
- method.addParam("Hello, Gateway");
- method.addParam(new Integer(12345));
- method.addParam(new Boolean(true));
- method.addParam(Arrays.asList(8,6,7,5,3,0,9));
+ // configure the connection
+ HttpConnection conn = new HttpConnection(args[0]);
- // sync test
- HttpRequest req = new GatewayRequest(conn, "opensrf.math", method).send();
- Object resp;
- while ( (resp = req.recv()) != null) {
- System.out.println("Sync Response: " + resp);
- }
+ Method method = new Method("opensrf.system.echo");
+ method.addParam("Hello, Gateway");
+ method.addParam(new Integer(12345));
+ method.addParam(new Boolean(true));
+ method.addParam(Arrays.asList(8,6,7,5,3,0,9));
- // exceptions are captured instead of thrown,
- // primarily to better support async requests
- if (req.failed()) {
- req.getFailure().printStackTrace();
- return;
- }
+ // sync test
+ HttpRequest req = new GatewayRequest(conn, "opensrf.math", method).send();
+ Object resp;
+ while ( (resp = req.recv()) != null) {
+ System.out.println("Sync Response: " + resp);
+ }
+
+ // async test
+ for (int i = 0; i < 10; i++) {
+ final int ii = i; // required for nested class
+ HttpRequest req2 = new GatewayRequest(conn, "opensrf.math", method);
+
+ req2.sendAsync(
+ new HttpRequestHandler() {
- // async test
- for (int i = 0; i < 10; i++) {
- final int ii = i; // required for nested class
- HttpRequest req2 = new GatewayRequest(conn, "opensrf.math", method);
- req2.sendAsync(
- new HttpRequestHandler() {
- public void onResponse(HttpRequest req, Object resp) {
- System.out.println("Async Response: " + ii + " : " + resp);
+ // called once per response
+ public void onResponse(HttpRequest req, Object resp) {
+ System.out.println("Async Response: " + ii + " : " + resp);
+ }
+
+ // called after all responses have been received
+ // used primarily when you don't know how many responses will be returned
+ public void onComplete(HttpRequest req) {
+ System.out.println("Async Request complete : " + ii);
+ }
+
+ // ruh-roh
+ public void onError(HttpRequest req, Exception ex) {
+ if (ex instanceof java.io.IOException)
+ System.err.println("Trouble communicating with gateway server!");
+ ex.printStackTrace();
+ }
}
- }
- );
+ );
+ }
+
+ } catch (java.net.MalformedURLException ex) {
+ System.err.println("Malformed Gateway URL! " + args[0]);
+ ex.printStackTrace();
+
+ } catch (java.io.IOException ex) {
+ System.err.println("Trouble communicating with gateway server!");
+ ex.printStackTrace();
}
}
}