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); } + } |
Free forum by Nabble | Edit this page |