Bugzilla#53913: Added document level cache to the PDF preloader
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop-pdf-images/trunk@1388420 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/PreloaderPDF.java b/src/java/org/apache/fop/render/pdf/pdfbox/PreloaderPDF.java
index 8293479..71966cb 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/PreloaderPDF.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/PreloaderPDF.java
@@ -23,6 +23,9 @@
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
import javax.imageio.stream.ImageInputStream;
import javax.xml.transform.Source;
@@ -40,10 +43,10 @@
import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;
-import org.apache.xmlgraphics.image.loader.util.SoftMapCache;
import org.apache.xmlgraphics.util.io.SubInputStream;
import org.apache.fop.datatypes.URISpecification;
+import org.apache.fop.render.pdf.pdfbox.Cache.ValueMaker;
/**
* Image preloader for PDF images.
@@ -54,7 +57,11 @@
private static final String PDF_HEADER = "%PDF-";
/** static PDDocument cache for faster multi-page processing */
- private static SoftMapCache pdfCache = null; //new SoftMapCache(true);
+ private static final Cache.Type CACHE_TYPE =Cache.Type.valueOf(
+ System.getProperty("fop.pdfbox.preloader-cache", Cache.Type.WEAK.name()).toUpperCase());
+
+ private static Map<Object, Cache<URI, PDDocument>> documentCacheMap
+ = Collections.synchronizedMap(new WeakHashMap<Object, Cache<URI, PDDocument>>());
//the cache here can cause problems because PDDocument that have been closed might still
//be accessed. Example: java.io.IOException: The handle is invalid
@@ -77,19 +84,21 @@
}
return info;
} finally {
- if (info != null) {
- ImageUtil.closeQuietly(src); //Image is fully read
- } else {
+ if (info == null) {
in.reset(); //Error detected or not a PDF file
}
}
}
- private static URI deriveDocumentURI(String uri) throws URISyntaxException {
- URI originalURI = new URI(URISpecification.escapeURI(uri));
- URI tempURI = new URI(originalURI.getScheme(),
- originalURI.getSchemeSpecificPart(), null);
- return tempURI;
+ private static URI deriveDocumentURI(String uri) throws ImageException {
+ try {
+ URI originalURI = new URI(URISpecification.escapeURI(uri));
+ URI tempURI = new URI(originalURI.getScheme(),
+ originalURI.getSchemeSpecificPart(), null);
+ return tempURI;
+ } catch (URISyntaxException e) {
+ throw new ImageException("Problem processing URI", e);
+ }
}
private ImageInfo loadPDF(String uri, Source src, ImageContext context) throws IOException,
@@ -98,25 +107,10 @@
int selectedPage = ImageUtil.needPageIndexFromURI(uri);
- URI docURI;
- try {
- docURI = deriveDocumentURI(src.getSystemId() != null ? src.getSystemId() : uri);
- } catch (URISyntaxException e) {
- //Can't get full document URI, so we can't cache later on
- docURI = null;
- }
- PDDocument pddoc;
- if (pdfCache != null && docURI != null) {
- pddoc = (PDDocument)pdfCache.get(docURI);
- if (pddoc == null) {
- pddoc = PDDocument.load(new SubInputStream(in, Integer.MAX_VALUE));
- pddoc = Interceptors.getInstance().interceptOnLoad(pddoc, docURI);
- pdfCache.put(docURI, pddoc);
- }
- } else {
- pddoc = PDDocument.load(new SubInputStream(in, Integer.MAX_VALUE));
- pddoc = Interceptors.getInstance().interceptOnLoad(pddoc, docURI);
- }
+ URI docURI = deriveDocumentURI(src.getSystemId());
+
+ PDDocument pddoc = getDocument(context, docURI, src);
+ pddoc = Interceptors.getInstance().interceptOnLoad(pddoc, docURI);
//Disable the warning about a missing close since we rely on the GC to decide when
//the cached PDF shall be disposed off.
@@ -180,4 +174,40 @@
+ "\nPlease use an OnLoadInterceptor to provide "
+ "suitable decryption material (ex. a password).", e);
}
+
+ private PDDocument getDocument(Object context, URI uri, Source src)
+ throws IOException {
+ try {
+ return getDocumentCache(context).getValue(uri, createDocumentMaker(src, uri));
+ } catch (IOException ioe) {
+ throw ioe;
+ } catch (Exception e) {
+ // We cannot recover from this
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Cache<URI, PDDocument> getDocumentCache(Object context) {
+ Cache<URI, PDDocument> documentCache = documentCacheMap.get(context);
+
+ if (documentCache == null) {
+ documentCache = Cache.createCache(CACHE_TYPE);
+ documentCacheMap.put(context, documentCache);
+ }
+ return documentCache;
+ }
+
+ private ValueMaker<PDDocument> createDocumentMaker(final Source src, final URI docURI) {
+ return new ValueMaker<PDDocument>() {
+ public PDDocument make() throws Exception {
+ final InputStream in = ImageUtil.needInputStream(src);
+ try {
+ PDDocument pddoc = PDDocument.load(new SubInputStream(in, Integer.MAX_VALUE));
+ return Interceptors.getInstance().interceptOnLoad(pddoc, docURI);
+ } finally {
+ ImageUtil.closeQuietly(src);
+ }
+ }
+ };
+ }
}