/* (c) 2014-2016 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 au.com.bytecode.opencsv.CSVReader;
import org.springframework.mock.web.MockHttpServletResponse;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import net.opengis.wfs.GetFeatureType;
import net.opengis.wfs.WfsFactory;
import org.geoserver.data.test.MockData;
import org.geoserver.platform.Operation;
import org.geoserver.wfs.WFSTestSupport;
import org.geoserver.wfs.request.FeatureCollectionResponse;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.memory.MemoryDataStore;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.feature.type.DateUtil;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class CSVOutputFormatTest extends WFSTestSupport {
@Test
public void testFullRequest() throws Exception {
MockHttpServletResponse resp = getAsServletResponse("wfs?version=1.1.0&request=GetFeature&typeName=sf:PrimitiveGeoFeature&outputFormat=csv","");
FeatureSource fs = getFeatureSource(MockData.PRIMITIVEGEOFEATURE);
// System.out.println(resp.getOutputStreamContent());
// check the mime type
assertEquals("text/csv", resp.getContentType());
// check the charset encoding
assertEquals("UTF-8", resp.getCharacterEncoding());
// check the content disposition
assertEquals("attachment; filename=PrimitiveGeoFeature.csv", resp.getHeader("Content-Disposition"));
// read the response back with a parser that can handle escaping, newlines and what not
List<String[]> lines = readLines(resp.getContentAsString());
// we should have one header line and then all the features in that feature type
assertEquals(fs.getCount(Query.ALL) + 1, lines.size());
for (String[] line : lines) {
// check each line has the expected number of elements (num of att + 1 for the id)
assertEquals(fs.getSchema().getDescriptors().size() + 1, line.length);
}
}
@Test
public void testEscapes() throws Exception {
// build some fake data in memory, the property data store cannot handle newlines in its data
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.add("geom", Point.class);
builder.add("label", String.class);
builder.add("dtg", Date.class);
builder.add("n", Integer.class);
builder.add("d", Double.class);
builder.setName("funnyLabels");
SimpleFeatureType type = builder.buildFeatureType();
Date d = (new SimpleDateFormat("yyyy-MM-dd")).parse("2016-01-01");
GeometryFactory gf = new GeometryFactory();
SimpleFeature f1 =
SimpleFeatureBuilder.build(
type,
new Object[] { gf.createPoint(new Coordinate(5, 8)), "A label with \"quotes\"", d, 10, 100.0 },
null);
SimpleFeature f2 =
SimpleFeatureBuilder.build(
type,
new Object[] { gf.createPoint(new Coordinate(5, 4)), "A long label\nwith newlines", d, 10, 200.0 },
null);
SimpleFeature f3 =
SimpleFeatureBuilder.build(
type,
new Object[] { gf.createPoint(new Coordinate(5, 4)), "A long label\r\nwith windows\r\nnewlines", d, 10, 300.0 },
null);
MemoryDataStore data = new MemoryDataStore();
data.addFeature(f1);
data.addFeature(f2);
data.addFeature(f3);
SimpleFeatureSource fs = data.getFeatureSource("funnyLabels");
// build the request objects and feed the output format
GetFeatureType gft = WfsFactory.eINSTANCE.createGetFeatureType();
Operation op = new Operation("GetFeature", getServiceDescriptor10(), null, new Object[] {gft});
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FeatureCollectionResponse fct =
FeatureCollectionResponse.adapt(WfsFactory.eINSTANCE.createFeatureCollectionType());
fct.getFeature().add(fs.getFeatures());
// write out the results
CSVOutputFormat format = new CSVOutputFormat(getGeoServer());
format.write(fct, bos, op);
// read the response back with a parser that can handle escaping, newlines and what not
List<String[]> lines = readLines(bos.toString());
// we should have one header line and then all the features in that feature type
assertEquals(fs.getCount(Query.ALL) + 1, lines.size());
for (String[] line : lines) {
// check each line has the expected number of elements
assertEquals(fs.getSchema().getAttributeCount() + 1, line.length);
}
// check we have the expected values in the string attributes
assertEquals(f1.getAttribute("label"), lines.get(1)[2]);
assertEquals(f2.getAttribute("label"), lines.get(2)[2]);
// the test CSVReader helpfully turns \r\n into \n for us.
assertEquals(((String) f3.getAttribute("label")).replace("\r\n", "\n"), lines.get(3)[2]);
// dates
assertEquals(DateUtil.serializeDateTime((Date) f1.getAttribute("dtg")), lines.get(1)[3]);
// Numbers
assertEquals(f1.getAttribute("n"), Integer.parseInt(lines.get(1)[4]));
assertEquals(f2.getAttribute("d"), Double.parseDouble(lines.get(2)[5]));
}
/**
* Convenience to read the csv content and
* @param csvContent
*
* @throws IOException
*/
private List<String[]> readLines(String csvContent) throws IOException {
CSVReader reader = new CSVReader(new StringReader(csvContent));
List<String[]> result = new ArrayList<String[]>();
String [] nextLine;
while ((nextLine = reader.readNext()) != null) {
result.add(nextLine);
}
return result;
}
}