Threading issues with SoapUI?

14 Aug

While performing the load test of our web service (of course with my favourite tool SoapUI) I was getting some errors when I used a number of threads at a time to call my service. Most error messages were related to an invalid XML format of the incoming message. I was told this probably had something to do with SoapUI (that would be the first drawback with it…). When multiple threads are used in SoapUI to sent the messages, they somehow would get mixed up and invalid SOAP messages were sent. So I was told.
After a few weeks I finally got some time to look in to it. To check if Soap UI was indeed messing up the SOAP messages, we made a Filter that outputted the incoming HTTP request to a log file. This filter was configured to receive the request before it would be received by the XFire servlet, but after it was decoded (we are using HTTPS for our web service communication). I will handle the code for this filter in another post, since it might be handy in other situations too.
After our tests with the filter in place we could only conclude that Soap UI was working correctly (what a surprise ;) ) and that all messages were sent in the correct SOAP format. So that forced us to look for the problem in another direction, may be even our own code ;). Looking for the cause of the problem I soon found out that all errors were traced back to one class (one of our own), the SchemaUtils.java. Here is the main part of the code:

import java.io.IOException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

public class SchemaUtils {

  private static final Validator VALIDATOR;
  private static final SchemaFactory SF;
  private static final Schema SCHEMAS;

  static {
     try {
        // Re-using Schema to parse and validate XML documents
        // create a SchemaFactory that conforms to W3C XML Schema
        SF = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);

        final StreamSource sSoapEnv = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENVELOPE);
        final StreamSource sSoapenc = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENCODING);
        final StreamSource sMyStuf = new StreamSource(MY_XML_CONSTANTS.XSD_MY_STUF);

        SCHEMAS = SF.newSchema(new Source[] {sSoapEnv, sSoapenc, sMyStuf });
        VALIDATOR = SCHEMAS.newValidator();
     } catch (Throwable e) {
        throw new ExceptionInInitializerError(e);
     }
  }

  /**
   * Validates XML against a XSD.
   */
  public static void validate(Source docSource) throws CustomXMLException {

     try {
        VALIDATOR.validate(docSource, null);
     } catch (SAXException e) {
        throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
     } catch (IOException e) {
        throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
     }
  }
}

As you might known, the class ‘Validator.java’ that is used here is NOT thread safe. This is told in the Javadoc of the class. So instead of pointing our fingers at the tools we were using we should be looking for the problem in our own code.
So actually there are two lessons here to be learned:
1. If there is found an error, make sure it isn’t in your own code before pointing to others
2. If someone tells you it isn’t a fault in their code, don’t just take that for granted, but try to proove it with a little testcase.

And for the record here is the modified class that is thread safe:

import java.io.IOException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

public class SchemaUtils {

  private static final SchemaFactory SF;
  private static final Schema SCHEMAS;

  static {
     try {
        // Re-using Schema to parse and validate XML documents
        // create a SchemaFactory that conforms to W3C XML Schema
        SF = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);

        final StreamSource sSoapEnv = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENVELOPE);
        final StreamSource sSoapenc = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENCODING);
        final StreamSource sMyStuf = new StreamSource(MY_XML_CONSTANTS.XSD_MY_STUF);

        SCHEMAS = SF.newSchema(new Source[] {sSoapEnv, sSoapenc, sMyStuf });
     } catch (Throwable e) {
        throw new ExceptionInInitializerError(e);
     }
  }

  /**
   * Validates XML against a XSD.
   */
  public static void validate(Source docSource) throws CustomXMLException {

     try {
        SCHEMAS.newValidator().validate(docSource, null);
     } catch (SAXException e) {
        throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
     } catch (IOException e) {
        throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
     }
  }
}

4 Responses to “Threading issues with SoapUI?”

  1. AB 30/12/2007 at 14:17 #

    I have been looking for code to do schema validation that also takes into account the soap envelope. This looks like what I need. Do you mind posing the details of how you have defined the envelope and the encoding schema as well as schema? Also, did you have to include anything related to SOAP-Envelope and encoding as part of your schema?

    final StreamSource sSoapEnv = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENVELOPE);

    final StreamSource sSoapenc = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENCODING);

    final StreamSource sMyStuf = new StreamSource(MY_XML_CONSTANTS.XSD_MY_STUF);

    Thank you very much

  2. Pascal Alma 01/01/2008 at 17:33 #

    I’m not sure I understand your question correctly but are you looking for these schema’s:
    http://www.w3.org/2001/06/soap-envelope
    and
    http://www.w3.org/2001/06/soap-encoding

    If not, can you please explain in more detail what you need so I can see if, and how, I may help you.

  3. AB 01/01/2008 at 23:39 #

    What I was trying to ask is how have you defined the two constants MY_XML_CONSTANTS.XSD_SOAP_ENVELOPE and MY_XML_CONSTANTS.XSD_SOAP_ENCODING ?

    Did you save the schemata from http://www.w3.org/2001/06/soap-envelope and http://www.w3.org/2001/06/soap-encoding locally as xsd files and used StreamSource with InputSource ?

    Also, I was told that I need to define the SOAP Envelope and SOAP Encoding schemata in my XSD file, which was giving me errors when defining. So I was wondering if you had to do that in your XSD_MY_STUF?

    Thanks again for your help

  4. Pascal Alma 07/01/2008 at 19:26 #

    Hi,

    The constants you mention are used as URL referring to the schema’s which I supplied in my .war file, so I can be sure the schema’s can be found.
    The constants are defined as Strings with the following values:
    http://myserver:8080/my-web-app/schemas/soapenc.xml
    http://myserver:8080/my-web-app/schemas/soapenv.xml
    http://myserver:8080/my-web-app/schemas/my-stuf.xsd

    (The part ‘http://myserver:8080/my-web-app/’ are configured by a property file so you can set them per server/deployment)

    Aout your other question: I did not have to define the SOAP schema’s in my own schema. I can not think of a reason why I should, to be honest. So I would say, try it without it and if this works, it’s okay, right?

    I hope this helps.

Comments are closed.

Follow

Get every new post delivered to your Inbox.

Join 97 other followers

%d bloggers like this: