From d870b8b1ca2e633b0f2b58969cc042888d07db6e Mon Sep 17 00:00:00 2001 From: Chris Jaekl Date: Sat, 13 Dec 2014 00:02:45 -0500 Subject: [PATCH 1/1] Identify bad responses coming back from the server, and throw a specific exception. Eventual goal is to react to this exception with a user-friendly error page. --- .../qd/http/InvalidResponseException.java | 25 +++++++++++ prod/net/jaekl/qd/http/RequestBroker.java | 7 +++ prod/net/jaekl/qd/xml/ParseErrorHandler.java | 29 ++++++++++++ .../net/jaekl/frank/octranspo/ServerTest.java | 6 +-- test/net/jaekl/qd/http/RequestBrokerMock.java | 21 ++++++--- test/net/jaekl/qd/http/RequestBrokerTest.java | 45 +++++++++++++++++-- 6 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 prod/net/jaekl/qd/http/InvalidResponseException.java create mode 100644 prod/net/jaekl/qd/xml/ParseErrorHandler.java diff --git a/prod/net/jaekl/qd/http/InvalidResponseException.java b/prod/net/jaekl/qd/http/InvalidResponseException.java new file mode 100644 index 0000000..525772e --- /dev/null +++ b/prod/net/jaekl/qd/http/InvalidResponseException.java @@ -0,0 +1,25 @@ +package net.jaekl.qd.http; + +import net.jaekl.qd.QDException; + +public class InvalidResponseException extends QDException { + private static final long serialVersionUID = 1L; + + String m_url; + String m_method; + + public InvalidResponseException(String url, String method, Throwable cause) { + super(cause); + + m_url = url; + m_method = method; + } + + public String getUrl() { return m_url; } + public String getMethod() { return m_method; } + + @Override + public String toString() { + return getClass().getName() + "; " + m_url + "/" + m_method; + } +} diff --git a/prod/net/jaekl/qd/http/RequestBroker.java b/prod/net/jaekl/qd/http/RequestBroker.java index 1a4ba4c..d063008 100644 --- a/prod/net/jaekl/qd/http/RequestBroker.java +++ b/prod/net/jaekl/qd/http/RequestBroker.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import net.jaekl.qd.QDException; import net.jaekl.qd.util.ExceptionUtils; +import net.jaekl.qd.xml.ParseErrorHandler; import net.jaekl.qd.xml.ParseHandler; import net.jaekl.qd.xml.ParseResult; @@ -25,6 +26,7 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.HttpClientBuilder; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; @@ -130,9 +132,14 @@ public class RequestBroker is = doSubmit(method, passedParams); XMLReader reader = XMLReaderFactory.createXMLReader(); ParseHandler ph = new ParseHandler(result); + ParseErrorHandler peh = new ParseErrorHandler(); reader.setContentHandler(ph); + reader.setErrorHandler(peh); reader.parse(new InputSource(is)); } + catch ( SAXParseException saxpe ) { + throw new InvalidResponseException(m_gatewayUrl, method, saxpe); + } catch ( InstantiationException | InvocationTargetException | IllegalAccessException diff --git a/prod/net/jaekl/qd/xml/ParseErrorHandler.java b/prod/net/jaekl/qd/xml/ParseErrorHandler.java new file mode 100644 index 0000000..ecdb780 --- /dev/null +++ b/prod/net/jaekl/qd/xml/ParseErrorHandler.java @@ -0,0 +1,29 @@ +// Copyright (C) 2014 Christian Jaekl + +// Simple SAX parse error handler. +// Necessary to avoid printing [Fatal Error] messages to stdout when something goes wrong. + +package net.jaekl.qd.xml; + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +public class ParseErrorHandler implements ErrorHandler { + + @Override + public void error(SAXParseException saxpe) throws SAXException { + throw saxpe; + } + + @Override + public void fatalError(SAXParseException saxpe) throws SAXException { + throw saxpe; + } + + @Override + public void warning(SAXParseException saxpe) throws SAXException { + throw saxpe; + } + +} diff --git a/test/net/jaekl/frank/octranspo/ServerTest.java b/test/net/jaekl/frank/octranspo/ServerTest.java index 7f576cb..ef90944 100644 --- a/test/net/jaekl/frank/octranspo/ServerTest.java +++ b/test/net/jaekl/frank/octranspo/ServerTest.java @@ -161,7 +161,7 @@ public class ServerTest { ArrayList params = new ArrayList(); params.add(new BasicNameValuePair(Server.STOP_NO, "1234")); - broker.setOutput(Server.GET_ROUTE_SUMMARY_FOR_STOP, params, ROUTE_SUMMARY_FOR_STOP); + broker.setResult(Server.GET_ROUTE_SUMMARY_FOR_STOP, params, ROUTE_SUMMARY_FOR_STOP); StopInfo stopInfo = sm.getRouteSummaryForStop(1234); @@ -200,7 +200,7 @@ public class ServerTest { params.add(new BasicNameValuePair(Server.STOP_NO, "7659")); params.add(new BasicNameValuePair(Server.ROUTE_NO, "1")); - broker.setOutput(Server.GET_NEXT_TRIPS_FOR_STOP, params, NEXT_TRIPS_FOR_STOP); + broker.setResult(Server.GET_NEXT_TRIPS_FOR_STOP, params, NEXT_TRIPS_FOR_STOP); StopInfo stopInfo = sm.getNextTripsForStop(7659, 1); @@ -254,7 +254,7 @@ public class ServerTest { ArrayList params = new ArrayList(); params.add(new BasicNameValuePair(Server.STOP_NO, "7659")); - broker.setOutput(Server.GET_NEXT_TRIPS_FOR_STOP_ALL_ROUTES, params, NEXT_TRIPS_FOR_STOP_ALL_ROUTES); + broker.setResult(Server.GET_NEXT_TRIPS_FOR_STOP_ALL_ROUTES, params, NEXT_TRIPS_FOR_STOP_ALL_ROUTES); StopInfo stopInfo = sm.getNextTripsForStopAllRoutes(7659); diff --git a/test/net/jaekl/qd/http/RequestBrokerMock.java b/test/net/jaekl/qd/http/RequestBrokerMock.java index 7e7624b..55a0598 100644 --- a/test/net/jaekl/qd/http/RequestBrokerMock.java +++ b/test/net/jaekl/qd/http/RequestBrokerMock.java @@ -59,31 +59,38 @@ public class RequestBrokerMock extends RequestBroker { } } - HashMap m_output; + HashMap m_result; public RequestBrokerMock(String gatewayUrl, ArrayList baseParams) { super(gatewayUrl, baseParams); - m_output = new HashMap(); + m_result = new HashMap(); } - public void setOutput(String method, ArrayList passedParams, String output) { + public void setResult(String method, ArrayList passedParams, Object result) { InputParams ip = new InputParams(method, passedParams); - m_output.put(ip, output); + m_result.put(ip, result); } @Override InputStream doSubmit(String method, ArrayList passedParams) throws QDException { InputParams ip = new InputParams(method, passedParams); - String output = m_output.get(ip); + Object result = m_result.get(ip); - if (null == output) { - Assert.fail("No output specified for given inputs."); + if (null == result) { + Assert.fail("No result specified for given inputs."); } + if (result instanceof QDException) { + throw (QDException)result; + } + + Assert.assertTrue(result instanceof String); + InputStream is = null; try { + String output = (String)result; is = new ByteArrayInputStream(output.getBytes("UTF-8")); } catch (UnsupportedEncodingException uee) { diff --git a/test/net/jaekl/qd/http/RequestBrokerTest.java b/test/net/jaekl/qd/http/RequestBrokerTest.java index 037e079..2892a17 100644 --- a/test/net/jaekl/qd/http/RequestBrokerTest.java +++ b/test/net/jaekl/qd/http/RequestBrokerTest.java @@ -9,6 +9,7 @@ import net.jaekl.qd.xml.XmlParseException; import org.apache.http.NameValuePair; import org.junit.Test; +import org.xml.sax.SAXParseException; public class RequestBrokerTest { @@ -83,11 +84,11 @@ public class RequestBrokerTest { // Try submitting a request (with a mocked-out http post component) // and validate that we do, in fact, return the expected text (XML). @Test - public void test_sumbit() throws QDException { + public void test_submit() throws QDException { ArrayList emptyParams = new ArrayList(); RequestBrokerMock rbm = new RequestBrokerMock(GATEWAY, emptyParams); - rbm.setOutput(METHOD, emptyParams, ROUTE_SUMMARY_FOR_STOP); + rbm.setResult(METHOD, emptyParams, ROUTE_SUMMARY_FOR_STOP); String actual = rbm.submit(METHOD, emptyParams); @@ -101,7 +102,7 @@ public class RequestBrokerTest { ArrayList emptyParams = new ArrayList(); RequestBrokerMock rbm = new RequestBrokerMock(GATEWAY, emptyParams); - rbm.setOutput(METHOD, emptyParams, ROUTE_SUMMARY_FOR_STOP); + rbm.setResult(METHOD, emptyParams, ROUTE_SUMMARY_FOR_STOP); ParseResult pr = rbm.submitAndParse(METHOD, emptyParams, RouteSummaryParse.class); @@ -167,4 +168,42 @@ public class RequestBrokerTest { Assert.assertEquals(passedParams, rbpem.getParamsPassed()); Assert.assertEquals(ParseResult.class, rbpem.getParserClassPassed()); } + + @Test + public void test_submitAndParse_nonXmlResponse() { + ArrayList emptyParams = new ArrayList(); + + RequestBrokerMock rbm = new RequestBrokerMock(GATEWAY, emptyParams); + rbm.setResult(METHOD, emptyParams, "No stop number specified"); + + try { + rbm.submitAndParse(METHOD, emptyParams, RouteSummaryParse.class); + Assert.fail("Should have thrown an InvalidResultException"); + } + catch (QDException qde) { + Assert.assertTrue(qde instanceof InvalidResponseException); + Assert.assertTrue(qde.toString().contains(GATEWAY)); + Assert.assertTrue(qde.toString().contains(METHOD)); + } + } + + @Test + public void test_submitAndParse_throwsInvalidResultException() { + InvalidResponseException ire = new InvalidResponseException(GATEWAY, METHOD, new SAXParseException("dummy", null)); + ArrayList emptyParams = new ArrayList(); + + RequestBrokerMock rbm = new RequestBrokerMock(GATEWAY, emptyParams); + rbm.setResult(METHOD, emptyParams, ire); + + try { + rbm.submitAndParse(METHOD, emptyParams, RouteSummaryParse.class); + Assert.fail("Should have thrown an exception"); + } + catch (QDException qde) { + Assert.assertTrue(qde instanceof InvalidResponseException); + Assert.assertEquals(ire, qde); + Assert.assertTrue(ire.toString().contains(GATEWAY)); + Assert.assertTrue(ire.toString().contains(METHOD)); + } + } } -- 2.39.2