When FOP is started in Main.startFOP() a java.io.BufferedOutputStream is instantiated and wrapped around an instantiated java.io.FileOutputStream. By wrapping the initial java.io.FileOutputStream with a java.io.BufferedOutputStream, FOP is not able to potentially make use of the nio FileChannel stuff which could provide more efficient final output writing (using modern operating system caching) [1].

This would especially be the case for AFP writing as output is initially written in two parts for memory saving reasons, one outputstream for document resources and one for the actual document. On completion of rendering the document is appended to the end of the document resources outputstream.

So I am proposing the introduction and instantiation of a FileChannelAccessibleBufferedOutputStream which extends java.io.BufferedOutputStream in Main.startFOP(). It will expose the getChannel() method of java.io.FileOutputStream. I have included the small code changes I am proposing below. Does this sound reasonable and would this cause any problems for anyone?

Adrian.

[1] http://java.sun.com/j2se/1.4.2/docs/guide/nio

Index: java/org/apache/fop/cli/Main.java
===================================================================
--- java/org/apache/fop/cli/Main.java   (revision 708875)
+++ java/org/apache/fop/cli/Main.java   (working copy)
@@ -21,6 +21,7 @@

 import java.io.File;
 import java.io.FileFilter;
+import java.io.FileOutputStream;
 import java.io.OutputStream;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
@@ -28,9 +29,9 @@
 import java.util.List;

 import org.apache.commons.io.IOUtils;
-
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.util.FileChannelAccessibleBufferedOutputStream;

 /**
  * Main command-line class for Apache FOP.
@@ -164,8 +165,9 @@

             try {
                 if (options.getOutputFile() != null) {
-                    out = new java.io.BufferedOutputStream(
-                            new 
java.io.FileOutputStream(options.getOutputFile()));
+                    FileOutputStream fileOutputStream
+                        = new 
java.io.FileOutputStream(options.getOutputFile());
+                    out = new 
FileChannelAccessibleBufferedOutputStream(fileOutputStream);
                     foUserAgent.setOutputFile(options.getOutputFile());
                 } else if (options.isOutputToStdOut()) {
                     out = new java.io.BufferedOutputStream(System.out);

--- snip ---

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: $ */
package org.apache.fop.util;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

/**
 * A BufferedOutputStream implementation that provides access to the underlying 
FileChannel.
 * This allows for the potential use of nio FileChannel.transferTo() and 
FileChannel.transferFrom().
 */
public class FileChannelAccessibleBufferedOutputStream extends 
java.io.BufferedOutputStream {

    private final FileOutputStream fos;

    /**
     * Main constructor
     *
     * @param fos file output stream
     */
    public FileChannelAccessibleBufferedOutputStream(FileOutputStream fos) {
        super(fos);
        this.fos = fos;
    }

    /**
     * Returns the file channel
     *
     * @return the file channel
     * @throws IOException thrown if an I/O exception of some sort has occurred
     */
    public FileChannel getChannel() throws IOException {
        flush(); // write out any buffered data
        return fos.getChannel();
    }
}


Reply via email to