You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AFPStreamer.java 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. /* $Id$ */
  18. package org.apache.fop.afp;
  19. import java.io.BufferedOutputStream;
  20. import java.io.File;
  21. import java.io.FileNotFoundException;
  22. import java.io.FileOutputStream;
  23. import java.io.IOException;
  24. import java.io.OutputStream;
  25. import java.io.RandomAccessFile;
  26. import java.util.Iterator;
  27. import java.util.Map;
  28. import org.apache.commons.logging.Log;
  29. import org.apache.commons.logging.LogFactory;
  30. import org.apache.fop.afp.modca.ResourceGroup;
  31. import org.apache.fop.afp.modca.StreamedResourceGroup;
  32. /**
  33. * Manages the streaming of the AFP output
  34. */
  35. public class AFPStreamer implements Streamable {
  36. /** Static logging instance */
  37. private static final Log log = LogFactory.getLog(AFPStreamer.class);
  38. private static final String AFPDATASTREAM_TEMP_FILE_PREFIX = "AFPDataStream_";
  39. private static final int BUFFER_SIZE = 4096; // 4k writing buffer
  40. private static final String DEFAULT_EXTERNAL_RESOURCE_FILENAME = "resources.afp";
  41. private final Factory factory;
  42. /** A mapping of external resource destinations to resource groups */
  43. private final Map/*<String,AFPExternalResourceGroup>*/pathResourceGroupMap
  44. = new java.util.HashMap/*<String,AFPExternalResourceGroup>*/();
  45. private StreamedResourceGroup printFileResourceGroup;
  46. /** Sets the default resource group file path */
  47. private String defaultResourceGroupFilePath = DEFAULT_EXTERNAL_RESOURCE_FILENAME;
  48. private File tempFile;
  49. /** temporary document outputstream */
  50. private OutputStream documentOutputStream;
  51. /** the final outputstream */
  52. private OutputStream outputStream;
  53. private RandomAccessFile documentFile;
  54. private DataStream dataStream;
  55. /**
  56. * Main constructor
  57. *
  58. * @param factory a factory
  59. */
  60. public AFPStreamer(Factory factory) {
  61. this.factory = factory;
  62. }
  63. /**
  64. * Creates a new DataStream
  65. *
  66. * @param paintingState the AFP painting state
  67. * @return a new {@link DataStream}
  68. * @throws IOException thrown if an I/O exception of some sort has occurred
  69. */
  70. public DataStream createDataStream(AFPPaintingState paintingState) throws IOException {
  71. this.tempFile = File.createTempFile(AFPDATASTREAM_TEMP_FILE_PREFIX, null);
  72. this.documentFile = new RandomAccessFile(tempFile, "rw");
  73. this.documentOutputStream = new BufferedOutputStream(
  74. new FileOutputStream(documentFile.getFD()));
  75. this.dataStream = factory.createDataStream(paintingState, documentOutputStream);
  76. return dataStream;
  77. }
  78. /**
  79. * Sets the default resource group file path
  80. *
  81. * @param filePath the default resource group file path
  82. */
  83. public void setDefaultResourceGroupFilePath(String filePath) {
  84. this.defaultResourceGroupFilePath = filePath;
  85. }
  86. /**
  87. * Returns the resource group for a given resource info
  88. *
  89. * @param level a resource level
  90. * @return a resource group for the given resource info
  91. */
  92. public ResourceGroup getResourceGroup(AFPResourceLevel level) {
  93. ResourceGroup resourceGroup = null;
  94. if (level.isInline()) { // no resource group for inline level
  95. return null;
  96. }
  97. if (level.isExternal()) {
  98. String filePath = level.getExternalFilePath();
  99. if (filePath == null) {
  100. log.warn("No file path provided for external resource, using default.");
  101. filePath = defaultResourceGroupFilePath;
  102. }
  103. resourceGroup = (ResourceGroup)pathResourceGroupMap.get(filePath);
  104. if (resourceGroup == null) {
  105. OutputStream os = null;
  106. try {
  107. os = new BufferedOutputStream(new FileOutputStream(filePath));
  108. } catch (FileNotFoundException fnfe) {
  109. log.error("Failed to create/open external resource group file '"
  110. + filePath + "'");
  111. } finally {
  112. if (os != null) {
  113. resourceGroup = factory.createStreamedResourceGroup(os);
  114. pathResourceGroupMap.put(filePath, resourceGroup);
  115. }
  116. }
  117. }
  118. } else if (level.isPrintFile()) {
  119. if (printFileResourceGroup == null) {
  120. // use final outputstream for print-file resource group
  121. printFileResourceGroup = factory.createStreamedResourceGroup(outputStream);
  122. }
  123. resourceGroup = printFileResourceGroup;
  124. } else {
  125. // resource group in afp document datastream
  126. resourceGroup = dataStream.getResourceGroup(level);
  127. }
  128. return resourceGroup;
  129. }
  130. /**
  131. * Closes off the AFP stream writing the document stream
  132. *
  133. * @throws IOException if an an I/O exception of some sort has occurred
  134. */
  135. // write out any external resource groups
  136. public void close() throws IOException {
  137. Iterator it = pathResourceGroupMap.entrySet().iterator();
  138. while (it.hasNext()) {
  139. StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next();
  140. resourceGroup.close();
  141. }
  142. // close any open print-file resource group
  143. if (printFileResourceGroup != null) {
  144. printFileResourceGroup.close();
  145. }
  146. // write out document
  147. writeToStream(outputStream);
  148. outputStream.close();
  149. // delete temporary file
  150. tempFile.delete();
  151. }
  152. /**
  153. * Sets the final outputstream
  154. *
  155. * @param outputStream an outputstream
  156. */
  157. public void setOutputStream(OutputStream outputStream) {
  158. this.outputStream = outputStream;
  159. }
  160. /** {@inheritDoc} */
  161. public void writeToStream(OutputStream os) throws IOException {
  162. // long start = System.currentTimeMillis();
  163. int len = (int)documentFile.length();
  164. int numChunks = len / BUFFER_SIZE;
  165. int remainingChunkSize = len % BUFFER_SIZE;
  166. byte[] buffer;
  167. documentFile.seek(0);
  168. if (numChunks > 0) {
  169. buffer = new byte[BUFFER_SIZE];
  170. for (int i = 0; i < numChunks; i++) {
  171. documentFile.read(buffer, 0, BUFFER_SIZE);
  172. os.write(buffer, 0, BUFFER_SIZE);
  173. }
  174. } else {
  175. buffer = new byte[remainingChunkSize];
  176. }
  177. if (remainingChunkSize > 0) {
  178. documentFile.read(buffer, 0, remainingChunkSize);
  179. os.write(buffer, 0, remainingChunkSize);
  180. }
  181. os.flush();
  182. // long end = System.currentTimeMillis();
  183. // log.debug("writing time " + (end - start) + "ms");
  184. }
  185. }