/* * Copyright (c) 2016 Fraunhofer IGD * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Fraunhofer IGD <http://www.igd.fraunhofer.de/> */ package de.fhg.igd.mapviewer.server.wms.capabilities; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jdesktop.swingx.mapviewer.GeoPosition; import org.jdesktop.swingx.mapviewer.GeotoolsConverter; import de.fhg.igd.mapviewer.server.wms.Messages; import de.fhg.igd.mapviewer.server.wms.WMSConfiguration; /** * WMS utility methods * * @author Simon Templer */ public abstract class WMSUtil { private static final Log log = LogFactory.getLog(WMSUtil.class); /** * Get the URI for a GetMap request * * @param capabilities the WMS capabilities * @param configuration the configuration * @param width the image width * @param height the image height * @param bounds the map bounds * @param styles the styles * @param format the format * @param transparent if a transparent background shall be used * @return the GetMap URI */ public static URI getMapURI(WMSCapabilities capabilities, WMSConfiguration configuration, int width, int height, WMSBounds bounds, String styles, String format, boolean transparent) { if (styles == null) styles = ""; //$NON-NLS-1$ if (format == null) { format = "image/png"; // FIXME //$NON-NLS-1$ } // get server URL String serverUrl; String mapUrl = capabilities.getMapURL(); if (mapUrl.endsWith("?") || mapUrl.endsWith("&")) //$NON-NLS-1$ //$NON-NLS-2$ serverUrl = mapUrl; else if (mapUrl.indexOf('?') >= 0) serverUrl = mapUrl + '&'; else serverUrl = mapUrl + '?'; List<Layer> layerList = getLayers(configuration.getLayers(), capabilities); String layers = getLayerString(layerList, true); // create query string String url = serverUrl + "VERSION=" + capabilities.getVersion() + "&REQUEST=" + //$NON-NLS-1$ //$NON-NLS-2$ "GetMap&SERVICE=WMS&Layers=" + layers + //$NON-NLS-1$ "&FORMAT=" + format + //$NON-NLS-1$ "&BBOX=" + bounds.getMinX() + "," + bounds.getMinY() + "," + bounds.getMaxX() + "," //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + bounds.getMaxY() + "&WIDTH=" + width + "&HEIGHT=" + height + //$NON-NLS-2$ "&SRS=" + bounds.getSRS() + //$NON-NLS-1$ "&STYLES=" + styles + //$NON-NLS-1$ "&TRANSPARENT=" + ((transparent) ? ("TRUE") : ("FALSE")) + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ // "&BGCOLOR=0xffffff" + "&EXCEPTIONS=application/vnd.ogc.se_inimage" + //$NON-NLS-1$ ""; //$NON-NLS-1$ return URI.create(url); } /** * Get the preferred bounding box. Tries to convert the bounding box if not * found with the preferred SRS * * @param capabilities the WMS capabilities * @param preferredEpsg the preferred EPSG code * @return the preferred bounding box, an available bounding box or * <code>null</code> if none is available */ public static WMSBounds getBoundingBox(WMSCapabilities capabilities, int preferredEpsg) { WMSBounds bounds = getPreferredBoundingBox(capabilities, preferredEpsg); String srs = "EPSG:" + preferredEpsg; if (bounds.getSRS().equals(srs)) { // matches preferred SRS return bounds; } else { try { // try to convert the bounding box to the preferred SRS int boxEpsg = Integer.parseInt(bounds.getSRS().substring(5)); GeoPosition topLeft = new GeoPosition(bounds.getMinX(), bounds.getMinY(), boxEpsg); GeoPosition bottomRight = new GeoPosition(bounds.getMaxX(), bounds.getMaxY(), boxEpsg); topLeft = GeotoolsConverter.getInstance().convert(topLeft, preferredEpsg); bottomRight = GeotoolsConverter.getInstance().convert(bottomRight, preferredEpsg); return new WMSBounds(srs, Math.min(topLeft.getX(), bottomRight.getX()), Math.min(topLeft.getY(), bottomRight.getY()), Math.max(topLeft.getX(), bottomRight.getX()), Math.max(topLeft.getY(), bottomRight.getY())); } catch (Exception e) { // fall back to bounds return bounds; } } } /** * Get the preferred bounding box * * @param capabilities the WMS capabilities * @param preferredEpsg the preferred EPSG code * @return the preferred bounding box, an available bounding box or * <code>null</code> */ private static WMSBounds getPreferredBoundingBox(WMSCapabilities capabilities, int preferredEpsg) { // get bounding boxes Map<String, WMSBounds> bbs = capabilities.getBoundingBoxes(); WMSBounds bb = null; if (!bbs.isEmpty()) { // bounding box present if (preferredEpsg != 0) { bb = bbs.get("EPSG:" + preferredEpsg); //$NON-NLS-1$ } if (bb != null) { // log.info("Found bounding box for preferred srs"); // //$NON-NLS-1$ } else { Iterator<WMSBounds> itBB = bbs.values().iterator(); while (bb == null && itBB.hasNext()) { WMSBounds temp = itBB.next(); if (temp.getSRS().startsWith("EPSG:") //$NON-NLS-1$ ) {// && // capabilities.getSupportedSRS().contains(temp.getSRS())) // { bb = temp; // log.info("Found epsg bounding box"); //$NON-NLS-1$ } } } } return bb; } /** * Get WMS capabilities * * @param baseUrl the base URL of the WMS * @return the WMS capabilities * * @throws WMSCapabilitiesException if reading the capabilities fails */ public static WMSCapabilities getCapabilities(String baseUrl) throws WMSCapabilitiesException { try { // try getting capabilities directly from the given URL return WMSCapabilities.getCapabilities(URI.create(baseUrl)); } catch (Exception e) { // add parameters to the URL and try again String capabilitiesUrl; if (baseUrl.endsWith("?") || baseUrl.endsWith("&")) //$NON-NLS-1$ //$NON-NLS-2$ capabilitiesUrl = baseUrl; else if (baseUrl.indexOf('?') >= 0) capabilitiesUrl = baseUrl + '&'; else capabilitiesUrl = baseUrl + '?'; // add default version parameter if (!capabilitiesUrl.matches(".*\\?.*[Vv][Ee][Rr][Ss][Ii][Oo][Nn]=.*")) { //$NON-NLS-1$ capabilitiesUrl += "VERSION=1.1.1&"; //$NON-NLS-1$ } // add request parameter if (!capabilitiesUrl.matches(".*\\?.*[Rr][Ee][Qq][Uu][Ee][Ss][Tt]=.*")) { //$NON-NLS-1$ capabilitiesUrl += "REQUEST=GetCapabilities&"; //$NON-NLS-1$ } // add service parameter if (!capabilitiesUrl.matches(".*\\?.*[Ss][Ee][Rr][Vv][Ii][Cc][Ee]=.*")) { //$NON-NLS-1$ capabilitiesUrl += "SERVICE=WMS&"; //$NON-NLS-1$ } if (capabilitiesUrl.endsWith("&")) { //$NON-NLS-1$ capabilitiesUrl = capabilitiesUrl.substring(0, capabilitiesUrl.length() - 1); } log.info("GetCapabilities URL: " + capabilitiesUrl); //$NON-NLS-1$ try { URI uri = URI.create(capabilitiesUrl); return WMSCapabilities.getCapabilities(uri); } catch (IllegalArgumentException e1) { throw new WMSCapabilitiesException(Messages.WMSUtil_8); } catch (WMSCapabilitiesException e1) { throw e1; } catch (Exception e1) { throw new WMSCapabilitiesException(Messages.WMSUtil_9); } } } /** * Get the WMS layers * * @param layerString the layer string * @param capabilities the WMS capabilities * @return the list of layers */ public static List<Layer> getLayers(String layerString, WMSCapabilities capabilities) { // determine layers to show List<String> showLayers = null; if (layerString != null && !layerString.isEmpty()) { String[] layers = layerString.split(","); //$NON-NLS-1$ showLayers = new ArrayList<String>(); for (String layer : layers) { showLayers.add(layer); } } List<Layer> layers = new ArrayList<Layer>(); for (Layer layer : capabilities.getLayers()) { if (showLayers != null) { try { layer.setSelected(showLayers.contains(layer.getName()) || showLayers.contains(URLEncoder.encode(layer.toString(), "UTF-8"))); //$NON-NLS-1$ } catch (UnsupportedEncodingException e) { log.warn("Unsupported encoding", e); //$NON-NLS-1$ } } layers.add(layer); } return layers; } /** * Get the string representation for the given layers * * @param layers the list of layers * @param encode if the layer string shall be encoded * @return the layers string */ public static String getLayerString(List<Layer> layers, boolean encode) { StringBuilder layBuf = new StringBuilder(); boolean init = true; for (Layer layer : layers) { if (layer.isSelected()) { if (!init) layBuf.append(','); else init = false; try { if (encode) { layBuf.append(URLEncoder.encode(layer.getName(), "UTF-8")); //$NON-NLS-1$ } else { layBuf.append(layer.getName()); } } catch (UnsupportedEncodingException e) { log.error("Could not add layer " + layer.getName(), e); //$NON-NLS-1$ } } } return layBuf.toString(); } }