src.gov.nasa.worldwind.wms.Capabilities Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of worldwindx Show documentation
Show all versions of worldwindx Show documentation
World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.wms;
import gov.nasa.worldwind.exception.*;
import gov.nasa.worldwind.retrieve.*;
import gov.nasa.worldwind.util.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.logging.Level;
/**
* @author tag
* @version $Id: Capabilities.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public abstract class Capabilities
{
public static final String WMS_SERVICE_NAME = "OGC:WMS";
protected Document doc;
protected Element service;
protected Element capability;
protected XPath xpath;
protected URL capsURL;
public static Capabilities retrieve(URI uri, String service) throws Exception
{
return retrieve(uri, service, null, null);
}
public static Capabilities retrieve(URI uri, Integer connectTimeout, Integer readTimeout) throws Exception
{
return retrieve(uri, null, connectTimeout, readTimeout);
}
public static Capabilities retrieve(URI uri, String service, Integer connectTimeout, Integer readTimeout)
throws Exception
{
if (uri == null)
{
String message = Logging.getMessage("nullValue.URIIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
InputStream is = null;
try
{
// Request the capabilities document from the server.
CapabilitiesRequest req = new CapabilitiesRequest(uri, service);
URL capsURL = req.getUri().toURL();
URLRetriever retriever = URLRetriever.createRetriever(capsURL, new RetrievalPostProcessor()
{
public ByteBuffer run(Retriever retriever)
{
return retriever.getBuffer();
}
});
if (retriever == null)
{
String message = Logging.getMessage("generic.UnrecognizedProtocol");
Logging.logger().severe(message);
throw new WWRuntimeException(message);
}
if (connectTimeout != null)
retriever.setConnectTimeout(connectTimeout);
if (readTimeout != null)
retriever.setReadTimeout(readTimeout);
retriever.call();
if (!retriever.getState().equals(URLRetriever.RETRIEVER_STATE_SUCCESSFUL))
{
String message = Logging.getMessage("generic.RetrievalFailed", uri.toString());
Logging.logger().severe(message);
throw new WWRuntimeException(message);
}
if (retriever.getBuffer() == null || retriever.getBuffer().limit() == 0)
{
String message = Logging.getMessage("generic.RetrievalReturnedNoContent", uri.toString());
Logging.logger().severe(message);
throw new WWRuntimeException(message);
}
if (retriever.getContentType().equalsIgnoreCase("application/vnd.ogc.se_xml"))
{
String exceptionMessage = WWXML.extractOGCServiceException(retriever.getBuffer());
String message = Logging.getMessage("WMS.ServiceException",
uri.toString() + ": " + (exceptionMessage != null ? exceptionMessage : ""));
Logging.logger().severe(message);
throw new WWRuntimeException(message);
}
// Parse the DOM as a capabilities document.
is = WWIO.getInputStreamFromByteBuffer(retriever.getBuffer());
Capabilities caps = Capabilities.parse(WWXML.createDocumentBuilder(true).parse(is));
if (caps != null)
caps.capsURL = capsURL;
return caps;
}
catch (URISyntaxException e)
{
Logging.logger().log(java.util.logging.Level.SEVERE,
Logging.getMessage("generic.URIInvalid", uri.toString()), e);
throw e;
}
catch (ParserConfigurationException e)
{
Logging.logger().fine(Logging.getMessage("WMS.ParserConfigurationException", uri.toString()));
throw e;
}
catch (IOException e)
{
Logging.logger().log(java.util.logging.Level.SEVERE,
Logging.getMessage("generic.ExceptionAttemptingToReadFrom", uri.toString()), e);
throw e;
}
catch (SAXException e)
{
Logging.logger().fine(Logging.getMessage("WMS.ParsingError", uri.toString()));
throw e;
}
finally
{
WWIO.closeStream(is, uri.toString());
}
}
public static Capabilities parse(Document doc)
{
XPath xpath = WWXML.makeXPath();
xpath.setNamespaceContext(new WMSNamespaceContext());
try
{
String exceptionMessage = WWXML.checkOGCException(doc);
if (exceptionMessage != null)
{
String message = Logging.getMessage("WMS.ServiceException", exceptionMessage);
Logging.logger().severe(message);
throw new ServiceException(exceptionMessage);
}
String version = xpath.evaluate(altPaths("*/@wms:version"), doc);
if (version == null || version.length() == 0)
return null;
if (version.compareTo("1.3") < 0)
return new CapabilitiesV111(doc, xpath);
else
return new CapabilitiesV130(doc, xpath);
}
catch (XPathExpressionException e)
{
Logging.logger().log(Level.SEVERE, "WMS.ParsingError", e);
return null;
}
}
protected Capabilities(Document doc, XPath xpath)
{
this.doc = doc;
this.xpath = xpath;
try
{
this.service = (Element) this.xpath.evaluate(altPaths("*/wms:Service"), doc, XPathConstants.NODE);
if (this.service == null)
{
String message = Logging.getMessage("WMS.NoServiceElement", "XML document");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.capability = (Element) this.xpath.evaluate(altPaths("*/wms:Capability"), doc, XPathConstants.NODE);
if (this.capability == null)
{
String message = Logging.getMessage("WMS.NoCapabilityElement", "XML document");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
}
catch (XPathExpressionException e)
{
Logging.logger().log(Level.SEVERE, "WMS.ParsingError", e);
}
}
public URL getCapsURL()
{
return capsURL;
}
private static String altPaths(String path) // hack for WW server layer names with leading pipe
{
return path != null ? path + "|" + path.replaceAll("wms:", "") : null;
}
protected String getText(String path)
{
return this.getText(null, path);
}
protected String getText(Element context, String path)
{
try
{
return this.xpath.evaluate(altPaths(path), context != null ? context : doc);
}
catch (XPathExpressionException e)
{
return null;
}
}
protected String[] getTextArray(Element context, String path)
{
try
{
NodeList nodes = (NodeList) this.xpath.evaluate(altPaths(path), context != null ? context : doc,
XPathConstants.NODESET);
if (nodes == null || nodes.getLength() == 0)
return null;
String[] strings = new String[nodes.getLength()];
for (int i = 0; i < nodes.getLength(); i++)
{
strings[i] = nodes.item(i).getTextContent();
}
return strings;
}
catch (XPathExpressionException e)
{
return null;
}
}
protected String[] getUniqueText(Element context, String path)
{
String[] strings = this.getTextArray(context, path);
if (strings == null)
return null;
ArrayList sarl = new ArrayList();
for (String s : strings)
{
if (!sarl.contains(s))
sarl.add(s);
}
return sarl.toArray(new String[1]);
}
protected Element getElement(Element context, String path)
{
try
{
Node node = (Node) this.xpath.evaluate(altPaths(path), context != null ? context : doc,
XPathConstants.NODE);
if (node == null)
return null;
return node instanceof Element ? (Element) node : null;
}
catch (XPathExpressionException e)
{
return null;
}
}
protected Element[] getElements(Element context, String path)
{
try
{
NodeList nodes = (NodeList) this.xpath.evaluate(altPaths(path), context != null ? context : doc,
XPathConstants.NODESET);
if (nodes == null || nodes.getLength() == 0)
return null;
Element[] elements = new Element[nodes.getLength()];
for (int i = 0; i < nodes.getLength(); i++)
{
Node node = nodes.item(i);
if (node instanceof Element)
elements[i] = (Element) node;
}
return elements;
}
catch (XPathExpressionException e)
{
return null;
}
}
protected Element[] getUniqueElements(Element context, String path, String uniqueTag)
{
Element[] elements = this.getElements(context, path);
if (elements == null)
return null;
HashMap styles = new HashMap();
for (Element e : elements)
{
String name = this.getText(e, uniqueTag);
if (name != null)
styles.put(name, e);
}
return styles.values().toArray(new Element[1]);
}
private HashMap namedLayerElements = new HashMap();
private HashMap namedLayers = new HashMap();
private void fillLayerList()
{
if (this.namedLayers.size() == 0)
{
Element[] nels = this.getElements(this.capability, "descendant::wms:Layer[wms:Name]");
if (nels == null || nels.length == 0)
return;
for (Element le : nels)
{
String name = this.getLayerName(le);
if (name != null)
{
Layer layer = new Layer(le);
this.namedLayers.put(name, layer);
this.namedLayerElements.put(le, layer);
}
}
}
}
public Document getDocument()
{
return this.doc;
}
public Element[] getNamedLayers()
{
if (this.namedLayerElements.size() == 0)
this.fillLayerList();
return this.namedLayerElements.keySet().toArray(new Element[this.namedLayerElements.size()]);
}
public Element getLayerByName(String layerName)
{
if (this.namedLayers.size() == 0)
this.fillLayerList();
Layer l = this.namedLayers.get(layerName);
return l != null ? l.element : null;
}
public Long getLayerLatestLastUpdateTime(Capabilities caps, String[] layerNames)
{
if (caps == null)
{
String message = Logging.getMessage("nullValue.WMSCapabilities");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (layerNames == null)
{
String message = Logging.getMessage("nullValue.WMSLayerNames");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
String lastUpdate = null;
for (String name : layerNames)
{
Element layer = caps.getLayerByName(name);
if (layer == null)
continue;
String update = caps.getLayerLastUpdate(layer);
if (update != null && update.length() > 0 && (lastUpdate == null || update.compareTo(lastUpdate) > 0))
lastUpdate = update;
}
if (lastUpdate != null)
{
try
{
return Long.parseLong(lastUpdate);
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", lastUpdate);
Logging.logger().warning(message);
}
}
return null;
}
public Double[] getLayerExtremeElevations(Capabilities caps, String[] layerNames)
{
if (caps == null)
{
String message = Logging.getMessage("nullValue.WMSCapabilities");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (layerNames == null)
{
String message = Logging.getMessage("nullValue.WMSLayerNames");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
String extremeMin = null;
String extremeMax = null;
for (String name : layerNames)
{
Element layer = caps.getLayerByName(name);
if (layer == null)
continue;
String min = caps.getLayerExtremeElevationsMin(layer);
if (min != null && (extremeMin == null || min.compareTo(min) > 0))
extremeMin = min;
String max = caps.getLayerExtremeElevationsMax(layer);
if (max != null && (extremeMax == null || max.compareTo(max) > 0))
extremeMax = max;
}
if (extremeMin != null || extremeMax != null)
{
try
{
Double[] extremes = new Double[] {null, null};
if (extremeMin != null)
extremes[0] = Double.parseDouble(extremeMin);
if (extremeMax != null)
extremes[1] = Double.parseDouble(extremeMax);
return extremes;
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError",
extremeMin != null ? extremeMin : "" + extremeMax != null ? extremeMax : "");
Logging.logger().severe(message);
}
}
return null;
}
// ********* Document Items ********* //
public String getVersion()
{
return this.getText("*/@wms:version");
}
public String getUpdateSequence()
{
return this.getText("*/@wms:updateSequence");
}
// ********* Service Items ********* //
public String getAbstract()
{
return this.getText(this.service, "wms:Abstract");
}
public String getAccessConstraints()
{
return this.getText(this.service, "wms:AccessConstraints");
}
public String getContactOrganization()
{
return this.getText(
this.service, "wms:ContactInformation/wms:ContactPersonPrimary/wms:ContactOrganization");
}
public String getContactPerson()
{
return this.getText(
this.service, "wms:ContactInformation/wms:ContactPersonPrimary/wms:ContactPerson");
}
public String getFees()
{
return this.getText(this.service, "wms:Fees");
}
public String[] getKeywordList()
{
return this.getTextArray(this.service, "wms:KeywordList/wms:Keyword");
}
public String getLayerLimit()
{
return this.getText(this.service, "wms:LayerLimit");
}
public String getMaxWidth()
{
return this.getText(this.service, "wms:MaxWidth");
}
public String getMaxHeight()
{
return this.getText(this.service, "wms:MaxHeight");
}
public String getServiceName()
{
return this.getText(this.service, "wms:Name");
}
public String getTitle()
{
return this.getText(this.service, "wms:Title");
}
// ********* Capability Items ********* //
public String getOnlineResource()
{
return this.getText(this.capability, "wms:OnlineResource/@xlink:href");
}
public String[] getGetCapabilitiesFormats()
{
return this.getTextArray(this.capability,
"wms:Request/wms:GetCapabilities/wms:Format");
}
public String getGetCapabilitiesRequestGetURL()
{
return this.getText(this.capability,
"wms:Request/wms:GetCapabilities/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href");
}
public String getGetCapabilitiesRequestPostURL()
{
return this.getText(this.capability,
"wms:Request/wms:GetCapabilities/wms:DCPType/wms:HTTP/wms:Post/wms:OnlineResource/@xlink:href");
}
public String[] getExceptionFormats()
{
return this.getTextArray(this.capability, "wms:Exception/wms:Format");
}
public String getFeatureInfoRequestGetURL()
{
return this.getText(this.capability,
"wms:Request/wms:GetFeatureInfo/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href");
}
public String getFeatureInfoRequestPostURL()
{
return this.getText(this.capability,
"wms:Request/wms:GetFeatureInfo/wms:DCPType/wms:HTTP/wms:Post/wms:OnlineResource/@xlink:href");
}
public String[] getGetMapFormats()
{
return this.getTextArray(this.capability,
"wms:Request/wms:GetMap/wms:Format");
}
public String getGetMapRequestGetURL()
{
return this.getText(this.capability,
"wms:Request/wms:GetMap/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href");
}
public String getGetMapRequestPostURL()
{
return this.getText(this.capability,
"wms:Request/wms:GetMap/wms:DCPType/wms:HTTP/wms:Post/wms:OnlineResource/@xlink:href");
}
public String getVendorSpecificCapabilities()
{
return this.getText(this.capability, "wms:VendorSpecificCapabilities");
}
public Element getLayer()
{
return this.getElement(this.capability, "wms:Layer");
}
// ********* Layer Items ********* //
protected static class Layer
{
protected HashMap styleElements = new HashMap();
protected final Element element;
protected Layer layer;
protected String name;
protected String title;
public Layer(Element element)
{
this.element = element;
}
}
public String getLayerAbstract(Element layer)
{
return this.getText(layer, "wms:Abstract");
}
public String getLayerAttributionTitle(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:Title");
}
public String getLayerAttributionURL(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:OnlineResource/@xlink:href");
}
public String getLayerAttributionLogoFormat(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/wms:Format");
}
public String getLayerAttributionLogoHeight(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/@wms:height");
}
public String getLayerAttributionLogoURL(Element layer)
{
return this.getText(layer,
"ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/wms:OnlineResource/@xlink:href");
}
public String getLayerAttributionLogoWidth(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/@wms:width");
}
public Element[] getLayerAuthorityURLs(Element layer)
{
return this.getUniqueElements(layer, "ancestor-or-self::wms:Layer/wms:AuthorityURL", "@wms:type");
}
public abstract BoundingBox[] getLayerBoundingBoxes(Element layer);
public String getLayerCascaded(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/@cascaded");
}
public String[] getLayerCRS(Element layer)
{
return this.getUniqueText(layer, "ancestor-or-self::wms:Layer/wms:CRS");
}
public String getLayerDataURLFormat(Element layer)
{
return this.getText(layer, "wms:DataURL/wms:Format");
}
public String getLayerDataURL(Element layer)
{
return this.getText(layer, "wms:DataURL/wms:OnlineResource/@xlink:href");
}
public Element[] getLayerDimensions(Element layer)
{
Element[] dims = this.getElements(layer, "ancestor-or-self::wms:Layer/wms:Dimension");
if (dims == null || dims.length == 0)
return null;
ArrayList uniqueDims = new ArrayList();
ArrayList dimNames = new ArrayList();
for (Element e : dims)
{
// Filter out dimensions with same name.
// Keep all those with a null name, even though wms says they're invalid. Let the app decide.
String name = this.getDimensionName(e);
if (name != null && dimNames.contains(name))
continue;
uniqueDims.add(e);
dimNames.add(name);
}
return uniqueDims.toArray(new Element[uniqueDims.size()]);
}
public Element[] getLayerExtents(Element layer)
{
Element[] extents = this.getElements(layer, "ancestor-or-self::wms:Layer/wms:Extent");
if (extents == null || extents.length == 0)
return null;
ArrayList uniqueExtents = new ArrayList();
ArrayList extentNames = new ArrayList();
for (Element e : extents)
{
// Filter out dimensions with same name.
// Keep all those with a null name, even though wms says they're invalid. Let the app decide.
String name = this.getDimensionName(e);
if (name != null && extentNames.contains(name))
continue;
uniqueExtents.add(e);
extentNames.add(name);
}
return uniqueExtents.toArray(new Element[uniqueExtents.size()]);
}
public abstract BoundingBox getLayerGeographicBoundingBox(Element layer);
public String getLayerFeatureListFormat(Element layer)
{
return this.getText(layer, "wms:FeatureListURL/wms:Format");
}
public String getLayerFeatureListURL(Element layer)
{
return this.getText(layer, "wms:FeatureListURL/wms:OnlineResource/@xlink:href");
}
public String getLayerFixedHeight(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/@fixedHeight");
}
public String getLayerFixedWidth(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/@fixedWidth");
}
public Element[] getLayerIdentifiers(Element layer)
{
return this.getUniqueElements(layer, "wms:Identifier", "wms:authority");
}
public String[] getLayerKeywordList(Element layer)
{
return this.getTextArray(layer, "wms:KeywordList/wms:Keyword");
}
public abstract String getLayerMaxScaleDenominator(Element layer);
public Element[] getLayerMetadataURLs(Element layer)
{
return this.getElements(layer, "wms:MetadataURL");
}
public abstract String getLayerMinScaleDenominator(Element layer);
public String getLayerName(Element layerElement)
{
Layer layer = this.namedLayerElements.get(layerElement);
return layer != null && layer.name != null ? layer.name : this.getText(layerElement, "wms:Name");
}
public String getLayerNoSubsets(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/@noSubsets");
}
public String getLayerOpaque(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/@opaque");
}
public String getLayerQueryable(Element layer)
{
return this.getText(layer, "ancestor-or-self::wms:Layer/@queryable");
}
public String[] getLayerSRS(Element layer)
{
return this.getUniqueText(layer, "ancestor-or-self::wms:Layer/wms:SRS");
}
public Element[] getLayerStyles(Element layerElement)
{
Layer layer = this.namedLayerElements.get(layerElement);
if (layer == null)
return null;
if (layer.styleElements != null && layer.styleElements.size() != 0)
return layer.styleElements.keySet().toArray(new Element[1]);
Element[] styleElements = this.getUniqueElements(layerElement, "ancestor-or-self::wms:Layer/wms:Style", "Name");
if (styleElements == null)
return null;
layer.styleElements = new HashMap();
for (Element se : styleElements)
{
Style style = new Style(se, layer);
layer.styleElements.put(se, style);
this.styleElements.put(se, style);
}
return layer.styleElements.keySet().toArray(new Element[1]);
}
public Element[] getLayerSubLayers(Element layer)
{
return this.getElements(layer, "wms:Layer");
}
public String getLayerTitle(Element layerElement)
{
Layer layer = this.namedLayerElements.get(layerElement);
if (layer == null)
return this.getText(layerElement, "wms:Title");
return layer.title != null ? layer.title : (layer.title = this.getText(layerElement, "wms:Title"));
}
public Element getLayerStyleByName(Element layerElement, String styleName)
{
Layer layer = this.namedLayerElements.get(layerElement);
if (layer == null)
return null;
if (layer.styleElements == null || layer.styleElements.size() == 0)
{
// Initialize the layer's style list.
this.getLayerStyles(layerElement);
if (layer.styleElements == null || layer.styleElements.size() == 0)
return null;
}
Collection