1/* 2 * ConversionOperation.java 3 * Copyright (C) 2005 Amin Ahmad. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * Amin Ahmad can be contacted at amin.ahmad@gmail.com or on the web at 20 * www.ahmadsoft.org. 21 */ 22package org.ahmadsoft.foprocessor.operations; 23 24import java.io.BufferedOutputStream; 25import java.io.File; 26import java.io.FileOutputStream; 27import java.io.IOException; 28import java.io.InputStream; 29import java.io.OutputStream; 30import java.util.Collection; 31import java.util.logging.Logger; 32 33import javax.xml.transform.Result; 34import javax.xml.transform.Source; 35import javax.xml.transform.Transformer; 36import javax.xml.transform.TransformerFactory; 37import javax.xml.transform.sax.SAXResult; 38import javax.xml.transform.stream.StreamSource; 39 40import org.ahmadsoft.foprocessor.core.FileRenderSpecification; 41import org.ahmadsoft.io.util.InterruptableInputStream; 42import org.apache.fop.apps.FOUserAgent; 43import org.apache.fop.apps.Fop; 44import org.apache.fop.apps.FopFactory; 45import org.eclipse.core.runtime.CoreException; 46import org.eclipse.core.runtime.IPath; 47import org.eclipse.core.runtime.IProgressMonitor; 48import org.eclipse.core.runtime.NullProgressMonitor; 49 50/** 51 * An operation that executes one or more XSL-FO render specifications. 52 * @author Amin Ahmad 53 */ 54public class ConversionOperation { 55 56 public interface Listener { 57 void onFinish(); 58 void onError(String msg, Throwable throwable); 59 } 60 61 private Collection<FileRenderSpecification> conversions; 62 private IProgressMonitor monitor; 63 private Listener listener; 64 65 private volatile boolean interrupted = false; 66 private InterruptableInputStream iis; 67 68 public ConversionOperation(Collection<FileRenderSpecification> conversions, IProgressMonitor monitor, Listener listener) { 69 super(); 70 this.conversions = conversions; 71 this.monitor = monitor; 72 this.listener = listener; 73 } 74 75 76 public void setProgressMonitor(IProgressMonitor monitor) { 77 this.monitor = monitor; 78 } 79 80 public void setInterrupted() { 81 interrupted = true; 82 if (iis != null) { 83 iis.setInterrupted(true); 84 } 85 } 86 87 // TODO log handling. 88 public void run() { 89 90 monitor.beginTask("Initializing", 3); 91 92 monitor.worked(1); 93 94 // Determine information about the files. 95 // 96 long totalByteSize = 0; 97 for (FileRenderSpecification spec: conversions) { 98 File file = spec.getInputFile().getRawLocation().toFile(); 99 100 if (file.exists()) { 101 totalByteSize += file.length(); 102 } 103 } 104 105 monitor.worked(2); 106 monitor.beginTask("Rendering", totalByteSize > Integer.MAX_VALUE ? Integer.MAX_VALUE: (int) totalByteSize); 107 108 Logger logger = Logger.getLogger("org.apache.fop"); 109 110 // Rendition loop 111 // 112 for (FileRenderSpecification spec: conversions) { 113 if (interrupted) 114 break; 115 116 IPath inputPath = spec.getInputFile().getRawLocation(); 117 IPath outputPath = spec.getOutputPath(); 118 119 FopFactory fopFactory = FopFactory.newInstance(); 120 FOUserAgent userAgent = fopFactory.newFOUserAgent(); 121 userAgent.setOutputFile(outputPath.toFile()); 122 if (inputPath != null) 123 userAgent.setBaseURL(inputPath.removeLastSegments(1).toFile().toURI().toString()); 124 125 //IFile outputFile = resource.getProject().getFile(outputPath); 126 127 OutputStream out = null; 128 129 File file = outputPath.toFile(); 130 try { 131 out = new BufferedOutputStream(new FileOutputStream(file)); 132 Fop driver = fopFactory.newFop(spec.getMimeType(),userAgent,out); 133 134 // Setup JAXP using identity transformer 135 TransformerFactory factory = TransformerFactory.newInstance(); 136 Transformer transformer = factory.newTransformer(); // identity transformer 137 138 iis = new InterruptableInputStream(new MeteredInputStream(spec.getInputFile().getContents(), monitor)); 139 Source src = new StreamSource(iis); 140 141 // Resulting SAX events (the generated FO) must be piped through to FOP 142 Result res = new SAXResult(driver.getDefaultHandler()); 143 144 // Start XSLT transformation and FOP processing 145 monitor.subTask(outputPath.lastSegment()); 146 logger.info("Beginning render for " + outputPath.lastSegment()); 147 transformer.transform(src, res); 148 } catch (Exception e) { 149 listener.onError(null, e); 150 continue; 151 } finally { 152 try { 153 if (out != null) out.close(); 154 if (iis != null) iis.close(); 155 } catch (IOException e) { 156 listener.onError(null, e); 157 } 158 159 try { 160 spec.getInputFile().getParent().refreshLocal(1, new NullProgressMonitor()); 161 } catch (CoreException e) { 162 listener.onError(null, e); 163 } 164 } 165 } 166 167 monitor.done(); 168 listener.onFinish(); 169 } 170} 171 172class MeteredInputStream extends InputStream { 173 private InputStream delegate; 174 private long bytesRead = 0; 175 private IProgressMonitor monitor; 176 177 public MeteredInputStream(InputStream delegate, IProgressMonitor monitor) { 178 super(); 179 this.delegate = delegate; 180 this.monitor = monitor; 181 } 182 183 public int available() throws IOException { 184 return delegate.available(); 185 } 186 187 public void close() throws IOException { 188 delegate.close(); 189 } 190 191 public boolean equals(Object obj) { 192 return delegate.equals(obj); 193 } 194 195 public int hashCode() { 196 return delegate.hashCode(); 197 } 198 199 public void mark(int readlimit) { 200 delegate.mark(readlimit); 201 } 202 203 public boolean markSupported() { 204 return delegate.markSupported(); 205 } 206 207 public int read() throws IOException { 208 int result = delegate.read(); 209 bytesRead += result == -1 ? 0: 1; 210 monitor.worked(result == -1 ? 0: 1); 211 return result; 212 } 213 214 public int read(byte[] b, int off, int len) throws IOException { 215 int result = delegate.read(b, off, len); 216 bytesRead += result; 217 monitor.worked(result); 218 return result; 219 } 220 221 public int read(byte[] b) throws IOException { 222 int result = delegate.read(b); 223 bytesRead += result; 224 monitor.worked(result); 225 return result; 226 } 227 228 public void reset() throws IOException { 229 delegate.reset(); 230 } 231 232 public long skip(long n) throws IOException { 233 return delegate.skip(n); 234 } 235 236 public String toString() { 237 return delegate.toString(); 238 } 239} 240