/*
* $Header: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/image/wms/WmsRequestHandler.java,v 1.5 2008/10/16 03:30:35 dietrick Exp $
*
* Copyright 2001-2005 OBR Centrum Techniki Morskiej, All rights reserved.
*
*/
package com.bbn.openmap.image.wms;
import java.awt.Color;
import java.awt.Paint;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
import com.bbn.openmap.Layer;
import com.bbn.openmap.event.ProjectionEvent;
import com.bbn.openmap.image.ImageFormatter;
import com.bbn.openmap.image.ImageServer;
import com.bbn.openmap.image.ImageServerConstants;
import com.bbn.openmap.image.MapRequestFormatException;
import com.bbn.openmap.proj.AspectRatioProjection;
import com.bbn.openmap.proj.GeoProj;
import com.bbn.openmap.proj.Proj;
import com.bbn.openmap.proj.ProjectionFactory;
import com.bbn.openmap.proj.coords.CoordinateReferenceSystem;
import com.bbn.openmap.proj.coords.LatLonPoint;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PropUtils;
import com.bbn.openmap.util.http.HttpConnection;
import com.bbn.openmap.util.http.IHttpResponse;
/**
* @version $Header:
* /cvs/CVS_LEBA/external/openmap/openmap/src/openmap/com/bbn/openmap
* /wms/WmsRequestHandler.java,v 1.2 2006/03/27 10:51:13 tomrak Exp $
* @author Adam Dawidowski
* @author wachu
* @author pitek
*/
public class WmsRequestHandler extends ImageServer implements ImageServerConstants {
/**
*/
private CapabilitiesSupport capabilities;
private Map<String, IWmsLayer> wmsLayerByName = new HashMap<String, IWmsLayer>();
private List<IWmsLayer> wmsLayers = new ArrayList<IWmsLayer>();
private WmsLayerFactory wmsLayerFactory;
private Map<String, ImageFormatter> imageFormatterByContentType = new HashMap<String, ImageFormatter>();
private FeatureInfoResponse featureInfoResponse;
public static final String WMSPrefix = CapabilitiesSupport.WMSPrefix;
private static final String FeatureInfoResponseClassNameProperty = "featureInfoResponse.class";
/**
* Creates a new WmsRequestHandler object.
*
* @param wmsScheme for capabilities description
* @param wmsHostName for capabilities description
* @param wmsPort for capabilities description
* @param wmsUrlPath for capabilities description
* @param props openmap properties to configure layers
* @throws IOException
* @throws WMSException
*/
public WmsRequestHandler(String wmsScheme, String wmsHostName, int wmsPort, String wmsUrlPath,
Properties props) throws IOException, WMSException {
super(props);
setProperties(props);
// separate antialias property for wms.
boolean antialias = PropUtils.booleanFromProperties(props, WMSPrefix + AntiAliasingProperty, false);
setDoAntiAliasing(antialias);
// for each Openmap Layer created by ImageServer (defined in properties)
// create corresponding IWmsLayer which contains all necessary
// information required by
// WMS (e.g getCapabilities method)
wmsLayerFactory = new WmsLayerFactory(props);
createWmsLayers();
// create a Map of all formatters by their contentType
for (ImageFormatter formatter : getFormatters().values()) {
imageFormatterByContentType.put(formatter.getContentType(), formatter);
}
// create FeatureInfoResponse from properties.
featureInfoResponse = (FeatureInfoResponse) PropUtils.objectFromProperties(props, WMSPrefix
+ FeatureInfoResponseClassNameProperty);
if (featureInfoResponse == null) {
featureInfoResponse = new DefaultFeatureInfoResponse();
}
// read from configuration fixed part of Capabilities Document returned
// in getCapabilities method
capabilities = new CapabilitiesSupport(props, wmsScheme, wmsHostName, wmsPort, wmsUrlPath);
List<String> formatsList = new ArrayList<String>(imageFormatterByContentType.keySet());
capabilities.setFormats(CapabilitiesSupport.FMT_GETMAP, formatsList);
capabilities.setFormats(CapabilitiesSupport.FMT_GETFEATUREINFO, getFeatureInfoResponse().getInfoFormats());
}
/**
* For each layer managed by ImageServer create corresponding IWmsLayer
* which contains additional information for WMS service about given openmap
* layer.
*
* For Layers that already implement IWmsLayer, the instances will be the
* same.
*/
protected void createWmsLayers() {
wmsLayerByName.clear();
wmsLayers.clear();
for (int i = 0; i < layers.length; i++) {
Layer layer = layers[i];
createWmsLayers(wmsLayerFactory.createWmsLayer(layer));
}
}
private void createWmsLayers(IWmsLayer layer) {
wmsLayerByName.put(layer.getWmsName(), layer);
wmsLayers.add(layer);
if (layer instanceof IWmsNestedLayer) {
IWmsNestedLayer n = (IWmsNestedLayer) layer;
if (n.getNestedLayers() != null) {
for (int i = 0; i < n.getNestedLayers().length; i++) {
createWmsLayers(n.getNestedLayers()[i]);
}
}
}
}
/**
* Set the request parameters on all the layers
*
* @see IWmsLayer#setRequestParameters(Properties requestParameters)
* @param requestProperties
*/
protected void setRequestParametersOnLayers(Properties requestProperties) {
// use a Set to make sure we only set it once for each layer
Set<String> handledNames = new HashSet<String>();
for (IWmsLayer wmsLayer : wmsLayers) {
if (!handledNames.contains(wmsLayer.getWmsName())) {
wmsLayer.setRequestParameters(requestProperties);
handledNames.add(wmsLayer.getWmsName());
}
if (wmsLayer instanceof IWmsNestedLayer) {
IWmsNestedLayer nestedLayer = (IWmsNestedLayer) wmsLayer;
// make sure the top layer also get info about the request
// parameters
if (!handledNames.contains(nestedLayer.getTopLayer().getWmsName())) {
nestedLayer.getTopLayer().setRequestParameters(requestProperties);
handledNames.add(nestedLayer.getTopLayer().getWmsName());
}
}
}
}
protected IWmsLayer getLayerByName(String wmsName) {
return (IWmsLayer) wmsLayerByName.get(wmsName);
}
/**
* Return the top OpenMap {@link Layer} for the given wms layer name.
*
* @param wmsName
* @return top layer
*/
protected Layer getTopLayerByName(String wmsName) {
IWmsLayer layer = getLayerByName(wmsName);
if (layer == null) {
return null;
}
if (layer instanceof IWmsNestedLayer) {
layer = ((IWmsNestedLayer) layer).getTopLayer();
}
if (layer instanceof DefaultLayerAdapter) {
return ((DefaultLayerAdapter) layer).layer;
}
if (layer instanceof Layer) {
return (Layer) layer;
}
throw new IllegalStateException("Top layer must be a OpenMap Layer, not "
+ layer.getClass());
}
/**
* @param requestProperties
* @param httpResponse output
* @throws IOException
* @throws MapRequestFormatException
*/
public void handleRequest(Properties requestProperties, IHttpResponse httpResponse)
throws IOException, MapRequestFormatException {
try {
String requestType = requestProperties.getProperty(REQUEST);
checkRequest(requestProperties);
if (requestType == null) {
throw new WMSException("Missing REQUEST type parameter");
}
setRequestParametersOnLayers(requestProperties);
if (requestType.equalsIgnoreCase(GETMAP)) {
Debug.message("ms", "OGCMRH: GetMap request...");
handleGetMapRequest(requestProperties, httpResponse);
} else if (requestType.equals(GETCAPABILITIES)) {
Debug.message("ms", "OGCMRH: GetCapabilities request...");
handleGetCapabilitiesRequest(requestProperties, httpResponse);
} else if (requestType.equalsIgnoreCase(GETFEATUREINFO)) {
Debug.message("ms", "OGCMRH: GetFeatureInfo request...");
handleGetFeatureInfoRequest(requestProperties, httpResponse);
} else if (requestType.equalsIgnoreCase(GETLEGENDGRAPHIC)) {
Debug.message("ms", "OGCMRH: GetFeatureInfo request...");
handleGetLegendGraphicRequest(requestProperties, httpResponse);
} else {
throw new WMSException("Invalid REQUEST parameter: " + requestType, WMSException.OPERATIONNOTSUPPORTED);
}
} catch (WMSException e) {
Debug.output("WMSException(" + e.getCode() + "): " + e.getMessage());
httpResponse.writeHttpResponse("application/vnd.ogc.se_xml", e.getXML());
}
}
/**
* @param requestProperties
* @param httpResponse output
* @throws IOException
* @throws MapRequestFormatException
* @throws WMSException
*/
public void handleGetMapRequest(Properties requestProperties, IHttpResponse httpResponse)
throws IOException, MapRequestFormatException, WMSException {
byte[] image = handleGetMapRequest(requestProperties);
if (Debug.debugging("imageserver")) {
Debug.output("OGCMRH: have completed image, size " + image.length);
}
String contentType = getFormatter().getContentType();
if (contentType == null) {
contentType = HttpConnection.CONTENT_PLAIN;
}
httpResponse.writeHttpResponse(contentType, image);
}
/**
* @param requestProperties
* @return byte array for image, formatted
* @throws IOException
* @throws MapRequestFormatException
* @throws WMSException
*/
public byte[] handleGetMapRequest(Properties requestProperties)
throws IOException, MapRequestFormatException, WMSException {
GetMapRequestParameters parameters = new GetMapRequestParameters();
checkVersion(requestProperties, parameters);
checkExceptions(requestProperties, parameters);
checkFormat(requestProperties, parameters);
setFormatter(parameters.formatter);
checkBackground(requestProperties, parameters);
Paint bgPaint = parameters.background;
checkProjectionType(requestProperties, parameters);
checkWidthAndHeight(requestProperties, parameters);
checkBoundingBox(requestProperties, parameters);
Proj projection = createProjection(requestProperties, parameters);
checkLayersAndStyles(requestProperties, parameters);
Debug.message("ms", "handleGetMapRequest: createImage layers:"
+ parameters.topLayerNames.toString());
return createImage(projection, parameters.width, parameters.height, parameters.topLayerNames, bgPaint);
}
public byte[] handleGetLegendGraphicRequest(Properties requestProperties)
throws IOException, MapRequestFormatException, WMSException {
GetLegendGraphicRequestParameters parameters = new GetLegendGraphicRequestParameters();
checkVersion(requestProperties, parameters);
checkExceptions(requestProperties, parameters);
checkWidthAndHeight(requestProperties, parameters);
checkFormat(requestProperties, parameters);
setFormatter(parameters.getFormatter());
checkLayerAndStyle(requestProperties, parameters);
Debug.message("ms", "handleGetLegendGraphic: createImage layer:" + parameters.layerName);
IWmsLayer layer = wmsLayerByName.get(parameters.layerName);
ImageFormatter imageFormatter = formatter.makeClone();
java.awt.Graphics graphics = createGraphics(imageFormatter, parameters.getWidth(), parameters.getHeight());
if (graphics == null) {
return new byte[0];
}
Legend legend = layer.getLegend();
if (legend != null) {
legend.setSize(parameters.getWidth(), parameters.getHeight());
legend.paint(graphics);
}
byte[] formattedImage = getFormattedImage(imageFormatter, parameters.getWidth(), parameters.getHeight());
graphics.dispose();
return formattedImage;
}
/**
* @param requestProperties
* @param httpResponse out
* @throws IOException
* @throws MapRequestFormatException
* @throws WMSException
*/
public void handleGetCapabilitiesRequest(Properties requestProperties,
IHttpResponse httpResponse)
throws IOException, MapRequestFormatException, WMSException {
String response = handleGetCapabilitiesRequest(requestProperties);
httpResponse.writeHttpResponse(HttpConnection.CONTENT_XML, response.getBytes("UTF-8"));
}
/**
* Get the {@link CapabilitiesSupport} object. The
* {@link CapabilitiesSupport} object can be modified and will be kept as
* long as the {@link WmsRequestHandler}.
*
* @return CapabilitiesSupport for capabilities
*/
public CapabilitiesSupport getCapabilities() {
return capabilities;
}
/**
* @param requestProperties
* @return String describing capabilities
* @throws IOException
* @throws MapRequestFormatException
* @throws WMSException
*/
public String handleGetCapabilitiesRequest(Properties requestProperties)
throws IOException, MapRequestFormatException, WMSException {
GetCapabilitiesRequestParameters parameters = new GetCapabilitiesRequestParameters();
checkVersion(requestProperties, parameters);
String format = requestProperties.getProperty(FORMAT);
if (format != null && !format.equals("application/vnd.ogc.wms_xml")) {
throw new WMSException("Invalid FORMAT parameter.", WMSException.INVALIDFORMAT);
}
Layer[] layers = getLayers();
for (int i = 0; i < layers.length; i++) {
if (layers[i].getPropertyPrefix() != null) {
getCapabilities().addLayer(wmsLayerFactory.createWmsLayer(layers[i]));
}
}
try {
return getCapabilities().generateXMLString(parameters.getVersion());
} catch (Exception e) {
e.printStackTrace();
throw new WMSException("Unable to compile a response due to server misconfiguration.", WMSException.INTERNALERROR);
}
}
/**
* @param requestProperties
* @param httpResponse out
* @throws IOException
* @throws MapRequestFormatException
* @throws WMSException
*/
public void handleGetLegendGraphicRequest(Properties requestProperties,
IHttpResponse httpResponse)
throws IOException, MapRequestFormatException, WMSException {
byte[] image = handleGetLegendGraphicRequest(requestProperties);
String contentType = getFormatter().getContentType();
httpResponse.writeHttpResponse(contentType, image);
}
/**
* <ul>
* <li>VERSION - checked
* <li>REQUEST - checked
* <li>EXCEPTIONS - checked
* <li>all from <code>GetMap</code> except VERSION and REQUEST
* <li>QUERY_LAYERS - specific
* <li>INFO_FORMAT - specific
* <li>FEATURE_COUNT - specific
* <li>I,J - specific
* </ul>
*
* @param requestProperties
* @param httpResponse
* @throws IOException
* @throws MapRequestFormatException
* @throws WMSException
*/
public void handleGetFeatureInfoRequest(Properties requestProperties, IHttpResponse httpResponse)
throws IOException, MapRequestFormatException, WMSException {
GetFeatureInfoRequestParameters parameters = new GetFeatureInfoRequestParameters();
checkVersion(requestProperties, parameters);
checkExceptions(requestProperties, parameters);
checkFormat(requestProperties, parameters);
setFormatter(parameters.formatter);
checkBackground(requestProperties, parameters);
checkProjectionType(requestProperties, parameters);
checkWidthAndHeight(requestProperties, parameters);
checkBoundingBox(requestProperties, parameters);
checkFeatureInfoPoint(requestProperties, parameters);
checkLayersAndStyles(requestProperties, parameters);
checkQueryLayers(requestProperties, parameters);
checkInfoFormat(requestProperties, parameters);
Proj projection = createProjection(requestProperties, parameters);
FeatureInfoResponse featureInfoResponse = getFeatureInfoResponse();
StringBuffer out = new StringBuffer();
featureInfoResponse.setOutput(parameters.infoFormat, out);
for (String queryLayerName : parameters.queryLayerNames) {
IWmsLayer wmslayer = wmsLayerByName.get(queryLayerName);
Layer layer = getTopLayerByName(queryLayerName);
layer.setProjection(new ProjectionEvent(this, projection));
LayerFeatureInfoResponse layerResponse = wmslayer.query(parameters.x, parameters.y);
featureInfoResponse.output(layerResponse);
}
featureInfoResponse.flush();
byte[] response = out.toString().getBytes("UTF-8");
httpResponse.writeHttpResponse(parameters.infoFormat, response);
}
private FeatureInfoResponse getFeatureInfoResponse() {
return featureInfoResponse;
}
/**
* TODO: This method covers the equivalent of a base class and returns the
* drawing, which is not rescaled. To them may be a problem. Scaling has
* been locked, because the forms are drawing without the alpha channel, and
* at least it will look odd.
*
* @param formatter
* @param scaledWidth
* @param scaledHeight
* @return byte array of formatted image bytes
*/
@Override
protected byte[] getFormattedImage(ImageFormatter formatter, int scaledWidth, int scaledHeight) {
Debug.message("imageserver", "ImageServer: using full scale image (unscaled).");
byte[] formattedImage = formatter.getImageBytes();
return formattedImage;
}
/**
* @param requestProperties
* @throws WMSException
*/
private void checkRequest(Properties requestProperties) throws WMSException {
String service = requestProperties.getProperty(SERVICE);
String requestType = requestProperties.getProperty(REQUEST);
boolean getcaps = ((requestType != null) && requestType.equals(GETCAPABILITIES));
if (getcaps) {
if ((service == null) || !service.equals("WMS")) {
throw new WMSException("Unsupported service name: " + service);
}
}
}
/**
* @param requestProperties
* @param parameters
* @throws WMSException
*/
private void checkProjectionType(Properties requestProperties,
GetMapRequestParameters parameters) throws WMSException {
String strSRS = requestProperties.getProperty(SRS);
if (strSRS == null) {
// wms 1.3.0 uses CRS parameter instead of SRS
strSRS = requestProperties.getProperty(CRS);
}
if (strSRS == null) {
throw new WMSException("Missing SRS parameter.");
}
CoordinateReferenceSystem crs = CoordinateReferenceSystem.getForCode(strSRS);
if (crs == null) {
throw new WMSException("Invalid SRS/CRS parameter: " + strSRS, WMSException.INVALIDSRS);
}
parameters.crs = crs;
}
private void checkWidthAndHeight(Properties requestProperties,
WidthAndHeightRequestParameters parameters)
throws WMSException {
String strWidth = requestProperties.getProperty(WIDTH);
if (strWidth == null) {
throw new WMSException("Missing WIDTH parameter.", WMSException.MISSINGDIMENSIONVALUE);
}
String strHeight = requestProperties.getProperty(HEIGHT);
if (strHeight == null) {
throw new WMSException("Missing HEIGHT parameter.", WMSException.MISSINGDIMENSIONVALUE);
}
parameters.setWidth(0);
try {
parameters.setWidth(Integer.parseInt(strWidth));
if (parameters.getWidth() <= 0) {
throw new WMSException("Invalid value encountered while parsing WIDTH parameter.");
}
} catch (NumberFormatException e) {
throw new WMSException("Invalid value encountered while parsing WIDTH parameter.");
}
parameters.setHeight(0);
try {
parameters.setHeight(Integer.parseInt(strHeight));
if (parameters.getHeight() <= 0) {
throw new WMSException("Invalid value encountered while parsing HEIGHT parameter.");
}
} catch (NumberFormatException e) {
throw new WMSException("Invalid value encountered while parsing HEIGHT parameter.");
}
}
/**
* @param requestProperties
* @param parameters
* @throws WMSException
*/
private void checkBoundingBox(Properties requestProperties, GetMapRequestParameters parameters)
throws WMSException {
String strBBox = requestProperties.getProperty(BBOX);
if (strBBox == null) {
throw new WMSException("Missing BBOX parameter.", WMSException.MISSINGDIMENSIONVALUE);
}
String[] arrayBBox = strBBox.split(",");
if (arrayBBox.length != 4) {
throw new WMSException("Invalid BBOX parameter. BBOX must contain exactly 4 values separated with comas.", WMSException.INVALIDDIMENSIONVALUE);
}
try {
// BBOX is minx, miny, maxx, maxy
double minX = Double.parseDouble(arrayBBox[0]);
double minY = Double.parseDouble(arrayBBox[1]);
double maxX = Double.parseDouble(arrayBBox[2]);
double maxY = Double.parseDouble(arrayBBox[3]);
double medY = ((maxY - minY) / 2d) + minY;
// This doesn't work over the dateline
double medX = ((maxX - minX) / 2d) + minX;
// Maybe we need to add a crs capability for figuring out medX if
// the dateline is being crossed. If we had a proper medX it
// wouldn't be a problem, OpenMap can handle creating images that
// cross the dateline.
// use CRS to convert BBOX to latlon values
CoordinateReferenceSystem crs = parameters.crs;
parameters.bboxLatLonLowerLeft = crs.inverse(minX, minY, parameters.getVersion().usesAxisOrder());
parameters.bboxLatLonUpperRight = crs.inverse(maxX, maxY, parameters.getVersion().usesAxisOrder());
parameters.bboxLatLonCenter = crs.inverse(medX, medY, parameters.getVersion().usesAxisOrder());
// TODO: use CRS to check value validity?
} catch (NumberFormatException e) {
throw new WMSException("Invalid BBOX parameter. BBOX parameter must be in the form of minx, miny, maxx, maxy"
+ " confirming to the selected SRS/CRS.", WMSException.INVALIDDIMENSIONVALUE);
}
}
private void checkLayersAndStyles(Properties requestProperties,
GetMapRequestParameters parameters) throws WMSException {
String strLayers = requestProperties.getProperty(LAYERS);
if (strLayers == null) {
throw new WMSException("LAYERS not specified.", WMSException.LAYERNOTDEFINED);
}
if (Debug.debugging("imageserver")) {
Debug.output("OGCMRH.checkLayersAndStyles: requested layers >> " + strLayers);
}
String[] layers_in = strLayers.replace('\"', '\0').split(",", -1);
// ... i style
String strStyles = requestProperties.getProperty(STYLES);
String[] styles_in = null;
if (strStyles != null) {
styles_in = strStyles.replace('\"', '\0').split(",", -1);
// wms-1.1.1 7.2.3.4. "If all layers are
// to be shown using the default style, either the form "STYLES=" or
// "STYLES=,,," is valid."
if (strStyles.length() == 0) {
styles_in = new String[layers_in.length];
Arrays.fill(styles_in, "");
}
if (styles_in.length != layers_in.length) {
throw new WMSException("Number of specified styles does not match the number of specified layers.");
}
}
parameters.topLayerNames.clear();
parameters.layerNames.clear();
/*
* The order of layers, because the WMS should first render layer at the
* bottom, the second tablet you any longer, etc. imageserver rendering
* in reverse order by the way, make sure the layers are there
*/
for (int i = layers_in.length - 1; i >= 0; i--) {
String layerName = layers_in[i];
IWmsLayer wmsLayer = (IWmsLayer) wmsLayerByName.get(layerName);
if (wmsLayer == null) {
throw new WMSException("Unknown layer specified (" + layerName + ").", WMSException.LAYERNOTDEFINED);
}
if (wmsLayer instanceof IWmsNestedLayer) {
IWmsNestedLayer nestedLayer = (IWmsNestedLayer) wmsLayer;
String topLayerName = nestedLayer.getTopLayer().getWmsName();
if (!parameters.topLayerNames.contains(topLayerName)) {
parameters.topLayerNames.add(topLayerName);
}
nestedLayer.setIsActive(true);
} else {
if (!parameters.topLayerNames.contains(layerName)) {
parameters.topLayerNames.add(layerName);
}
}
// apply style to layer
if (styles_in == null) {
wmsLayer.setDefaultStyle();
} else {
String styleName = styles_in[i];
if (styleName.length() == 0) {
wmsLayer.setDefaultStyle();
} else if (wmsLayer.isStyleSupported(styleName)) {
wmsLayer.setStyle(styleName);
} else {
throw new WMSException("Unknown style specified (" + styleName + ").", WMSException.STYLENOTDEFINED);
}
}
parameters.layerNames.add(layerName);
}
if (parameters.layerNames.isEmpty()) {
throw new WMSException("LAYERS not specified.", WMSException.LAYERNOTDEFINED);
}
}
private void checkLayerAndStyle(Properties requestProperties,
GetLegendGraphicRequestParameters parameters)
throws WMSException {
String layerName = requestProperties.getProperty(LAYER);
if (layerName == null) {
throw new WMSException(LAYER + " not specified.", WMSException.LAYERNOTDEFINED);
}
IWmsLayer wmsLayer = wmsLayerByName.get(layerName);
if (wmsLayer == null) {
throw new WMSException("Unknown layer specified (" + layerName + ").", WMSException.LAYERNOTDEFINED);
}
parameters.layerName = layerName;
// apply style to layer
String styleName = requestProperties.getProperty(STYLE);
if (styleName == null) {
wmsLayer.setDefaultStyle();
} else if (styleName.length() == 0) {
wmsLayer.setDefaultStyle();
} else if (wmsLayer.isStyleSupported(styleName)) {
wmsLayer.setStyle(styleName);
} else {
throw new WMSException("Unknown style specified (" + styleName + ").", WMSException.STYLENOTDEFINED);
}
}
private void checkQueryLayers(Properties requestProperties,
GetFeatureInfoRequestParameters parameters) throws WMSException {
String strLayers = requestProperties.getProperty(QUERY_LAYERS);
if (strLayers == null) {
throw new WMSException("QUERY_LAYERS not specified.", WMSException.LAYERNOTDEFINED);
}
if (Debug.debugging("imageserver")) {
Debug.output("OGCMRH.checkQueryLayers: requested layers >> " + strLayers);
}
String[] layers_in = strLayers.replace('\"', '\0').split(",", -1);
parameters.queryLayerNames.clear();
for (int i = 0; i < layers_in.length; i++) {
String layerName = layers_in[i];
if (!parameters.layerNames.contains(layerName)) {
throw new WMSException("Layers missing Query Layer " + layerName + ".", WMSException.LAYERNOTDEFINED);
}
IWmsLayer layer = (IWmsLayer) wmsLayerByName.get(layerName);
if (layer == null) {
throw new WMSException("Could not find layer " + layerName);
}
if (!layer.isQueryable()) {
throw new WMSException("Layer " + layerName + " is not queryable");
}
parameters.queryLayerNames.add(layerName);
}
}
/**
* Create and return a Projection object based on the wms request
* parameters.
*
* @param requestProperties
* @param parameters
* @return Proj object for projection
* @throws WMSException
*/
private Proj createProjection(Properties requestProperties, GetMapRequestParameters parameters)
throws WMSException {
Properties projProps = new Properties();
projProps.put(ProjectionFactory.CENTER, new LatLonPoint.Double(0f, 0f));
projProps.setProperty(ProjectionFactory.WIDTH, Integer.toString(parameters.width));
projProps.setProperty(ProjectionFactory.HEIGHT, Integer.toString(parameters.height));
GeoProj projection = parameters.crs.createProjection(projProps);
parameters.crs.prepareProjection(projection);
projection.setScale(projection.getMinScale());
LatLonPoint llp1 = parameters.bboxLatLonLowerLeft;
LatLonPoint llp2 = parameters.bboxLatLonUpperRight;
Debug.message("wms", "bbox toLatLon: 1: " + llp1 + ", 2: " + llp2 + ", center: "
+ parameters.bboxLatLonCenter);
projection.setCenter(parameters.bboxLatLonCenter);
int intnewwidth = parameters.width;
int intnewheight = parameters.height;
float newscale = projection.getScale(llp1, llp2, new Point(0, 0), new Point(intnewwidth, intnewheight));
projection.setScale(newscale);
// OGC 01-068r3 (wms 1.1.1) 7.2.3.8. "In the case where the aspect ratio
// of the BBOX and the ratio width/height are different, the WMS shall
// stretch the returned map so that the resulting
// pixels could themselves be rendered in the aspect ratio of the BBOX"
Point2D xyp1 = projection.forward(llp1);
Point2D xyp2 = projection.forward(llp2);
int w = (int) (xyp2.getX() - xyp1.getX());
int h = (int) (xyp1.getY() - xyp2.getY());
if (Math.abs(w - parameters.width) > 2 || Math.abs(h - parameters.height) > 2) {
Debug.message("wms", "use aspect ratio fix");
projection.setWidth(w);
projection.setHeight(h);
projection.setCenter(parameters.bboxLatLonCenter);
float underlyingScale = projection.getScale(llp1, llp2, new Point(0, 0), new Point(w, h));
projection.setScale(underlyingScale);
AspectRatioProjection p = new AspectRatioProjection(projection, parameters.width, parameters.height);
projection = p;
}
return projection;
}
/**
* @param requestProperties
* @param parameters
* @throws WMSException
*/
private void checkFormat(Properties requestProperties, FormatRequestParameter parameters)
throws WMSException {
String format = requestProperties.getProperty(FORMAT);
// hack to handle WMS clients like ArcGIS 9.2 that are issuing
// GetFeatureInfo without FORMAT parameter
if ((format == null) && (parameters instanceof GetFeatureInfoRequestParameters)) {
parameters.setFormatter(getFormatters().values().iterator().next());
format = parameters.getFormatter().getContentType();
}
if (format == null) {
throw new WMSException("Missing FORMAT parameter.", WMSException.INVALIDFORMAT);
}
parameters.setFormatter(imageFormatterByContentType.get(format));
if (parameters.getFormatter() == null) {
throw new WMSException("Invalid FORMAT parameter: " + format, WMSException.INVALIDFORMAT);
}
}
private void checkVersion(Properties requestProperties, WmsRequestParameters parameters)
throws WMSException {
String versionString = requestProperties.getProperty(VERSION);
if (versionString == null) {
parameters.setVersion(Version.getDefault());
Debug.message("wms", "missing version string. default to " + parameters.getVersion());
} else {
if (parameters instanceof GetCapabilitiesRequestParameters) {
parameters.setVersion(Version.getVersionBestMatch(versionString));
} else {
parameters.setVersion(Version.getVersion(versionString));
}
if (parameters.getVersion() == null) {
throw new WMSException("Unsupported protocol version: " + versionString);
}
}
}
private void checkExceptions(Properties requestProperties, WmsRequestParameters parameters)
throws WMSException {
Version version = parameters.getVersion();
if (version == null) {
return;
}
String ex = requestProperties.getProperty(EXCEPTIONS);
// exceptions parameter is optional. ignore if missing.
if (ex == null) {
return;
}
// ArcGIS uses both 1.1.1 and 1.3.0 type exceptions value with 1.3.0, so
// we should not throw here.
// TODO: handle optional exceptions value after OpenMap wms get support
// for image base exceptions
}
private void checkFeatureInfoPoint(Properties requestProperties,
GetFeatureInfoRequestParameters parameters)
throws WMSException {
parameters.x = -1;
parameters.y = -1;
try {
parameters.x = Integer.parseInt(requestProperties.getProperty(X));
} catch (NumberFormatException e) {
throw new WMSException("Invalid X parameter: " + requestProperties.getProperty(X), WMSException.INVALIDPOINT);
}
try {
parameters.y = Integer.parseInt(requestProperties.getProperty(Y));
} catch (NumberFormatException e) {
throw new WMSException("Invalid Y parameter: " + requestProperties.getProperty(Y), WMSException.INVALIDPOINT);
}
}
private void checkInfoFormat(Properties requestProperties,
GetFeatureInfoRequestParameters parameters) throws WMSException {
String format = requestProperties.getProperty(INFO_FORMAT);
if (format == null) {
// INFO_FORMAT is optional. default to html, then text
if (getFeatureInfoResponse().getInfoFormats().contains(HttpConnection.CONTENT_HTML)) {
format = HttpConnection.CONTENT_HTML;
} else {
format = HttpConnection.CONTENT_PLAIN;
}
} else if (!getFeatureInfoResponse().getInfoFormats().contains(format)) {
throw new WMSException("Invalid value for " + INFO_FORMAT + ": " + format, WMSException.INVALIDFORMAT);
}
parameters.infoFormat = format;
}
/**
* @param requestProperties
* @param parameters
* @throws WMSException
*/
private void checkBackground(Properties requestProperties, GetMapRequestParameters parameters)
throws WMSException {
String transparent = requestProperties.getProperty(TRANSPARENT);
String bgcolor = requestProperties.getProperty(BGCOLOR);
if (transparent != null) {
if (transparent.equals("1") || transparent.equalsIgnoreCase("TRUE")) {
parameters.setTransparent(true);
// if user explicit set TRANSPARENT=TRUE, then skip any BGCOLOR.
// This is not strictly according to wms standard, but as some
// clients (gaia) send BGCOLOR=...&TRANSPARENT=TRUE
bgcolor = null;
} else if (transparent.equals("0") || transparent.equalsIgnoreCase("FALSE")) {
parameters.setTransparent(false);
} else {
throw new WMSException("Invalid TRANSPARENT format '" + transparent
+ "'. Please specify a boolean value (0,1,FALSE,TRUE)");
}
}
if (bgcolor != null) {
if (Pattern.matches("0x[0-9a-fA-F]{6}", bgcolor)) {
// for some reason, ColorFactory.parseColor(test) always return
// black..
parameters.background = Color.decode(bgcolor);
// wms only allow for 24 bit BGCOLOR without transparency, so if
// there is a BGCOLOR, the image will not be transparent
parameters.setTransparent(false);
} else {
throw new WMSException("Invalid BGCOLOR format. Please specify an hexadecimal"
+ " number in the form 0xXXXXXX, where X is a hexadecimal digit (0..9,A-F)");
}
}
// hint to the ImageServer
setTransparent(parameters.getTransparent());
setBackground(parameters.background);
}
}