You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2016/10/08 17:07:15 UTC
svn commit: r1763922 - in /poi: site/src/documentation/content/xdocs/
trunk/src/ooxml/java/org/apache/poi/
trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/
trunk/src/ooxml/testcases/org/apache/poi/
Author: kiwiwings
Date: Sat Oct 8 17:07:15 2016
New Revision: 1763922
URL: http://svn.apache.org/viewvc?rev=1763922&view=rev
Log:
Bug 60226 - ClassLoader workaround for OSGI when processing OOXML files
Modified:
poi/site/src/documentation/content/xdocs/faq.xml
poi/site/src/documentation/content/xdocs/status.xml
poi/trunk/src/ooxml/java/org/apache/poi/POIXMLTypeLoader.java
poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
poi/trunk/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java
Modified: poi/site/src/documentation/content/xdocs/faq.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/faq.xml?rev=1763922&r1=1763921&r2=1763922&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/faq.xml (original)
+++ poi/site/src/documentation/content/xdocs/faq.xml Sat Oct 8 17:07:15 2016
@@ -577,4 +577,21 @@ and
</p>
</answer>
</faq>
+ <faq>
+ <question>
+ Can POI be used with OSGI?
+ </question>
+ <answer>
+ <p>Starting with POI 3.16 there's a workaround for OSGIs context classloader handling,
+ i.e. it replaces the threads current context classloader with an implementation of
+ limited class view. This will lead to IllegalStateExceptions, as xmlbeans can't find
+ the xml schema definitions in this reduced view. The workaround is to initialize
+ the classloader delegate of <em>POIXMLTypeLoader</em> , which defaults to the current
+ thread context classloader. The initialization should take place before any other
+ OOXML related calls. The class in the example could be any class, which is
+ part of the poi-ooxml-schema or ooxml-schema:<br/>
+ <em> POIXMLTypeLoader.setClassLoader(CTTable.class.getClassLoader());</em>
+ </p>
+ </answer>
+ </faq>
</faqs>
Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1763922&r1=1763921&r2=1763922&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Sat Oct 8 17:07:15 2016
@@ -40,6 +40,7 @@
</devs>
<release version="3.16-beta1" date="2016-11-??">
+ <action dev="PD" type="add" fixes-bug="60226">ClassLoader workaround for OSGI when processing OOXML files</action>
<action dev="PD" type="add" fixes-bug="60187">SS Common: support BorderStyle enums in RegionUtil</action>
<action dev="PD" type="add" fixes-bug="59857">Password protected files with "Microsoft Enhanced Cryptographic Provider v1.0"</action>
<action dev="PD" type="fix" fixes-bug="59687">XSSF: Comments removed from wrong row when removing a row from a sheet with empty rows</action>
Modified: poi/trunk/src/ooxml/java/org/apache/poi/POIXMLTypeLoader.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/POIXMLTypeLoader.java?rev=1763922&r1=1763921&r2=1763922&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/POIXMLTypeLoader.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/POIXMLTypeLoader.java Sat Oct 8 17:07:15 2016
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
+import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
@@ -32,6 +33,7 @@ import javax.xml.stream.XMLStreamReader;
import org.apache.poi.util.DocumentHelper;
import org.apache.xmlbeans.SchemaType;
+import org.apache.xmlbeans.SchemaTypeLoader;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
@@ -46,6 +48,8 @@ import org.xml.sax.SAXException;
@SuppressWarnings("deprecation")
public class POIXMLTypeLoader {
+ private static ThreadLocal<ClassLoader> classLoader = new ThreadLocal<ClassLoader>();
+
public static final XmlOptions DEFAULT_XML_OPTIONS;
static {
DEFAULT_XML_OPTIONS = new XmlOptions();
@@ -80,8 +84,32 @@ public class POIXMLTypeLoader {
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) {
- 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 {
@@ -113,34 +141,34 @@ public class POIXMLTypeLoader {
public static XmlObject parse(InputStream jiois, SchemaType type, XmlOptions options) throws XmlException, IOException {
try {
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) {
throw new IOException("Unable to parse xml bean", e);
}
}
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 {
try {
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) {
throw new XmlException("Unable to parse xml bean", e);
}
}
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 {
- 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 {
- return XmlBeans.getContextTypeLoader().newValidatingXMLInputStream(xis, type, getXmlOptions(options));
+ return getTypeLoader().newValidatingXMLInputStream(xis, type, getXmlOptions(options));
}
}
Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java?rev=1763922&r1=1763921&r2=1763922&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java Sat Oct 8 17:07:15 2016
@@ -19,8 +19,6 @@
package org.apache.poi.xslf.usermodel;
-import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
-
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
@@ -29,7 +27,6 @@ import java.util.List;
import javax.xml.namespace.QName;
-import org.apache.poi.POIXMLException;
import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawTableShape;
import org.apache.poi.sl.draw.DrawTextShape;
@@ -37,7 +34,6 @@ import org.apache.poi.sl.usermodel.Table
import org.apache.poi.util.Internal;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlCursor;
-import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
@@ -53,6 +49,7 @@ import org.openxmlformats.schemas.presen
public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>,
TableShape<XSLFShape,XSLFTextParagraph> {
/* 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 List<XSLFTableRow> _rows;
@@ -60,28 +57,30 @@ public class XSLFTable extends XSLFGraph
/*package*/ XSLFTable(CTGraphicalObjectFrame shape, XSLFSheet sheet){
super(shape, sheet);
- XmlObject[] rs = shape.getGraphic().getGraphicData()
- .selectPath("declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' ./a:tbl");
- if (rs.length == 0) {
- throw new IllegalStateException("a:tbl element was not found in\n " + shape.getGraphic().getGraphicData());
+ CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
+ XmlCursor xc = god.newCursor();
+ if (!xc.toChild(DRAWINGML_URI, "tbl")) {
+ throw new IllegalStateException("a:tbl element was not found in\n " + god);
}
+ XmlObject xo = xc.getObject();
// 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
- if(rs[0] instanceof XmlAnyTypeImpl){
- try {
- rs[0] = CTTable.Factory.parse(rs[0].toString(), DEFAULT_XML_OPTIONS);
- }catch (XmlException e){
- throw new POIXMLException(e);
- }
- }
-
- _table = (CTTable) rs[0];
- CTTableRow[] trArray = _table.getTrArray();
- _rows = new ArrayList<XSLFTableRow>(trArray.length);
- for(CTTableRow row : trArray) {
- XSLFTableRow xr = new XSLFTableRow(row, this);
- _rows.add(xr);
+ if (xo instanceof XmlAnyTypeImpl){
+ String errStr =
+ "Schemas (*.xsb) for CTTable can't be loaded - usually this happens when OSGI " +
+ "loading is used and the thread context classloader has no reference to " +
+ "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();
+
+ _rows = new ArrayList<XSLFTableRow>(_table.sizeOfTrArray());
+ for(CTTableRow row : _table.getTrArray()) {
+ _rows.add(new XSLFTableRow(row, this));
}
updateRowColIndexes();
}
@@ -171,13 +170,18 @@ public class XSLFTable extends XSLFGraph
frame.addNewXfrm();
CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
- XmlCursor cursor = gr.newCursor();
- cursor.toNextToken();
- cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tbl"));
- cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tblPr"));
- cursor.toNextToken();
- cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tblGrid"));
- cursor.dispose();
+ XmlCursor grCur = gr.newCursor();
+ grCur.toNextToken();
+ grCur.beginElement(new QName(DRAWINGML_URI, "tbl"));
+
+ CTTable tbl = CTTable.Factory.newInstance();
+ tbl.addNewTblPr();
+ tbl.addNewTblGrid();
+ XmlCursor tblCur = tbl.newCursor();
+
+ tblCur.moveXmlContents(grCur);
+ tblCur.dispose();
+ grCur.dispose();
gr.setUri(TABLE_URI);
return frame;
}
Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java?rev=1763922&r1=1763921&r2=1763922&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java Sat Oct 8 17:07:15 2016
@@ -27,6 +27,7 @@ import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -41,6 +42,8 @@ import org.apache.poi.openxml4j.opc.Pack
import org.apache.poi.util.NullOutputStream;
import org.apache.poi.util.PackageHelper;
import org.apache.poi.util.TempFile;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFShape;
import org.junit.Test;
/**
@@ -277,4 +280,38 @@ public final class TestPOIXMLDocument {
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();
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org