package com.revolsys.gis.wms; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.gis.wms.capabilities.WmsCapabilities; import com.revolsys.gis.wms.capabilities.WmsLayerDefinition; import com.revolsys.io.map.MapObjectFactoryRegistry; import com.revolsys.raster.BufferedGeoreferencedImage; import com.revolsys.raster.GeoreferencedImage; import com.revolsys.spring.resource.UrlResource; import com.revolsys.util.Exceptions; import com.revolsys.util.Property; import com.revolsys.util.Strings; import com.revolsys.webservice.AbstractWebService; import com.revolsys.webservice.WebServiceResource; public class WmsClient extends AbstractWebService<WmsLayerDefinition> implements WebServiceResource { public static final String J_TYPE = "ogcWmsServer"; public static int getCoordinateSystemId(final String srs) { int coordinateSystemId = 4326; try { final int colonIndex = srs.indexOf(':'); if (colonIndex != -1) { coordinateSystemId = Integer.valueOf(srs.substring(colonIndex + 1)); } } catch (final Throwable e) { } return coordinateSystemId; } public static GeometryFactory getGeometryFactory(final String srs) { final int coordinateSystemId = getCoordinateSystemId(srs); final GeometryFactory geometryFactory = GeometryFactory.floating(coordinateSystemId, 2); return geometryFactory; } public static void mapObjectFactoryInit() { MapObjectFactoryRegistry.newFactory(J_TYPE, "OGC WMS Server", WmsClient::newOgcWmsClient); } public static WmsClient newOgcWmsClient(final Map<String, ? extends Object> properties) { final String serviceUrl = (String)properties.get("serviceUrl"); if (Property.hasValue(serviceUrl)) { final WmsClient client = new WmsClient(serviceUrl); client.setProperties(properties); return client; } else { throw new IllegalArgumentException("Missing serviceUrl"); } } private WmsCapabilities capabilities; public WmsClient(final String serviceUrl) { super(serviceUrl); } public WmsCapabilities getCapabilities() { if (this.capabilities == null) { loadCapabilities(); } return this.capabilities; } @Override @SuppressWarnings("unchecked") public <C extends WebServiceResource> C getChild(final String name) { if (name == null) { return null; } else { final WmsCapabilities capabilities = getCapabilities(); return (C)capabilities.getLayer(name); } } @Override public List<WmsLayerDefinition> getChildren() { final WmsCapabilities capabilities = getCapabilities(); return capabilities.getLayers(); } public WmsLayerDefinition getLayer(final String layerName) { final WmsCapabilities capabilities = getCapabilities(); if (capabilities == null) { return null; } else { return capabilities.getLayer(layerName); } } public GeoreferencedImage getMapImage(final List<String> layers, final List<String> styles, final String srid, final BoundingBox boundingBox, final String format, final int width, final int height) { final UrlResource mapUrl = getMapUrl(layers, styles, srid, boundingBox, format, width, height); try ( final InputStream in = mapUrl.getInputStream()) { final BufferedImage image = ImageIO.read(in); if (image == null) { return new BufferedGeoreferencedImage(boundingBox, width, height); } else { return new BufferedGeoreferencedImage(boundingBox, image); } } catch (final IOException e) { throw Exceptions.wrap("Error loading: " + mapUrl, e); } } public GeoreferencedImage getMapImage(final String layer, final String style, final String srid, final BoundingBox boundingBox, final String format, final int width, final int height) { return getMapImage(Collections.singletonList(layer), Collections.singletonList(style), srid, boundingBox, format, width, height); } public UrlResource getMapUrl(final List<String> layers, final List<String> styles, final String srid, final BoundingBox envelope, final String format, final int width, final int height) { final WmsCapabilities capabilities = getCapabilities(); final String version = capabilities.getVersion(); final Map<String, Object> parameters = new LinkedHashMap<>(); parameters.put("SERVICE", "WMS"); if (version.equals("1.0.0")) { parameters.put(WmsParameters.WMTVER, version); parameters.put(WmsParameters.REQUEST, WmsParameterValues.MAP); } else { parameters.put(WmsParameters.VERSION, version); parameters.put(WmsParameters.REQUEST, WmsParameterValues.GET_MAP); } parameters.put(WmsParameters.LAYERS, Strings.toString(layers)); String style; if (styles == null) { style = ""; } else { style = Strings.toString(styles); for (int i = styles.size(); i < layers.size(); i++) { style += ","; } } parameters.put(WmsParameters.STYLES, style); if (version.equals("1.3.0")) { parameters.put(WmsParameters.CRS, srid); } else { parameters.put(WmsParameters.SRS, srid); } final String bbox = envelope.getMinX() + "," + envelope.getMinY() + "," + envelope.getMaxX() + "," + envelope.getMaxY(); parameters.put(WmsParameters.BBOX, bbox); parameters.put(WmsParameters.WIDTH, width); parameters.put(WmsParameters.HEIGHT, height); parameters.put(WmsParameters.FORMAT, format); final String exceptionFormat = capabilities.getExceptionFormat(); parameters.put(WmsParameters.EXCEPTIONS, exceptionFormat); parameters.put(WmsParameters.TRANSPARENT, "TRUE"); UrlResource requestUrl = null;// = getCapabilities().getRequestUrl("GetMap", // "GET"); if (requestUrl == null) { requestUrl = getServiceUrl(); } return requestUrl.newUrlResource(parameters); } public UrlResource getMapUrl(final String layer, final String style, final String srid, final BoundingBox envelope, final String format, final int width, final int height) { return getMapUrl(Collections.singletonList(layer), Collections.singletonList(style), srid, envelope, format, width, height); } @Override public String getWebServiceTypeName() { return J_TYPE; } public boolean isConnected() { return this.capabilities != null; } public WmsCapabilities loadCapabilities() { final Map<String, Object> parameters = new LinkedHashMap<>(); parameters.put(WmsParameters.SERVICE, WmsParameterValues.WMS); parameters.put(WmsParameters.REQUEST, WmsParameterValues.GET_CAPABILITIES); final UrlResource capabilitiesUrl = newServiceUrlResource(parameters); try ( InputStream in = capabilitiesUrl.getInputStream()) { final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setValidating(false); documentBuilderFactory.setNamespaceAware(true); final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); final Document document = documentBuilder.parse(in); this.capabilities = new WmsCapabilities(this, document.getDocumentElement()); return this.capabilities; } catch (final Throwable e) { throw Exceptions.wrap("Unable to read capabilities: " + capabilitiesUrl, e); } } @Override public void refresh() { loadCapabilities(); } }