1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* $Id: CachedRenderPagesModel.java 1863625 2019-07-23 10:41:07Z ssteiner $ */ 19 20 package org.apache.fop.area; 21 22 import java.io.BufferedInputStream; 23 import java.io.BufferedOutputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.ObjectInputStream; 27 import java.io.ObjectOutputStream; 28 import java.io.OutputStream; 29 import java.net.URI; 30 import java.util.HashMap; 31 import java.util.Iterator; 32 import java.util.Map; 33 34 import org.xml.sax.SAXException; 35 36 import org.apache.commons.io.IOUtils; 37 38 import org.apache.xmlgraphics.io.TempResourceURIGenerator; 39 40 import org.apache.fop.apps.FOPException; 41 import org.apache.fop.apps.FOUserAgent; 42 import org.apache.fop.fonts.FontInfo; 43 44 /** 45 * A simple cached render pages model. 46 * If the page is prepared for later rendering then this saves 47 * the page contents to a file and once the page is resolved 48 * the contents are reloaded. 49 */ 50 public class CachedRenderPagesModel extends RenderPagesModel { 51 52 private Map<PageViewport, URI> pageMap = new HashMap<PageViewport, URI>(); 53 54 /** Base directory to save temporary file in, typically points to the user's temp dir. */ 55 private final URI tempBaseURI; 56 private static final TempResourceURIGenerator TEMP_URI_GENERATOR 57 = new TempResourceURIGenerator("cached-pages"); 58 59 /** 60 * Main Constructor 61 * @param userAgent FOUserAgent object for process 62 * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). 63 * @param fontInfo FontInfo object 64 * @param stream OutputStream 65 * @throws FOPException if the renderer cannot be properly initialized 66 */ CachedRenderPagesModel(FOUserAgent userAgent, String outputFormat, FontInfo fontInfo, OutputStream stream)67 public CachedRenderPagesModel(FOUserAgent userAgent, String outputFormat, 68 FontInfo fontInfo, OutputStream stream) throws FOPException { 69 super(userAgent, outputFormat, fontInfo, stream); 70 tempBaseURI = TEMP_URI_GENERATOR.generate(); 71 } 72 73 /** {@inheritDoc} */ 74 @Override checkPreparedPages(PageViewport newpage, boolean renderUnresolved)75 protected boolean checkPreparedPages(PageViewport newpage, boolean renderUnresolved) { 76 for (Iterator iter = prepared.iterator(); iter.hasNext();) { 77 PageViewport pageViewport = (PageViewport)iter.next(); 78 if (pageViewport.isResolved() || renderUnresolved) { 79 if (pageViewport != newpage) { 80 try { 81 // load page from cache 82 URI tempURI = pageMap.get(pageViewport); 83 log.debug("Loading page from: " + tempURI); 84 InputStream inStream = renderer.getUserAgent().getResourceResolver().getResource(tempURI); 85 ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(inStream)); 86 try { 87 pageViewport.loadPage(in); 88 } finally { 89 IOUtils.closeQuietly(inStream); 90 IOUtils.closeQuietly(in); 91 } 92 pageMap.remove(pageViewport); 93 } catch (Exception e) { 94 AreaEventProducer eventProducer = AreaEventProducer.Provider.get( 95 renderer.getUserAgent().getEventBroadcaster()); 96 eventProducer.pageLoadError(this, pageViewport.getPageNumberString(), e); 97 } 98 } 99 100 renderPage(pageViewport); 101 pageViewport.clear(); 102 iter.remove(); 103 } else { 104 if (!renderer.supportsOutOfOrder()) { 105 break; 106 } 107 } 108 } 109 if (newpage != null && newpage.getPage() != null) { 110 savePage(newpage); 111 newpage.clear(); 112 } 113 return renderer.supportsOutOfOrder() || prepared.isEmpty(); 114 } 115 116 /** 117 * Save a page. 118 * It saves the contents of the page to a file. 119 * 120 * @param page the page to prepare 121 */ savePage(PageViewport page)122 protected void savePage(PageViewport page) { 123 try { 124 // save page to cache 125 ObjectOutputStream tempstream; 126 String fname = "/fop-page-" + page.getPageIndex() + ".ser"; 127 URI tempURI = URI.create(tempBaseURI + fname); 128 OutputStream outStream = renderer.getUserAgent().getResourceResolver().getOutputStream(tempURI); 129 tempstream = new ObjectOutputStream(new BufferedOutputStream(outStream)); 130 try { 131 page.savePage(tempstream); 132 } finally { 133 IOUtils.closeQuietly(tempstream); 134 } 135 pageMap.put(page, tempURI); 136 if (log.isDebugEnabled()) { 137 log.debug("Page saved to temporary file: " + tempURI); 138 } 139 } catch (IOException ioe) { 140 AreaEventProducer eventProducer 141 = AreaEventProducer.Provider.get( 142 renderer.getUserAgent().getEventBroadcaster()); 143 eventProducer.pageSaveError(this, page.getPageNumberString(), ioe); 144 } 145 } 146 147 /** {@inheritDoc} */ 148 @Override endDocument()149 public void endDocument() throws SAXException { 150 super.endDocument(); 151 } 152 } 153 154