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 we 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:

JAVA:
  1. import java.io.IOException;
  2.  
  3. import javax.xml.parsers.DocumentBuilderFactory;
  4. import javax.xml.parsers.ParserConfigurationException;
  5. import javax.xml.transform.Source;
  6. import javax.xml.transform.stream.StreamSource;
  7. import javax.xml.validation.Schema;
  8. import javax.xml.validation.SchemaFactory;
  9. import javax.xml.validation.Validator;
  10.  
  11. public class SchemaUtils {
  12.  
  13.   private static final Validator VALIDATOR;
  14.   private static final SchemaFactory SF;
  15.   private static final Schema SCHEMAS;
  16.  
  17.   static {
  18.      try {
  19.         // Re-using Schema to parse and validate XML documents
  20.         // create a SchemaFactory that conforms to W3C XML Schema
  21.         SF = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
  22.  
  23.         final StreamSource sSoapEnv = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENVELOPE);
  24.         final StreamSource sSoapenc = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENCODING);
  25.         final StreamSource sMyStuf = new StreamSource(MY_XML_CONSTANTS.XSD_MY_STUF);
  26.  
  27.         SCHEMAS = SF.newSchema(new Source[] {sSoapEnv, sSoapenc, sMyStuf });
  28.         VALIDATOR = SCHEMAS.newValidator();
  29.      } catch (Throwable e) {
  30.         throw new ExceptionInInitializerError(e);
  31.      }
  32.   }
  33.  
  34.   /**
  35.    * Validates XML against a XSD.
  36.    */
  37.   public static void validate(Source docSource) throws CustomXMLException {
  38.  
  39.      try {
  40.         VALIDATOR.validate(docSource, null);
  41.      } catch (SAXException e) {
  42.         throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
  43.      } catch (IOException e) {
  44.         throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
  45.      }
  46.   }
  47. }

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, please 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:

JAVA:
  1. import java.io.IOException;
  2.  
  3. import javax.xml.parsers.DocumentBuilderFactory;
  4. import javax.xml.parsers.ParserConfigurationException;
  5. import javax.xml.transform.Source;
  6. import javax.xml.transform.stream.StreamSource;
  7. import javax.xml.validation.Schema;
  8. import javax.xml.validation.SchemaFactory;
  9. import javax.xml.validation.Validator;
  10.  
  11. public class SchemaUtils {
  12.  
  13.   private static final SchemaFactory SF;
  14.   private static final Schema SCHEMAS;
  15.  
  16.   static {
  17.      try {
  18.         // Re-using Schema to parse and validate XML documents
  19.         // create a SchemaFactory that conforms to W3C XML Schema
  20.         SF = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
  21.  
  22.         final StreamSource sSoapEnv = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENVELOPE);
  23.         final StreamSource sSoapenc = new StreamSource(MY_XML_CONSTANTS.XSD_SOAP_ENCODING);
  24.         final StreamSource sMyStuf = new StreamSource(MY_XML_CONSTANTS.XSD_MY_STUF);
  25.  
  26.         SCHEMAS = SF.newSchema(new Source[] {sSoapEnv, sSoapenc, sMyStuf });
  27.      } catch (Throwable e) {
  28.         throw new ExceptionInInitializerError(e);
  29.      }
  30.   }
  31.  
  32.   /**
  33.    * Validates XML against a XSD.
  34.    */
  35.   public static void validate(Source docSource) throws CustomXMLException {
  36.  
  37.      try {
  38.         SCHEMAS.newValidator().validate(docSource, null);
  39.      } catch (SAXException e) {
  40.         throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
  41.      } catch (IOException e) {
  42.         throw new CustomXMLException(CustomErrorMessage.CUST_XML017, e);
  43.      }
  44.   }
  45. }