svn commit: r603483 - in /ofbiz/trunk: applications/content/src/org/ofbiz/content/email/ applications/content/src/org/ofbiz/content/output/ framework/example/src/org/ofbiz/example/ framework/webapp/src/org/ofbiz/webapp/view/ framework/widget/src/org/of...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r603483 - in /ofbiz/trunk: applications/content/src/org/ofbiz/content/email/ applications/content/src/org/ofbiz/content/output/ framework/example/src/org/ofbiz/example/ framework/webapp/src/org/ofbiz/webapp/view/ framework/widget/src/org/of...

adrianc
Author: adrianc
Date: Tue Dec 11 22:38:23 2007
New Revision: 603483

URL: http://svn.apache.org/viewvc?rev=603483&view=rev
Log:
FOP code improvements, based on https://issues.apache.org/jira/browse/OFBIZ-1414.

The Jira issue mentions rendering to temp files, but I kept that out of the commit. If we get out of memory errors in the future, it will be easy to add it back in.

Added:
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopWorker.java
Modified:
    ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java
    ofbiz/trunk/applications/content/src/org/ofbiz/content/output/OutputServices.java
    ofbiz/trunk/framework/example/src/org/ofbiz/example/ExamplePrintServices.java
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopFactory.java
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/FopPdfViewHandler.java
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoFormRenderer.java
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoScreenRenderer.java
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenFopViewHandler.java

Modified: ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java (original)
+++ ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java Tue Dec 11 22:38:23 2007
@@ -36,7 +36,7 @@
 import org.ofbiz.service.LocalDispatcher;
 import org.ofbiz.service.ServiceUtil;
 import org.ofbiz.service.mail.MimeMessageWrapper;
-import org.ofbiz.webapp.view.ApacheFopFactory;
+import org.ofbiz.webapp.view.ApacheFopWorker;
 import org.ofbiz.widget.html.HtmlScreenRenderer;
 import org.ofbiz.widget.screen.ScreenRenderer;
 import org.xml.sax.SAXException;
@@ -355,27 +355,19 @@
                 }
                 */
 
-                // create the in/output stream for the generation
+                // create the input stream for the generation
+                StreamSource src = new StreamSource(new StringReader(writer.toString()));
+
+                // create the output stream for the generation
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
                 
-                FopFactory fopFactory = ApacheFopFactory.instance();
-                Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, baos);
-                TransformerFactory transFactory = TransformerFactory.newInstance();
-                Transformer transformer = transFactory.newTransformer();
-
-                Reader reader = new StringReader(writer.toString());
-                Source src = new StreamSource(reader);
-                Result res = new SAXResult(fop.getDefaultHandler());
-                
-                // Start XSLT transformation and FOP processing
-                transformer.transform(src, res);
+                Fop fop = ApacheFopWorker.createFopInstance(baos, MimeConstants.MIME_PDF);
+                ApacheFopWorker.transform(src, null, fop);
+
                 // and generate the PDF
                 baos.flush();
                 baos.close();
 
-                // We don't want to cache the images that get loaded by the FOP engine
-                fopFactory.getImageFactory().clearCaches();
-
                 // store in the list of maps for sendmail....
                 List bodyParts = FastList.newInstance();
                 if (bodyText != null) {
@@ -397,12 +389,6 @@
             } catch (FOPException fe) {
                 String errMsg = "Error rendering PDF attachment for email: " + fe.toString();
                 Debug.logError(fe, errMsg, module);
-                return ServiceUtil.returnError(errMsg);
-            } catch (TransformerConfigurationException tce) {
-                String errMsg = "FOP TransformerConfiguration Exception: " + tce.toString();
-                return ServiceUtil.returnError(errMsg);
-            } catch (TransformerException te) {
-                String errMsg = "FOP transform failed: " + te.toString();
                 return ServiceUtil.returnError(errMsg);
             } catch (SAXException se) {
                 String errMsg = "Error rendering PDF attachment for email: " + se.toString();

Modified: ofbiz/trunk/applications/content/src/org/ofbiz/content/output/OutputServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/org/ofbiz/content/output/OutputServices.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/src/org/ofbiz/content/output/OutputServices.java (original)
+++ ofbiz/trunk/applications/content/src/org/ofbiz/content/output/OutputServices.java Tue Dec 11 22:38:23 2007
@@ -31,7 +31,7 @@
 import org.ofbiz.service.GenericServiceException;
 import org.ofbiz.service.LocalDispatcher;
 import org.ofbiz.service.ServiceUtil;
-import org.ofbiz.webapp.view.ApacheFopFactory;
+import org.ofbiz.webapp.view.ApacheFopWorker;
 import org.ofbiz.widget.fo.FoFormRenderer;
 import org.ofbiz.widget.html.HtmlScreenRenderer;
 import org.ofbiz.widget.screen.ScreenRenderer;
@@ -126,27 +126,18 @@
             screensAtt.getContext().put("formStringRenderer", foFormRenderer);
             screensAtt.render(screenLocation);
 
-            // create the in/output stream for the generation
+            // create the input stream for the generation
+            StreamSource src = new StreamSource(new StringReader(writer.toString()));
+
+            // create the output stream for the generation
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            
+            Fop fop = ApacheFopWorker.createFopInstance(baos, MimeConstants.MIME_PDF);
+            ApacheFopWorker.transform(src, null, fop);
 
-            FopFactory fopFactory = ApacheFopFactory.instance();
-            Fop fop = fopFactory.newFop(contentType, baos);
-            TransformerFactory transFactory = TransformerFactory.newInstance();
-            Transformer transformer = transFactory.newTransformer();
-
-            Reader reader = new StringReader(writer.toString());
-            Source src = new StreamSource(reader);
-            Result res = new SAXResult(fop.getDefaultHandler());
-
-            // Start XSLT transformation and FOP processing
-            transformer.transform(src, res);
-            // and generate the stream
             baos.flush();
             baos.close();
 
-            // We don't want to cache the images that get loaded by the FOP engine
-            fopFactory.getImageFactory().clearCaches();
-
             // Print is sent
             DocFlavor psInFormat = new DocFlavor.INPUT_STREAM(printerContentType);
             InputStream bais = new ByteArrayInputStream(baos.toByteArray());
@@ -209,12 +200,6 @@
             String errMsg = "Error rendering [" + contentType + "]: " + fe.toString();
             Debug.logError(fe, errMsg, module);
             return ServiceUtil.returnError(errMsg);
-        } catch (TransformerConfigurationException tce) {
-            String errMsg = "FOP TransformerConfiguration Exception: " + tce.toString();
-            return ServiceUtil.returnError(errMsg);
-        } catch (TransformerException te) {
-            String errMsg = "FOP transform failed: " + te.toString();
-            return ServiceUtil.returnError(errMsg);
         } catch (SAXException se) {
             String errMsg = "Error rendering [" + contentType + "]: " + se.toString();
             Debug.logError(se, errMsg, module);
@@ -258,27 +243,18 @@
             screensAtt.getContext().put("formStringRenderer", foFormRenderer);
             screensAtt.render(screenLocation);
 
-            // create the in/output stream for the generation
+            // create the input stream for the generation
+            StreamSource src = new StreamSource(new StringReader(writer.toString()));
+
+            // create the output stream for the generation
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            
+            Fop fop = ApacheFopWorker.createFopInstance(baos, MimeConstants.MIME_PDF);
+            ApacheFopWorker.transform(src, null, fop);
 
-            FopFactory fopFactory = ApacheFopFactory.instance();
-            Fop fop = fopFactory.newFop(contentType, baos);
-            TransformerFactory transFactory = TransformerFactory.newInstance();
-            Transformer transformer = transFactory.newTransformer();
-
-            Reader reader = new StringReader(writer.toString());
-            Source src = new StreamSource(reader);
-            Result res = new SAXResult(fop.getDefaultHandler());
-
-            // Start XSLT transformation and FOP processing
-            transformer.transform(src, res);
-            // and generate the stream
             baos.flush();
             baos.close();
 
-            // We don't want to cache the images that get loaded by the FOP engine
-            fopFactory.getImageFactory().clearCaches();
-
             fileName += UtilDateTime.nowAsString();
             if ("application/pdf".equals(contentType)) {
                 fileName += ".pdf";
@@ -307,12 +283,6 @@
         } catch (FOPException fe) {
             String errMsg = "Error rendering [" + contentType + "]: " + fe.toString();
             Debug.logError(fe, errMsg, module);
-            return ServiceUtil.returnError(errMsg);
-        } catch (TransformerConfigurationException tce) {
-            String errMsg = "FOP TransformerConfiguration Exception: " + tce.toString();
-            return ServiceUtil.returnError(errMsg);
-        } catch (TransformerException te) {
-            String errMsg = "FOP transform failed: " + te.toString();
             return ServiceUtil.returnError(errMsg);
         } catch (SAXException se) {
             String errMsg = "Error rendering [" + contentType + "]: " + se.toString();

Modified: ofbiz/trunk/framework/example/src/org/ofbiz/example/ExamplePrintServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/src/org/ofbiz/example/ExamplePrintServices.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/framework/example/src/org/ofbiz/example/ExamplePrintServices.java (original)
+++ ofbiz/trunk/framework/example/src/org/ofbiz/example/ExamplePrintServices.java Tue Dec 11 22:38:23 2007
@@ -20,13 +20,12 @@
 
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.Fop;
-import org.apache.fop.apps.FopFactory;
 import org.apache.fop.apps.MimeConstants;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
 import org.ofbiz.service.DispatchContext;
 import org.ofbiz.service.ServiceUtil;
-import org.ofbiz.webapp.view.ApacheFopFactory;
+import org.ofbiz.webapp.view.ApacheFopWorker;
 import org.ofbiz.widget.html.HtmlScreenRenderer;
 import org.ofbiz.widget.screen.ScreenRenderer;
 import org.xml.sax.SAXException;
@@ -51,14 +50,6 @@
 import javax.print.attribute.standard.Copies;
 import javax.print.attribute.standard.Sides;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.stream.StreamSource;
 
 public class ExamplePrintServices {
@@ -98,46 +89,16 @@
             return ServiceUtil.returnError(errMsg);
         }
 
-        String reportXmlDocument = reportWriter.toString();
+        // set the input source (XSL-FO) and generate the PDF
+        StreamSource src = new StreamSource(new StringReader(reportWriter.toString()));
 
-        // create the in/output stream for the generation
+        // create the output stream for the generation
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        
-        
-        FopFactory fopFactory;
+
         try {
-            fopFactory = ApacheFopFactory.instance();
-            Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
-            TransformerFactory transFactory = TransformerFactory.newInstance();
-            Transformer transformer = transFactory.newTransformer();
-
-            // set the input source (XSL-FO) and generate the PDF
-            Reader reader = new StringReader(reportXmlDocument);
-            Source src = new StreamSource(reader);
-            
-            // load the FOP driver
-
-            // Get handler that is used in the generation process
-            Result res = new SAXResult(fop.getDefaultHandler());
-            
-            // read the XSL-FO XML into the W3 Document
-            
-            // Start XSLT transformation and FOP processing
-            transformer.transform(src, res);
-            // and generate the PDF
-            // We don't want to cache the images that get loaded by the FOP engine
-            fopFactory.getImageFactory().clearCaches();
-            
+            Fop fop = ApacheFopWorker.createFopInstance(out, MimeConstants.MIME_PDF);
+            ApacheFopWorker.transform(src, null, fop);
         } catch (FOPException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (TransformerConfigurationException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (TransformerFactoryConfigurationError e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (TransformerException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopFactory.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopFactory.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopFactory.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopFactory.java Tue Dec 11 22:38:23 2007
@@ -18,11 +18,9 @@
  *******************************************************************************/
 package org.ofbiz.webapp.view;
 
-import org.apache.fop.apps.FopFactory;
-import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.webapp.view.ApacheFopWorker;
 
-import java.io.File;
+import org.apache.fop.apps.FopFactory;
 
 /**
  * Apache FOP Factory used to provide a singleton instance of the FopFactory.  Best pratices recommended
@@ -34,34 +32,8 @@
 
     public static final String module = ApacheFopFactory.class.getName();
     
-    private static final FopFactory fopFactory;
-
-    static {
-        // Create the factory
-        fopFactory = FopFactory.newInstance();
-
-        // Limit the validation for backwards compatibility
-        fopFactory.setStrictValidation(false);
-        
-        try {
-            String fopPath = UtilProperties.getPropertyValue("fop.properties", "fop.path", "framework/webapp/config");
-            File userConfigFile = new File(fopPath + "/fop.xconf");
-            fopFactory.setUserConfig(userConfigFile);
-            String fopFontBaseUrl = fopFactory.getFontBaseURL();
-            if (fopFontBaseUrl == null) {
-                String ofbizHome = System.getProperty("ofbiz.home");
-                fopFontBaseUrl = UtilProperties.getPropertyValue("fop.properties", "fop.font.base.url",
-                                    "file:///" + ofbizHome + "/framework/webapp/config/");
-                fopFactory.setFontBaseURL(fopFontBaseUrl);
-            }
-            Debug.logInfo("FOP-FontBaseURL: " + fopFontBaseUrl, module);
-        } catch (Exception e) {
-            Debug.logWarning("Error reading FOP configuration", module);
-        }
-    }
-
+    /** @deprecated use ApacheFopWorker.getFactoryInstance() */
     public static FopFactory instance() {
-        return fopFactory;
+        return ApacheFopWorker.getFactoryInstance();
     }
-
 }

Added: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopWorker.java?rev=603483&view=auto
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopWorker.java (added)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/ApacheFopWorker.java Tue Dec 11 22:38:23 2007
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * 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.
+ *******************************************************************************/
+package org.ofbiz.webapp.view;
+
+import java.io.*;
+import java.net.URL;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.FopFactory;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.MimeConstants;
+
+import org.ofbiz.base.location.FlexibleLocation;
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.base.util.UtilValidate;
+
+/**
+ * Apache FOP worker class.
+ */
+
+public class ApacheFopWorker {
+
+    public static final String module = ApacheFopWorker.class.getName();
+    /** File name prefix used for temporary files. Currently set to
+     * <code>org.ofbiz.webapp.view.ApacheFopWorker-</code>.
+     */
+    public static final String tempFilePrefix = "org.ofbiz.webapp.view.ApacheFopWorker-";
+    
+    protected static FopFactory fopFactory = null;
+
+    /** Returns an instance of the FopFactory class. FOP documentation recommends
+     * the reuse of the factory instance because of the startup time.
+     * @return FopFactory The FopFactory instance
+     */
+    public static FopFactory getFactoryInstance() {
+        if (fopFactory == null) {
+            synchronized (ApacheFopWorker.class) {
+                if (fopFactory != null) {
+                    return fopFactory;
+                }
+                // Create the factory
+                fopFactory = FopFactory.newInstance();
+
+                // Limit the validation for backwards compatibility
+                fopFactory.setStrictValidation(false);
+
+                try {
+                    String fopPath = UtilProperties.getPropertyValue("fop.properties", "fop.path", "framework/webapp/config");
+                    File userConfigFile = new File(fopPath + "/fop.xconf");
+                    fopFactory.setUserConfig(userConfigFile);
+                    String fopFontBaseUrl = fopFactory.getFontBaseURL();
+                    if (fopFontBaseUrl == null) {
+                        String ofbizHome = System.getProperty("ofbiz.home");
+                        fopFontBaseUrl = UtilProperties.getPropertyValue("fop.properties", "fop.font.base.url", "file:///" + ofbizHome + "/framework/webapp/config/");
+                        fopFactory.setFontBaseURL(fopFontBaseUrl);
+                    }
+                    Debug.logInfo("FOP-FontBaseURL: " + fopFontBaseUrl, module);
+                } catch (Exception e) {
+                    Debug.logWarning("Error reading FOP configuration", module);
+                }
+            }
+        }
+        return fopFactory;
+    }
+    
+    /** Transform an xsl-fo file to the specified file format.
+     * @param srcFile The xsl-fo File instance
+     * @param destFile The target (result) File instance
+     * @param stylesheetFile Optional stylesheet File instance
+     * @param outputFormat Optional output format, defaults to "application/pdf"
+     */
+    public static void transform(File srcFile, File destFile, File stylesheetFile, String outputFormat) throws IOException, FOPException {
+        StreamSource src = new StreamSource(srcFile);
+        StreamSource stylesheet = stylesheetFile == null ? null : new StreamSource(stylesheetFile);
+        BufferedOutputStream dest = new BufferedOutputStream(new FileOutputStream(destFile));
+        Fop fop = createFopInstance(dest, outputFormat);
+        if (fop.getUserAgent().getBaseURL() == null) {
+            String baseURL = null;
+            try {
+                File parentFile = new File(srcFile.getAbsolutePath()).getParentFile();
+                baseURL = parentFile.toURI().toURL().toExternalForm();
+            } catch (Exception e) {
+                baseURL = "";
+            }
+            fop.getUserAgent().setBaseURL(baseURL);
+        }
+        transform(src, stylesheet, fop);
+        dest.close();
+    }
+
+    /** Transform an xsl-fo InputStream to the specified OutputStream format.
+     * @param srcStream The xsl-fo InputStream instance
+     * @param destStream The target (result) OutputStream instance
+     * @param stylesheetStream Optional stylesheet InputStream instance
+     * @param outputFormat Optional output format, defaults to "application/pdf"
+     */
+    public static void transform(InputStream srcStream, OutputStream destStream, InputStream stylesheetStream, String outputFormat) throws FOPException {
+        StreamSource src = new StreamSource(srcStream);
+        StreamSource stylesheet = stylesheetStream == null ? null : new StreamSource(stylesheetStream);
+        Fop fop = createFopInstance(destStream, outputFormat);
+        transform(src, stylesheet, fop);
+    }
+
+    /** Transform an xsl-fo StreamSource to the specified output format.
+     * @param src The xsl-fo StreamSource instance
+     * @param stylesheet Optional stylesheet StreamSource instance
+     * @param fop
+     */
+    public static void transform(StreamSource src, StreamSource stylesheet, Fop fop) throws FOPException {
+        Result res = new SAXResult(fop.getDefaultHandler());
+        try {
+            TransformerFactory factory = TransformerFactory.newInstance();
+            Transformer transformer;
+            if (stylesheet == null) {
+                transformer = factory.newTransformer();
+            } else {
+                transformer = factory.newTransformer(stylesheet);
+            }
+            transformer.setURIResolver(new LocalResolver(transformer.getURIResolver()));
+            transformer.transform(src, res);
+            FopFactory fopFactory = getFactoryInstance();
+            fopFactory.getImageFactory().clearCaches();
+        } catch (Exception e) {
+            throw new FOPException(e);
+        }
+    }
+    
+    /** Returns a new Fop instance. Note: FOP documentation recommends using
+     * a Fop instance for one transform run only.
+     * @param out The target (result) OutputStream instance
+     * @param outputFormat Optional output format, defaults to "application/pdf"
+     * @return Fop instance
+     */
+    public static Fop createFopInstance(OutputStream out, String outputFormat) throws FOPException {
+        if (UtilValidate.isEmpty(outputFormat)) {
+            outputFormat = MimeConstants.MIME_PDF;
+        }
+        FopFactory fopFactory = getFactoryInstance();
+        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
+        Fop fop;
+        if (out != null) {
+            fop = fopFactory.newFop(outputFormat, foUserAgent, out);
+        } else {
+            fop = fopFactory.newFop(outputFormat, foUserAgent);
+        }
+        return fop;
+    }
+    
+    /** Returns a temporary File instance. The temporary file name starts with
+     * <a href="#tempFilePrefix">tempFilePrefix</a> and ends with ".xml".
+     * Calling methods are responsible for deleting the temporary file.<p>
+     * FOP performs transforms in memory, so if there is any chance FO output
+     * will be more than a few pages, it would be best to keep FO input in a temporary
+     * file.</p>
+     * @return File instance
+     */
+    public static File createTempFoXmlFile() throws IOException {
+        File tempXmlFile = File.createTempFile(tempFilePrefix, ".xml");
+        tempXmlFile.deleteOnExit();
+        return tempXmlFile;
+    }
+
+    /** Returns a temporary File instance. The temporary file name starts with
+     * <a href="#tempFilePrefix">tempFilePrefix</a> and ends with ".res".
+     * Calling methods are responsible for deleting the temporary file.<p>
+     * FOP performs transforms in memory, so if there is any chance FO output
+     * will be more than a few pages, it would be best to keep FO output in a temporary
+     * file.</p>
+     * @return File instance
+     */
+    public static File createTempResultFile() throws IOException {
+        File tempResultFile = File.createTempFile(tempFilePrefix, ".res");
+        tempResultFile.deleteOnExit();
+        return tempResultFile;
+    }
+
+    /** Local URI resolver for the Transformer class.
+     */
+    public static class LocalResolver implements URIResolver {
+
+        private URIResolver defaultResolver;
+
+        protected LocalResolver() {}
+        
+        public LocalResolver(URIResolver defaultResolver) {
+            this.defaultResolver = defaultResolver;
+        }
+
+        public Source resolve(String href, String base) throws TransformerException {
+            URL locationUrl = null;
+            try {
+                locationUrl = FlexibleLocation.resolveLocation(href);
+                if (locationUrl != null) {
+                    return new StreamSource(locationUrl.openStream());
+                }
+            } catch (Exception e) {
+                throw new TransformerException(e.getMessage());
+            }
+            return defaultResolver.resolve(href, base);
+        }
+    }
+}

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/FopPdfViewHandler.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/FopPdfViewHandler.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/FopPdfViewHandler.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/view/FopPdfViewHandler.java Tue Dec 11 22:38:23 2007
@@ -20,10 +20,14 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
 import java.io.StringWriter;
 import java.io.Writer;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
@@ -53,8 +57,10 @@
         
         // render the byte array
         ByteArrayOutputStream out = null;
+        Reader reader = new StringReader(writer.toString());
+        Source src = new StreamSource(reader);
         try {
-            out = FopRenderer.render(writer);
+            ApacheFopWorker.transform(src, out, null, contentType);
         } catch (GeneralException e) {
             throw new ViewHandlerException(e.getMessage(), e.getNested());
         }

Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoFormRenderer.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoFormRenderer.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoFormRenderer.java (original)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoFormRenderer.java Tue Dec 11 22:38:23 2007
@@ -48,13 +48,14 @@
 import org.ofbiz.widget.form.ModelFormField.TextField;
 import org.ofbiz.widget.form.ModelFormField.TextFindField;
 import org.ofbiz.widget.form.ModelFormField.TextareaField;
+import org.ofbiz.widget.html.HtmlWidgetRenderer;
 
 
 /**
  * Widget Library - FO Form Renderer implementation
  *
  */
-public class FoFormRenderer implements FormStringRenderer {
+public class FoFormRenderer extends HtmlWidgetRenderer implements FormStringRenderer {
 
     public static final String module = FoFormRenderer.class.getName();
     
@@ -68,12 +69,6 @@
         this.response = response;
     }
 
-    public void appendWhitespace(StringBuffer buffer) {
-        // appending line ends for now, but this could be replaced with a simple space or something
-        buffer.append("\r\n");
-        //buffer.append(' ');
-    }
-
     private void makeBlockString(StringBuffer buffer, String widgetStyle, String text) {
         buffer.append("<fo:block");
         if (UtilValidate.isNotEmpty(widgetStyle)) {
@@ -88,31 +83,31 @@
     public void renderDisplayField(StringBuffer buffer, Map context, DisplayField displayField) {
         ModelFormField modelFormField = displayField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), displayField.getDescription(context));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderHyperlinkField(StringBuffer buffer, Map context, HyperlinkField hyperlinkField) {
         ModelFormField modelFormField = hyperlinkField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), hyperlinkField.getDescription(context));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderTextField(StringBuffer buffer, Map context, TextField textField) {
         ModelFormField modelFormField = textField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, textField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderTextareaField(StringBuffer buffer, Map context, TextareaField textareaField) {
         ModelFormField modelFormField = textareaField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, textareaField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderDateTimeField(StringBuffer buffer, Map context, DateTimeField dateTimeField) {
         ModelFormField modelFormField = dateTimeField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, dateTimeField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderDropDownField(StringBuffer buffer, Map context, DropDownField dropDownField) {
@@ -140,7 +135,7 @@
                 }
             }
         }
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderCheckField(StringBuffer buffer, Map context, CheckField checkField) {
@@ -174,12 +169,15 @@
     }
 
     public void renderFormOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
+        renderBeginningBoundaryComment(buffer, "Form Widget", modelForm);
     }
 
     public void renderFormClose(StringBuffer buffer, Map context, ModelForm modelForm) {
+        renderEndingBoundaryComment(buffer, "Form Widget", modelForm);
     }
 
     public void renderMultiFormClose(StringBuffer buffer, Map context, ModelForm modelForm) {
+        renderEndingBoundaryComment(buffer, "Form Widget", modelForm);
     }
 
     public void renderFormatListWrapperOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
@@ -198,28 +196,28 @@
                 buffer.append(FoScreenRenderer.getFoStyle(areaStyle));
             }
             buffer.append("/>");
-            this.appendWhitespace(buffer);
+            appendWhitespace(buffer);
         }
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatListWrapperClose(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("</fo:table-body>");
         buffer.append("</fo:table>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatHeaderRowOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("<fo:table-header>");
         buffer.append("<fo:table-row>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatHeaderRowClose(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("</fo:table-row>");
         buffer.append("</fo:table-header>");
         buffer.append("<fo:table-body>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatHeaderRowCellOpen(StringBuffer buffer, Map context, ModelForm modelForm, ModelFormField modelFormField, int positionSpan) {
@@ -232,23 +230,23 @@
         buffer.append("font-weight=\"bold\" text-align=\"center\" border=\"solid black\" padding=\"2pt\"");
         buffer.append(">");
         buffer.append("<fo:block>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatHeaderRowCellClose(StringBuffer buffer, Map context, ModelForm modelForm, ModelFormField modelFormField) {
         buffer.append("</fo:block>");
         buffer.append("</fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatHeaderRowFormCellOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("<fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatHeaderRowFormCellClose(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("</fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatHeaderRowFormCellTitleSeparator(StringBuffer buffer, Map context, ModelForm modelForm, ModelFormField modelFormField, boolean isLast) {
@@ -256,12 +254,12 @@
 
     public void renderFormatItemRowOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("<fo:table-row>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatItemRowClose(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("</fo:table-row>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatItemRowCellOpen(StringBuffer buffer, Map context, ModelForm modelForm, ModelFormField modelFormField, int positionSpan) {
@@ -277,62 +275,62 @@
         }
         buffer.append(FoScreenRenderer.getFoStyle(areaStyle));
         buffer.append(">");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatItemRowCellClose(StringBuffer buffer, Map context, ModelForm modelForm, ModelFormField modelFormField) {
         buffer.append("</fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatItemRowFormCellOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("<fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatItemRowFormCellClose(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("</fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     // TODO: multi columns (position attribute) in single forms are still not implemented
     public void renderFormatSingleWrapperOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("<fo:table>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
         buffer.append("<fo:table-column column-width=\"2in\"/>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
         buffer.append("<fo:table-column/>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
         buffer.append("<fo:table-body>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
     public void renderFormatSingleWrapperClose(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("</fo:table-body>");
         buffer.append("</fo:table>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatFieldRowOpen(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("<fo:table-row>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatFieldRowClose(StringBuffer buffer, Map context, ModelForm modelForm) {
         buffer.append("</fo:table-row>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
 
     public void renderFormatFieldRowTitleCellOpen(StringBuffer buffer, Map context, ModelFormField modelFormField) {
         buffer.append("<fo:table-cell font-weight=\"bold\" text-align=\"right\" padding=\"3pt\">");
         buffer.append("<fo:block>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatFieldRowTitleCellClose(StringBuffer buffer, Map context, ModelFormField modelFormField) {
         buffer.append("</fo:block>");
         buffer.append("</fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatFieldRowSpacerCell(StringBuffer buffer, Map context, ModelFormField modelFormField) {
@@ -340,12 +338,12 @@
 
     public void renderFormatFieldRowWidgetCellOpen(StringBuffer buffer, Map context, ModelFormField modelFormField, int positions, int positionSpan, Integer nextPositionInRow) {
         buffer.append("<fo:table-cell text-align=\"left\" padding=\"2pt\" padding-left=\"5pt\">");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatFieldRowWidgetCellClose(StringBuffer buffer, Map context, ModelFormField modelFormField, int positions, int positionSpan, Integer nextPositionInRow) {
         buffer.append("</fo:table-cell>");
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderFormatEmptySpace(StringBuffer buffer, Map context, ModelForm modelForm) {
@@ -355,25 +353,25 @@
     public void renderTextFindField(StringBuffer buffer, Map context, TextFindField textFindField) {
         ModelFormField modelFormField = textFindField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, textFindField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderRangeFindField(StringBuffer buffer, Map context, RangeFindField rangeFindField) {
         ModelFormField modelFormField = rangeFindField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, rangeFindField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderDateFindField(StringBuffer buffer, Map context, DateFindField dateFindField) {
         ModelFormField modelFormField = dateFindField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, dateFindField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderLookupField(StringBuffer buffer, Map context, LookupField lookupField) {
         ModelFormField modelFormField = lookupField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, lookupField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderNextPrev(StringBuffer buffer, Map context, ModelForm modelForm) {
@@ -382,7 +380,7 @@
     public void renderFileField(StringBuffer buffer, Map context, FileField textField) {
         ModelFormField modelFormField = textField.getModelFormField();
         this.makeBlockString(buffer, modelFormField.getWidgetStyle(), modelFormField.getEntry(context, textField.getDefaultValue(context)));
-        this.appendWhitespace(buffer);
+        appendWhitespace(buffer);
     }
 
     public void renderPasswordField(StringBuffer buffer, Map context, PasswordField passwordField) {

Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoScreenRenderer.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoScreenRenderer.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoScreenRenderer.java (original)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/fo/FoScreenRenderer.java Tue Dec 11 22:38:23 2007
@@ -20,34 +20,18 @@
 
 import java.io.IOException;
 import java.io.Writer;
-import java.util.Locale;
 import java.util.Map;
 
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.GeneralException;
-import org.ofbiz.base.util.UtilFormatOut;
-import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilProperties;
 import org.ofbiz.base.util.UtilValidate;
-import org.ofbiz.entity.GenericDelegator;
-import org.ofbiz.entity.GenericValue;
-import org.ofbiz.webapp.control.RequestHandler;
-import org.ofbiz.webapp.taglib.ContentUrlTag;
-import org.ofbiz.widget.WidgetContentWorker;
+import org.ofbiz.widget.html.HtmlWidgetRenderer;
 import org.ofbiz.widget.screen.ModelScreenWidget;
 import org.ofbiz.widget.screen.ScreenStringRenderer;
-import org.ofbiz.service.LocalDispatcher;
-import javolution.util.FastMap;
 
 /**
  * Widget Library - HTML Form Renderer implementation
  */
-public class FoScreenRenderer implements ScreenStringRenderer {
+public class FoScreenRenderer extends HtmlWidgetRenderer implements ScreenStringRenderer {
 
     public static final String module = FoScreenRenderer.class.getName();
 
@@ -63,10 +47,10 @@
     }
 
     public void renderSectionBegin(Writer writer, Map context, ModelScreenWidget.Section section) throws IOException {
-        // do nothing, this is just a place holder container for HTML
+        renderBeginningBoundaryComment(writer, section.isMainSection?"Screen":"Section Widget", section);
     }
     public void renderSectionEnd(Writer writer, Map context, ModelScreenWidget.Section section) throws IOException {
-        // do nothing, this is just a place holder container for HTML
+        renderEndingBoundaryComment(writer, section.isMainSection?"Screen":"Section Widget", section);
     }
 
     public void renderContainerBegin(Writer writer, Map context, ModelScreenWidget.Container container) throws IOException {
@@ -141,10 +125,5 @@
 
     public void renderSubContentEnd(Writer writer, Map context, ModelScreenWidget.SubContent content) throws IOException {
         // TODO: not implemented
-    }
-
-    public void appendWhitespace(Writer writer) throws IOException {
-        // appending line ends for now, but this could be replaced with a simple space or something
-        writer.write("\r\n");
     }
 }

Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenFopViewHandler.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenFopViewHandler.java?rev=603483&r1=603482&r2=603483&view=diff
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenFopViewHandler.java (original)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenFopViewHandler.java Tue Dec 11 22:38:23 2007
@@ -23,20 +23,14 @@
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.xml.transform.*;
-import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.stream.StreamSource;
 
-import org.apache.fop.apps.FopFactory;
 import org.apache.fop.apps.Fop;
-import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.apps.FOPException;
 
 import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.webapp.view.ApacheFopWorker;
 import org.ofbiz.webapp.view.ViewHandler;
 import org.ofbiz.webapp.view.ViewHandlerException;
-import org.ofbiz.webapp.view.ApacheFopFactory;
 import org.ofbiz.widget.fo.FoFormRenderer;
 import org.ofbiz.widget.fo.FoScreenRenderer;
 
@@ -50,8 +44,6 @@
     protected ServletContext servletContext = null;
     protected FoScreenRenderer foScreenRenderer = new FoScreenRenderer();
 
-    private final String DEFAULT_ERROR_TEMPLATE = "component://common/widget/CommonScreens.xml#FoError";
-
     /**
      * @see org.ofbiz.webapp.view.ViewHandler#init(javax.servlet.ServletContext)
      */
@@ -64,15 +56,8 @@
      */
     public void render(String name, String page, String info, String contentType, String encoding, HttpServletRequest request, HttpServletResponse response) throws ViewHandlerException {
 
-        if (UtilValidate.isEmpty(contentType)) {
-            contentType = "application/pdf";
-        }
-        
         // render and obtain the XSL-FO
         Writer writer = new StringWriter();
-
-        FopFactory fopFactory = ApacheFopFactory.instance();
-
         try {
             ScreenRenderer screens = new ScreenRenderer(writer, null, foScreenRenderer);
             screens.populateContextForRequest(request, response, servletContext);
@@ -84,88 +69,45 @@
             throw new ViewHandlerException("Problems with the response writer/output stream", t);
         }
 
+        // set the input source (XSL-FO) and generate the output stream of contentType
+        Reader reader = new StringReader(writer.toString());
+        StreamSource src = new StreamSource(reader);
+        if (Debug.verboseOn()) {
+            Debug.logVerbose("Transforming the following xsl-fo template: " + writer.toString(), module);
+        }
+
         ByteArrayOutputStream out = new ByteArrayOutputStream();
 
-        TransformerFactory transFactory = TransformerFactory.newInstance();
+        try {
+            Fop fop = ApacheFopWorker.createFopInstance(out, contentType);
+            ApacheFopWorker.transform(src, null, fop);
+        } catch (Exception e) {
+            throw createException("Unable to transform FO file", e, response);
+        }
+        // set the content type and length
+        response.setContentType(contentType);
+        response.setContentLength(out.size());
 
+        // write to the browser
         try {
-            Fop fop = fopFactory.newFop(contentType, out);
-            Transformer transformer = transFactory.newTransformer();
+            out.writeTo(response.getOutputStream());
+            response.getOutputStream().flush();
+        } catch (IOException e) {
+            throw createException("Unable write to browser OutputStream", e, response);
+        }
+    }
 
-            // set the input source (XSL-FO) and generate the output stream of contentType
-            Reader reader = new StringReader(writer.toString());
-            Source src = new StreamSource(reader);
-
-            if (Debug.verboseOn()) {
-                Debug.logVerbose("Transforming the following xsl-fo template: " + writer.toString(), module);
-            }
-            /*
-            try {
-                String buf = writer.toString();
-                java.io.FileWriter fw = new java.io.FileWriter(new java.io.File("/tmp/xslfo.out"));
-                fw.write(buf.toString());
-                fw.close();
-            } catch (IOException e) {
-                throw new ViewHandlerException("Unable write to browser OutputStream", e);            
-            }
-            */
-
-            // Get handler that is used in the generation process
-            Result res = new SAXResult(fop.getDefaultHandler());
-
-            try {
-                // Transform the FOP XML source
-                transformer.transform(src, res);
-
-            } catch (TransformerException e) {
-                Debug.logError("FOP transform failed: " + e, module );
-                Debug.logInfo("Rendering the error message using the default error template: " + DEFAULT_ERROR_TEMPLATE, module );
-                try {
-                    writer = new StringWriter();
-                    out = new ByteArrayOutputStream();
-                    fopFactory = ApacheFopFactory.instance();
-                    transFactory = TransformerFactory.newInstance();
-                    transformer = transFactory.newTransformer();
-                    fop = fopFactory.newFop(contentType, out);
-                    res = new SAXResult(fop.getDefaultHandler());
-                    ScreenRenderer screens = new ScreenRenderer(writer, null, foScreenRenderer);
-                    screens.populateContextForRequest(request, response, servletContext);
-                    screens.getContext().put("errorMessage", e.toString());
-                    screens.render(DEFAULT_ERROR_TEMPLATE);
-                    transformer.transform(new StreamSource(new StringReader(writer.toString())), res);
-                } catch (Throwable t) {
-                    // If we cannot even create the error page, then we return the original error
-                    throw new ViewHandlerException("Unable to transform FO to " + contentType, e);
-                }
-            }
-
-            // We don't want to cache the images that get loaded by the FOP engine
-            fopFactory.getImageFactory().clearCaches();
-
-            // set the content type and length
-            response.setContentType(contentType);
-            response.setContentLength(out.size());
-
-            // write to the browser
-            try {
-                out.writeTo(response.getOutputStream());
-                response.getOutputStream().flush();
-            } catch (IOException e) {
-                throw new ViewHandlerException("Unable write to browser OutputStream", e);
-            }
-
-        } catch (TransformerConfigurationException e) {
-            Debug.logError("FOP TransformerConfiguration Exception " + e, module);
-            throw new ViewHandlerException("Transformer Configuration Error", e);
-        } catch (FOPException e) {
-            Debug.logError("FOP Exception " + e, module);
-            throw new ViewHandlerException("FOP Error", e);
-        } finally {
-            try {
-                out.close();
-            } catch (IOException e) {
-                Debug.logError("Unable to close output stream " + e, module);
-            }
+    protected ViewHandlerException createException(String msg, Exception e, HttpServletResponse response) {
+        Debug.logError(msg + ": " + e, module);
+        String htmlString = "<html><head><title>FOP Rendering Error</title></head><body>" + msg + ": " + e.getMessage() + "</body></html>";
+        response.setContentType("text/html");
+        response.setContentLength(htmlString.length());
+        try {
+            response.getOutputStream().write(htmlString.getBytes());
+        } catch (IOException i) {
+            Debug.logError("Multiple errors rendering FOP", module);
         }
+        return new ViewHandlerException(msg, e);
     }
+
 }