Background:
We have an Oracle 11g database running a Java Virtual Machine with JRE version 1.6.0_43. Our user interface is hosted on an Apache webserver which interfaces with the database through mod-plsql.
We have some PLSQL procedures calling Java procedures stored in Java Sources in the database - one example is a Java procedure we use to generate XLS files.
We've previously been using the Apache POI suite version 3.8 to generate XLS files from XML using the DOM Parser, but we've upgraded to POI 3.9 so that we can use the Streaming XSSF Workbook classes to efficiently generate XLSX files (SXSSF was available in POI 3.8 but a core procedure, dispose(), was not made available until POI 3.9).
Also for efficiency reasons we're using StAX parsing (XMLStreamReader) when generating XLSX files as opposed to the broadly more memory-hungry DOM Parser method we use for XLS generation.
To upgrade Java POI 3.8 to 3.9 in our database we had a two-step process:
1) Run dropjava on the jars comprising the POI 3.8 suite:
dropjava -user=xxxxxx@xxxxxx poi-3.8-20120326.jar poi-examples-3.8-20120326.jar poi-excelant-3.8-20120326.jar poi-ooxml-3.8-20120326.jar poi-ooxml-schemas-3.8-20120326.jar poi-scratchpad-3.8-20120326.jar lib\commons-logging-1.1.jar lib\junit-3.8.1.jar lib\log4j-1.2.13.jar ooxml-lib\dom4j-1.6.1.jar ooxml-lib\stax-api-1.0.1.jar ooxml-lib\xmlbeans-2.3.0.jar
2) We then ran a loadjava command to install the 3.9 suite:
loadjava -user=xxxxxx@xxxxxx -genmissing -resolve -force poi-3.9-20121203.jar poi-examples-3.9-20121203.jar poi-excelant-3.9-20121203.jar poi-ooxml-3.9-20121203.jar poi-ooxml-schemas-3.9-20121203.jar poi-scratchpad-3.9-20121203.jar lib\commons-logging-1.1.jar lib\junit-3.8.1.jar lib\log4j-1.2.13.jar ooxml-lib\dom4j-1.6.1.jar ooxml-lib\stax-api-1.0.1.jar ooxml-lib\xmlbeans-2.3.0.jar
The XLSX generation did not work at all at first; we received this exception in Java at runtime:
java.lang.ClassCastException
We didn't confirm which specific class caused the problem, but we noticed that, after installing POI 3.9 (which includes the StAX stax-api-1.0.1 jar), there were some duplicates in our Java class library in the database. Specifically, these classes and their paths were duplicated (and being imported into our xlsx-generating Java Source):
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
Reasoning that the duplicates could be causing the exception, we removed the StAX parser jar (the StAX suite was "folded-in" to the core JDK at some point before our Java version, so there could be no need to import the StAX jar included with POI 3.9):
dropjava -user=xxxxxx@xxxxxx ooxml-lib\stax-api-1.0.1.jar
This removed the duplicate classes and resolved the ClassCastException, i.e. it no longer occurs. But there is a new issue.
Problem:
The new XLSX method now fails intermittently at runtime with this error:
javax.xml.stream.FactoryFinder$ConfigurationError: Provider com.sun.xml.stream.ZephyrParserFactory not found
The class in question, com.sun.xml.stream.ZephyrParserFactory, is seemingly installed correctly in our database. We've done some testing on a separate platform and we've found that removing that class entirely breaks our parsing completely, i.e. we are confident the class is installed on our live platform because our code works most of the time but would work none of the time if the class was not installed.
The error only occurs roughly once every 10 or so XLSX generation attempts (we've tested using both different files and the same file each time - it doesn't seem to matter what the content of the XML is). This line of code generates the error:
XMLInputFactory factory = XMLInputFactory.newInstance();
With some investigation, we've found that whether or not the error occurs depends on which Oracle session is processing the initial HTTP request received by the webserver. I feel like the real question here is what could be causing only certain Oracle sessions to fail to access the Zephyr class as a Provider and produce the error? Any ideas would be greatly appreciated.
Based on:
how to override a service provider in java
and
https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/SJSXP4.html
you can set a System Property for javax.xml.stream.XMLInputFactory to specify the implementation class to use to create implementation instances of XMLInputFactory at runtime.
We had such an implementation class available in the core Java API stored in our db class library:
XMLInputFactoryImpl
We now use a line like this at the start of our Java procedure to set a System Property for the duration of that Oracle session:
System.setProperty("javax.xml.stream.XMLInputFactory", "<class path>XMLInputFactoryImpl");
This has seemingly resolved the XMLInputFactory service provider confusion that some of our Oracle sessions were encountering at runtime.