aims-ks / atlasmapper

Automatically exported from code.google.com/p/atlasmapper
2 stars 0 forks source link

Add support for DataURL in capabilities document (NASA WMS) #107

Open elawrey opened 8 years ago

elawrey commented 8 years ago

The WMS spec allows links to data in the capabilities document. It would be good to add support for this. The NASA Scientific Visualisation Studio is an example service with DataURLs http://svs.gsfc.nasa.gov/cgi-bin/wms?

gaellafond commented 5 years ago

GeoTools parser for GetCapabilities document enforce that the document follows the DTD rules (validation rules are actually hardcodded on the library). In the NASA GetCapabilities document, there is tags like this one: <Dimension name="sequence" units=""/> with no value defined for property "units".

NASA own custom DTD specifically (and hardcodded validation rules in GeoTools library) mentioned that the "units" tag is REQUIRED:

<!ATTLIST Dimension
          name CDATA #REQUIRED
          units CDATA #REQUIRED
          unitSymbol CDATA #IMPLIED>

Parsing this document would either require developing our own GetCapabilities document parser or finding a way to disable DTD validation while parsing the document.

gaellafond commented 5 years ago

I found many ways to disable the DTD validation for the GeoTools parser, but none seems to work:

    private WMSCapabilities getCapabilities(InputStream inputStream)
            throws SAXException, RevivableThreadInterruptedException, ParserConfigurationException {

        RevivableThread.checkForInterruption();

        Map hints = new HashMap<Object, Object>();
        hints.put(DocumentHandler.DEFAULT_NAMESPACE_HINT_KEY, WMSSchema.getInstance());
        hints.put(DocumentFactory.VALIDATION_HINT, Boolean.FALSE);

        // Disable DTD validation
        hints.put(Hints.ENTITY_RESOLVER, null);

        if (hints != null && hints.containsKey(Hints.ENTITY_RESOLVER)) {
            Object resolver = hints.get(Hints.ENTITY_RESOLVER);

            System.out.println("RESOLVER: " + resolver);
        } else {
            System.out.println("RESOLVER CAN NOT BE SET!!!");
        }

        // Disable DTD validation
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        saxParserFactory.setFeature("http://xml.org/sax/features/namespaces", false);
        saxParserFactory.setFeature("http://xml.org/sax/features/validation", false);
        saxParserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
        saxParserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        saxParserFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        saxParserFactory.setValidating(false);
        hints.put(XMLHandlerHints.SAX_PARSER_FACTORY, saxParserFactory);

        Object object = DocumentFactory.getInstance(inputStream, hints, Level.WARNING);
        RevivableThread.checkForInterruption();

        if (object instanceof ServiceException) {
            throw (ServiceException)object;
        }

        return (WMSCapabilities)object;
    }
gaellafond commented 5 years ago

I eventually found out that GeoTools do not even care about the DTD. The specification is hardcodded in the library org.geotools.data.wms.xml.WMSComplexTypes$_DimensionType

private static Attribute[] attrs =
  new Attribute[] {
    new WMSAttribute(
        null,
        "name",
        WMSSchema.NAMESPACE,
        XSISimpleTypes.String.getInstance(),
        Attribute.REQUIRED,
        null,
        null,
        false),
    new WMSAttribute(
        null,
        "units",                                         <=====
        WMSSchema.NAMESPACE,
        XSISimpleTypes.String.getInstance(),
        Attribute.REQUIRED,                              <=====
        null,
        null,
        false),
    new WMSAttribute("unitSymbol", XSISimpleTypes.String.getInstance()),
    new WMSAttribute("default", XSISimpleTypes.String.getInstance()),
    new WMSAttribute("current", XSISimpleTypes.Boolean.getInstance()),
    new WMSAttribute(
        null,
        "multipleValues",
        WMSSchema.NAMESPACE,
        XSISimpleTypes.Boolean.getInstance(),
        Attribute.OPTIONAL,
        "0",
        null,
        false),
    new WMSAttribute(
        null,
        "nearestValue",
        WMSSchema.NAMESPACE,
        XSISimpleTypes.Boolean.getInstance(),
        Attribute.OPTIONAL,
        "0",
        null,
        false)
  };