package com.constellio.data.io;
import static java.io.File.createTempFile;
import static java.util.concurrent.Executors.newFixedThreadPool;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.document.DocumentFamily;
import org.artofsolving.jodconverter.document.DocumentFormat;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeException;
import org.artofsolving.jodconverter.office.OfficeManager;
import com.constellio.data.io.services.facades.IOServices;
public class ConversionManager implements AutoCloseable {
public static int BASE_PORT = 2002;
private final IOServices ioServices;
private final OfficeManager processPool;
private final ExecutorService executor;
private final File workingFolder;
public ConversionManager(IOServices ioServices, int numberOfProcesses, File workingFolder) {
this.ioServices = ioServices;
this.workingFolder = workingFolder;
executor = newFixedThreadPool(numberOfProcesses);
processPool = getOfficeManagerConfiguration(numberOfProcesses).buildOfficeManager();
processPool.start();
}
public Future<File> convertToPDFAsync(final InputStream inputStream, final String originalName) {
return executor.submit(new Callable<File>() {
@Override
public File call() {
return convertToPDF(inputStream, originalName);
}
});
}
public File convertToPDF(InputStream inputStream, String originalName) {
File input = null;
File output = null;
try {
input = createTempFile("original", originalName, workingFolder);
save(inputStream, input);
output = createTempFile("converted", originalName + ".pdf", workingFolder);
convertToPDF(input, output);
return output;
} catch (IOException | OfficeException e) {
ioServices.deleteQuietly(output);
throw new RuntimeException(e);
} finally {
ioServices.deleteQuietly(input);
}
}
public void close() {
executor.shutdown();
try {
if (!executor.awaitTermination(15, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
processPool.stop();
}
private DefaultOfficeManagerConfiguration getOfficeManagerConfiguration(int numberOfProcesses) {
int[] ports = new int[numberOfProcesses];
for (int i = 0; i < numberOfProcesses; i++) {
ports[i] = BASE_PORT + i;
}
return new DefaultOfficeManagerConfiguration().setPortNumbers(ports);
}
private void save(InputStream inputStream, File file)
throws IOException {
try (OutputStream outputStream = new FileOutputStream(file)) {
ioServices.copyLarge(inputStream, outputStream);
} finally {
ioServices.closeQuietly(inputStream);
}
}
private void convertToPDF(File input, File output) {
OfficeDocumentConverter converter = new OfficeDocumentConverter(processPool);
converter.convert(input, output, toPDFa());
}
private DocumentFormat toPDFa() {
Map<String, Object> filterData = new HashMap<>();
filterData.put("SelectPdfVersion", 1);
Map<String, Object> properties = new HashMap<>();
properties.put("FilterName", "writer_pdf_Export");
properties.put("FilterData", filterData);
DocumentFormat format = new DocumentFormat("PDF/A", "pdf", "application/pdf");
format.setStoreProperties(DocumentFamily.TEXT, properties);
format.setStoreProperties(DocumentFamily.DRAWING, properties);
return format;
}
}