/* Copyright (c) 2001 - 2007 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.vfny.geoserver.wms.requests;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.MapLayerInfo;
import org.geoserver.wms.WMS;
import org.geoserver.wms.kvp.GetMapKvpRequestReader;
import org.vfny.geoserver.Request;
import org.vfny.geoserver.wms.WmsException;
/**
* Builds a GetFeatureInfo request object given by a set of CGI parameters supplied in the
* constructor.
*
* <p>
* Request parameters:
* </p>
*
* @author Gabriel Roldan, Axios Engineering
* @version $Id: GetFeatureInfoKvpReader.java 13268 2009-09-03 10:14:04Z aaime $
*/
public class GetFeatureInfoKvpReader extends WmsKvpRequestReader {
/** DOCUMENT ME! */
private static final Logger LOGGER = org.geotools.util.logging.Logging
.getLogger("org.vfny.geoserver.requests.readers.wms");
/** the request wich will be built by getRequest method */
private GetFeatureInfoRequest request;
/** GetMap request reader used to parse the map context parameters needed. */
private GetMapKvpRequestReader getMapReader;
/**
* Creates a new GetMapKvpReader object.
*
* @param kvpPairs
* Key Values pairs of the request
* @param wms
* The wms config object.
*/
public GetFeatureInfoKvpReader(Map kvpPairs, WMS wms) {
super(kvpPairs, wms);
getMapReader = new GetMapKvpRequestReader(wms);
}
/**
* Produces a <code>GetMapRequest</code> instance by parsing the GetMap mandatory, optional and
* custom parameters.
*
* @param httpRequest
* the servlet request who's application object holds the server configuration
*
* @return a <code>GetMapRequest</code> completely setted up upon the parameters passed to this
* reader
*
* @throws ServiceException
* DOCUMENT ME!
* @throws WmsException
* DOCUMENT ME!
*/
public Request getRequest(HttpServletRequest httpRequest) throws ServiceException {
// WMService service = (WMService) getServiceRef();
// WMS wms = service.getWMS();
request = new GetFeatureInfoRequest(getWMS());
request.setHttpServletRequest(httpRequest);
String version = getRequestVersion();
request.setVersion(version);
//getMapReader.setFormatRequired(false);
GetMapRequest getMapPart = new GetMapRequest(getWMS());
try {
getMapPart = getMapReader.read(getMapPart, super.kvpPairs, super.kvpPairs);
} catch (Exception e) {
throw new WmsException(e);
}
request.setGetMapRequest(getMapPart);
// parse query layers
request.setQueryLayers(parseLayers(getWMS()));
// make sure they are a subset of layers
List<MapLayerInfo> getMapLayers = new ArrayList(Arrays.asList(getMapPart.getLayers()));
List<MapLayerInfo> queryLayers = new ArrayList<MapLayerInfo>(Arrays.asList(request.getQueryLayers()));
queryLayers.removeAll(getMapLayers);
if(queryLayers.size() > 0) {
// we've already expanded base layers so let's avoid list the names, they are not
// the original ones anymore
throw new WmsException("QUERY_LAYERS contains layers not cited in LAYERS. " +
"It should be a proper subset of those instead");
}
String format = getValue("INFO_FORMAT");
if (format == null) {
// HACK: how we define the default info format?
// Not sure I understand the question. If we don't like it here
// then put it as the default in the FeatureInfoRequest. If
// we want to allow users to be able to set it then we can put
// it as a config parameter in the WMS service section. -ch
format = "text/plain";
} else {
final List formats = org.vfny.geoserver.wms.responses.GetFeatureInfoResponse
.getFormats();
if (!formats.contains(format)) {
throw new WmsException("Invalid format '" + format + "', supported formats are "
+ formats, "InvalidParameterValue", "info_format");
}
}
request.setInfoFormat(format);
request.setFeatureCount(1); // DJB: according to the WMS spec (7.3.3.7 FEATURE_COUNT) this
// should be 1. also tested for by cite
try {
int maxFeatures = Integer.parseInt(getValue("FEATURE_COUNT"));
request.setFeatureCount(maxFeatures);
} catch (NumberFormatException ex) {
// do nothing, FEATURE_COUNT is optional
}
try {
int x = Integer.parseInt(getValue("X"));
int y = Integer.parseInt(getValue("Y"));
request.setXPixel(x);
request.setYPixel(y);
} catch (NumberFormatException ex) {
throw new WmsException("X and Y incorrectly specified");
}
String exceptionsFormat = getValue("EXCEPTIONS");
request.setExeptionFormat(exceptionsFormat);
return request;
}
/**
* Obtains the FeatureTypeInfo objects of the layers to query given by the
* <code>QUERY_LAYERS</code>parameter.
*
* @return the list of layers to query.
*
* @throws WmsException
* if the parameter <code>QUERY_LAYERS</code> does not exists, has no layer names,
* or has at least an invalid layer name.
*/
private MapLayerInfo[] parseLayers(WMS wms) throws WmsException {
final List<String> queryLayers = readFlat(getValue("QUERY_LAYERS"), INNER_DELIMETER);
// expand base layers, if there is any
// if(wms.getBaseMapLayers() != null) {
// for (int i = 0; i < layers.size(); i++) {
// String layerGroup = (String) wms.getBaseMapLayers().get(layers.get(i));
// if(layerGroup != null) {
// List layerGroupExpanded = readFlat(layerGroup, INNER_DELIMETER);
// layers.remove(i);
// layers.addAll(i, layerGroupExpanded);
// }
// }
// }
if (queryLayers.size() == 0) {
throw new WmsException("No QUERY_LAYERS has been requested, or no "
+ "queriable layer in the request anyways", getClass().getName());
}
List<MapLayerInfo> layerInfos = new ArrayList<MapLayerInfo>();
for (String layerName : queryLayers) {
LayerInfo layerInfo = wms.getLayerByName(layerName);
if (layerInfo == null) {
LayerGroupInfo layerGroup = wms.getLayerGroupByName(layerName);
if (layerGroup == null) {
throw new WmsException("Layer " + layerName + " does not exist",
"LayerNotDefined");
}
for (LayerInfo li : layerGroup.getLayers()) {
layerInfos.add(new MapLayerInfo(li));
}
} else {
layerInfos.add(new MapLayerInfo(layerInfo));
}
}
return layerInfos.toArray(new MapLayerInfo[layerInfos.size()]);
}
}