/* Copyright (c) 2001 - 2011 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.geosearch.rest;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogInfo;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.ows.util.KvpMap;
import org.geoserver.rest.AbstractResource;
import org.geoserver.rest.RestletException;
import org.geoserver.rest.format.DataFormat;
import org.geoserver.rest.util.RESTUtils;
import org.geoserver.wms.DefaultWebMapService;
import org.geoserver.wms.GetMap;
import org.geoserver.wms.GetMapOutputFormat;
import org.geoserver.wms.GetMapRequest;
import org.geoserver.wms.MapLayerInfo;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSMapContent;
import org.geoserver.wms.WebMap;
import org.geoserver.wms.map.GetMapKvpRequestReader;
import org.geoserver.wms.map.XMLTransformerMap;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.util.logging.Logging;
import org.restlet.Context;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.Representation;
import org.springframework.util.Assert;
/**
* @author groldan
* @see LayerKMLDocumentFormat
*/
public class GeoSearchLayer extends AbstractResource {
private static final Logger LOGGER = Logging.getLogger(GeoSearchLayer.class);
private final CatalogInfo layer;
private final GeoServer geoserver;
public GeoSearchLayer(final Context context, final Request request, final Response response,
final CatalogInfo layer, GeoServer geoserver) {
super(context, request, response);
this.layer = layer;
this.geoserver = geoserver;
}
@Override
public void handleGet() {
final WMS wms = new WMS(geoserver) {
/**
* Override to KMLMetadataDocumentMapOutputFormat does not need to be in the spring
* context and hence available to the whole geoserver
*
* @see org.geoserver.wms.WMS#getMapOutputFormat(java.lang.String)
*/
@Override
public GetMapOutputFormat getMapOutputFormat(final String mimeType) {
if (KMLMetadataDocumentMapOutputFormat.MIME_TYPE.equals(mimeType)) {
return new KMLMetadataDocumentMapOutputFormat(this);
}
return super.getMapOutputFormat(mimeType);
}
};
GetMapKvpRequestReader reader = new GetMapKvpRequestReader(wms);
reader.setHttpRequest(RESTUtils.getServletRequest(getRequest()));
GetMapRequest getMapRequest = getRequest(layer);
final String title;
final String description;
String[] keywords = {};
if (layer instanceof LayerInfo) {
LayerInfo layerInfo = (LayerInfo) layer;
title = layerInfo.getResource().getTitle();
description = layerInfo.getResource().getAbstract();
List<String> kws = layerInfo.getResource().keywordValues();
if (kws != null) {
keywords = kws.toArray(new String[kws.size()]);
}
} else {
LayerGroupInfo lgi = (LayerGroupInfo) layer;
title = getTitle(lgi);
description = getDescription(lgi);
keywords = getKeyWords(lgi);
}
WMSMapContent context = new WMSMapContent(getMapRequest);
context.setTitle(title);
context.setAbstract(description);
context.setKeywords(keywords);
context.setMapWidth(getMapRequest.getWidth());
context.setMapHeight(getMapRequest.getHeight());
context.getViewport().setBounds((ReferencedEnvelope) getMapRequest.getBbox());
WebMap webMap;
try {
webMap = new GetMap(wms).run(getMapRequest, context);
} catch (Exception e) {
e.printStackTrace();
throw new RestletException(e.getMessage(), Status.SERVER_ERROR_INTERNAL, e);
}
// final WebMap webMap = wmsService.getMap(getMapRequest);
Assert.isTrue(webMap instanceof XMLTransformerMap);
DataFormat format = getFormatGet();
Representation representation = format.toRepresentation(webMap);
Response response = getResponse();
response.setEntity(representation);
}
/**
* @see org.geoserver.rest.AbstractResource#createSupportedFormats(org.restlet.data.Request,
* org.restlet.data.Response)
*/
@Override
protected List<DataFormat> createSupportedFormats(final Request request, final Response response) {
final List<DataFormat> siteMapFormats = new ArrayList<DataFormat>(1);
siteMapFormats.add(new LayerKMLDocumentFormat());
return siteMapFormats;
}
@SuppressWarnings("unchecked")
private GetMapRequest getRequest(CatalogInfo info) {
GetMapRequest request = new GetMapRequest();
request.setVersion("1.1.1");
Catalog catalog = geoserver.getCatalog();
List<MapLayerInfo> layers = expandLayers(catalog, info);
request.setLayers(layers);
request.setFormat(KMLMetadataDocumentMapOutputFormat.MIME_TYPE);
request.setBbox(getLatLonBbox(info));
request.setSRS("EPSG:4326");
// proxy aware base url?
String baseurl = getRequest().getRootRef().getParentRef().toString();
request.setBaseUrl(baseurl);
request.setRawKvp(new KvpMap());
int maxFeatures = 1000;
if (info instanceof LayerGroupInfo) {
maxFeatures = maxFeatures / ((LayerGroupInfo) info).getLayers().size();
}
request.setMaxFeatures(maxFeatures);
try {
DefaultWebMapService.autoSetMissingProperties(request);
} catch (Exception e) {
throw new RestletException(
"Could not set figure out automatically a good preview link for " + info,
Status.SERVER_ERROR_INTERNAL, e);
}
return request;
}
private ReferencedEnvelope getLatLonBbox(CatalogInfo info) {
if (info instanceof LayerInfo) {
return ((LayerInfo) info).getResource().getLatLonBoundingBox();
}
LayerGroupInfo lgi = (LayerGroupInfo) info;
ReferencedEnvelope latLonBoundingBox;
latLonBoundingBox = lgi.getBounds();
try {
latLonBoundingBox = latLonBoundingBox.transform(DefaultGeographicCRS.WGS84, true);
} catch (Exception e) {
LOGGER.log(Level.INFO, "Error transforming " + lgi.getName()
+ " LayerGroup's bounds to EPSG:4326", e);
latLonBoundingBox = new ReferencedEnvelope(DefaultGeographicCRS.WGS84);
try {
for (LayerInfo li : lgi.getLayers()) {
ReferencedEnvelope llbb = li.getResource().getLatLonBoundingBox();
latLonBoundingBox.expandToInclude(llbb.transform(DefaultGeographicCRS.WGS84,
true));
}
} catch (Exception e2) {
throw new RuntimeException(e2);
}
}
return latLonBoundingBox;
}
/**
* Expands the specified name into a list of layer info names
*/
private List<MapLayerInfo> expandLayers(Catalog catalog, CatalogInfo info) {
List<MapLayerInfo> layers = new ArrayList<MapLayerInfo>();
if (info instanceof LayerInfo) {
layers.add(new MapLayerInfo((LayerInfo) info));
} else {
for (LayerInfo l : ((LayerGroupInfo) info).getLayers()) {
layers.add(new MapLayerInfo(l));
}
}
return layers;
}
private String[] getKeyWords(LayerGroupInfo lgi) {
Set<String> kws = new TreeSet<String>();
for (LayerInfo li : lgi.getLayers()) {
List<String> keywords = li.getResource().keywordValues();
if (keywords != null) {
kws.addAll(keywords);
}
}
return kws.toArray(new String[kws.size()]);
}
private String getDescription(LayerGroupInfo lgi) {
StringBuilder desc = new StringBuilder();
for (LayerInfo li : lgi.getLayers()) {
desc.append(li.getResource().getPrefixedName());
desc.append(": ");
String lidesc = li.getResource().getAbstract();
if (lidesc != null) {
desc.append(lidesc);
}
desc.append("\n");
}
return desc.toString();
}
private String getTitle(LayerGroupInfo lgi) {
StringBuilder title = new StringBuilder("Layer Group composed of: ");
for (LayerInfo li : lgi.getLayers()) {
title.append("\"").append(li.getResource().getTitle()).append("\" ");
}
return title.toString();
}
}