From: Bill Erickson Date: Fri, 16 Mar 2012 13:56:13 +0000 (-0400) Subject: Java Gateway interface improved exception handling X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=b4c8d84b00e23084a0ea47c0d9b00ac291efb047;p=working%2FOpenSRF.git Java Gateway interface improved exception handling Handle any exceptions that should not reasonably occur in normal operation under the covers. Bubble the rest up. Update test code with examples. Signed-off-by: Bill Erickson Signed-off-by: Dan Scott --- diff --git a/src/java/org/opensrf/net/http/GatewayRequest.java b/src/java/org/opensrf/net/http/GatewayRequest.java index 00631bf..696d8d4 100644 --- a/src/java/org/opensrf/net/http/GatewayRequest.java +++ b/src/java/org/opensrf/net/http/GatewayRequest.java @@ -28,74 +28,75 @@ public class GatewayRequest extends HttpRequest { 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 result = null; + // parse the JSON response + Map result = null; - try { - result = (Map) new JSONReader(readBuf.toString()).readObject(); - } catch (org.opensrf.util.JSONException ex) { - ex.printStackTrace(); - return null; - } + try { + result = (Map) new JSONReader(readBuf.toString()).readObject(); - String status = result.get("status").toString(); - if (!"200".equals(status)) { - failed = true; - // failure = - } + } 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) { @@ -116,10 +117,15 @@ public class GatewayRequest extends HttpRequest { } 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(); diff --git a/src/java/org/opensrf/net/http/HttpConnection.java b/src/java/org/opensrf/net/http/HttpConnection.java index 32fdebc..c40b9f9 100644 --- a/src/java/org/opensrf/net/http/HttpConnection.java +++ b/src/java/org/opensrf/net/http/HttpConnection.java @@ -29,12 +29,17 @@ public class HttpConnection { 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; @@ -66,19 +71,22 @@ public class HttpConnection { //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 { diff --git a/src/java/org/opensrf/net/http/HttpRequest.java b/src/java/org/opensrf/net/http/HttpRequest.java index d91a127..8a4a39f 100644 --- a/src/java/org/opensrf/net/http/HttpRequest.java +++ b/src/java/org/opensrf/net/http/HttpRequest.java @@ -8,23 +8,41 @@ import java.net.HttpURLConnection; 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 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; @@ -32,8 +50,14 @@ public abstract class HttpRequest { 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); } @@ -48,19 +72,24 @@ public abstract class HttpRequest { } 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; } diff --git a/src/java/org/opensrf/net/http/HttpRequestHandler.java b/src/java/org/opensrf/net/http/HttpRequestHandler.java index 9c0f9e5..c30a4f6 100644 --- a/src/java/org/opensrf/net/http/HttpRequestHandler.java +++ b/src/java/org/opensrf/net/http/HttpRequestHandler.java @@ -1,5 +1,6 @@ package org.opensrf.net.http; +import org.opensrf.util.*; import java.util.List; /* @@ -9,8 +10,6 @@ public abstract class HttpRequestHandler { /** * Called when all responses have been received. - * - * If discardResponses() returns true, will be passed null. */ public void onComplete(HttpRequest request) { } @@ -22,4 +21,8 @@ public abstract class HttpRequestHandler { */ public void onResponse(HttpRequest request, Object response) { } + + public void onError(HttpRequest request, Exception ex) { + Logger.error("HttpRequest Error: " + ex.getStackTrace()); + } } diff --git a/src/java/org/opensrf/test/TestGateway.java b/src/java/org/opensrf/test/TestGateway.java index 967e929..1ac6d90 100644 --- a/src/java/org/opensrf/test/TestGateway.java +++ b/src/java/org/opensrf/test/TestGateway.java @@ -10,47 +10,67 @@ import java.util.Arrays; 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(); } } }