Remember the scene in the movie “Independence Day,” when Will Smith uploads a software virus into the evil aliens’ spaceship? Let’s do something similar and add a bug into a quickstart, and then use the debugger to find the bug and even fix it.
Some of the types of bugs that you have to deal with in a services and message based system involve when there are problems in the content in the messages, and how the services are (or are not) able to handle those problems. What sorts of bad things can happen to good messages? Missing a field, wrong namespace, malformed XML, errors in the headers, etc. The debugger makes it possible to tweak a message to debug a problem, without having to redeploy the service.
The quickstart that we’ll look at is “validate-xml.” This quickstart demonstrates the SwitchYard XML validator. The quickstart deploys a service that accepts a message and returns an object that is transformed with XLST. The incoming message is checked for XML validity, so that malformed messages are caught. Before we can run the quickstart, it must be deployed in the same manner as the rules-camel-cbr quickstart that we looked at earlier in this article.
The quickstart’s application diagram is very simple as only one service (“OrderService”) is implemented. This service only accepts a message and returns an object that is processed by the XLST transformer, but it’s adequate for our purposes. The diagram looks like this:
The test application that we want to run is: validate-xml/src/test/java/org/switchyard/quickstarts/validate/xml/WebServiceTest.java
This application executes separate two Junit tests. First, it verifies that a properly formatted SOAP message can be transformed and validated, and then it verifies that an intentionally malformed SOAP message (that is, a message that contains invalid XML) is caught.
Before we look at causing and catching a bug, let’s examine the message tansformation that is performed by this quickstart. The transformation is performed with the order.xslt file in the quickstart. It’s a simple transformation in that it transforms incoming messages that look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<orders:order xmlns:orders="urn:switchyard-quickstart:validate-xml:0.1.0">
<orderId>PO-19838-XYZ</orderId>
<itemId>BUTTER</itemId>
<quantity>200</quantity>
</orders:order>
</soapenv:Body>
</soapenv:Envelope>
Into objects that look like this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<orders:orderAck xmlns:orders="urn:switchyard-quickstart:validate-xml:0.1.0">
<orderId>PO-19838-XYZ</orderId>
<accepted>true</accepted>
<status>Order Accepted</status>
</orders:orderAck>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The change simply indicates whether the incoming order was accepted.
If we set our breakpoint on the “OrderService” service:
And then run/debug the WebServiceTest, we can view the message, before and after its transformation, in the debugger. Here’s the message before transformation:
And here’s the message after its transformation:
The second test in the WebServiceTest intentionally sends a message that includes an invalid XML element.
The invalid SOAP message looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<orders:order xmlns:orders="urn:switchyard-quickstart:validate-xml:0.1.0">
<orderId>PO-19838-XYZ</orderId>
<itemId>BUTTER</itemId>
<quantity>200</quantity>
<invalid-element>This element is not allowed by XML Schema.</invalid-element>
</orders:order>
</soapenv:Body>
</soapenv:Envelope>
Yes, it’s easy to spot the invalid XML. ;-)
Let’s expand on this test application a bit and alter it to not gracefully trap the error resulting from the invalid XML. To do this, we’ll edit the invokeOrderWebServiceValidationFail() method and change this:
Assert.assertTrue("Unexpected response: " + response, response.contains("1 validation error(s)") && response.contains("invalid-element"));
Assert.assertFalse("Unexpected response: " + response, response.contains("1 validation error(s)") && response.contains("invalid-element"));
So that when we run the test, we see this JUnit error:
java.lang.AssertionError: Unexpected response: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>SWITCHYARD014000: Validator 'org.switchyard.validate.xml.internal.XmlValidator' failed: 1 validation error(s):
org.xml.sax.SAXParseException: cvc-complex-type.2.4.d: Invalid content was found starting with element 'invalid-element'. No child element is expected at this point.
</faultstring></soap:Fault></soap:Body></soap:Envelope>
Before we can debug the OrderService, we must set our breakpoint:
Then we edit the breakpoint’s properties. For our example, we want the trigger to be set for the validation of incoming messages:
When we run/debug the WebServiceTest program, the breakpoint is reached and we can examine the message contents:
And, there’s the invalid XML element. What makes the debugger especially useful is that we can now edit the message and remove the invalid XML:
And then allow the program to resume its operation. In this way, we can determine if the program has any other bugs before we correct the cause of the invalid XML, redeploy, etc.