Bug 60226 - ClassLoader workaround for OSGI when processing OOXML files
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1763922 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9b908a1994
commit
cb03495d36
@ -23,6 +23,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -32,6 +33,7 @@ import javax.xml.stream.XMLStreamReader;
|
|||||||
|
|
||||||
import org.apache.poi.util.DocumentHelper;
|
import org.apache.poi.util.DocumentHelper;
|
||||||
import org.apache.xmlbeans.SchemaType;
|
import org.apache.xmlbeans.SchemaType;
|
||||||
|
import org.apache.xmlbeans.SchemaTypeLoader;
|
||||||
import org.apache.xmlbeans.XmlBeans;
|
import org.apache.xmlbeans.XmlBeans;
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
@ -46,6 +48,8 @@ import org.xml.sax.SAXException;
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class POIXMLTypeLoader {
|
public class POIXMLTypeLoader {
|
||||||
|
|
||||||
|
private static ThreadLocal<ClassLoader> classLoader = new ThreadLocal<ClassLoader>();
|
||||||
|
|
||||||
public static final XmlOptions DEFAULT_XML_OPTIONS;
|
public static final XmlOptions DEFAULT_XML_OPTIONS;
|
||||||
static {
|
static {
|
||||||
DEFAULT_XML_OPTIONS = new XmlOptions();
|
DEFAULT_XML_OPTIONS = new XmlOptions();
|
||||||
@ -80,8 +84,32 @@ public class POIXMLTypeLoader {
|
|||||||
return options == null ? DEFAULT_XML_OPTIONS : options;
|
return options == null ? DEFAULT_XML_OPTIONS : options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link ClassLoader} which is used, when XmlBeans are dynamically instantiated -
|
||||||
|
* opposed to being loaded by the factory class which is accompanied by each generated XmlBeans interface.
|
||||||
|
* <p>
|
||||||
|
* This is especially necessary in a context which doesn't guarantee that the current (thread) context
|
||||||
|
* cassloader has access to all XmlBeans schema definitions (*.xsb) - which is typically in OSGI the case.
|
||||||
|
* <p>
|
||||||
|
* The classloader will be only set for the current thread in a {@link ThreadLocal}. Although the
|
||||||
|
* ThreadLocal is implemented via a {@link WeakReference}, it's good style to {@code null} the classloader
|
||||||
|
* when the user code is finalized.
|
||||||
|
*
|
||||||
|
* @param cl the classloader to be used when XmlBeans classes and definitions are looked up
|
||||||
|
*/
|
||||||
|
public static void setClassLoader(ClassLoader cl) {
|
||||||
|
classLoader.set(cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SchemaTypeLoader getTypeLoader() {
|
||||||
|
ClassLoader cl = classLoader.get();
|
||||||
|
return (cl == null)
|
||||||
|
? XmlBeans.getContextTypeLoader()
|
||||||
|
: XmlBeans.typeLoaderForClassLoader(cl);
|
||||||
|
}
|
||||||
|
|
||||||
public static XmlObject newInstance(SchemaType type, XmlOptions options) {
|
public static XmlObject newInstance(SchemaType type, XmlOptions options) {
|
||||||
return XmlBeans.getContextTypeLoader().newInstance(type, getXmlOptions(options));
|
return getTypeLoader().newInstance(type, getXmlOptions(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XmlObject parse(String xmlText, SchemaType type, XmlOptions options) throws XmlException {
|
public static XmlObject parse(String xmlText, SchemaType type, XmlOptions options) throws XmlException {
|
||||||
@ -113,34 +141,34 @@ public class POIXMLTypeLoader {
|
|||||||
public static XmlObject parse(InputStream jiois, SchemaType type, XmlOptions options) throws XmlException, IOException {
|
public static XmlObject parse(InputStream jiois, SchemaType type, XmlOptions options) throws XmlException, IOException {
|
||||||
try {
|
try {
|
||||||
Document doc = DocumentHelper.readDocument(jiois);
|
Document doc = DocumentHelper.readDocument(jiois);
|
||||||
return XmlBeans.getContextTypeLoader().parse(doc.getDocumentElement(), type, getXmlOptions(options));
|
return getTypeLoader().parse(doc.getDocumentElement(), type, getXmlOptions(options));
|
||||||
} catch (SAXException e) {
|
} catch (SAXException e) {
|
||||||
throw new IOException("Unable to parse xml bean", e);
|
throw new IOException("Unable to parse xml bean", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XmlObject parse(XMLStreamReader xsr, SchemaType type, XmlOptions options) throws XmlException {
|
public static XmlObject parse(XMLStreamReader xsr, SchemaType type, XmlOptions options) throws XmlException {
|
||||||
return XmlBeans.getContextTypeLoader().parse(xsr, type, getXmlOptions(options));
|
return getTypeLoader().parse(xsr, type, getXmlOptions(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XmlObject parse(Reader jior, SchemaType type, XmlOptions options) throws XmlException, IOException {
|
public static XmlObject parse(Reader jior, SchemaType type, XmlOptions options) throws XmlException, IOException {
|
||||||
try {
|
try {
|
||||||
Document doc = DocumentHelper.readDocument(new InputSource(jior));
|
Document doc = DocumentHelper.readDocument(new InputSource(jior));
|
||||||
return XmlBeans.getContextTypeLoader().parse(doc.getDocumentElement(), type, getXmlOptions(options));
|
return getTypeLoader().parse(doc.getDocumentElement(), type, getXmlOptions(options));
|
||||||
} catch (SAXException e) {
|
} catch (SAXException e) {
|
||||||
throw new XmlException("Unable to parse xml bean", e);
|
throw new XmlException("Unable to parse xml bean", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XmlObject parse(Node node, SchemaType type, XmlOptions options) throws XmlException {
|
public static XmlObject parse(Node node, SchemaType type, XmlOptions options) throws XmlException {
|
||||||
return XmlBeans.getContextTypeLoader().parse(node, type, getXmlOptions(options));
|
return getTypeLoader().parse(node, type, getXmlOptions(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XmlObject parse(XMLInputStream xis, SchemaType type, XmlOptions options) throws XmlException, XMLStreamException {
|
public static XmlObject parse(XMLInputStream xis, SchemaType type, XmlOptions options) throws XmlException, XMLStreamException {
|
||||||
return XmlBeans.getContextTypeLoader().parse(xis, type, getXmlOptions(options));
|
return getTypeLoader().parse(xis, type, getXmlOptions(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XMLInputStream newValidatingXMLInputStream ( XMLInputStream xis, SchemaType type, XmlOptions options ) throws XmlException, XMLStreamException {
|
public static XMLInputStream newValidatingXMLInputStream ( XMLInputStream xis, SchemaType type, XmlOptions options ) throws XmlException, XMLStreamException {
|
||||||
return XmlBeans.getContextTypeLoader().newValidatingXMLInputStream(xis, type, getXmlOptions(options));
|
return getTypeLoader().newValidatingXMLInputStream(xis, type, getXmlOptions(options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@
|
|||||||
|
|
||||||
package org.apache.poi.xslf.usermodel;
|
package org.apache.poi.xslf.usermodel;
|
||||||
|
|
||||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
|
||||||
|
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -29,7 +27,6 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
import org.apache.poi.POIXMLException;
|
|
||||||
import org.apache.poi.sl.draw.DrawFactory;
|
import org.apache.poi.sl.draw.DrawFactory;
|
||||||
import org.apache.poi.sl.draw.DrawTableShape;
|
import org.apache.poi.sl.draw.DrawTableShape;
|
||||||
import org.apache.poi.sl.draw.DrawTextShape;
|
import org.apache.poi.sl.draw.DrawTextShape;
|
||||||
@ -37,7 +34,6 @@ import org.apache.poi.sl.usermodel.TableShape;
|
|||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.util.Units;
|
import org.apache.poi.util.Units;
|
||||||
import org.apache.xmlbeans.XmlCursor;
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
|
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
|
||||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
|
||||||
@ -53,6 +49,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFra
|
|||||||
public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>,
|
public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>,
|
||||||
TableShape<XSLFShape,XSLFTextParagraph> {
|
TableShape<XSLFShape,XSLFTextParagraph> {
|
||||||
/* package */ static final String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
|
/* package */ static final String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
|
||||||
|
/* package */ static final String DRAWINGML_URI = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
||||||
|
|
||||||
private CTTable _table;
|
private CTTable _table;
|
||||||
private List<XSLFTableRow> _rows;
|
private List<XSLFTableRow> _rows;
|
||||||
@ -60,28 +57,30 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
|
|||||||
/*package*/ XSLFTable(CTGraphicalObjectFrame shape, XSLFSheet sheet){
|
/*package*/ XSLFTable(CTGraphicalObjectFrame shape, XSLFSheet sheet){
|
||||||
super(shape, sheet);
|
super(shape, sheet);
|
||||||
|
|
||||||
XmlObject[] rs = shape.getGraphic().getGraphicData()
|
CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
|
||||||
.selectPath("declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' ./a:tbl");
|
XmlCursor xc = god.newCursor();
|
||||||
if (rs.length == 0) {
|
if (!xc.toChild(DRAWINGML_URI, "tbl")) {
|
||||||
throw new IllegalStateException("a:tbl element was not found in\n " + shape.getGraphic().getGraphicData());
|
throw new IllegalStateException("a:tbl element was not found in\n " + god);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XmlObject xo = xc.getObject();
|
||||||
// Pesky XmlBeans bug - see Bugzilla #49934
|
// Pesky XmlBeans bug - see Bugzilla #49934
|
||||||
// it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
|
// it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
|
||||||
if(rs[0] instanceof XmlAnyTypeImpl){
|
if (xo instanceof XmlAnyTypeImpl){
|
||||||
try {
|
String errStr =
|
||||||
rs[0] = CTTable.Factory.parse(rs[0].toString(), DEFAULT_XML_OPTIONS);
|
"Schemas (*.xsb) for CTTable can't be loaded - usually this happens when OSGI " +
|
||||||
}catch (XmlException e){
|
"loading is used and the thread context classloader has no reference to " +
|
||||||
throw new POIXMLException(e);
|
"the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
|
||||||
}
|
"e.g. with CTTable.class.getClassLoader()"
|
||||||
|
;
|
||||||
|
throw new IllegalStateException(errStr);
|
||||||
}
|
}
|
||||||
|
_table = (CTTable)xo;
|
||||||
|
xc.dispose();
|
||||||
|
|
||||||
_table = (CTTable) rs[0];
|
_rows = new ArrayList<XSLFTableRow>(_table.sizeOfTrArray());
|
||||||
CTTableRow[] trArray = _table.getTrArray();
|
for(CTTableRow row : _table.getTrArray()) {
|
||||||
_rows = new ArrayList<XSLFTableRow>(trArray.length);
|
_rows.add(new XSLFTableRow(row, this));
|
||||||
for(CTTableRow row : trArray) {
|
|
||||||
XSLFTableRow xr = new XSLFTableRow(row, this);
|
|
||||||
_rows.add(xr);
|
|
||||||
}
|
}
|
||||||
updateRowColIndexes();
|
updateRowColIndexes();
|
||||||
}
|
}
|
||||||
@ -171,13 +170,18 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
|
|||||||
|
|
||||||
frame.addNewXfrm();
|
frame.addNewXfrm();
|
||||||
CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
|
CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
|
||||||
XmlCursor cursor = gr.newCursor();
|
XmlCursor grCur = gr.newCursor();
|
||||||
cursor.toNextToken();
|
grCur.toNextToken();
|
||||||
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tbl"));
|
grCur.beginElement(new QName(DRAWINGML_URI, "tbl"));
|
||||||
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tblPr"));
|
|
||||||
cursor.toNextToken();
|
CTTable tbl = CTTable.Factory.newInstance();
|
||||||
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tblGrid"));
|
tbl.addNewTblPr();
|
||||||
cursor.dispose();
|
tbl.addNewTblGrid();
|
||||||
|
XmlCursor tblCur = tbl.newCursor();
|
||||||
|
|
||||||
|
tblCur.moveXmlContents(grCur);
|
||||||
|
tblCur.dispose();
|
||||||
|
grCur.dispose();
|
||||||
gr.setUri(TABLE_URI);
|
gr.setUri(TABLE_URI);
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import static org.junit.Assert.fail;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -41,6 +42,8 @@ import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
|||||||
import org.apache.poi.util.NullOutputStream;
|
import org.apache.poi.util.NullOutputStream;
|
||||||
import org.apache.poi.util.PackageHelper;
|
import org.apache.poi.util.PackageHelper;
|
||||||
import org.apache.poi.util.TempFile;
|
import org.apache.poi.util.TempFile;
|
||||||
|
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
||||||
|
import org.apache.poi.xslf.usermodel.XSLFShape;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -277,4 +280,38 @@ public final class TestPOIXMLDocument {
|
|||||||
open.close();
|
open.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=IllegalStateException.class)
|
||||||
|
public void testOSGIClassLoadingAsIs() throws IOException {
|
||||||
|
Thread thread = Thread.currentThread();
|
||||||
|
ClassLoader cl = thread.getContextClassLoader();
|
||||||
|
InputStream is = POIDataSamples.getSlideShowInstance().openResourceAsStream("table_test.pptx");
|
||||||
|
try {
|
||||||
|
thread.setContextClassLoader(cl.getParent());
|
||||||
|
XMLSlideShow ppt = new XMLSlideShow(is);
|
||||||
|
ppt.getSlides().get(0).getShapes();
|
||||||
|
} finally {
|
||||||
|
thread.setContextClassLoader(cl);
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOSGIClassLoadingFixed() throws IOException {
|
||||||
|
Thread thread = Thread.currentThread();
|
||||||
|
ClassLoader cl = thread.getContextClassLoader();
|
||||||
|
InputStream is = POIDataSamples.getSlideShowInstance().openResourceAsStream("table_test.pptx");
|
||||||
|
try {
|
||||||
|
thread.setContextClassLoader(cl.getParent());
|
||||||
|
POIXMLTypeLoader.setClassLoader(cl);
|
||||||
|
XMLSlideShow ppt = new XMLSlideShow(is);
|
||||||
|
ppt.getSlides().get(0).getShapes();
|
||||||
|
} finally {
|
||||||
|
thread.setContextClassLoader(cl);
|
||||||
|
POIXMLTypeLoader.setClassLoader(null);
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user