ingo@1417: package de.intevation.flys.client.server;
ingo@1417: 
ingo@1417: import java.io.InputStream;
ingo@1417: import java.io.IOException;
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: 
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: 
ingo@1417: import org.apache.log4j.Logger;
ingo@1417: 
ingo@1417: import de.intevation.artifacts.common.utils.XMLUtils;
ingo@1417: 
ingo@1417: import de.intevation.flys.client.shared.exceptions.ServerException;
ingo@1417: import de.intevation.flys.client.shared.model.Capabilities;
ingo@1417: import de.intevation.flys.client.shared.model.ContactInformation;
ingo@1417: import de.intevation.flys.client.shared.model.WMSLayer;
ingo@1417: 
ingo@1417: 
ingo@1417: public class CapabilitiesParser {
ingo@1417: 
ingo@1417:     private static final Logger logger =
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: 
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) {
ingo@1417:         logger.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 {
ingo@1487:             Capabilities caps = getCapabilities(System.getProperty("test.wms"));
ingo@1487: 
ingo@1487:             logger.debug(caps.toString());
ingo@1417:         }
ingo@1417:         catch (ServerException se) {
ingo@1417:             se.printStackTrace();
ingo@1417:         }
ingo@1417: 
ingo@1417:         logger.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: 
ingo@1417:             logger.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) {
ingo@1417:             logger.warn(mue, mue);
ingo@1417:             throw new ServerException(ERR_MALFORMED_URL);
ingo@1417:         }
ingo@1417:         catch (IOException ioe) {
ingo@1417:             logger.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:     {
ingo@1417:         logger.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: 
ingo@1417:         logger.debug("Found fees: " + fees);
ingo@1417:         logger.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: 
ingo@1417:         List<WMSLayer> layers = parseLayers(layerNodes, onlineResource);
ingo@1417: 
ingo@1417:         return new Capabilities(
ingo@1417:             title,
ingo@1417:             onlineResource,
ingo@1417:             ci,
ingo@1417:             fees,
ingo@1417:             accessConstraints,
ingo@1417:             layers);
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) {
ingo@1417:             logger.info("No '/WMS_Capabilities' node found.");
ingo@1417:             logger.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<WMSLayer> parseLayers(
ingo@1417:         NodeList layersNode,
ingo@1417:         String   onlineResource
ingo@1417:     ) {
ingo@1417:         int len = layersNode != null ? layersNode.getLength() : 0;
ingo@1417: 
ingo@1417:         logger.debug("Node has " + len + " layers.");
ingo@1417: 
ingo@1417:         List<WMSLayer> layers = new ArrayList<WMSLayer>(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: 
ingo@1417:         logger.debug("Found layer: " + title + "(" + name + ")");
ingo@1417: 
ingo@1417:         List<String> 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<WMSLayer> layers = parseLayers(layersNodes, onlineResource);
ingo@1417: 
ingo@1417:         return new WMSLayer(onlineResource, title, name, srs, layers);
ingo@1417:     }
ingo@1417: 
ingo@1417: 
ingo@1417:     protected static List<String> 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) {
ingo@1488:                 logger.debug("No explicit SRS for this layer specified.");
ingo@1488:                 return null;
ingo@1488:             }
ingo@1488:         }
ingo@1488: 
ingo@1488:         List<String> allSRS = new ArrayList<String>();
ingo@1488: 
ingo@1488:         for (int i = 0, n = srsNodes.getLength(); i < n; i++) {
ingo@1488:             List<String> 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<String> parseSRSItem(String srsStr) {
ingo@1417:         if (srsStr == null || srsStr.length() == 0) {
ingo@1417:             return null;
ingo@1417:         }
ingo@1417: 
ingo@1488:         List<String> allSRS = new ArrayList<String>();
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()) {
ingo@1488:             logger.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 :