| /* |
| * 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. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.afp; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.URI; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.apache.commons.io.IOUtils; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.xmlgraphics.io.TempResourceURIGenerator; |
| |
| import org.apache.fop.afp.modca.ResourceGroup; |
| import org.apache.fop.afp.modca.StreamedResourceGroup; |
| import org.apache.fop.apps.io.InternalResourceResolver; |
| |
| /** |
| * Manages the streaming of the AFP output |
| */ |
| public class AFPStreamer implements Streamable { |
| /** Static logging instance */ |
| private static final Log LOG = LogFactory.getLog(AFPStreamer.class); |
| |
| private static final String DEFAULT_EXTERNAL_RESOURCE_FILENAME = "resources.afp"; |
| |
| private static final TempResourceURIGenerator TEMP_URI_GENERATOR |
| = new TempResourceURIGenerator("AFPDataStream_"); |
| |
| private final Factory factory; |
| |
| private final InternalResourceResolver resourceResolver; |
| |
| /** A mapping of external resource destinations to resource groups */ |
| private final Map<URI, ResourceGroup> pathResourceGroupMap = new HashMap<URI, ResourceGroup>(); |
| |
| private StreamedResourceGroup printFileResourceGroup; |
| |
| /** Sets the default resource group file path */ |
| private URI defaultResourceGroupUri; |
| |
| private final URI tempUri; |
| |
| /** temporary document outputstream */ |
| private OutputStream tempOutputStream; |
| |
| /** the final outputstream */ |
| private OutputStream outputStream; |
| |
| private DataStream dataStream; |
| |
| /** |
| * Main constructor |
| * |
| * @param factory a factory |
| * @param resourceResolver resource resolver |
| */ |
| public AFPStreamer(Factory factory, InternalResourceResolver resourceResolver) { |
| this.factory = factory; |
| this.resourceResolver = resourceResolver; |
| this.tempUri = TEMP_URI_GENERATOR.generate(); |
| defaultResourceGroupUri = URI.create(DEFAULT_EXTERNAL_RESOURCE_FILENAME); |
| |
| } |
| |
| /** |
| * Creates a new DataStream |
| * |
| * @param paintingState the AFP painting state |
| * @return a new {@link DataStream} |
| * @throws IOException thrown if an I/O exception of some sort has occurred |
| */ |
| public DataStream createDataStream(AFPPaintingState paintingState) throws IOException { |
| this.tempOutputStream = new BufferedOutputStream(resourceResolver.getOutputStream(tempUri)); |
| this.dataStream = factory.createDataStream(paintingState, tempOutputStream); |
| return dataStream; |
| } |
| |
| /** |
| * Sets the default resource group URI. |
| * |
| * @param uri the default resource group URI |
| */ |
| public void setDefaultResourceGroupUri(URI uri) { |
| this.defaultResourceGroupUri = uri; |
| } |
| |
| /** |
| * Returns the resource group for a given resource info |
| * |
| * @param level a resource level |
| * @return a resource group for the given resource info |
| */ |
| public ResourceGroup getResourceGroup(AFPResourceLevel level) { |
| ResourceGroup resourceGroup = null; |
| if (level.isInline()) { // no resource group for inline level |
| return null; |
| } |
| if (level.isExternal()) { |
| URI uri = level.getExternalURI(); |
| if (uri == null) { |
| LOG.warn("No file path provided for external resource, using default."); |
| uri = defaultResourceGroupUri; |
| } |
| resourceGroup = pathResourceGroupMap.get(uri); |
| if (resourceGroup == null) { |
| OutputStream os = null; |
| try { |
| os = new BufferedOutputStream(resourceResolver.getOutputStream(uri)); |
| } catch (IOException ioe) { |
| LOG.error("Failed to create/open external resource group for uri '" |
| + uri + "'"); |
| } finally { |
| if (os != null) { |
| resourceGroup = factory.createStreamedResourceGroup(os); |
| pathResourceGroupMap.put(uri, resourceGroup); |
| } |
| } |
| } |
| } else if (level.isPrintFile()) { |
| if (printFileResourceGroup == null) { |
| // use final outputstream for print-file resource group |
| printFileResourceGroup = factory.createStreamedResourceGroup(outputStream); |
| } |
| resourceGroup = printFileResourceGroup; |
| } else { |
| // resource group in afp document datastream |
| resourceGroup = dataStream.getResourceGroup(level); |
| } |
| return resourceGroup; |
| } |
| |
| /** |
| * Closes off the AFP stream writing the document stream |
| * |
| * @throws IOException if an an I/O exception of some sort has occurred |
| */ |
| // write out any external resource groups |
| public void close() throws IOException { |
| Iterator it = pathResourceGroupMap.values().iterator(); |
| while (it.hasNext()) { |
| StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next(); |
| resourceGroup.close(); |
| } |
| // close any open print-file resource group |
| if (printFileResourceGroup != null) { |
| printFileResourceGroup.close(); |
| } |
| // write out document |
| writeToStream(outputStream); |
| outputStream.close(); |
| } |
| |
| /** |
| * Sets the final outputstream |
| * |
| * @param outputStream an outputstream |
| */ |
| public void setOutputStream(OutputStream outputStream) { |
| this.outputStream = outputStream; |
| } |
| |
| /** {@inheritDoc} */ |
| public void writeToStream(OutputStream os) throws IOException { |
| tempOutputStream.close(); |
| InputStream tempInputStream = resourceResolver.getResource(tempUri); |
| IOUtils.copy(tempInputStream, os); |
| //TODO this should notify the stream provider that it is safe to delete the temp data |
| tempInputStream.close(); |
| os.flush(); |
| } |
| } |