Skip to content

Commit

Permalink
[GEOS-8611] Allow DescribeDomain to return a selection of dimensions (#…
Browse files Browse the repository at this point in the history
…2779)

[GEOS-8611] Allow DescribeDomain to return a selection of dimensions
  • Loading branch information
aaime committed Mar 1, 2018
1 parent fdf0925 commit c44ed73
Show file tree
Hide file tree
Showing 16 changed files with 359 additions and 225 deletions.
24 changes: 22 additions & 2 deletions doc/en/user/source/community/wmts-multidimensional/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,17 @@ This operation is useful to understand which domains are available in our layer
* - TileMatrixSet
- Yes
- Tile matrix set identifier
* - BBOX=minx,miny,maxx,maxy
* - bbox=minx,miny,maxx,maxy
- No
- Bounding box corners (lower left, upper right) in CRS units
* - DimensionIdentifier
- No
- At most one per dimension, a range described as min/max, restricting the domain of this dimension
* - Domains
- No
- A comma separated list of domain names to be returned, in case only a subset is required. The space domain is identified by "bbox".

The ``BBOX`` parameter allows the client to restrict the ``DescribeDomains`` operation to a certain spatial area, by default the layer extent will be used.
The ``bbox`` parameter allows the client to restrict the ``DescribeDomains`` operation to a certain spatial area, by default the layer extent will be used.

The ``DimensionIdentifier`` parameter can be used to restrict the domain values of a certain dimension, this is useful to answer questions like which elevations values are available in a specific day.

Expand Down Expand Up @@ -233,6 +236,23 @@ the result will be similar to this:
So for time 2016-02-23T03:00:00.000Z there is only values measured at 200.0 meters.

In case only the space domain is of interest, the following request will do:

.. code-block:: guess
http://localhost:8080/geoserver/gwc/service/wmts?REQUEST=DescribeDomains&Version=1.0.0&Layer=some_layer&TileMatrixSet=EPSG:4326&elevation=0/500&time=2016-02-23T03:00:00.000Z&domains=bbox
and the result will be similar to this:

.. code-block:: xml
<Domains xmlns="http://demo.geo-solutions.it/share/wmts-multidim/wmts_multi_dimensional.xsd" xmlns:ows="http://www.opengis.net/ows/1.1">
<SpaceDomain>
<BoundingBox CRS="EPSG:4326"
maxx="179.875" maxy="89.9375" minx="-180.125" miny="-90.125"/>
</SpaceDomain>
</Domains>
GetHistogram
^^^^^^^^^^^^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ public void encode(Object object) throws IllegalArgumentException {
});
start("Domains", nameSpaces);
Map<String, Tuple<Integer, List<String>>> domainsValues = new HashMap<>();
ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope();
domains.getDimensions().forEach(dimension -> {
Tuple<ReferencedEnvelope, Tuple<Integer, List<String>>> dimensionValues = dimension.getDomainValuesAsStrings(domains.getFilter());
referencedEnvelope.expandToInclude(dimensionValues.first);
domainsValues.put(dimension.getDimensionName(), dimensionValues.second);
Tuple<Integer, List<String>> dimensionValues = dimension.getDomainValuesAsStrings(domains.getFilter());
domainsValues.put(dimension.getDimensionName(), dimensionValues);
});
handleBoundingBox(referencedEnvelope);
if (domains.getSpatialDomain() != null && !domains.getSpatialDomain().isEmpty()) {
handleBoundingBox(domains.getSpatialDomain());
}
domainsValues.entrySet().forEach(dimensionValues -> handleDimension(dimensionValues.getKey(), dimensionValues.getValue()));
end("Domains");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
public class Domains {

private final List<Dimension> dimensions;
private final ReferencedEnvelope boundingBox;
private final ReferencedEnvelope spatialDomain;
private final Filter filter;

private final LayerInfo layerInfo;
Expand All @@ -38,16 +38,16 @@ public class Domains {
public Domains(List<Dimension> dimensions, LayerInfo layerInfo, ReferencedEnvelope boundingBox, Filter filter) {
this.dimensions = dimensions;
this.layerInfo = layerInfo;
this.boundingBox = boundingBox;
this.spatialDomain = boundingBox;
this.filter = filter;
}

public List<Dimension> getDimensions() {
return dimensions;
}

ReferencedEnvelope getBoundingBox() {
return boundingBox;
ReferencedEnvelope getSpatialDomain() {
return spatialDomain;
}

public Filter getFilter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
package org.geoserver.gwc.wmts;

import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.DimensionInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.PublishedInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.gwc.layer.CatalogConfiguration;
import org.geoserver.gwc.layer.GeoServerTileLayer;
Expand All @@ -17,16 +21,16 @@
import org.geoserver.ows.util.KvpUtils;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.WMS;
import org.geoserver.wms.dimension.DimensionFilterBuilder;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.visitor.SimplifyingFilterVisitor;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.gml2.bindings.GML2EncodingUtils;
import org.geotools.referencing.CRS;
import org.geotools.resources.CRSUtilities;
import org.geotools.util.logging.Logging;
import org.geowebcache.GeoWebCacheException;
import org.geowebcache.conveyor.Conveyor;
import org.geowebcache.grid.GridSubset;
import org.geowebcache.grid.SRS;
import org.geowebcache.io.XMLBuilder;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.layer.TileLayerDispatcher;
Expand All @@ -35,12 +39,18 @@
import org.geowebcache.storage.StorageBroker;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -51,6 +61,8 @@
public final class MultiDimensionalExtension extends WMTSExtensionImpl {

private final static Logger LOGGER = Logging.getLogger(MultiDimensionalExtension.class);
public static final String SPACE_DIMENSION = "bbox";
public static final Set<String> ALL_DOMAINS = Collections.emptySet();

private final FilterFactory filterFactory = CommonFactoryFinder.getFilterFactory();

Expand Down Expand Up @@ -101,26 +113,23 @@ public boolean handleRequest(Conveyor candidateConveyor) throws OWSException {
executeDescribeDomainsOperation(conveyor);
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Error executing describe domains operation.", exception);
throw new OWSException(500, "NoApplicableCode", "",
"Error executing describe domains operation:" + exception.getMessage());
return rethrowException(exception, "Error executing describe domains operation:");
}
break;
case GET_HISTOGRAM:
try {
executeGetHistogramOperation(conveyor);
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Error executing get histogram operation.", exception);
throw new OWSException(500, "NoApplicableCode", "",
"Error executing get histogram operation:" + exception.getMessage());
rethrowException(exception, "Error executing get histogram operation:");
}
break;
case GET_FEATURE:
try {
executeGetFeatureOperation(conveyor);
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Error executing get feature operation.", exception);
throw new OWSException(500, "NoApplicableCode", "",
"Error executing get feature operation:" + exception.getMessage());
rethrowException(exception, "Error executing get feature operation:");
}
break;
default:
Expand All @@ -129,24 +138,37 @@ public boolean handleRequest(Conveyor candidateConveyor) throws OWSException {
return true;
}

public boolean rethrowException(Exception exception, String s) throws OWSException {
if (exception instanceof OWSException) {
throw (OWSException) exception;
}
throw new OWSException(500, "NoApplicableCode", "", s + exception.getMessage());
}

@Override
public void encodeLayer(XMLBuilder xmlBuilder, TileLayer tileLayer) throws IOException {
LayerInfo layerInfo = getLayerInfo(tileLayer, tileLayer.getName());
if (layerInfo == null) {
// dimension are not supported for this layer (maybe is a layer group)
return;
}
List<Dimension> dimensions = DimensionsUtils.extractDimensions(wms, layerInfo);
encodeLayerDimensions(xmlBuilder, dimensions);
try {
List<Dimension> dimensions = DimensionsUtils.extractDimensions(wms, layerInfo, ALL_DOMAINS);
encodeLayerDimensions(xmlBuilder, dimensions);
} catch (OWSException e) {
// should not happen
throw new RuntimeException(e);
}
}

private Domains getDomains(SimpleConveyor conveyor) throws Exception {
// getting and parsing the mandatory parameters
String layerName = (String) conveyor.getParameter("layer", true);
TileLayer tileLayer = tileLayerDispatcher.getTileLayer(layerName);
LayerInfo layerInfo = getLayerInfo(tileLayer, layerName);
Set<String> requestedDomains = getRequestedDomains(conveyor.getParameter("domains", false));
// getting this layer dimensions along with its values
List<Dimension> dimensions = DimensionsUtils.extractDimensions(wms, layerInfo);
List<Dimension> dimensions = DimensionsUtils.extractDimensions(wms, layerInfo, requestedDomains);
// let's see if we have a spatial limitation
ReferencedEnvelope boundingBox = (ReferencedEnvelope) conveyor.getParameter("bbox", false);
// if we have a bounding box we need to set the crs based on the tile matrix set
Expand All @@ -162,15 +184,42 @@ private Domains getDomains(SimpleConveyor conveyor) throws Exception {
boundingBox = new ReferencedEnvelope(boundingBox, CRS.decode(gridSubset.getSRS().toString()));
}
// add any domain provided restriction and set the bounding box
Filter filter = Filter.INCLUDE;
ResourceInfo resource = layerInfo.getResource();
Filter filter = DimensionsUtils.getBoundingBoxFilter(resource, boundingBox, filterFactory);
for (Dimension dimension : dimensions) {
Object restriction = conveyor.getParameter(dimension.getDimensionName(), false);
dimension.setBoundingBox(boundingBox);
dimension.addDomainRestriction(restriction);
filter = filterFactory.and(filter, dimension.getFilter());
if (restriction != null) {
Tuple<String, String> attributes = DimensionsUtils.getAttributes(resource, dimension);
filter = appendDomainRestrictionsFilter(filter, attributes.first, attributes.second, restriction);
}
}
// compute the bounding box
ReferencedEnvelope spatialDomain = null;
if (requestedDomains == ALL_DOMAINS || requestedDomains.contains(SPACE_DIMENSION)) {
spatialDomain = DimensionsUtils.getBounds(resource, filter);
}
// encode the domains
return new Domains(dimensions, layerInfo, boundingBox, SimplifyingFilterVisitor.simplify(filter));
return new Domains(dimensions, layerInfo, spatialDomain, SimplifyingFilterVisitor.simplify(filter));
}

/**
* Helper method that will build a dimension domain values filter based on this dimension start and end
* attributes. The created filter will be merged with the provided filter.
*/
protected Filter appendDomainRestrictionsFilter(Filter filter, String startAttribute, String endAttribute, Object domainRestrictions) {
DimensionFilterBuilder dimensionFilterBuilder = new DimensionFilterBuilder(filterFactory);
List<Object> restrictionList = domainRestrictions instanceof Collection ? new ArrayList<>((Collection) domainRestrictions) : Arrays.asList(domainRestrictions);
dimensionFilterBuilder.appendFilters(startAttribute, endAttribute, restrictionList);
return filterFactory.and(filter, dimensionFilterBuilder.getFilter());
}

private Set<String> getRequestedDomains(Object domains) {
if (domains == null) {
return ALL_DOMAINS;
}

String[] domainNames = domains.toString().trim().split("\\s*,\\s*");
return new LinkedHashSet<>(Arrays.asList(domainNames));
}

private void executeDescribeDomainsOperation(SimpleConveyor conveyor) throws Exception {
Expand Down Expand Up @@ -242,7 +291,7 @@ private void encodeLayerDimension(XMLBuilder xml, Dimension dimension) throws IO
xml.simpleElement("ows:Identifier", dimension.getDimensionName(), true);
// default value is mandatory
xml.simpleElement("Default", dimension.getDefaultValueAsString(), true);
for (String value : dimension.getDomainValuesAsStrings(Filter.INCLUDE).second.second) {
for (String value : dimension.getDomainValuesAsStrings(Filter.INCLUDE).second) {
xml.simpleElement("Value", value, true);
}
xml.endElement("Dimension");
Expand Down

0 comments on commit c44ed73

Please sign in to comment.