package fr.acxio.tools.agia.file.pdf;
/*
* Copyright 2014 Acxio
*
* Licensed 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.
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdfwriter.COSWriter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.core.io.Resource;
import fr.acxio.tools.agia.io.ResourceFactory;
import fr.acxio.tools.agia.io.ResourceFactoryConstants;
import fr.acxio.tools.agia.io.ResourcesFactory;
/**
* <p>
* A tasklet which can split many PDF at once.
* </p>
* <p>
* It can be configured through the Resource and PDDocument factories.
* </p>
*
* @author pcollardez
*
*/
public class SplitPDFTasklet implements Tasklet {
private static final Logger LOGGER = LoggerFactory.getLogger(SplitPDFTasklet.class);
private ResourcesFactory sourceFactory;
private ResourceFactory destinationFactory;
private boolean forceReplace = false;
private PDDocumentFactory documentFactory;
public void setSourceFactory(ResourcesFactory sSourceFactory) {
sourceFactory = sSourceFactory;
}
public void setDestinationFactory(ResourceFactory sDestinationFactory) {
destinationFactory = sDestinationFactory;
}
public void setDocumentFactory(PDDocumentFactory sDocumentFactory) {
documentFactory = sDocumentFactory;
}
public void setForceReplace(boolean sForceReplace) {
forceReplace = sForceReplace;
}
@Override
public RepeatStatus execute(StepContribution sContribution, ChunkContext sChunkContext) throws Exception {
Map<String, Object> aSourceParams = new HashMap<String, Object>();
aSourceParams.put(ResourceFactoryConstants.PARAM_STEP_EXEC, ((sChunkContext != null) && (sChunkContext.getStepContext() != null)) ? sChunkContext
.getStepContext().getStepExecution() : null);
Resource[] aSourceResources = sourceFactory.getResources(aSourceParams);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("{} file(s) to split", aSourceResources.length);
}
for (Resource aSourceResource : aSourceResources) {
if (sContribution != null) {
sContribution.incrementReadCount();
}
File aOriginFile = aSourceResource.getFile();
if (aOriginFile.exists()) {
int aOutputCount = splitFile(aSourceResource, sChunkContext);
if (sContribution != null) {
sContribution.incrementWriteCount(aOutputCount);
}
} else {
throw new SplitPDFException("File not found: " + aOriginFile);
}
}
return RepeatStatus.FINISHED;
}
private int splitFile(Resource sSourceResource, ChunkContext sChunkContext) throws Exception {
Map<String, Object> aDestinationParams = new HashMap<String, Object>();
aDestinationParams.put(ResourceFactoryConstants.PARAM_SOURCE, sSourceResource);
aDestinationParams.put(ResourceFactoryConstants.PARAM_STEP_EXEC, ((sChunkContext != null) && (sChunkContext.getStepContext() != null)) ? sChunkContext
.getStepContext().getStepExecution() : null);
Resource aDestination = null;
int aResult = 0;
PDDocumentContainer aDocumentContainer = null;
try {
aDocumentContainer = documentFactory.getDocument(sSourceResource.getFile());
List<PDDocument> documents = aDocumentContainer.getParts();
for (int i = 0; i < documents.size(); i++) {
PDDocument doc = documents.get(i);
// Output file factory
int aTryCount = 10;
do {
aDestination = destinationFactory.getResource(aDestinationParams);
aTryCount--;
} while (!forceReplace && (aTryCount > 0) && (aDestination != null) && aDestination.exists());
if ((aTryCount == 0) && !forceReplace) {
throw new SplitPDFException("Cannot create a new destination filename");
}
if (aDestination != null) {
if (aDestination.exists() && LOGGER.isWarnEnabled()) {
LOGGER.warn("Replacing {}", aDestination.getFile().getAbsolutePath());
}
writeDocument(doc, aDestination.getFile().getAbsolutePath());
doc.close();
} else {
throw new SplitPDFException("No destination specified");
}
aResult++;
}
} finally {
if (aDocumentContainer != null) {
aDocumentContainer.close();
}
}
return aResult;
}
private void writeDocument(PDDocument doc, String fileName) throws IOException, COSVisitorException {
FileOutputStream output = null;
COSWriter writer = null;
try {
FileUtils.forceMkdir(new File(fileName).getAbsoluteFile().getParentFile());
output = new FileOutputStream(fileName);
writer = new COSWriter(output);
writer.write(doc);
} finally {
if (output != null) {
output.close();
}
if (writer != null) {
writer.close();
}
}
}
}