--- src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java (working copy) @@ -687,8 +687,9 @@ * Output stream to save this part. * @throws OpenXML4JException * If any exception occur. + * @throws IOException */ - public abstract boolean save(OutputStream zos) throws OpenXML4JException; + public abstract void save(OutputStream zos) throws OpenXML4JException, IOException; /** * Load the content of this part. --- src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java (working copy) @@ -31,20 +31,25 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; import org.w3c.dom.Document; public final class StreamHelper { + private static final POILogger logger = POILogFactory.getLogger(StreamHelper.class); + private StreamHelper() { // Do nothing } - - private static final TransformerFactory transformerFactory = TransformerFactory.newInstance(); - - private static synchronized Transformer getIdentityTransformer() throws TransformerException { - return transformerFactory.newTransformer(); - } + private static final TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + private static synchronized Transformer getIdentityTransformer() throws TransformerException { + return transformerFactory.newTransformer(); + } + /** * Save the document object in the specified output stream. * @@ -52,36 +57,31 @@ * The XML document. * @param outStream * The OutputStream in which the XML document will be written. - * @return true if the xml is successfully written in the stream, - * else false. + * @throws TransformerException if an error occurred while transforming XML Source. + * @throws IOException if the output stream is closed. */ - public static boolean saveXmlInStream(Document xmlContent, - OutputStream outStream) { - try { - Transformer trans = getIdentityTransformer(); - Source xmlSource = new DOMSource(xmlContent); - // prevent close of stream by transformer: - Result outputTarget = new StreamResult(new FilterOutputStream( - outStream) { - @Override - public void write(byte b[], int off, int len) - throws IOException { - out.write(b, off, len); - } + public static void saveXmlInStream(Document xmlContent, + OutputStream outStream) throws TransformerException, IOException { + Transformer trans = getIdentityTransformer(); + Source xmlSource = new DOMSource(xmlContent); + // prevent close of stream by transformer: + Result outputTarget = new StreamResult(new FilterOutputStream( + outStream) { + @Override + public void write(byte b[], int off, int len) + throws IOException { + out.write(b, off, len); + } - @Override - public void close() throws IOException { - out.flush(); // only flush, don't close! - } - }); - trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - trans.setOutputProperty(OutputKeys.INDENT, "yes"); - trans.setOutputProperty(OutputKeys.STANDALONE, "yes"); - trans.transform(xmlSource, outputTarget); - } catch (TransformerException e) { - return false; - } - return true; + @Override + public void close() throws IOException { + out.flush(); // only flush, don't close! + } + }); + trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + trans.setOutputProperty(OutputKeys.INDENT, "yes"); + trans.setOutputProperty(OutputKeys.STANDALONE, "yes"); + trans.transform(xmlSource, outputTarget); } /** @@ -91,18 +91,14 @@ * The source stream. * @param outStream * The destination stream. - * @return true if the operation succeed, else return false. + * throws IOException if the input stream cannot be read or the output stream cannot be written to. + * Verify that both streams are open. */ - public static boolean copyStream(InputStream inStream, OutputStream outStream) { - try { - byte[] buffer = new byte[1024]; - int bytesRead; - while ((bytesRead = inStream.read(buffer)) >= 0) { - outStream.write(buffer, 0, bytesRead); - } - } catch (Exception e) { - return false; + public static void copyStream(InputStream inStream, OutputStream outStream) throws IOException { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inStream.read(buffer)) >= 0) { + outStream.write(buffer, 0, bytesRead); } - return true; } } --- src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java (working copy) @@ -473,12 +473,16 @@ throwExceptionIfReadOnly(); final ZipOutputStream zos; + final boolean newZOSWasCreated; try { - if (!(outputStream instanceof ZipOutputStream)) + if (!(outputStream instanceof ZipOutputStream)) { zos = new ZipOutputStream(outputStream); - else + newZOSWasCreated = true; + } else { zos = (ZipOutputStream) outputStream; - + newZOSWasCreated = false; + } + // If the core properties part does not exist in the part list, // we save it as well if (this.getPartsByRelationshipType(PackageRelationshipTypes.CORE_PROPERTIES).size() == 0 && @@ -525,23 +529,31 @@ PartMarshaller marshaller = partMarshallers .get(part._contentType); if (marshaller != null) { - if (!marshaller.marshall(part, zos)) { - throw new OpenXML4JException( - "The part " - + part.getPartName().getURI() - + " fail to be saved in the stream with marshaller " - + marshaller); + try { + marshaller.marshall(part, zos); + } catch (final OpenXML4JException e) { + final String msg = "The part " + + part.getPartName().getURI() + + " fail to be saved in the stream with marshaller " + + marshaller; + throw new OpenXML4JException(msg, e); } } else { - if (!defaultPartMarshaller.marshall(part, zos)) - throw new OpenXML4JException( - "The part " - + part.getPartName().getURI() - + " fail to be saved in the stream with marshaller " - + defaultPartMarshaller); + try { + defaultPartMarshaller.marshall(part, zos); + } catch (final OpenXML4JException e) { + final String msg = "The part " + + part.getPartName().getURI() + + " fail to be saved in the stream with marshaller " + + defaultPartMarshaller; + throw new OpenXML4JException(msg, e); + } } } - zos.close(); + + if (newZOSWasCreated) { + zos.close(); + } } catch (OpenXML4JRuntimeException e) { // no need to wrap this type of Exception throw e; --- src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java (working copy) @@ -120,8 +120,8 @@ } @Override - public boolean save(OutputStream os) throws OpenXML4JException { - return new ZipPartMarshaller().marshall(this, os); + public void save(OutputStream os) throws OpenXML4JException, IOException { + new ZipPartMarshaller().marshall(this, os); } @Override --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java (working copy) @@ -409,8 +409,9 @@ * The output stream use to save the XML content of the content * types part. * @return true if the operation success, else false. + * @throws IOException */ - public boolean save(OutputStream outStream) { + public void save(OutputStream outStream) throws IOException { Document xmlOutDoc = DocumentHelper.createDocument(); // Building namespace @@ -432,7 +433,7 @@ xmlOutDoc.normalize(); // Save content in the specified output stream - return this.saveImpl(xmlOutDoc, outStream); + this.saveImpl(xmlOutDoc, outStream); } /** @@ -475,5 +476,5 @@ * @param out * The output stream use to write the content type XML. */ - public abstract boolean saveImpl(Document content, OutputStream out); + public abstract void saveImpl(Document content, OutputStream out) throws IOException; } --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java (working copy) @@ -108,8 +108,9 @@ } @Override - public boolean save(OutputStream os) throws OpenXML4JException { - return new ZipPartMarshaller().marshall(this, os); + public void save(OutputStream os) throws OpenXML4JException, IOException { + ZipPartMarshaller marshaller = new ZipPartMarshaller(); + marshaller.marshall(this, os); } @Override --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java (working copy) @@ -653,7 +653,7 @@ } @Override - public boolean save(OutputStream zos) { + public void save(OutputStream zos) { throw new InvalidOperationException("Operation not authorized. This part may only be manipulated using the getters and setters on PackagePropertiesPart"); } --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartMarshaller.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartMarshaller.java (working copy) @@ -17,6 +17,7 @@ package org.apache.poi.openxml4j.opc.internal; +import java.io.IOException; import java.io.OutputStream; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; @@ -43,7 +44,8 @@ * @throws OpenXML4JException * Throws only if any other exceptions are thrown by inner * methods. + * @throws IOException if an error occurred while writing to output stream. Verify that {@code out} is open for writing. */ - public boolean marshall(PackagePart part, OutputStream out) - throws OpenXML4JException; + public void marshall(PackagePart part, OutputStream out) + throws OpenXML4JException, IOException; } --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java (working copy) @@ -23,6 +23,8 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import javax.xml.transform.TransformerException; + import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.StreamHelper; @@ -38,7 +40,7 @@ * @see ContentTypeManager */ public class ZipContentTypeManager extends ContentTypeManager { - private static POILogger logger = POILogFactory.getLogger(ZipContentTypeManager.class); + private static final POILogger logger = POILogFactory.getLogger(ZipContentTypeManager.class); /** * Delegate constructor to the super constructor. @@ -56,7 +58,7 @@ @SuppressWarnings("resource") @Override - public boolean saveImpl(Document content, OutputStream out) { + public void saveImpl(Document content, OutputStream out) throws IOException { ZipOutputStream zos = null; if (out instanceof ZipOutputStream) zos = (ZipOutputStream) out; @@ -68,15 +70,16 @@ // Referenced in ZIP zos.putNextEntry(partEntry); // Saving data in the ZIP file - if (!StreamHelper.saveXmlInStream(content, zos)) { - return false; - } + StreamHelper.saveXmlInStream(content, zos); zos.closeEntry(); - } catch (IOException ioe) { - logger.log(POILogger.ERROR, "Cannot write: " + CONTENT_TYPES_PART_NAME - + " in Zip !", ioe); - return false; + } catch (IOException e) { + final String msg = "Cannot write: " + CONTENT_TYPES_PART_NAME + " in Zip !"; + logger.log(POILogger.ERROR, msg, e); + throw new IOException(msg, e); + } catch (TransformerException e) { + final String msg = "Cannot write: " + CONTENT_TYPES_PART_NAME + " in Zip !"; + logger.log(POILogger.ERROR, msg, e); + throw new IOException(msg, e); } - return true; } } --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/DefaultMarshaller.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/DefaultMarshaller.java (working copy) @@ -17,6 +17,7 @@ package org.apache.poi.openxml4j.opc.internal.marshallers; +import java.io.IOException; import java.io.OutputStream; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; @@ -37,9 +38,10 @@ * * @throws OpenXML4JException * If any error occur. + * @throws IOException */ - public boolean marshall(PackagePart part, OutputStream out) - throws OpenXML4JException { - return part.save(out); + public void marshall(PackagePart part, OutputStream out) + throws OpenXML4JException, IOException { + part.save(out); } } --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/PackagePropertiesMarshaller.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/PackagePropertiesMarshaller.java (working copy) @@ -87,7 +87,7 @@ * true. */ @Override - public boolean marshall(PackagePart part, OutputStream out) + public void marshall(PackagePart part, OutputStream out) throws OpenXML4JException { if (!(part instanceof PackagePropertiesPart)) throw new IllegalArgumentException( @@ -120,7 +120,6 @@ addSubject(); addTitle(); addVersion(); - return true; } /** --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java (working copy) @@ -22,6 +22,8 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import javax.xml.transform.TransformerException; + import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.StreamHelper; @@ -35,7 +37,7 @@ public final class ZipPackagePropertiesMarshaller extends PackagePropertiesMarshaller { @Override - public boolean marshall(PackagePart part, OutputStream out) + public void marshall(PackagePart part, OutputStream out) throws OpenXML4JException { if (!(out instanceof ZipOutputStream)) { throw new IllegalArgumentException("ZipOutputStream expected!"); @@ -51,13 +53,12 @@ zos.putNextEntry(ctEntry); // Add entry in ZIP super.marshall(part, out); // Marshall the properties inside a XML // Document - if (!StreamHelper.saveXmlInStream(xmlDoc, out)) { - return false; - } + StreamHelper.saveXmlInStream(xmlDoc, out); zos.closeEntry(); } catch (IOException e) { throw new OpenXML4JException(e.getLocalizedMessage(), e); + } catch (TransformerException e) { + throw new OpenXML4JException(e.getLocalizedMessage(), e); } - return true; } } --- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java (revision 1760210) +++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java (working copy) @@ -24,6 +24,8 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import javax.xml.transform.TransformerException; + import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import org.apache.poi.openxml4j.opc.PackageNamespaces; import org.apache.poi.openxml4j.opc.PackagePart; @@ -48,7 +50,7 @@ * @author Julien Chable */ public final class ZipPartMarshaller implements PartMarshaller { - private static POILogger logger = POILogFactory.getLogger(ZipPartMarshaller.class); + private static final POILogger logger = POILogFactory.getLogger(ZipPartMarshaller.class); /** * Save the specified part. @@ -56,8 +58,8 @@ * @throws OpenXML4JException * Throws if an internal exception is thrown. */ - public boolean marshall(PackagePart part, OutputStream os) - throws OpenXML4JException { + public void marshall(PackagePart part, OutputStream os) + throws IOException, OpenXML4JException { if (!(os instanceof ZipOutputStream)) { logger.log(POILogger.ERROR,"Unexpected class " + os.getClass().getName()); throw new OpenXML4JException("ZipOutputStream expected !"); @@ -68,7 +70,7 @@ // check if there is anything to save for some parts. We don't do this for all parts as some code // might depend on empty parts being saved, e.g. some unit tests verify this currently. if(part.getSize() == 0 && part.getPartName().getName().equals(XSSFRelation.SHARED_STRINGS.getDefaultFileName())) { - return true; + return; } ZipOutputStream zos = (ZipOutputStream) os; @@ -92,9 +94,9 @@ } zos.closeEntry(); } catch (IOException ioe) { - logger.log(POILogger.ERROR,"Cannot write: " + part.getPartName() + ": in ZIP", - ioe); - return false; + final String msg = "Cannot write: " + part.getPartName() + ": in ZIP"; + logger.log(POILogger.ERROR, msg, ioe); + throw new IOException(msg, ioe); } // Saving relationship part @@ -106,7 +108,6 @@ relationshipPartName, zos); } - return true; } /** @@ -119,10 +120,13 @@ * @param zos * Zip output stream in which to save the XML content of the * relationships serialization. + * @throws IOException if an error occurred while saving the relationship part + * to the output stream. This is often because the output stream is closed. + * @throws OpenXML4JException if an error occurred while transforming the XML source. */ - public static boolean marshallRelationshipPart( + public static void marshallRelationshipPart( PackageRelationshipCollection rels, PackagePartName relPartName, - ZipOutputStream zos) { + ZipOutputStream zos) throws IOException, OpenXML4JException { // Building xml Document xmlOutDoc = DocumentHelper.createDocument(); // make something like