package es.upm.fi.dia.oeg.map4rdf.server.servlet;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.json.JSONArray;
import org.json.JSONObject;
import com.fasterxml.jackson.core.JsonFactory.Feature;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import es.upm.fi.dia.oeg.map4rdf.client.util.ConfigurationUtil;
import es.upm.fi.dia.oeg.map4rdf.server.conf.multiple.MultipleConfigurations;
import es.upm.fi.dia.oeg.map4rdf.server.dao.DaoException;
import es.upm.fi.dia.oeg.map4rdf.share.FacetConstraint;
import es.upm.fi.dia.oeg.map4rdf.share.GeoResource;
import es.upm.fi.dia.oeg.map4rdf.share.Geometry;
import es.upm.fi.dia.oeg.map4rdf.share.MultiPolygon;
import es.upm.fi.dia.oeg.map4rdf.share.Point;
import es.upm.fi.dia.oeg.map4rdf.share.PolyLine;
import es.upm.fi.dia.oeg.map4rdf.share.Polygon;
import es.upm.fi.dia.oeg.map4rdf.share.WKTGeometry;
import es.upm.fi.dia.oeg.map4rdf.share.WKTGeometryBean;
@Singleton
public class GeoJSONService extends HttpServlet {
private static final long serialVersionUID = 4940408910832985953L;
private MultipleConfigurations configurations;
private static enum GeoJSON_Types{Point,LineString,Polygon,MultiPolygon};
private static enum WKTTypes{Point, LineString, Polygon,MultiPoint,MultiPolygon,MultiLineString}
private static final String[] reservedParameters = { ConfigurationUtil.CONFIGURATION_ID };
private Logger LOG = Logger.getLogger(GeoJSONService.class);
@Inject
public GeoJSONService(MultipleConfigurations configurations) {
this.configurations = configurations;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Set<FacetConstraint> constraints = getFacetConstraints(req);
String configID = getConfigurationID(req);
try {
List<GeoResource> resources = configurations
.getConfiguration(configID).getMap4rdfDao()
.getGeoResources(null, constraints);
resp.setContentType("application/json");
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"","resources.json");
resp.setHeader(headerKey, headerValue);
writeGeoJSON(resources, resp.getOutputStream());
} catch (DaoException daoException) {
throw new ServletException(daoException);
}
}
private void writeGeoJSON(List<GeoResource> resources,
ServletOutputStream outputStream) {
JSONObject featureCollection = new JSONObject();
try {
featureCollection.put("type", "FeatureCollection");
JSONArray featureList = new JSONArray();
// iterate through your list
for (GeoResource resource : resources) {
featureList.put(getJSONofResource(resource));
featureCollection.put("features", featureList);
}
} catch (Exception e) {
LOG.error("Can't save json object. ", e);
}
try {
outputStream.print(featureCollection.toString());
outputStream.flush();
outputStream.close();
} catch (IOException e) {
LOG.error("Can't print in output stream the result. ", e);
}
}
private JSONObject getJSONofResource(GeoResource resource) throws Exception{
JSONObject toReturn = new JSONObject();
toReturn.put("type", "Feature");
JSONObject properties = new JSONObject();
properties.put("uri", resource.getUri());
JSONObject labels = new JSONObject();
for(String lang:resource.getLangs()){
labels.put(lang, resource.getLabel(lang));
}
properties.put("labels", labels);
toReturn.put("properties", properties);
for (Geometry geometry : resource.getGeometries()) {
switch (geometry.getType()) {
case POINT:
Point point = (Point) geometry;
toReturn.put("geometry", getJSONofPoint(point));
break;
case POLYGON:
Polygon polygon = (Polygon) geometry;
toReturn.put("geometry", getJSONofPolygon(polygon));
break;
case CIRCLE:
//Circle circle = (Circle) geometry;
//TODO Implement GeoJSON circle
break;
case MULTIPOLYGON:
MultiPolygon multiPolygon = (MultiPolygon) geometry;
toReturn.put("geometry", getJSONofMultiPolygon(multiPolygon));
break;
case POLYLINE:
PolyLine polyLine = (PolyLine) geometry;
toReturn.put("geometry", getJSONofPolyline(polyLine));
break;
case WKTGEOMETRY:
WKTGeometry wkt = (WKTGeometry)geometry;
toReturn.put("geometry", getJSONofWKT(wkt));
break;
default:
break;
}
}
return toReturn;
}
private JSONObject getJSONofWKT(WKTGeometry geometryWKT){
JSONObject toReturn = new JSONObject();
String wkt = geometryWKT.getWKT();
String realWKTText="";
int firtsIndex=-1;
for(WKTTypes i: WKTTypes.values()){
int index=wkt.toLowerCase().indexOf(i.toString().toLowerCase());
if(index>=0 && (index<firtsIndex || firtsIndex==-1)){
firtsIndex=index;
}
}
if(firtsIndex==-1){
return null;
}
realWKTText=wkt.substring(firtsIndex, wkt.length());
com.vividsolutions.jts.geom.GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
WKTReader reader = new WKTReader(geometryFactory);
try {
com.vividsolutions.jts.geom.Geometry geometry = reader.read(realWKTText);
GeometryJSON gjson = new GeometryJSON();
StringWriter writer = new StringWriter();
gjson.write(geometry, writer);
String json = writer.toString();
toReturn = new JSONObject(json);
} catch (ParseException e) {
return null;
} catch (IOException e) {
return null;
}
return toReturn;
}
private JSONObject getJSONofPoint(Point geometryPoint) {
JSONObject point = new JSONObject();
point.put("type", GeoJSON_Types.Point.toString());
JSONArray coord = new JSONArray();
coord.put(geometryPoint.getX());
coord.put(geometryPoint.getY());
point.put("coordinates", coord);
return point;
}
private JSONObject getJSONofPolygon(Polygon polygon) {
JSONObject polygonJSON = new JSONObject();
polygonJSON.put("type", GeoJSON_Types.Polygon.toString());
JSONArray allPolygons = new JSONArray();
JSONArray onePolygon = new JSONArray();
for(Point point: polygon.getPoints()){
JSONArray coord = new JSONArray();
coord.put(point.getX());
coord.put(point.getY());
onePolygon.put(coord);
}
allPolygons.put(onePolygon);
polygonJSON.put("coordinates", allPolygons);
return polygonJSON;
}
private JSONObject getJSONofMultiPolygon(MultiPolygon multiPolygon) {
JSONObject multiPolygonJSON = new JSONObject();
multiPolygonJSON.put("type", GeoJSON_Types.MultiPolygon.toString());
JSONArray polygonsArray = new JSONArray();
for(Polygon polygon: multiPolygon.getPolygons()){
JSONArray allPolygons = new JSONArray();
JSONArray onePolygon = new JSONArray();
for(Point point: polygon.getPoints()){
JSONArray coord = new JSONArray();
coord.put(point.getX());
coord.put(point.getY());
onePolygon.put(coord);
}
allPolygons.put(onePolygon);
polygonsArray.put(allPolygons);
}
multiPolygonJSON.put("coordinates", polygonsArray);
return multiPolygonJSON;
}
private JSONObject getJSONofPolyline(PolyLine polyLine) {
JSONObject polylineJSON = new JSONObject();
polylineJSON.put("type", GeoJSON_Types.LineString.toString());
JSONArray lineString = new JSONArray();
for(Point point: polyLine.getPoints()){
JSONArray coord = new JSONArray();
coord.put(point.getX());
coord.put(point.getY());
lineString.put(coord);
}
polylineJSON.put("coordinates", lineString);
return polylineJSON;
}
private Set<FacetConstraint> getFacetConstraints(HttpServletRequest req) {
Set<FacetConstraint> constraints = new HashSet<FacetConstraint>();
Enumeration<String> paramNames = (Enumeration<String>) req
.getParameterNames();
while (paramNames.hasMoreElements()) {
String facetId = paramNames.nextElement();
boolean isReservedParam = false;
for (String toTest : reservedParameters) {
if (toTest.toLowerCase().trim()
.equals(facetId.toLowerCase().trim())) {
isReservedParam = true;
break;
}
}
if (!isReservedParam) {
String[] valueIds = req.getParameterValues(facetId);
for (String valueId : valueIds) {
constraints.add(new FacetConstraint(facetId, valueId));
}
}
}
return constraints;
}
private String getConfigurationID(HttpServletRequest req)
throws ServletException {
String value = req.getParameter(ConfigurationUtil.CONFIGURATION_ID);
if (value == null || value.isEmpty()) {
throw new ServletException("Bad parameter value of parameter key: "
+ ConfigurationUtil.CONFIGURATION_ID);
}
return value;
}
}