/* **********************************************************************
* $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/plugin/wms/WMSPlugIn.java,v $
* $Revision: 1.9 $
* $Date: 2008/09/19 18:13:34 $
* $Author: dietrick $
*
* Code provided by Raj Singh, raj@rajsingh.org
* Updates provided by Holger Kohler, Holger.Kohler@dsto.defence.gov.au
* Raj Singh updates in July 2002 to:
* - support WMS versions 1.0.8, 1.1.0 and 1.1.1
* - make JPEG image quality setting adjustable
* *********************************************************************
*/
package com.bbn.openmap.plugin.wms;
import java.awt.geom.Point2D;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.StringTokenizer;
import com.bbn.openmap.image.ImageServerConstants;
import com.bbn.openmap.image.WMTConstants;
import com.bbn.openmap.plugin.WebImagePlugIn;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PropUtils;
/**
* This class asks for an image from an OpenGIS compliant Web Map Server (WMS).
* Make sure that OpenMap is using the LLXY projection, because this plugin is
* only asking for images that are in the Spatial Reference System EPS 4326
* projection, and anything else won't match up. This class will be growing to
* be more interactive with the WMS.
*
* It has some properties that you can set in the openmap.properties file:
*
* <pre>
*
* #For the plugin layer, add wms_plugin to openmap.layers list
* wms_plugin=com.bbn.openmap.plugin.wms.WMSPlugIn
* wms_plugin.wmsserver=A URL for the WMS server (eg. http://host.domain.name/servlet/com.esri.wms.Esrimap)
* wms_plugin.wmsversion=OpenGIS WMS version number (eg. 1.1.1)
* wms_plugin.format=image format (eg. image/jpeg, image/png)
* wms_plugin.transparent=true or false, depends on imageformat
* wms_plugin.backgroundcolor=RGB hex string (RRGGBB)
* wms_plugin.layers=comma separated list of map layer names (eg. SDE.SASAUS_BND_COASTL,SDE.SASAUS_BND_POLBNDL)
* wms_plugin.styles=comma separated list of layer rendering styles corresponding to the layers listed
* wms_plugin.vendorspecificnames=comma separated list of vendor specific parameter names in order (eg. SERVICENAME)
* wms_plugin.vendorspecificvalues=comma separated list of vendor specific parameter values in order (eg. default)
*
* </pre>
*
* <p>
* One of the best demo WMS servers can be found at:
* http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi
*/
public class WMSPlugIn extends WebImagePlugIn implements ImageServerConstants {
/** URL to the server script that responds to WMS map requests */
protected String wmsServer = null;
/** GIF, PNG, JPEG, etc. (anything the server supports) */
protected String imageFormat = "image/png";
/**
* If using a lossy image format, such as jpeg, set this to high, medium or
* low
*/
protected String imageQuality = "MEDIUM";
/** Specify the color for non-data areas of the image in r,g,b */
protected String backgroundColor = "0x00FFFFFF";
/** true=make the backgroundColor transparent */
protected String transparent = "true";
/** version of the Web map server spec the server supports */
protected String wmsVersion = "1.1.1";
/** Comma-separated list of layer names */
protected String layers = null;
/** Comma-separated list of style names */
protected String styles = null;
/** Comma-separated list of vendor specific parameter names */
protected String vendorSpecificNames = null;
/** Comma-separated list of vendor specific parameter values */
protected String vendorSpecificValues = null;
/** Same as wmsServer */
protected String queryHeader = null;
/** Keyword for map request. Changes to MAP for WMS version 1.0.0 */
protected String mapRequestName = WMTConstants.GETMAP;
/**
* Keyword for error handling. Changes to INIMAGE for WMS version under
* 1.1.0. Changes to application/vnd.ogc.se+inimage for versions greater
* than 1.1.1
*/
protected String errorHandling = "application/vnd.ogc.se_inimage";
public final static String WMSNameProperty = "wmsname";
public final static String WMSServerProperty = "wmsserver";
public final static String ImageFormatProperty = "format";
public final static String BackgroundColorProperty = "backgroundcolor";
public final static String TransparentProperty = "transparent";
public static final String WMSVersionProperty = "wmsversion";
public static final String LayersProperty = "layers";
public static final String StylesProperty = "styles";
public static final String VendorSpecificNamesProperty = "vendorspecificnames";
public static final String VendorSpecificValuesProperty = "vendorspecificvalues";
/** integer identifier for high image quality */
public static final int LOSSY_IMAGE_QUALITY_HIGH = 2;
/** integer identifier for medium image quality */
public static final int LOSSY_IMAGE_QUALITY_MEDIUM = 1;
/** integer identifier for low image quality */
public static final int LOSSY_IMAGE_QUALITY_LOW = 0;
public WMSPlugIn() {
}
/**
* Add new layers to the server request, using the default style.
*/
public void addLayers(String[] ls) {
addLayers(ls, null);
}
/**
* Add new layers to the server request, using specified styles.
*/
public void addLayers(String[] ls, String[] st) {
// DFD - do they have to be the same length? How about we just
// use the styles we have for that number of layers, and let
// the defaults take over for the rest.
// if (ls.length != st.length) {
// return null;
// }
for (int j = 0; j < ls.length; j++) {
layers += "," + ls[j];
// Put some other checks in here instead of the length
// check above.
if (st == null || j >= st.length || st[j] == null) {
styles += ",";
} else {
styles += "," + st[j];
}
}
}
/**
* Create the query to be sent to the server, based on current settings.
*/
public String createQueryString(Projection p) {
if (queryHeader == null) {
return null;
}
String bbox = "undefined";
String height = "undefined";
String width = "undefined";
String sCoordParamName = WMTConstants.SRS;
if (p != null) {
Point2D ul = p.getUpperLeft();
Point2D lr = p.getLowerRight();
if (wmsVersion.compareTo("1.3.0") == 0) {
bbox = Double.toString(lr.getY()) + "," + Double.toString(ul.getX()) + ","
+ Double.toString(ul.getY()) + "," + Double.toString(lr.getX());
sCoordParamName = WMTConstants.CRS;
errorHandling = "INIMAGE";
} else {
bbox = Double.toString(ul.getX()) + "," + Double.toString(lr.getY()) + ","
+ Double.toString(lr.getX()) + "," + Double.toString(ul.getY());
}
height = Integer.toString(p.getHeight());
width = Integer.toString(p.getWidth());
}
StringBuffer buf = new StringBuffer(queryHeader);
buf.append("?").append(WMTConstants.VERSION).append("=").append(wmsVersion).append("&").append(WMTConstants.REQUEST).append("=").append(mapRequestName).append("&").append(sCoordParamName).append("=").append("EPSG:4326").append("&").append(WMTConstants.BBOX).append("=").append(bbox).append("&").append(WMTConstants.HEIGHT).append("=").append(height).append("&").append(WMTConstants.WIDTH).append("=").append(width).append("&").append(WMTConstants.EXCEPTIONS).append("=").append(errorHandling);
if (imageFormat != null) {
buf.append("&").append(WMTConstants.FORMAT).append("=").append(imageFormat);
String baseImageFormat = imageFormat;
if (baseImageFormat.indexOf('/') > 0)
baseImageFormat = baseImageFormat.substring(baseImageFormat.indexOf('/'));
if (baseImageFormat.equals(WMTConstants.IMAGEFORMAT_JPEG)) {
buf.append("&quality=").append(imageQuality);
}
}
if (transparent != null) {
buf.append("&").append(WMTConstants.TRANSPARENT).append("=").append(transparent);
}
if (backgroundColor != null) {
buf.append("&").append(WMTConstants.BGCOLOR).append("=").append(backgroundColor);
}
if (layers != null) {
buf.append("&").append(WMTConstants.LAYERS).append("=").append(layers);
}
String cStyles = styles;
if (cStyles == null) {
cStyles = "";
}
// if (styles != null) {
buf.append("&").append(WMTConstants.STYLES).append("=").append(cStyles);
// }
if (Debug.debugging("wms")) {
Debug.output("query string: " + buf);
}
/*
* Included to allow for one or more vendor specific parameters to be
* specified such as ESRI's ArcIMS's "ServiceName" parameter.
*/
if (vendorSpecificNames != null) {
if (vendorSpecificValues != null) {
StringTokenizer nameTokenizer = new StringTokenizer(vendorSpecificNames, ",");
StringTokenizer valueTokenizer = new StringTokenizer(vendorSpecificValues, ",");
String paramName = null;
String paramValue = null;
while (nameTokenizer.hasMoreTokens()) {
try {
paramName = nameTokenizer.nextToken();
paramValue = valueTokenizer.nextToken();
buf.append("&").append(paramName).append("=").append(paramValue);
} catch (NoSuchElementException e) {
if (Debug.debugging("wms")) {
Debug.output("WMSPlugIn.getRectangle(): " + "parameter \"" + paramName
+ "\" has no value");
}
}
}
}
}
return buf.toString();
}
/**
* Method to set the properties in the PropertyConsumer. The prefix is a
* string that should be prepended to each property key (in addition to a
* separating '.') in order for the PropertyConsumer to uniquely identify
* properties meant for it, in the midst of Properties meant for several
* objects.
*
* @param prefix a String used by the PropertyConsumer to prepend to each
* property value it wants to look up -
* setList.getProperty(prefix.propertyKey). If the prefix had already
* been set, then the prefix passed in should replace that previous
* value.
*
* @param setList a Properties object that the PropertyConsumer can use to
* retrieve expected properties it can use for configuration.
*/
public void setProperties(String prefix, Properties setList) {
super.setProperties(prefix, setList);
prefix = PropUtils.getScopedPropertyPrefix(prefix);
wmsServer = setList.getProperty(prefix + WMSServerProperty);
if (wmsServer == null) {
Debug.error("WMSPlugIn needs a WMS server.");
}
queryHeader = wmsServer;
setImageFormat(setList.getProperty(prefix + ImageFormatProperty, getImageFormat()));
setTransparent(setList.getProperty(prefix + TransparentProperty, getTransparent()));
setBackgroundColor(setList.getProperty(prefix + BackgroundColorProperty, getBackgroundColor()));
setWmsVersion(setList.getProperty(prefix + WMSVersionProperty, getWmsVersion()));
layers = setList.getProperty(prefix + LayersProperty);
styles = setList.getProperty(prefix + StylesProperty);
/**
* Include for vendor specific parameters
*/
setVendorSpecificNames(setList.getProperty(prefix + VendorSpecificNamesProperty, getVendorSpecificNames()));
setVendorSpecificValues(setList.getProperty(prefix + VendorSpecificValuesProperty, getVendorSpecificValues()));
} // end setProperties
public Properties getProperties(Properties props) {
props = super.getProperties(props);
String prefix = PropUtils.getScopedPropertyPrefix(this);
props.put(prefix + WMSServerProperty, PropUtils.unnull(wmsServer));
props.put(prefix + ImageFormatProperty, PropUtils.unnull(imageFormat));
props.put(prefix + TransparentProperty, PropUtils.unnull(transparent));
props.put(prefix + BackgroundColorProperty, PropUtils.unnull(backgroundColor));
props.put(prefix + WMSVersionProperty, PropUtils.unnull(wmsVersion));
props.put(prefix + LayersProperty, PropUtils.unnull(layers));
props.put(prefix + StylesProperty, PropUtils.unnull(styles));
props.put(prefix + VendorSpecificNamesProperty, PropUtils.unnull(vendorSpecificNames));
props.put(prefix + VendorSpecificValuesProperty, PropUtils.unnull(vendorSpecificValues));
return props;
}
public Properties getPropertyInfo(Properties props) {
props = super.getPropertyInfo(props);
props.put(initPropertiesProperty, WMSServerProperty + " " + WMSVersionProperty + " "
+ LayersProperty + " " + StylesProperty + " " + VendorSpecificNamesProperty + " "
+ VendorSpecificValuesProperty + " " + ImageFormatProperty + " "
+ TransparentProperty + " " + BackgroundColorProperty);
props.put(WMSServerProperty, "URL to the server script that responds to WMS map requests");
props.put(ImageFormatProperty, "Image format (GIF, PNG, JPEG)");
props.put(TransparentProperty, "Flag to indicate that background of image should be tranparent");
props.put(TransparentProperty + ScopedEditorProperty, "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor");
props.put(BackgroundColorProperty, "The Background color for the image");
props.put(BackgroundColorProperty + ScopedEditorProperty, "com.bbn.openmap.util.propertyEditor.ColorPropertyEditor");
props.put(WMSVersionProperty, "The WMS specification version");
props.put(LayersProperty, "A list of layers to use in the query");
props.put(StylesProperty, "A list of layer styles to use in the query");
props.put(VendorSpecificNamesProperty, "Vendor-specific capability names to use in the query");
props.put(VendorSpecificValuesProperty, "Vendor-specific capability values for the names");
return props;
}
public String getImageFormat() {
return imageFormat;
}
public void setImageFormat(String newImageFormat) {
if (newImageFormat.indexOf('/') > 0) {
imageFormat = newImageFormat;
} else {
// convert "PNG" to "image/png" to be compatible with old OpenMap
// practice
imageFormat = "image/" + newImageFormat.toLowerCase();
}
}
public void setImageQuality(int newImageQuality) {
if (newImageQuality == WMSPlugIn.LOSSY_IMAGE_QUALITY_HIGH)
imageQuality = "HIGH";
else if (newImageQuality == WMSPlugIn.LOSSY_IMAGE_QUALITY_MEDIUM)
imageQuality = "MEDIUM";
else if (newImageQuality == WMSPlugIn.LOSSY_IMAGE_QUALITY_LOW)
imageQuality = "LOW";
}
public String getImageQuality() {
return imageQuality;
}
public void setImageQuality(String imageQuality) {
this.imageQuality = imageQuality;
}
public String getTransparent() {
return transparent;
}
public void setTransparent(String transparent) {
if (transparent != null) {
transparent = Boolean.valueOf(transparent).toString().toUpperCase();
}
this.transparent = transparent;
}
public String getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(String backgroundColor) {
if (backgroundColor != null) {
if (backgroundColor.length() > 6) {
backgroundColor = backgroundColor.substring(backgroundColor.length() - 6);
}
if (!backgroundColor.startsWith("0x")) {
backgroundColor = "0x" + backgroundColor;
}
}
this.backgroundColor = backgroundColor;
}
public String getErrorHandling() {
return errorHandling;
}
public void setErrorHandling(String errorHandling) {
this.errorHandling = errorHandling;
}
public String getLayers() {
return layers;
}
public void setLayers(String layers) {
this.layers = layers;
}
public String getMapRequestName() {
return mapRequestName;
}
public void setMapRequestName(String mapRequestName) {
this.mapRequestName = mapRequestName;
}
public String getQueryHeader() {
return queryHeader;
}
public void setQueryHeader(String queryHeader) {
this.queryHeader = queryHeader;
}
public String getStyles() {
return styles;
}
public void setStyles(String styles) {
this.styles = styles;
}
public String getVendorSpecificNames() {
return vendorSpecificNames;
}
public void setVendorSpecificNames(String vendorSpecificNames) {
this.vendorSpecificNames = vendorSpecificNames;
}
public String getVendorSpecificValues() {
return vendorSpecificValues;
}
public void setVendorSpecificValues(String vendorSpecificValues) {
this.vendorSpecificValues = vendorSpecificValues;
}
public String getWmsServer() {
return wmsServer;
}
public void setWmsServer(String wmsServer) {
this.wmsServer = wmsServer;
}
// make this better!
public String getServerName() {
return wmsServer;
}
public String getWmsVersion() {
return wmsVersion;
}
/**
* Does more than just set the version, it also adjusts other parameters
* based on version. Be careful calling this without knowing what it does
* and how it affects other settings.
*
* @param wmsVer
*/
public void setWmsVersion(String wmsVer) {
if (wmsVer == null || wmsVer.length() == 0) {
wmsVer = "1.1.1";
Debug.output("WMSPlugin: wmsVersion was null, now set to 1.1.1");
}
if (Debug.debugging("wms")) {
Debug.output("WMSPlugIn: set up with header \"" + queryHeader + "\"");
}
java.util.StringTokenizer st = new java.util.StringTokenizer(wmsVer, ".");
int majorVersion = Integer.parseInt(st.nextToken());
int midVersion = Integer.parseInt(st.nextToken());
int minorVersion = Integer.parseInt(st.nextToken());
// set the REQUEST parameter
if (majorVersion == 1 && midVersion == 0 && minorVersion < 3) {
mapRequestName = WMTConstants.MAP;
}
// set the image type parameter
if (majorVersion == 1 && minorVersion > 7 && !imageFormat.startsWith("image/")) {
imageFormat = "image/" + imageFormat;
}
// set the error handling parameter
if (majorVersion == 1 && midVersion == 0) {
errorHandling = "INIMAGE";
} else if (majorVersion == 1 && midVersion >= 1 && minorVersion > 1) {
errorHandling = "application/vnd.ogc.se+inimage";
} else if (majorVersion > 1) {
errorHandling = "application/vnd.ogc.se+inimage";
}
this.wmsVersion = wmsVer;
}
} // end WMSPlugin