/*
* Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com]
* 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.
*/
package de.ks.idnadrev.expimp.xls;
import com.google.common.util.concurrent.MoreExecutors;
import de.ks.idnadrev.expimp.DependencyGraph;
import de.ks.idnadrev.expimp.xls.result.XlsxImportResultCollector;
import de.ks.idnadrev.expimp.xls.result.XlsxImportSheetResult;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.enterprise.inject.spi.CDI;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
public class XlsxImporter {
private static final Logger log = LoggerFactory.getLogger(XlsxImporter.class);
protected XlsxImportResultCollector resultCollector;
protected final ExecutorService executorService;
protected DependencyGraph dependencyGraph;
protected boolean throwOnError = false;
protected XlsImportCfg importCfg = new XlsImportCfg().replaceExisting();
public XlsxImporter() {
this(MoreExecutors.newDirectExecutorService());
}
public XlsxImporter(ExecutorService executorService) {
this.executorService = executorService;
dependencyGraph = CDI.current().select(DependencyGraph.class).get();
}
public XlsxImporter setImportCfg(XlsImportCfg importCfg) {
this.importCfg = importCfg;
return this;
}
public XlsImportCfg getImportCfg() {
return importCfg;
}
public XlsxImportResultCollector importFromFile(File file) {
resultCollector = new XlsxImportResultCollector();
checkFile(file);
OPCPackage pkg = openPackage(file);
try {
XSSFReader reader = new XSSFReader(pkg);
SharedStringsTable sharedStringsTable = reader.getSharedStringsTable();//used by ms office to store all string values
log.info("Importing from {}", file);
Map<Integer, Collection<SingleSheetImport>> importStages = new HashMap<>();
XSSFReader.SheetIterator iterator = (XSSFReader.SheetIterator) reader.getSheetsData();
while (iterator.hasNext()) {
InputStream sheetStream = iterator.next();
String sheetName = iterator.getSheetName();
final XlsxImportSheetResult result = resultCollector.getSheetResult(sheetName);
Class<?> class2Import;
try {
class2Import = getClass().getClassLoader().loadClass(sheetName);
} catch (ClassNotFoundException e) {
log.info("Could not load class to import {} will skip sheet.", sheetName);
result.generalError("Could not load class to import " + sheetName + " will skip sheet.", e);
continue;
}
if (class2Import != null) {
if (importCfg.getIgnored().contains(class2Import)) {
continue;
}
int stage = dependencyGraph.getStage(class2Import);
importStages.putIfAbsent(stage, new LinkedList<>());
SingleSheetImport singleSheetImport = new SingleSheetImport(class2Import, sheetStream, dependencyGraph, reader, result, importCfg);
importStages.get(stage).add(singleSheetImport);
}
}
importStages.entrySet().forEach(stage -> {
try {
executorService.invokeAll(stage.getValue());
List<List<Future<?>>> collect = stage.getValue().stream()//
.map(sheet -> sheet.getRunAfterImport().stream().map((Runnable r) -> executorService.submit(r)).collect(Collectors.<Future<?>>toList()))//
.collect(Collectors.<List<Future<?>>>toList());
for (List<Future<?>> futureList : collect) {
futureList.forEach(future -> {
try {
future.get();
} catch (ExecutionException e) {
if (throwOnError) {
log.error("Could not run after sheet ", e);
throw new RuntimeException(e);
}
} catch (InterruptedException e) {
//
}
});
}
} catch (InterruptedException e1) {
//
}
});
} catch (OpenXML4JException | IOException e) {
resultCollector.generalError("Could not read " + file, e);
if (throwOnError) {
log.error("Could not read {}", file, e);
throw new RuntimeException(e);
}
} finally {
try {
pkg.close();
} catch (IOException e) {
resultCollector.generalError("Could not close package " + pkg, e);
if (throwOnError) {
log.error("Could not close package {}", pkg, e);
}
}
}
return resultCollector;
}
protected OPCPackage openPackage(File file) {
OPCPackage pkg = null;
try {
pkg = OPCPackage.open(file);
} catch (InvalidFormatException e) {
log.error("Could not create opc package for file {}", file, e);
throw new RuntimeException(e);
}
return pkg;
}
private void checkFile(File file) {
if (file == null) {
throw new NullPointerException("File must not be null");
}
if (!file.exists()) {
throw new IllegalArgumentException("File " + file + " has to exist");
}
}
public boolean isThrowOnError() {
return throwOnError;
}
public void setThrowOnError(boolean throwOnError) {
this.throwOnError = throwOnError;
}
}