/*
* 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.primitives.Primitives;
import com.google.common.util.concurrent.MoreExecutors;
import de.ks.idnadrev.expimp.DependencyGraph;
import de.ks.idnadrev.expimp.EntityExportSource;
import de.ks.idnadrev.expimp.Exporter;
import de.ks.persistence.entity.AbstractPersistentObject;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.enterprise.inject.spi.CDI;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
public class XlsxExporter implements Exporter {
private static final Logger log = LoggerFactory.getLogger(XlsxExporter.class);
protected final SXSSFWorkbook workbook;
protected ExecutorService executorService;
protected final ColumnProvider provider;
public XlsxExporter() {
this(MoreExecutors.newDirectExecutorService());
}
public XlsxExporter(ExecutorService executorService) {
workbook = new SXSSFWorkbook();
workbook.setCompressTempFiles(true);
this.executorService = executorService;
provider = new ColumnProvider(CDI.current().select(DependencyGraph.class).get());
}
public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
@Override
public void export(File file, EntityExportSource<?>... sources) {
List<EntityExportSource<?>> exportSources = Arrays.asList(sources);
export(file, exportSources);
}
@Override
public void export(File file, List<EntityExportSource<?>> sources) {
if (file.exists()) {
file.delete();
}
List<Future<?>> futures = sources.stream()//
.filter(s -> s.getIds().size() > 0)//
.map(s -> {
return executorService.submit(() -> {
String identifier = s.getIdentifier();
log.info("Exporting {} to {}", identifier, file);
Sheet sheet = workbook.createSheet(identifier);
exportSource(sheet, s);
});
}).collect(Collectors.toList());
join(futures);
try (FileOutputStream out = new FileOutputStream(file)) {
workbook.write(out);
} catch (IOException e) {
log.error("Could not write file {}", file, e);
} finally {
workbook.dispose();
}
}
private void join(List<Future<?>> export) {
export.forEach(sheet -> {
try {
sheet.get();
} catch (InterruptedException e) {
//
} catch (ExecutionException e) {
log.error("Failed to export", e);
throw new RuntimeException(e.getCause());
}
});
}
protected void exportSource(Sheet sheet, EntityExportSource<?> source) {
List<XlsxColumn> columns = getColumnDefinitions(source);
createTitle(sheet, columns);
int rowId = 1;
for (AbstractPersistentObject object : source) {
Row row = sheet.createRow(rowId);
for (int columnId = 0; columnId < columns.size(); columnId++) {
XlsxColumn column = columns.get(columnId);
Object value = column.getValue(object);
if (value == null) {
row.createCell(columnId, Cell.CELL_TYPE_BLANK);
} else {
Cell cell = row.createCell(columnId, column.getCellType());
cell.setCellStyle(column.getCellStyle(workbook));
setCellValue(sheet.getWorkbook().getCreationHelper(), cell, value);
}
}
rowId++;
}
for (int columnId = 0; columnId < columns.size(); columnId++) {
try {
sheet.autoSizeColumn(columnId);
} catch (NullPointerException e) {
//
}
}
}
private void createTitle(Sheet sheet, List<XlsxColumn> columns) {
Row title = sheet.createRow(0);
for (int columnId = 0; columnId < columns.size(); columnId++) {
XlsxColumn column = columns.get(columnId);
Cell titleCell = title.createCell(columnId, Cell.CELL_TYPE_STRING);
RichTextString richTextString = workbook.getCreationHelper().createRichTextString(column.getIdentifier());
titleCell.setCellValue(richTextString);
CellStyle cellStyle = getTitleStyle();
titleCell.setCellStyle(cellStyle);
}
}
private CellStyle getTitleStyle() {
CellStyle cellStyle = workbook.createCellStyle();
Font font = workbook.createFont();
font.setFontHeightInPoints((short) 12);
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
cellStyle.setFont(font);
return cellStyle;
}
protected void setCellValue(CreationHelper creationHelper, Cell cell, Object value) {
if (value instanceof Number) {
double cellValue = ((Number) value).doubleValue();
cell.setCellValue(cellValue);
} else if (Number.class.isAssignableFrom(Primitives.wrap(value.getClass()))) {
double cellValue = (double) value;
cell.setCellValue(cellValue);
} else if (value instanceof String) {
RichTextString richTextString = creationHelper.createRichTextString((String) value);
cell.setCellValue(richTextString);
} else if (value instanceof LocalDateTime) {
long time = Timestamp.valueOf(((LocalDateTime) value)).getTime();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
cell.setCellValue(cal);
}
}
protected List<XlsxColumn> getColumnDefinitions(EntityExportSource<?> source) {
List<XlsxColumn> collect = provider.getColumns(source).stream()//
.filter(c -> !source.getConfig().getIgnoredFields().contains(c.getIdentifier()))//
.collect(Collectors.toList());
return collect;
}
}