/* Copyright (C) 2001, 2006 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. */ package gov.nasa.worldwind.layers; import gov.nasa.worldwind.avlist.*; import gov.nasa.worldwind.geom.*; import gov.nasa.worldwind.util.*; import gov.nasa.worldwind.wms.*; import org.w3c.dom.Element; import java.net.*; /** * @author tag * @version $Id: WMSLayerFactory.java 5055 2008-04-14 05:19:11Z tgaskins $ */ public class WMSLayerFactory { public static Layer newLayer(Capabilities caps, AVList params) { if (caps == null) { String message = Logging.getMessage("nullValue.WMSCapabilities"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (params == null) { String message = Logging.getMessage("nullValue.LayerConfigParams"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } String layerNames = params.getStringValue(AVKey.LAYER_NAMES); if (layerNames == null || layerNames.length() == 0) { String message = Logging.getMessage("nullValue.WMSLayerNames"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } String[] names = layerNames.split(","); if (names == null || names.length == 0) { String message = Logging.getMessage("nullValue.WMSLayerNames"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } for (String name : names) { if (caps.getLayerByName(name) == null) { String message = Logging.getMessage("WMS.LayerNameMissing", name); Logging.logger().severe(message); throw new IllegalArgumentException(message); } } params.setValue(AVKey.DATASET_NAME, layerNames); String mapRequestURIString = caps.getGetMapRequestGetURL(); mapRequestURIString = fixGetMapString(mapRequestURIString); if (params.getValue(AVKey.SERVICE) == null) params.setValue(AVKey.SERVICE, mapRequestURIString); mapRequestURIString = params.getStringValue(AVKey.SERVICE); if (mapRequestURIString == null || mapRequestURIString.length() == 0) { Logging.logger().severe("WMS.RequestMapURLMissing"); throw new IllegalArgumentException(Logging.getMessage("WMS.RequestMapURLMissing")); } String styleNames = params.getStringValue(AVKey.STYLE_NAMES); if (params.getValue(AVKey.DATA_CACHE_NAME) == null) { try { URI mapRequestURI = new URI(mapRequestURIString); String cacheName = WWIO.formPath(mapRequestURI.getAuthority(), mapRequestURI.getPath(), layerNames, styleNames); params.setValue(AVKey.DATA_CACHE_NAME, cacheName); } catch (URISyntaxException e) { String message = Logging.getMessage("WMS.RequestMapURLBad", mapRequestURIString); Logging.logger().severe(message); throw new IllegalArgumentException(message); } } // Determine image format to request. if (params.getStringValue(AVKey.IMAGE_FORMAT) == null) { String imageFormat = chooseImageFormat(caps); params.setValue(AVKey.IMAGE_FORMAT, imageFormat); } if (params.getStringValue(AVKey.IMAGE_FORMAT) == null) { Logging.logger().severe("WMS.NoImageFormats"); throw new IllegalArgumentException(Logging.getMessage("WMS.NoImageFormats")); } // Determine bounding sector. Sector sector = (Sector) params.getValue(AVKey.SECTOR); if (sector == null) { for (String name : names) { BoundingBox bb = caps.getLayerGeographicBoundingBox(caps.getLayerByName(name)); if (bb == null) { Logging.logger().log(java.util.logging.Level.SEVERE, "WMS.NoGeographicBoundingBoxForLayer", name); continue; } sector = Sector.union(sector, Sector.fromDegrees( clamp(bb.getMiny(), -90d, 90d), clamp(bb.getMaxy(), -90d, 90d), clamp(bb.getMinx(), -180d, 180d), clamp(bb.getMaxx(), -180d, 180d))); } if (sector == null) { Logging.logger().severe("WMS.NoGeographicBoundingBox"); throw new IllegalArgumentException(Logging.getMessage("WMS.NoGeographicBoundingBox")); } params.setValue(AVKey.SECTOR, sector); } if (params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA) == null) { Angle delta = Angle.fromDegrees(36); params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(delta, delta)); } if (params.getValue(AVKey.TILE_WIDTH) == null) params.setValue(AVKey.TILE_WIDTH, 512); if (params.getValue(AVKey.TILE_HEIGHT) == null) params.setValue(AVKey.TILE_HEIGHT, 512); if (params.getValue(AVKey.FORMAT_SUFFIX) == null) params.setValue(AVKey.FORMAT_SUFFIX, ".dds"); if (params.getValue(AVKey.NUM_LEVELS) == null) params.setValue(AVKey.NUM_LEVELS, 14); // approximately 0.5 meters per pixel if (params.getValue(AVKey.NUM_EMPTY_LEVELS) == null) params.setValue(AVKey.NUM_EMPTY_LEVELS, 0); // TODO: adjust for subsetable, fixedimage, etc. params.setValue(AVKey.TILE_URL_BUILDER, new URLBuilder(caps, layerNames, styleNames, params)); TiledImageLayer layer = new BasicTiledImageLayer(new LevelSet(params)); layer.setUseTransparentTextures(true); // layer.setShowImageTileOutlines(true); // layer.setDrawTileIDs(true); layer.setName(makeTitle(caps, layerNames, styleNames)); return layer; } private static double clamp(double v, double min, double max) { return v < min ? min : v > max ? max : v; } private static String fixGetMapString(String gms) { gms = gms.trim(); int qMarkIndex = gms.indexOf("?"); if (qMarkIndex < 0) gms += "?"; else if (qMarkIndex != gms.length() - 1) if (gms.lastIndexOf("&") != gms.length() - 1) gms += "&"; return gms; } private static String makeTitle(Capabilities caps, String layerNames, String styleNames) { String[] lNames = layerNames.split(","); String[] sNames = styleNames != null ? styleNames.split(",") : null; StringBuilder sb = new StringBuilder(); for (int i = 0; i < lNames.length; i++) { if (sb.length() > 0) sb.append(", "); String layerName = lNames[i]; Element layer = caps.getLayerByName(layerName); String layerTitle = caps.getLayerTitle(layer); sb.append(layerTitle != null ? layerTitle : layerName); if (sNames == null || sNames.length <= i) continue; String styleName = sNames[i]; Element style = caps.getLayerStyleByName(layer, styleName); if (style == null) continue; sb.append(" : "); String styleTitle = caps.getStyleTitle(layer, style); sb.append(styleTitle != null ? styleTitle : styleName); } return sb.toString(); } private static final String[] formatOrderPreference = new String[] { "image/dds", "image/png", "image/jpeg" }; private static String chooseImageFormat(Capabilities caps) { String[] formats = caps.getGetMapFormats(); if (formats == null || formats.length == 0) return null; for (String s : formatOrderPreference) { for (String f : formats) { if (f.equalsIgnoreCase(s)) return f; } } return formats[0]; // none recognized; just use the first in the caps list } private static class URLBuilder implements TileUrlBuilder { private static final String MAX_VERSION = "1.3.0"; private final String layerNames; private final String styleNames; private final String imageFormat; private final String wmsVersion; private final String crs; public String URLTemplate = null; private URLBuilder(Capabilities caps, String layerNames, String styleNames, AVList params) { this.layerNames = layerNames; this.styleNames = styleNames; this.imageFormat = params.getStringValue(AVKey.IMAGE_FORMAT); String version = caps.getVersion(); if (version == null || version.compareTo(MAX_VERSION) >= 0) { this.wmsVersion = MAX_VERSION; this.crs = "&crs=CRS:84"; } else { this.wmsVersion = version; this.crs = "&srs=EPSG:4326"; } } public URL getURL(Tile tile, String altImageFormat) throws MalformedURLException { StringBuffer sb; if (this.URLTemplate == null) { sb = new StringBuffer(tile.getLevel().getService()); sb.append("service=WMS"); sb.append("&request=GetMap"); sb.append("&version="); sb.append(this.wmsVersion); sb.append(this.crs); sb.append("&layers="); sb.append(this.layerNames); sb.append("&styles="); sb.append(this.styleNames != null ? this.styleNames : "default"); sb.append("&width="); sb.append(tile.getLevel().getTileWidth()); sb.append("&height="); sb.append(tile.getLevel().getTileHeight()); sb.append("&format="); if (altImageFormat == null) sb.append(this.imageFormat); else sb.append(altImageFormat); sb.append("&transparent=TRUE"); sb.append("&bgcolor=0x000000"); this.URLTemplate = sb.toString(); } else { sb = new StringBuffer(this.URLTemplate); } Sector s = tile.getSector(); sb.append("&bbox="); sb.append(s.getMinLongitude().getDegrees()); sb.append(","); sb.append(s.getMinLatitude().getDegrees()); sb.append(","); sb.append(s.getMaxLongitude().getDegrees()); sb.append(","); sb.append(s.getMaxLatitude().getDegrees()); sb.append("&"); // terminate the query string return new java.net.URL(sb.toString().replace(" ", "%20")); } } } // Below is a start at code to crete a layer given a template GetMap URL. // // private URLBuilder(URI URLTemplate) // { // // TODO: Arg check // this.URLTemplate = URLTemplate.toString(); // this.layerNames = extractWMSParameter("layers", URLTemplate); // this.styleNames = extractWMSParameter("styles", URLTemplate); // this.imageFormat = extractWMSParameter("format", URLTemplate); // this.wmsVersion = extractWMSParameter("version", URLTemplate); // // String c = extractWMSParameter("crs", URLTemplate); // this.crs = c != null ? c : extractWMSParameter("srs", URLTemplate); // } // // public static Layer newLayer(String urlTemplate, Sector layerExtent, AVList params) // { // URI mapRequestURI; // try // { // mapRequestURI = new URI(urlTemplate); // } // catch (URISyntaxException e) // { // String message = Logging.getMessage("WMS.RequestMapURLBad", urlTemplate); // Logging.logger().severe(message); // throw new IllegalArgumentException(message); // } // // return newLayer(mapRequestURI, layerExtent, params); // } // // public static Layer newLayer(URI mapRequestURI, Sector layerExtent, AVList params) // { // if (mapRequestURI == null) // { // String message = Logging.getMessage("nullValue.WMSCapabilities"); // TODO: proper log message // Logging.logger().severe(message); // throw new IllegalArgumentException(message); // } // // if (params == null) // params = new AVListImpl(); // // // Determine bounding sector. // Sector sector = layerExtent != null ? layerExtent : (Sector) params.getValue(AVKey.SECTOR); // if (sector == null) // { // Logging.logger().severe("WMS.NoGeographicBoundingBox"); // throw new IllegalArgumentException(Logging.getMessage("WMS.NoGeographicBoundingBox")); // } // params.setValue(AVKey.SECTOR, sector); // // String layerNames = extractWMSParameter("layers", mapRequestURI); // String styleNames = extractWMSParameter("styles", mapRequestURI); // String width = extractWMSParameter("width", mapRequestURI); // params.setValue(AVKey.TILE_WIDTH, width); // String height = extractWMSParameter("height", mapRequestURI); // params.setValue(AVKey.TILE_HEIGHT, height); // // String cacheName = params.getStringValue(AVKey.DATA_CACHE_NAME); // if (cacheName == null) // cacheName = WWIO.formPath(mapRequestURI.getAuthority(), mapRequestURI.getPath(), layerNames, styleNames); // params.setValue(AVKey.DATA_CACHE_NAME, cacheName); // // if (params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA) == null) // { // Angle delta = Angle.fromDegrees(36); // params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(delta, delta)); // } // // if (params.getValue(AVKey.FORMAT_SUFFIX) == null) // params.setValue(AVKey.FORMAT_SUFFIX, ".dds"); // if (params.getValue(AVKey.NUM_LEVELS) == null) // params.setValue(AVKey.NUM_LEVELS, 14); // approximately 0.5 meters per pixel // if (params.getValue(AVKey.NUM_EMPTY_LEVELS) == null) // params.setValue(AVKey.NUM_EMPTY_LEVELS, 0); // // // TODO: adjust for subsetable, fixedimage, etc. // // params.setValue(AVKey.TILE_URL_BUILDER, new URLBuilder(mapRequestURI)); // // TiledImageLayer layer = new BasicTiledImageLayer(new LevelSet(params)); // layer.setUseTransparentTextures(true); //// layer.setShowImageTileOutlines(true); //// layer.setDrawTileIDs(true); // // String layerTitle = params.getStringValue(AVKey.TITLE); // layer.setName(layerTitle != null ? layerTitle : layerNames + " : " + styleNames); // // return layer; // } // //private static String extractWMSParameter(String paramName, URI uri) //{ // String qs = uri.getRawQuery(); // if (qs == null) // return null; // // String[] wmsParams = qs.split("&"); // for (String wmsParam : wmsParams) // { // if (wmsParam.toLowerCase().startsWith(paramName)) // { // String[] av = wmsParam.split("="); // if (av.length != 2 || av[1] == null) // return null; // // return av[1]; // } // } // // return null; //}