blob: 6963e006d0b432318cfe26b028ee5815abd33252 [file] [log] [blame]
/*******************************************************************************
* 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.apache.ofbiz.webapp.view;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.ofbiz.base.location.FlexibleLocation;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.FileUtil;
import org.apache.ofbiz.base.util.UtilProperties;
import org.apache.ofbiz.base.util.UtilValidate;
/**
* Apache FOP worker class.
*/
public final class ApacheFopWorker {
public static final String module = ApacheFopWorker.class.getName();
/** File name prefix used for temporary files. Currently set to
* <code>org.apache.ofbiz.webapp.view.ApacheFopWorker-</code>.
*/
private static final String tempFilePrefix = "org.apache.ofbiz.webapp.view.ApacheFopWorker-";
private static FopFactory fopFactory = null;
private static final int encryptionLengthBitsDefault = 128;
private static final String encryptionLengthDefault = UtilProperties.getPropertyValue("fop", "fop.encryption-length.default", String.valueOf(encryptionLengthBitsDefault));
private static final String userPasswordDefault = UtilProperties.getPropertyValue("fop", "fop.userPassword.default");
private static final String ownerPasswordDefault = UtilProperties.getPropertyValue("fop", "fop.ownerPassword.default");
private static final String allowPrintDefault = UtilProperties.getPropertyValue("fop", "fop.allowPrint.default", "true");
private static final String allowCopyContentDefault = UtilProperties.getPropertyValue("fop", "fop.allowCopyContent.default", "true");
private static final String allowEditContentDefault = UtilProperties.getPropertyValue("fop", "fop.allowEditContent.default", "true");
private static final String allowEditAnnotationsDefault = UtilProperties.getPropertyValue("fop", "fop.allowEditAnnotations.default", "true");
private static final String allowFillInFormsDefault = UtilProperties.getPropertyValue("fop", "fop.allowFillInForms.default", "true");
private static final String allowAccessContentDefault = UtilProperties.getPropertyValue("fop", "fop.allowAccessContent.default", "true");
private static final String allowAssembleDocumentDefault = UtilProperties.getPropertyValue("fop", "fop.allowAssembleDocument.default", "true");
private static final String allowPrintHqDefault = UtilProperties.getPropertyValue("fop", "fop.allowPrintHq.default", "true");
private static final String encryptMetadataDefault = UtilProperties.getPropertyValue("fop", "fop.encrypt-metadata.default", "true");
private static final String fopPath = UtilProperties.getPropertyValue("fop", "fop.path", "/framework/webapp/config");
private static final String fopFontBaseProperty = UtilProperties.getPropertyValue("fop", "fop.font.base.url", "/framework/webapp/config/");
private ApacheFopWorker() {}
/** 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;
}
try {
String ofbizHome = System.getProperty("ofbiz.home");
File userConfigFile = FileUtil.getFile(ofbizHome + fopPath + "/fop.xconf");
if (userConfigFile.exists()) {
fopFactory = FopFactory.newInstance(userConfigFile);
} else {
Debug.logWarning("FOP configuration file not found: " + userConfigFile, module);
}
File fontBaseFile = FileUtil.getFile(ofbizHome + fopFontBaseProperty);
if (fontBaseFile.isDirectory()) {
fopFactory.getFontManager().setResourceResolver(ResourceResolverFactory.createDefaultInternalResourceResolver(fontBaseFile.toURI()));
} else {
Debug.logWarning("FOP font base URL not found: " + fontBaseFile, module);
}
Debug.logInfo("FOP FontBaseURL: " + fopFactory.getFontManager().getResourceResolver().getBaseURI(), module);
} catch (Exception e) {
Debug.logWarning(e, "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);
try (BufferedOutputStream dest = new BufferedOutputStream(new FileOutputStream(destFile))) {
Fop fop = createFopInstance(dest, outputFormat);
transform(src, stylesheet, fop);
}
}
/** 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);
} 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 {
return createFopInstance(out, outputFormat, null);
}
/** 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"
* @param foUserAgent FOUserAgent object which may contains encryption-params in render options
* @return Fop instance
*/
public static Fop createFopInstance(OutputStream out, String outputFormat, FOUserAgent foUserAgent) throws FOPException {
if (UtilValidate.isEmpty(outputFormat)) {
outputFormat = MimeConstants.MIME_PDF;
}
if (UtilValidate.isEmpty(foUserAgent)) {
FopFactory fopFactory = getFactoryInstance();
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.
*/
private static class LocalResolver implements URIResolver {
private URIResolver defaultResolver;
private LocalResolver() {}
private 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);
}
}
public static String getEncryptionLengthDefault() {
return encryptionLengthDefault;
}
public static String getUserPasswordDefault() {
return userPasswordDefault;
}
public static String getOwnerPasswordDefault() {
return ownerPasswordDefault;
}
public static String getAllowPrintDefault() {
return allowPrintDefault;
}
public static String getAllowCopyContentDefault() {
return allowCopyContentDefault;
}
public static String getAllowEditContentDefault() {
return allowEditContentDefault;
}
public static String getAllowEditAnnotationsDefault() {
return allowEditAnnotationsDefault;
}
public static String getAllowAccessContentDefault() {
return allowAccessContentDefault;
}
public static String getAllowFillInFormsDefault() {
return allowFillInFormsDefault;
}
public static String getAllowAssembleDocumentDefault() {
return allowAssembleDocumentDefault;
}
public static String getAllowPrintHqDefault() {
return allowPrintHqDefault;
}
public static String getEncryptMetadataDefault() {
return encryptMetadataDefault;
}
}