/* (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.json;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import org.apache.commons.io.IOUtils;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.ows.Dispatcher;
import org.geoserver.ows.Request;
import org.geoserver.platform.Operation;
import org.geoserver.platform.ServiceException;
import org.geoserver.wfs.WFSDescribeFeatureTypeOutputFormat;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import com.vividsolutions.jts.geom.Geometry;
/**
* A DescribeFeatureType output format that generates a JSON schema instead of a XML one
*
* @author Andrea Aime - GeoSolutions
* @author Carlo Cancellieri - GeoSolutions
*
*/
public class JSONDescribeFeatureTypeResponse extends WFSDescribeFeatureTypeOutputFormat {
// private final static Logger LOGGER = Logging.getLogger(JSONDescribeFeatureTypeResponse.class);
public JSONDescribeFeatureTypeResponse(GeoServer gs, final String mime) {
super(gs, mime);
}
@Override
protected void write(FeatureTypeInfo[] featureTypeInfos, OutputStream output,
Operation describeFeatureType) throws IOException {
if (featureTypeInfos.length == 0) {
throw new IOException("Unable to write an empty feature info array.");
}
// prepare to write out
OutputStreamWriter osw = null;
Writer outWriter = null;
try {
osw = new OutputStreamWriter(output, gs.getSettings().getCharset());
outWriter = new BufferedWriter(osw);
// jsonp?
final boolean jsonp = JSONType.useJsonp(getMimeType(featureTypeInfos,
describeFeatureType));
if (jsonp) {
outWriter.write(getCallbackFunction() + "(");
}
// starting with JSon
GeoJSONBuilder jw = new GeoJSONBuilder(outWriter);
jw.object();
jw.key("elementFormDefault");
jw.value("qualified");
jw.key("targetNamespace");
NamespaceInfo nsInfo = featureTypeInfos[0].getNamespace();
jw.value(nsInfo.getURI());
jw.key("targetPrefix");
jw.value(nsInfo.getName());
jw.key("featureTypes");
// in general one can describe more than one feature type
jw.array();
for (int i = 0; i < featureTypeInfos.length; i++) {
FeatureTypeInfo ft = featureTypeInfos[i];
jw.object();
jw.key("typeName").value(ft.getName());
SimpleFeatureType schema = (SimpleFeatureType) ft.getFeatureType();
jw.key("properties");
jw.array();
for (AttributeDescriptor ad : schema.getAttributeDescriptors()) {
if (ad == schema.getGeometryDescriptor()) {
// this one we already described
describeProperty(ad.getLocalName(), ad, jw, true);
} else {
describeProperty(ad.getLocalName(), ad, jw, false);
}
}
jw.endArray();
jw.endObject(); // end of the feature type schema
}
jw.endArray();
jw.endObject();
// jsonp?
if (jsonp) {
outWriter.write(")");
}
outWriter.flush();
} finally {
IOUtils.closeQuietly(osw);
IOUtils.closeQuietly(outWriter);
}
}
private String getCallbackFunction() {
Request request = Dispatcher.REQUEST.get();
if (request == null) {
return JSONType.CALLBACK_FUNCTION;
}
return JSONType.getCallbackFunction(request.getKvp());
}
private static void describeProperty(String name, AttributeDescriptor ad, GeoJSONBuilder jw,
boolean isGeometry) {
jw.object();
jw.key("name").value(name);
jw.key("maxOccurs").value(ad.getMaxOccurs());
jw.key("minOccurs").value(ad.getMinOccurs());
jw.key("nillable").value((ad.getMinOccurs() > 0) ? false : true);
Class<?> binding = ad.getType().getBinding();
if (isGeometry) {
jw.key("type").value("gml:" + mapToJsonType(binding));
} else {
jw.key("type").value("xsd:" + mapToJsonType(binding));
}
jw.key("localType").value(mapToJsonType(binding));
jw.endObject(); // end of attribute description
}
private static String mapToJsonType(Class<?> binding) {
if (Long.class.isAssignableFrom(binding) || Integer.class.isAssignableFrom(binding)
|| Short.class.isAssignableFrom(binding) || Byte.class.isAssignableFrom(binding)) {
return "int";
} else if (Number.class.isAssignableFrom(binding)) {
return "number";
} else if (Boolean.class.isAssignableFrom(binding)) {
return "boolean";
} else if (Geometry.class.isAssignableFrom(binding)) {
return binding.getSimpleName();
} else if (java.sql.Date.class.isAssignableFrom(binding)) {
return "date";
} else if (java.sql.Time.class.isAssignableFrom(binding)) {
return "time";
} else if (java.util.Date.class.isAssignableFrom(binding)) {
return "date-time";
} else {
return "string";
}
}
@Override
public String getMimeType(Object value, Operation operation) throws ServiceException {
return getOutputFormat();
}
}