/* * $Header: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/image/wms/CapabilitiesSupport.java,v 1.5 2009/01/15 19:38:33 dietrick Exp $ * * Copyright 2001-2005 OBR Centrum Techniki Morskiej, All rights reserved. * */ package com.bbn.openmap.image.wms; import java.awt.geom.Dimension2D; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import com.bbn.openmap.image.ImageServer; import com.bbn.openmap.image.WMTConstants; import com.bbn.openmap.proj.coords.AxisOrder; import com.bbn.openmap.proj.coords.BoundingBox; import com.bbn.openmap.proj.coords.CoordinateReferenceSystem; /** * @version $Header: * /cvs/CVS_LEBA/external/openmap/openmap/src/openmap/com/bbn/openmap * /wms/CapabilitiesSupport.java,v 1.1 2006/03/21 10:27:54 tomrak Exp $ * @author pitek */ public class CapabilitiesSupport { public static final String WMSPrefix = ImageServer.OpenMapPrefix + "wms."; public static final int FMT_GETMAP = 0; public static final int FMT_GETFEATUREINFO = 1; private Map<Integer, List<String>> formatsList = new HashMap<Integer, List<String>>(); private String onlineResource; private List<String> keywordsList = null; private String wmsTitle = null; private String wmsAbstract = null; private int updateSequence = 1; private List<IWmsLayer> wmslayers = new ArrayList<IWmsLayer>(); private String layersTitle; private Collection<String> crsCodes = CoordinateReferenceSystem.getCodes(); /** * Creates a new instance of CapabilitiesSupport * * @param props * @param scheme * @param hostName * @param port * @param path * @throws WMSException */ CapabilitiesSupport(Properties props, String scheme, String hostName, int port, String path) throws WMSException { wmsTitle = props.getProperty(WMSPrefix + "Title", "Sample Title"); wmsAbstract = props.getProperty(WMSPrefix + "Abstract", "Sample Abstract"); layersTitle = props.getProperty(WMSPrefix + "LayersTitle", "Sample Layer List"); String[] strKeywords = props.getProperty(WMSPrefix + "Keyword", "").split(" "); List<String> keywords = Arrays.asList(strKeywords); setKeywords(keywords); setUrl(scheme, hostName, port, path); List<String> al = new ArrayList<String>(); setFormats(FMT_GETMAP, al); setFormats(FMT_GETFEATUREINFO, al); } /** * Set url to wms servlet. * * @param scheme * @param hostName * @param port * @param path a String like "/myproject/wms" */ public void setUrl(String scheme, String hostName, int port, String path) { StringBuilder url = new StringBuilder(); url.append(scheme); url.append("://"); url.append(hostName); if (!((scheme.equals("http") && (port == 80)) || (scheme.equals("https") && (port == 443)))) { url.append(":"); url.append(port); } url.append(path); setUrl(url.toString()); } /** * Set url to wms servlet like "http://myserver/myproject/wms" * * @param url */ public void setUrl(String url) { this.onlineResource = url; } /** * @return Document specifying capabilities. */ private Document generateCapabilitiesDocument(Version version) { Document doc = version.createCapabilitiesDocumentStart(); Element root = doc.getDocumentElement(); root.setAttribute("version", version.getVersionString()); root.setAttribute("updateSequence", Integer.toString(updateSequence)); Element service = doc.createElement("Service"); service.appendChild(textnode(doc, "Name", version.getServiceName())); service.appendChild(textnode(doc, "Title", wmsTitle)); service.appendChild(textnode(doc, "Abstract", wmsAbstract)); if (!keywordsList.isEmpty()) { Element keywordListElement = doc.createElement("KeywordList"); for (int i = 0; i < keywordsList.size(); i++) { keywordListElement.appendChild(textnode(doc, "Keyword", (String) keywordsList.get(i))); } service.appendChild(keywordListElement); } service.appendChild(onlineResource(doc, onlineResource)); service.appendChild(textnode(doc, "Fees", "none")); service.appendChild(textnode(doc, "AccessConstraints", "none")); root.appendChild(service); Node capability = doc.createElement("Capability"); Element request = doc.createElement("Request"); request.appendChild(requestcap(doc, WMTConstants.GETCAPABILITIES, version.getCapabiltiesFormats(), "Get", onlineResource)); request.appendChild(requestcap(doc, WMTConstants.GETMAP, formatsList.get(FMT_GETMAP), "Get", onlineResource)); request.appendChild(requestcap(doc, WMTConstants.GETFEATUREINFO, formatsList.get(FMT_GETFEATUREINFO), "Get", onlineResource)); capability.appendChild(request); Element exceptionElement = doc.createElement("Exception"); for (String format : version.getExceptionFormats()) { exceptionElement.appendChild(textnode(doc, "Format", format)); } capability.appendChild(exceptionElement); capability.appendChild(createLayersElement(doc, version)); root.appendChild(capability); return doc; } private Element createLayersElement(Document doc, Version version) { Element layers = doc.createElement("Layer"); layers.appendChild(textnode(doc, "Title", layersTitle)); for (Iterator<String> it = crsCodes.iterator(); it.hasNext();) { layers.appendChild(textnode(doc, version.getCoordinateReferenceSystemAcronym(), it.next())); } // append bounding boxes layers.appendChild(version.createLatLonBoundingBox(doc)); for (Iterator<String> it = crsCodes.iterator(); it.hasNext();) { appendSRSBoundingBox(doc, layers, it.next(), version); } // append layers // in OpenMap, the layer on top is listed first, but in WMS // Capabilities, the layer on top is listed at the bottom List<IWmsLayer> reverseLayers = new ArrayList<IWmsLayer>(wmslayers); Collections.reverse(reverseLayers); for (IWmsLayer wmsLayer : reverseLayers) { createLayerElement(doc, layers, wmsLayer, version); } return layers; } private void createLayerElement(Document doc, Element layers, IWmsLayer wmsLayer, Version version) { org.w3c.dom.Element layerElement = (org.w3c.dom.Element) node(doc, "Layer"); layerElement.setAttribute("queryable", wmsLayer.isQueryable() ? "1" : "0"); // implied layerElement.setAttribute("cascaded", "0"); layerElement.setAttribute("opaque", "0"); layerElement.setAttribute("noSubsets", "0"); // implied layerElement.setAttribute("fixedWidth", "0"); // implied layerElement.setAttribute("fixedHeight", "0"); layerElement.appendChild(textnode(doc, "Name", wmsLayer.getWmsName())); layerElement.appendChild(textnode(doc, "Title", wmsLayer.getTitle())); if (wmsLayer.getAbstract() != null) { layerElement.appendChild(textnode(doc, "Abstract", wmsLayer.getAbstract())); } // add styles IWmsLayerStyle[] styles = wmsLayer.getStyles(); if (styles != null) { for (int i = 0; i < styles.length; i++) { IWmsLayerStyle style = styles[i]; org.w3c.dom.Element styleElement = (org.w3c.dom.Element) node(doc, "Style"); styleElement.appendChild(textnode(doc, "Name", style.getName())); // "default" styleElement.appendChild(textnode(doc, "Title", style.getTitle())); // "Default // style" if (style.getAbstract() != null) { styleElement.appendChild(textnode(doc, "Abstract", style.getAbstract())); } // tell the layer about the style so the style can used legend // graphics wmsLayer.setStyle(style.getName()); Legend legend = wmsLayer.getLegend(); if (legend != null) { for (Dimension2D dimension : legend.getSizeHints()) { int width = (int) dimension.getWidth(); int height = (int) dimension.getHeight(); String format = "image/png"; Element legendURLElement = (Element) node(doc, "LegendURL"); legendURLElement.setAttribute("width", Integer.toString(width)); legendURLElement.setAttribute("height", Integer.toString(height)); legendURLElement.appendChild(textnode(doc, "Format", format)); StringBuilder url = new StringBuilder(); // would be nicer to use FMT_GETLEGENDGRAPHIC, but it // may not be listed url.append(onlineResource); url.append("?").append(WMTConstants.SERVICE).append("=WMS"); url.append("&").append(WMTConstants.VERSION).append("="); url.append(version.getVersionString()); url.append("&").append(WMTConstants.REQUEST).append("="); url.append(WMTConstants.GETLEGENDGRAPHIC); url.append("&").append(WMTConstants.LAYER).append("="); url.append(wmsLayer.getWmsName()); url.append("&").append(WMTConstants.STYLE).append("=").append(style.getName()); url.append("&").append(WMTConstants.FORMAT).append("=").append(format); url.append("&").append(WMTConstants.WIDTH).append("=").append(width); url.append("&").append(WMTConstants.HEIGHT).append("=").append(height); legendURLElement.appendChild(onlineResource(doc, url.toString())); styleElement.appendChild(legendURLElement); } } layerElement.appendChild(styleElement); } } // add nested layers if (wmsLayer instanceof IWmsNestedLayer) { IWmsLayer[] nestedLayers = ((IWmsNestedLayer) wmsLayer).getNestedLayers(); if (nestedLayers != null) { for (int i = 0; i < nestedLayers.length; i++) { createLayerElement(doc, layerElement, nestedLayers[i], version); } } } layers.appendChild(layerElement); } /** */ public void incUpdateSequence() { updateSequence++; } /** * @param request * @param formats * @return true if request type handled */ public boolean setFormats(int request, Collection<String> formats) { switch (request) { case FMT_GETMAP: case FMT_GETFEATUREINFO: formatsList.put(request, new ArrayList<String>(formats)); return true; default: return false; } } /** * @param url */ public void setOnlineResource(String url) { this.onlineResource = url; } /** * @param keywordsList */ public void setKeywords(List<String> keywordsList) { this.keywordsList = keywordsList; } public void addLayer(IWmsLayer wmsLayer) { wmslayers.add(wmsLayer); } public void setLayersTitle(String title) { this.layersTitle = title; } private void appendSRSBoundingBox(Document doc, Element layers, String crsCode, Version version) { CoordinateReferenceSystem crs = CoordinateReferenceSystem.getForCode(crsCode); BoundingBox bbox = crs.getBoundingBox(); if (bbox == null) { return; } org.w3c.dom.Element e1 = (org.w3c.dom.Element) node(doc, "BoundingBox"); e1.setAttribute(version.getCoordinateReferenceSystemAcronym(), crs.getCode()); if (version.usesAxisOrder() && (crs.getAxisOrder() == AxisOrder.northBeforeEast)) { // wms 1.3.0. 6.7.4 EXAMPLE 2 // "A <BoundingBox> representing the entire Earth in the EPSG:4326 // Layer CRS would be written as <BoundingBox CRS="EPSG:4326" // minx="-90" miny="-180" maxx="90" maxy="180">. A BBOX parameter // requesting a map of the entire Earth would be written in this CRS // as // BBOX=-90,-180,90,180." e1.setAttribute("minx", Double.toString(bbox.getMinY())); e1.setAttribute("miny", Double.toString(bbox.getMinX())); e1.setAttribute("maxx", Double.toString(bbox.getMaxY())); e1.setAttribute("maxy", Double.toString(bbox.getMaxX())); } else { e1.setAttribute("minx", Double.toString(bbox.getMinX())); e1.setAttribute("miny", Double.toString(bbox.getMinY())); e1.setAttribute("maxx", Double.toString(bbox.getMaxX())); e1.setAttribute("maxy", Double.toString(bbox.getMaxY())); } layers.appendChild(e1); } /** * Generate String out of the XML document object * * @throws IOException, TransformerException, * TransformerConfigurationException */ String generateXMLString(Version version) throws IOException, TransformerConfigurationException, TransformerException { StringWriter strWriter = new StringWriter(); Transformer tr = TransformerFactory.newInstance().newTransformer(); tr.setOutputProperty(OutputKeys.INDENT, "yes"); tr.setOutputProperty(OutputKeys.METHOD, "xml"); tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); tr.setOutputProperty(OutputKeys.VERSION, "1.0"); tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); Document document = generateCapabilitiesDocument(version); // system id not transformed by default transformer if (document.getDoctype() != null) { tr.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, document.getDoctype().getSystemId()); } // Serialize XML Document tr.transform(new DOMSource(document), new StreamResult(strWriter)); return strWriter.toString(); } /** * @param Name * @param Text * @return Node created for doc with name */ private Node textnode(Document doc, String Name, String text) { Element e1 = doc.createElement(Name); if (text == null) { text = ""; } Node n = doc.createTextNode(text); e1.appendChild(n); return e1; } /** * @param doc Document * @param Name name * @return Node created for doc with name */ private Node node(Document doc, String Name) { return doc.createElement(Name); } private Node onlineResource(Document doc, String url) { Element onlineResource = doc.createElement("OnlineResource"); onlineResource.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); onlineResource.setAttribute("xlink:type", "simple"); onlineResource.setAttribute("xlink:href", url); return onlineResource; } /** * @param doc * @param requestName like "GetMap" * @param formatList * @param methodName like "Get" or "Post" * @param url * @return Node */ private Node requestcap(Document doc, String requestName, Collection<String> formatList, String methodName, String url) { Element methodNode = doc.createElement(methodName); methodNode.appendChild(onlineResource(doc, url)); Element httpNode = doc.createElement("HTTP"); httpNode.appendChild(methodNode); Element dcpTypeNode = doc.createElement("DCPType"); dcpTypeNode.appendChild(httpNode); Element requestNameNode = doc.createElement(requestName); for (String format : formatList) { requestNameNode.appendChild(textnode(doc, "Format", format)); } requestNameNode.appendChild(dcpTypeNode); return requestNameNode; } }