teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5861: * Software engineering by Intevation GmbH teichmann@5861: * teichmann@5993: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5993: * documentation coming with Dive4Elements River for details. teichmann@5861: */ teichmann@5861: teichmann@5835: package org.dive4elements.river.client.server; ingo@1417: teichmann@6831: import org.dive4elements.artifacts.common.utils.XMLUtils; teichmann@6831: import org.dive4elements.river.client.shared.exceptions.ServerException; teichmann@6831: import org.dive4elements.river.client.shared.model.Capabilities; teichmann@6831: import org.dive4elements.river.client.shared.model.ContactInformation; teichmann@6831: import org.dive4elements.river.client.shared.model.WMSLayer; teichmann@6831: christian@6198: import java.io.IOException; ingo@1417: import java.io.InputStream; ingo@1417: import java.net.MalformedURLException; ingo@1417: import java.net.URL; ingo@1417: import java.net.URLConnection; ingo@1417: import java.util.ArrayList; ingo@1417: import java.util.List; ingo@1417: import java.util.regex.Matcher; ingo@1417: import java.util.regex.Pattern; ingo@1417: ingo@1417: import javax.xml.xpath.XPathConstants; ingo@1417: christian@6198: import org.apache.log4j.Logger; ingo@1417: import org.w3c.dom.Document; ingo@1488: import org.w3c.dom.Element; ingo@1417: import org.w3c.dom.Node; ingo@1417: import org.w3c.dom.NodeList; ingo@1417: christian@6198: /** christian@6198: * Parser for GetCapabilities of a WMS. christian@6198: */ ingo@1417: public class CapabilitiesParser { ingo@1417: teichmann@8203: private static final Logger log = ingo@1417: Logger.getLogger(CapabilitiesParser.class); ingo@1417: ingo@1417: ingo@1417: public static final String ERR_GC_REQUEST_FAILED = ingo@1417: "error_gc_req_failed"; ingo@1417: ingo@1417: public static final String ERR_GC_DOC_NOT_VALID = ingo@1417: "error_gc_doc_not_valid"; ingo@1417: ingo@1417: public static final String ERR_MALFORMED_URL = ingo@1417: "error_malformed_url"; ingo@1417: ingo@1417: ingo@1417: public static final String XPATH_WMS_CAPS = ingo@1417: "/WMS_Capabilities"; ingo@1417: ingo@1417: public static final String XPATH_WMT_CAPS = ingo@1417: "/WMT_MS_Capabilities"; ingo@1417: ingo@1417: public static final String XPATH_TITLE = ingo@1417: "Service/Title/text()"; ingo@1417: ingo@1417: public static final String XPATH_ONLINE_RESOURCE = ingo@1417: "Service/OnlineResource/@href"; ingo@1417: ingo@1417: public static final String XPATH_CONTACT_INFORMATION = ingo@1417: "Service/ContactInformation"; ingo@1417: ingo@1417: public static final String XPATH_CI_PERSON = ingo@1417: "ContactPersonPrimary/ContactPerson/text()"; ingo@1417: ingo@1417: public static final String XPATH_CI_ORGANIZATION = ingo@1417: "ContactPersonPrimary/ContactOrganization/text()"; ingo@1417: ingo@1417: public static final String XPATH_CI_ADDRESS = ingo@1417: "ContactAddress/Address/text()"; ingo@1417: ingo@1417: public static final String XPATH_CI_CITY = ingo@1417: "ContactAddress/City/text()"; ingo@1417: ingo@1417: public static final String XPATH_CI_POSTCODE = ingo@1417: "ContactAddress/PostCode/text()"; ingo@1417: ingo@1417: public static final String XPATH_CI_PHONE = ingo@1417: "ContactVoiceTelephone/text()"; ingo@1417: ingo@1417: public static final String XPATH_CI_EMAIL = ingo@1417: "ContactElectronicMailAddress/text()"; ingo@1417: ingo@1417: public static final String XPATH_FEES = ingo@1417: "Service/Fees/text()"; ingo@1417: ingo@1417: public static final String XPATH_ACCESS_CONSTRAINTS = ingo@1417: "Service/AccessConstraints/text()"; ingo@1417: ingo@1417: public static final String XPATH_LAYERS = ingo@1417: "Capability/Layer"; ingo@1417: christian@6198: public static final String XPATH_MAP_FORMAT = christian@6198: "Capability/Request/GetMap/Format"; christian@6198: christian@6221: public static final String XPATH_GETMAP_ONLINERESOURCE = christian@6221: "Capability/Request/GetMap/DCPType/HTTP/Get/OnlineResource/@href"; christian@6221: ingo@1417: public static final Pattern SRS_PATTERN = Pattern.compile("(EPSG:\\d+)*"); ingo@1417: ingo@1417: ingo@1417: private CapabilitiesParser() { ingo@1417: } ingo@1417: ingo@1417: ingo@1417: public static void main(String[] args) { teichmann@8203: log.info("Do static Capabilities request/parsing."); ingo@1417: bjoern@3479: String log4jProperties = System.getenv(BaseServletContextListener.LOG4J_PROPERTIES); ingo@1417: LoggingConfigurator.init(log4jProperties); ingo@1417: ingo@1417: try { christian@6198: String wmsURL = System.getProperty("test.wms"); christian@6198: if (wmsURL == null || args.length > 0) { christian@6198: wmsURL = args[0]; christian@6198: } christian@6198: Capabilities caps = getCapabilities(wmsURL); ingo@1487: teichmann@8203: log.debug(caps.toString()); christian@6198: System.out.println(caps.toString()); ingo@1417: } ingo@1417: catch (ServerException se) { ingo@1417: se.printStackTrace(); ingo@1417: } ingo@1417: teichmann@8203: log.info("Finished fetching capabiltiies."); ingo@1417: } ingo@1417: ingo@1417: ingo@1417: public static Capabilities getCapabilities(String urlStr) ingo@1417: throws ServerException ingo@1417: { ingo@1417: try { ingo@1417: URL url = new URL(urlStr); ingo@1417: teichmann@8203: log.debug("Open connection to url: " + urlStr); ingo@1417: ingo@1417: URLConnection conn = url.openConnection(); ingo@1417: conn.connect(); ingo@1417: ingo@1417: InputStream is = conn.getInputStream(); ingo@1417: ingo@1417: return parse(is); ingo@1417: } ingo@1417: catch (MalformedURLException mue) { teichmann@8203: log.warn(mue, mue); ingo@1417: throw new ServerException(ERR_MALFORMED_URL); ingo@1417: } ingo@1417: catch (IOException ioe) { teichmann@8203: log.warn(ioe, ioe); ingo@1417: } ingo@1417: ingo@1417: throw new ServerException(ERR_GC_REQUEST_FAILED); ingo@1417: } ingo@1417: ingo@1417: ingo@1417: protected static Capabilities parse(InputStream is) ingo@1417: throws ServerException ingo@1417: { teichmann@8203: log.debug("GCServiceImpl.parseCapabilitiesResponse"); ingo@1417: ingo@1417: Document doc = XMLUtils.parseDocument(is, false); ingo@1417: ingo@1417: if (doc == null) { ingo@1417: throw new ServerException(ERR_GC_DOC_NOT_VALID); ingo@1417: } ingo@1417: ingo@1417: return CapabilitiesParser.parse(doc); ingo@1417: } ingo@1417: ingo@1417: ingo@1417: public static Capabilities parse(Document doc) ingo@1417: throws ServerException ingo@1417: { ingo@1417: Node capabilities = getCapabilitiesNode(doc); ingo@1417: ingo@1417: String title = (String) XMLUtils.xpath( ingo@1417: capabilities, ingo@1417: XPATH_TITLE, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String onlineResource = (String) XMLUtils.xpath( ingo@1417: capabilities, ingo@1417: XPATH_ONLINE_RESOURCE, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String fees = (String) XMLUtils.xpath( ingo@1417: capabilities, ingo@1417: XPATH_FEES, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String accessConstraints = (String) XMLUtils.xpath( ingo@1417: capabilities, ingo@1417: XPATH_ACCESS_CONSTRAINTS, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: Node contactInformation = (Node) XMLUtils.xpath( ingo@1417: capabilities, ingo@1417: XPATH_CONTACT_INFORMATION, ingo@1417: XPathConstants.NODE); ingo@1417: ingo@1417: ContactInformation ci = parseContactInformation(contactInformation); ingo@1417: teichmann@8203: log.debug("Found fees: " + fees); teichmann@8203: log.debug("Found access constraints: " + accessConstraints); ingo@1417: ingo@1417: NodeList layerNodes = (NodeList) XMLUtils.xpath( ingo@1417: capabilities, ingo@1417: XPATH_LAYERS, ingo@1417: XPathConstants.NODESET); ingo@1417: christian@6221: String getMapOnlineResource = (String) XMLUtils.xpath( christian@6221: capabilities, christian@6221: XPATH_GETMAP_ONLINERESOURCE, christian@6221: XPathConstants.STRING); christian@6221: christian@6221: List layers = parseLayers(layerNodes, getMapOnlineResource); ingo@1417: christian@6198: // Parse MIME types of supported return types, e.g. image/jpeg christian@6198: NodeList mapFormatNodes = (NodeList) christian@6198: XMLUtils.xpath(capabilities, XPATH_MAP_FORMAT, XPathConstants.NODESET); christian@6198: List mapFormats = new ArrayList(); christian@6198: for (int n = 0; n < mapFormatNodes.getLength(); n++) { christian@6198: mapFormats.add(mapFormatNodes.item(n).getTextContent()); christian@6198: } christian@6198: ingo@1417: return new Capabilities( ingo@1417: title, ingo@1417: onlineResource, ingo@1417: ci, ingo@1417: fees, ingo@1417: accessConstraints, christian@6198: layers, christian@6198: mapFormats); ingo@1417: } ingo@1417: ingo@1417: ingo@1417: protected static Node getCapabilitiesNode(Document doc) ingo@1417: throws ServerException { ingo@1417: Node capabilities = (Node) XMLUtils.xpath( ingo@1417: doc, ingo@1417: XPATH_WMS_CAPS, ingo@1417: XPathConstants.NODE); ingo@1417: ingo@1417: if (capabilities == null) { teichmann@8203: log.info("No '/WMS_Capabilities' node found."); teichmann@8203: log.info("Try to find a '/WMT_MS_Capabilities' node."); ingo@1417: ingo@1417: capabilities = (Node) XMLUtils.xpath( ingo@1417: doc, ingo@1417: XPATH_WMT_CAPS, ingo@1417: XPathConstants.NODE); ingo@1417: } ingo@1417: ingo@1417: if (capabilities == null) { ingo@1417: throw new ServerException(ERR_GC_DOC_NOT_VALID); ingo@1417: } ingo@1417: ingo@1417: return capabilities; ingo@1417: } ingo@1417: ingo@1417: ingo@1417: protected static ContactInformation parseContactInformation(Node node) { ingo@1417: String person = (String) XMLUtils.xpath( ingo@1417: node, ingo@1417: XPATH_CI_PERSON, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String organization = (String) XMLUtils.xpath( ingo@1417: node, ingo@1417: XPATH_CI_ORGANIZATION, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String address = (String) XMLUtils.xpath( ingo@1417: node, ingo@1417: XPATH_CI_ADDRESS, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String postcode = (String) XMLUtils.xpath( ingo@1417: node, ingo@1417: XPATH_CI_POSTCODE, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String city = (String) XMLUtils.xpath( ingo@1417: node, ingo@1417: XPATH_CI_CITY, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String phone = (String) XMLUtils.xpath( ingo@1417: node, ingo@1417: XPATH_CI_PHONE, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String email = (String) XMLUtils.xpath( ingo@1417: node, ingo@1417: XPATH_CI_EMAIL, ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: ContactInformation ci = new ContactInformation(); ingo@1417: ci.setPerson(person); ingo@1417: ci.setOrganization(organization); ingo@1417: ci.setAddress(address); ingo@1417: ci.setPostcode(postcode); ingo@1417: ci.setCity(city); ingo@1417: ci.setPhone(phone); ingo@1417: ci.setEmail(email); ingo@1417: ingo@1417: return ci; ingo@1417: } ingo@1417: ingo@1417: ingo@1417: /** ingo@1417: * @param layersNode ingo@1417: * @param onlineResource ingo@1417: * ingo@1417: * @return ingo@1417: */ ingo@1417: protected static List parseLayers( ingo@1417: NodeList layersNode, ingo@1417: String onlineResource ingo@1417: ) { ingo@1417: int len = layersNode != null ? layersNode.getLength() : 0; ingo@1417: teichmann@8203: log.debug("Node has " + len + " layers."); ingo@1417: ingo@1417: List layers = new ArrayList(len); ingo@1417: ingo@1417: for (int i = 0; i < len; i++) { ingo@1417: layers.add(parseLayer(layersNode.item(i), onlineResource)); ingo@1417: } ingo@1417: ingo@1417: return layers; ingo@1417: } ingo@1417: ingo@1417: ingo@1417: protected static WMSLayer parseLayer(Node layerNode, String onlineResource) { ingo@1417: String title = (String) XMLUtils.xpath( ingo@1417: layerNode, ingo@1417: "Title/text()", ingo@1417: XPathConstants.STRING); ingo@1417: ingo@1417: String name = (String) XMLUtils.xpath( ingo@1417: layerNode, ingo@1417: "Name/text()", ingo@1417: XPathConstants.STRING); ingo@1417: teichmann@8203: log.debug("Found layer: " + title + "(" + name + ")"); ingo@1417: christian@6199: boolean queryable = true; christian@6199: Node queryableAttr = layerNode.getAttributes().getNamedItem("queryable"); christian@6199: if (queryableAttr != null && queryableAttr.getNodeValue().equals("0")) { christian@6199: queryable = false; christian@6199: } christian@6199: ingo@1417: List srs = parseSRS(layerNode); ingo@1417: ingo@1417: NodeList layersNodes = (NodeList) XMLUtils.xpath( ingo@1417: layerNode, ingo@1417: "Layer", ingo@1417: XPathConstants.NODESET); ingo@1417: ingo@1417: List layers = parseLayers(layersNodes, onlineResource); ingo@1417: christian@6199: return new WMSLayer(onlineResource, title, name, srs, layers, queryable); ingo@1417: } ingo@1417: ingo@1417: ingo@1417: protected static List parseSRS(Node layerNode) { ingo@1488: NodeList srsNodes = ((Element) layerNode).getElementsByTagName("SRS"); ingo@1417: ingo@1488: if (srsNodes.getLength() == 0) { ingo@1488: srsNodes = ((Element) layerNode).getElementsByTagName("CRS"); ingo@1488: ingo@1488: if (srsNodes.getLength() == 0) { teichmann@8203: log.debug("No explicit SRS for this layer specified."); ingo@1488: return null; ingo@1488: } ingo@1488: } ingo@1488: ingo@1488: List allSRS = new ArrayList(); ingo@1488: ingo@1488: for (int i = 0, n = srsNodes.getLength(); i < n; i++) { ingo@1488: List srs = parseSRSItem(srsNodes.item(i).getTextContent()); ingo@1488: ingo@1488: if (srs != null && srs.size() > 0) { ingo@1488: allSRS.addAll(srs); ingo@1488: } ingo@1488: } ingo@1488: ingo@1488: return allSRS; ingo@1488: } ingo@1488: ingo@1488: ingo@1488: protected static List parseSRSItem(String srsStr) { ingo@1417: if (srsStr == null || srsStr.length() == 0) { ingo@1417: return null; ingo@1417: } ingo@1417: ingo@1488: List allSRS = new ArrayList(); ingo@1488: ingo@1488: if (srsStr.indexOf(" ") <= 0) { ingo@1488: String srs = getSRSFromString(srsStr); ingo@1488: if (srs != null && srs.length() > 0) { ingo@1488: allSRS.add(srs); ingo@1488: } ingo@1488: ingo@1488: return allSRS; ingo@1488: } ingo@1488: ingo@1417: String[] splittedSrs = srsStr.split(" "); ingo@1417: ingo@1417: for (String singleSrs: splittedSrs) { ingo@1488: String srs = getSRSFromString(singleSrs); ingo@1488: if (srs != null && srs.length() > 0) { ingo@1488: allSRS.add(srs); ingo@1417: } ingo@1417: } ingo@1417: ingo@1488: return allSRS; ingo@1488: } ingo@1488: ingo@1488: ingo@1488: protected static String getSRSFromString(String singleSrs) { ingo@1488: Matcher m = SRS_PATTERN.matcher(singleSrs); ingo@1488: ingo@1488: if (m.matches()) { teichmann@8203: log.debug("Found SRS '" + m.group(1) + "'"); ingo@1488: return m.group(1); ingo@1488: } ingo@1488: ingo@1488: return null; ingo@1417: } ingo@1417: } ingo@1417: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :