/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs.response;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.geoserver.config.GeoServer;
import org.geoserver.platform.Operation;
import org.geoserver.platform.ServiceException;
import org.geoserver.wfs.WFSGetFeatureOutputFormat;
import org.geoserver.wfs.request.FeatureCollectionResponse;
import org.geoserver.wfs.request.GetFeatureRequest;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
/**
* Abstract base class for Excel WFS output format
*
* @author Sebastian Benthall, OpenGeo, seb@opengeo.org and Shane StClair, Axiom Consulting,
* shane@axiomalaska.com
*/
public abstract class ExcelOutputFormat extends WFSGetFeatureOutputFormat {
private static Logger log = Logger.getLogger(ExcelOutputFormat.class);
protected static int CELL_CHAR_LIMIT = (int) Math.pow(2, 15) - 1; // 32,767
protected static String TRUNCATE_WARNING = "DATA TRUNCATED";
protected int rowLimit;
protected int colLimit;
protected String fileExtension;
protected String mimeType;
public ExcelOutputFormat(GeoServer gs, String formatName) {
super(gs, formatName);
}
protected abstract Workbook getNewWorkbook();
/**
* @return mime type;
*/
@Override
public String getMimeType(Object value, Operation operation) throws ServiceException {
return mimeType;
}
@Override
public String getAttachmentFileName(Object value, Operation operation) {
GetFeatureRequest request = GetFeatureRequest.adapt(operation.getParameters()[0]);
String outputFileName = request.getQueries().get(0).getTypeNames().get(0).getLocalPart();
return outputFileName + "." + fileExtension;
}
@Override
public String getPreferredDisposition(Object value, Operation operation) {
return DISPOSITION_ATTACH;
}
/**
* @see WFSGetFeatureOutputFormat#write(Object, OutputStream, Operation)
*/
@Override
protected void write(FeatureCollectionResponse featureCollection, OutputStream output,
Operation getFeature) throws IOException ,ServiceException {
// Create the workbook
Workbook wb = getNewWorkbook();
CreationHelper helper = wb.getCreationHelper();
ExcelCellStyles styles = new ExcelCellStyles(wb);
for (Iterator it = featureCollection.getFeature().iterator(); it.hasNext();) {
SimpleFeatureCollection fc = (SimpleFeatureCollection) it.next();
// create the sheet for this feature collection
Sheet sheet = wb.createSheet(fc.getSchema().getTypeName());
// write out the header
Row header = sheet.createRow(0);
SimpleFeatureType ft = fc.getSchema();
Cell cell;
cell = header.createCell(0);
cell.setCellValue(helper.createRichTextString("FID"));
for (int i = 0; i < ft.getAttributeCount() && i < colLimit; i++) {
AttributeDescriptor ad = ft.getDescriptor(i);
cell = header.createCell(i + 1);
cell.setCellValue(helper.createRichTextString(ad.getLocalName()));
cell.setCellStyle(styles.getHeaderStyle());
}
// write out the features
SimpleFeatureIterator i = fc.features();
int r = 0; // row index
try {
Row row;
while (i.hasNext()) {
r++; // start at 1, since header is at 0
row = sheet.createRow(r);
cell = row.createCell(0);
if (r == (rowLimit - 1) && i.hasNext()) {
// there are more features than rows available in this
// Excel format. write out a warning line and break
RichTextString rowWarning = helper.createRichTextString(TRUNCATE_WARNING
+ ": ROWS " + r + " - " + fc.size() + " NOT SHOWN");
cell.setCellValue(rowWarning);
cell.setCellStyle(styles.getWarningStyle());
break;
}
SimpleFeature f = i.next();
cell.setCellValue(helper.createRichTextString(f.getID()));
for (int j = 0; j < f.getAttributeCount() && j < colLimit; j++) {
Object att = f.getAttribute(j);
if (att != null) {
cell = row.createCell(j + 1);
if (att instanceof Number) {
cell.setCellValue(((Number) att).doubleValue());
} else if (att instanceof Date) {
cell.setCellValue((Date) att);
cell.setCellStyle(styles.getDateStyle());
} else if (att instanceof Calendar) {
cell.setCellValue((Calendar) att);
cell.setCellStyle(styles.getDateStyle());
} else if (att instanceof Boolean) {
cell.setCellValue((Boolean) att);
} else {
// ok, it seems we have no better way than dump it as a string
String stringVal = att.toString();
// if string length > excel cell limit, truncate it and warn the
// user, otherwise excel workbook will be corrupted
if (stringVal.length() > CELL_CHAR_LIMIT) {
stringVal = TRUNCATE_WARNING
+ " "
+ stringVal.substring(0, CELL_CHAR_LIMIT
- TRUNCATE_WARNING.length() - 1);
cell.setCellStyle(styles.getWarningStyle());
}
cell.setCellValue(helper.createRichTextString(stringVal));
}
}
}
}
} finally {
i.close();
}
}
// write to output
wb.write(output);
}
}