I'm using the Amazon S3 SDK in two separate wars running on the same Tomcat. I initialize an AmazonS3Client in the @PostConstruct of one of my Spring services.
If I run these wars separately, everything usually works fine. If I run them together, one of them - the second one to start up - throws the following exception:
com.amazonaws.AmazonClientException: Couldn't initialize a sax driver for the XMLReader
I have a workaround where I set the following System property if this happens, after catching the AmazonClientException:
try {
init();
} catch (AmazonClientException ase) {
System.setProperty("org.xml.sax.driver", "com.sun.org.apache.xerces.internal.parsers.SAXParser");
init();
}
But this is of course horrible. Is there a better way to do this? Why does this occur in these circumstances?
UPDATE: At first, it seemed that moving the intitalization of the AmazonS3Client out of the @PostConstruct and initializing it lazily prevented this error completely. But apparently it still occurs sometimes - even when I only run one war instead of both.
The XMLReader goes through a series of steps to identify which drive to use. Quoting the docs
Looking at the code for the AWS SDK ...
public XmlResponsesSaxParser() throws AmazonClientException {
// Ensure we can load the XML Reader.
try {
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e) {
// oops, lets try doing this (needed in 1.4)
System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");
try {
// Try once more...
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e2) {
throw new AmazonClientException("Couldn't initialize a sax driver for the XMLReader");
}
}
}
There are a couple of things I don't like about that code.
These points make it harder to debug the issue. The best educated guess I can make is that the crimson parser is accessible in one class loading path but absent in the other. A conclusive way to find the problem would be to set a breakpoint on the code that tries to instantiate the reader and find what the underlying root cause is.
as it uses the singleton model, the only way to isolate this calls would be to have entire set of SAX-related JARs within the WARs themselves (they would load to different classloaders). It worked for me the time I had the same problem. This will have a PermGen impact, but what to do.. Or if you don't mind to change the S3 lib, make this method static synchronized and share the lib. If the Amazon guys make this calls synchronized this wouldn't be issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With