/* Copyright (c) 2001 - 2009 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.sfs;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.sf.json.JSONArray;
import org.apache.commons.io.IOUtils;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.rest.format.StreamDataFormat;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.json.simple.JSONObject;
import org.opengis.referencing.FactoryException;
import org.restlet.data.MediaType;
/**
* Streams out all the enabled feture type layers into a Simple Feature Service capabilities
* document
*
* @author Andrea Aime - GeoSolutions
*
*/
public class CapabilitiesJSONFormat extends StreamDataFormat {
protected CapabilitiesJSONFormat() {
super(MediaType.APPLICATION_JSON);
}
@Override
protected Object read(InputStream in) throws IOException {
throw new UnsupportedOperationException("Can't read capabilities documents with this class");
}
@Override
protected void write(Object object, OutputStream out) throws IOException {
Catalog catalog = (Catalog) object;
Writer writer = null;
try {
writer = new OutputStreamWriter(out);
writer.write("[");
// write out the layers
List<LayerInfo> layers = getFeatureTypeLayers(catalog);
for (Iterator it = layers.iterator(); it.hasNext();) {
LayerInfo layerInfo = (LayerInfo) it.next();
Map json = toJSON(layerInfo);
JSONObject.writeJSONString(json, writer);
if (it.hasNext()) {
writer.write(",\n");
}
}
writer.write("]");
} finally {
IOUtils.closeQuietly(writer);
}
}
/**
* Maps a layer info to the capabilities json structure. Using a linked hash map under covers to
* preserve the order of the attributes
*
* @param layerInfo
* @return
* @throws IOException
*/
private Map toJSON(LayerInfo layerInfo) throws IOException {
final ResourceInfo resource = layerInfo.getResource();
try {
LinkedHashMap json = new LinkedHashMap();
json.put("name", resource.getPrefixedName());
try {
json.put("bbox", toJSON(resource.boundingBox()));
} catch(Exception e) {
throw ((IOException) new IOException("Failed to get the resource bounding box of:" + resource.getPrefixedName()).initCause(e));
}
json.put("crs", "urn:ogc:def:crs:EPSG:" + CRS.lookupEpsgCode(resource.getCRS(), false));
json.put("axisorder", "xy");
return json;
} catch (FactoryException e) {
throw ((IOException) new IOException("Failed to lookup the EPSG code").initCause(e));
}
}
/**
* Maps a referenced envelope into a json bbox
*
* @param bbox
* @return
*/
private JSONArray toJSON(ReferencedEnvelope bbox) {
JSONArray json = new JSONArray();
json.add(bbox.getMinX());
json.add(bbox.getMinY());
json.add(bbox.getMaxX());
json.add(bbox.getMaxY());
return json;
}
/**
* Finds all the enabled layers mapped to a FeatureTypeInfo
*
* @param catalog
* @return
*/
List<LayerInfo> getFeatureTypeLayers(Catalog catalog) {
// TODO: use a query/streaming mechanism once we have catalog queries to avoid
// loading a million layers in memory
List<LayerInfo> layers = new ArrayList(catalog.getLayers());
for (Iterator it = layers.iterator(); it.hasNext();) {
LayerInfo layerInfo = (LayerInfo) it.next();
if (!layerInfo.isEnabled()) {
it.remove();
} else if (!(layerInfo.getResource() instanceof FeatureTypeInfo)) {
it.remove();
}
}
return layers;
}
}