Skip to content

Commit

Permalink
WFS3 getTile
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandor777 authored and aaime committed Sep 28, 2018
1 parent 040b6b1 commit e492eee
Show file tree
Hide file tree
Showing 19 changed files with 661 additions and 28 deletions.
5 changes: 5 additions & 0 deletions src/community/wfs3/pom.xml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
<artifactId>gs-vectortiles</artifactId> <artifactId>gs-vectortiles</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.geowebcache</groupId>
<artifactId>gwc-core</artifactId>
<version>${gwc.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId> <artifactId>jackson-core</artifactId>
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
import org.geoserver.wfs3.response.CollectionsDocument; import org.geoserver.wfs3.response.CollectionsDocument;
import org.geoserver.wfs3.response.ConformanceDocument; import org.geoserver.wfs3.response.ConformanceDocument;
import org.geoserver.wfs3.response.LandingPageDocument; import org.geoserver.wfs3.response.LandingPageDocument;
import org.geoserver.wfs3.response.TilingSchemesDocument;
import org.geotools.util.logging.Logging; import org.geotools.util.logging.Logging;
import org.geowebcache.config.DefaultGridsets;
import org.opengis.filter.FilterFactory2; import org.opengis.filter.FilterFactory2;


/** WFS 3.0 implementation */ /** WFS 3.0 implementation */
Expand All @@ -47,10 +49,17 @@ public class DefaultWebFeatureService30 implements WebFeatureService30 {
private FilterFactory2 filterFactory; private FilterFactory2 filterFactory;
private final GeoServer geoServer; private final GeoServer geoServer;
private WebFeatureService20 wfs20; private WebFeatureService20 wfs20;
private final DefaultGridsets gridSets;


public DefaultWebFeatureService30(GeoServer geoServer, WebFeatureService20 wfs20) { public DefaultWebFeatureService30(GeoServer geoServer, WebFeatureService20 wfs20) {
this(geoServer, wfs20, new DefaultGridsets(true, true));
}

public DefaultWebFeatureService30(
GeoServer geoServer, WebFeatureService20 wfs20, DefaultGridsets gridSets) {
this.geoServer = geoServer; this.geoServer = geoServer;
this.wfs20 = wfs20; this.wfs20 = wfs20;
this.gridSets = gridSets;
} }


public FilterFactory2 getFilterFactory() { public FilterFactory2 getFilterFactory() {
Expand Down Expand Up @@ -166,4 +175,20 @@ public OpenAPI api(APIRequest request) {
public WFSInfo getServiceInfo() { public WFSInfo getServiceInfo() {
return geoServer.getService(WFSInfo.class); return geoServer.getService(WFSInfo.class);
} }

@Override
public TilingSchemesDocument tilingSchemes(TilingSchemesRequest request) {
return new TilingSchemesDocument(geoServer, gridSets);
}

@Override
public FeatureCollectionResponse getTile(org.geoserver.wfs3.GetFeatureType request) {

WFS3GetFeature gf = new WFS3GetFeature(getServiceInfo(), getCatalog());
gf.setFilterFactory(filterFactory);
gf.setStoredQueryProvider(getStoredQueryProvider());
FeatureCollectionResponse response = gf.run(new GetFeatureRequest.WFS20(request));

return response;
}
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
/** This class extends WFS 2.0 GetFeatureType just to allow having a custom KVP reader for it */ /** This class extends WFS 2.0 GetFeatureType just to allow having a custom KVP reader for it */
public class GetFeatureType extends GetFeatureTypeImpl { public class GetFeatureType extends GetFeatureTypeImpl {


private String resolution; private Integer resolution;


/** Custom vector tile resolution */ /** Custom vector tile resolution */
public String getResolution() { public Integer getResolution() {
return resolution; return resolution;
} }


public void setResolution(String resolution) { public void setResolution(Integer resolution) {
this.resolution = resolution; this.resolution = resolution;
} }
} }
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,54 @@
/* (c) 2018 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs3;

import org.apache.commons.lang3.StringUtils;

/** Current tiling request scope data, for context propagation */
public class TileDataRequest {

private String tilingScheme;
private Long level;
private Long row;
private Long col;

public TileDataRequest() {}

public boolean isTileRequest() {
return (StringUtils.isNotBlank(tilingScheme) && level != null && row != null & col != null);
}

public String getTilingScheme() {
return tilingScheme;
}

public void setTilingScheme(String tilingScheme) {
this.tilingScheme = tilingScheme;
}

public Long getLevel() {
return level;
}

public void setLevel(Long level) {
this.level = level;
}

public Long getRow() {
return row;
}

public void setRow(Long row) {
this.row = row;
}

public Long getCol() {
return col;
}

public void setCol(Long col) {
this.col = col;
}
}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,7 @@
/* (c) 2018 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs3;

public class TilingSchemesRequest extends BaseRequest {}
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.RequestWrapper;
import org.geoserver.catalog.Catalog; import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.LayerInfo;
import org.geoserver.filters.GeoServerFilter; import org.geoserver.filters.GeoServerFilter;
import org.geoserver.ows.HttpErrorCodeException; import org.geoserver.ows.HttpErrorCodeException;
import org.geoserver.wfs.kvp.BBoxKvpParser; import org.geoserver.wfs.kvp.BBoxKvpParser;
import org.geoserver.wfs3.response.RFCGeoJSONFeaturesResponse; import org.geoserver.wfs3.response.RFCGeoJSONFeaturesResponse;
import org.geoserver.wms.mapbox.MapBoxTileBuilderFactory;
import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.logging.Logging; import org.geotools.util.logging.Logging;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -91,6 +91,10 @@ private class RequestWrapper extends HttpServletRequestWrapper {
private String outputFormat; private String outputFormat;
private String featureId; private String featureId;
private String limit; private String limit;
private String tilingScheme;
private String level;
private String row;
private String col;


private RequestWrapper(HttpServletRequest wrapped) { private RequestWrapper(HttpServletRequest wrapped) {
super(wrapped); super(wrapped);
Expand Down Expand Up @@ -159,6 +163,28 @@ private RequestWrapper(HttpServletRequest wrapped) {
} }
return matches; return matches;
}); });
// collections/{collectionId}/tiles/{tilingSchemeId}/{level}/{row}/{col}
matchers.add(
path -> {
Matcher matcher =
Pattern.compile(
"/collections/([^/]+)/tiles/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?")
.matcher(path);
boolean matches = matcher.matches();
if (matches) {
request = "getTile";
String layerName = matcher.group(1);
if (layerName != null) {
layerName = urlDecode(layerName);
}
setLayerName(layerName);
this.tilingScheme = urlDecode(matcher.group(2));
this.level = urlDecode(matcher.group(3));
this.row = urlDecode(matcher.group(4));
this.col = urlDecode(matcher.group(5));
}
return matches;
});


// loop over the matchers // loop over the matchers
boolean matched = false; boolean matched = false;
Expand All @@ -173,6 +199,8 @@ private RequestWrapper(HttpServletRequest wrapped) {
throw new HttpErrorCodeException( throw new HttpErrorCodeException(
HttpStatus.NOT_FOUND.value(), "Unsupported path " + pathInfo); HttpStatus.NOT_FOUND.value(), "Unsupported path " + pathInfo);
} }
} else if (pathInfo.startsWith("/tilingSchemes")) {
request = "tilingSchemes";
} else { } else {
throw new HttpErrorCodeException( throw new HttpErrorCodeException(
HttpStatus.NOT_FOUND.value(), "Unsupported path " + pathInfo); HttpStatus.NOT_FOUND.value(), "Unsupported path " + pathInfo);
Expand All @@ -195,6 +223,8 @@ private RequestWrapper(HttpServletRequest wrapped) {
} }
} else if ("getFeature".equals(request)) { } else if ("getFeature".equals(request)) {
this.outputFormat = RFCGeoJSONFeaturesResponse.MIME; this.outputFormat = RFCGeoJSONFeaturesResponse.MIME;
} else if ("getTile".equals(request)) {
this.outputFormat = MapBoxTileBuilderFactory.MIME_TYPE;
} }


// support for the limit parameter // support for the limit parameter
Expand Down Expand Up @@ -245,7 +275,12 @@ public Map<String, String[]> getParameterMap() {
filtered.put("service", new String[] {"WFS"}); filtered.put("service", new String[] {"WFS"});
filtered.put("version", new String[] {"3.0.0"}); filtered.put("version", new String[] {"3.0.0"});
filtered.put("request", new String[] {request}); filtered.put("request", new String[] {request});
filtered.put("srsName", new String[] {"EPSG:4326"}); if ("GoogleMapsCompatible".equals(this.tilingScheme)) {
filtered.put("srsName", new String[] {"EPSG:3857"});
} else {
filtered.put("srsName", new String[] {"EPSG:4326"});
}

String bbox = super.getParameter("bbox"); String bbox = super.getParameter("bbox");
if (bbox != null) { if (bbox != null) {
try { try {
Expand Down Expand Up @@ -274,6 +309,10 @@ public Map<String, String[]> getParameterMap() {
if (limit != null && !limit.isEmpty()) { if (limit != null && !limit.isEmpty()) {
filtered.put("count", new String[] {limit}); filtered.put("count", new String[] {limit});
} }
if (tilingScheme != null) filtered.put("tilingScheme", new String[] {tilingScheme});
if (level != null) filtered.put("level", new String[] {level});
if (row != null) filtered.put("row", new String[] {row});
if (col != null) filtered.put("col", new String[] {col});
return filtered; return filtered;
} }


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.geoserver.wfs3.response.CollectionsDocument; import org.geoserver.wfs3.response.CollectionsDocument;
import org.geoserver.wfs3.response.ConformanceDocument; import org.geoserver.wfs3.response.ConformanceDocument;
import org.geoserver.wfs3.response.LandingPageDocument; import org.geoserver.wfs3.response.LandingPageDocument;
import org.geoserver.wfs3.response.TilingSchemesDocument;
import org.geotools.util.Version; import org.geotools.util.Version;


public interface WebFeatureService30 { public interface WebFeatureService30 {
Expand Down Expand Up @@ -63,4 +64,10 @@ public interface WebFeatureService30 {
* @return * @return
*/ */
FeatureCollectionResponse getFeature(GetFeatureType request); FeatureCollectionResponse getFeature(GetFeatureType request);

/** Tiling Schemes available list */
TilingSchemesDocument tilingSchemes(TilingSchemesRequest request);

/** Queries Features for the requested tile coordinate */
FeatureCollectionResponse getTile(GetFeatureType request);
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
import org.geoserver.platform.ServiceException; import org.geoserver.platform.ServiceException;
import org.geoserver.wfs.request.Query; import org.geoserver.wfs.request.Query;
import org.geoserver.wfs3.GetFeatureType; import org.geoserver.wfs3.GetFeatureType;
import org.geoserver.wfs3.TileDataRequest;
import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.DateRange; import org.geotools.util.DateRange;
import org.geowebcache.config.DefaultGridsets;
import org.geowebcache.grid.BoundingBox;
import org.geowebcache.grid.GridSet;
import org.locationtech.jts.geom.Envelope; import org.locationtech.jts.geom.Envelope;
import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.FeatureType;
import org.opengis.filter.Filter; import org.opengis.filter.Filter;
Expand All @@ -35,8 +39,13 @@


public class GetFeatureKvpRequestReader extends org.geoserver.wfs.kvp.GetFeatureKvpRequestReader { public class GetFeatureKvpRequestReader extends org.geoserver.wfs.kvp.GetFeatureKvpRequestReader {


public GetFeatureKvpRequestReader(GeoServer geoServer, FilterFactory filterFactory) { private DefaultGridsets gridSets;
private TileDataRequest tileData;

public GetFeatureKvpRequestReader(
GeoServer geoServer, FilterFactory filterFactory, DefaultGridsets gridSets) {
super(GetFeatureType.class, null, geoServer, filterFactory); super(GetFeatureType.class, null, geoServer, filterFactory);
this.gridSets = gridSets;
} }


@Override @Override
Expand All @@ -51,7 +60,7 @@ public Object read(Object request, Map kvp, Map rawKvp) throws Exception {
} }
// resolution vendor parameter: // resolution vendor parameter:
if (kvp.containsKey("resolution")) { if (kvp.containsKey("resolution")) {
gf.setResolution((String) kvp.get("resolution")); gf.setResolution((Integer) kvp.get("resolution"));
} }
return gf; return gf;
} }
Expand Down Expand Up @@ -99,9 +108,48 @@ private Filter getFullFilter(Map kvp) throws IOException {
Filter filter = buildTimeFilter(timeSpecification, timeProperties); Filter filter = buildTimeFilter(timeSpecification, timeProperties);
filters.add(filter); filters.add(filter);
} }
// BBOX filter for tileScheme, level, col, row
if (kvp.containsKey("level")
&& kvp.containsKey("row")
&& kvp.containsKey("col")
&& kvp.containsKey("tilingScheme")) {
try {
long level = Long.parseLong((String) kvp.get("level"));
long col = Long.parseLong((String) kvp.get("col"));
long row = Long.parseLong((String) kvp.get("row"));
String tilingScheme = (String) kvp.get("tilingScheme");
GridSet gridset = gridSet(tilingScheme);
// gridset.getSrs()
if (gridset != null) {
BoundingBox gbbox = gridset.boundsFromIndex(new long[] {col, row, level});
filters.add(
filterFactory.bbox(
"",
gbbox.getMinX(),
gbbox.getMinY(),
gbbox.getMaxX(),
gbbox.getMaxY(),
gridset.getSrs().toString()));
// tile request scoped data
tileData.setTilingScheme(tilingScheme);
tileData.setLevel(level);
tileData.setCol(col);
tileData.setRow(row);
}
} catch (NumberFormatException e) {
// don't worry, all will be fine
}
}
return mergeFiltersAnd(filters); return mergeFiltersAnd(filters);
} }


private GridSet gridSet(String tilingScheme) {
if (gridSets.getGridSet(tilingScheme).isPresent()) {
return gridSets.getGridSet(tilingScheme).get();
}
return null;
}

private Filter buildTimeFilter(Object timeSpec, List<String> timeProperties) { private Filter buildTimeFilter(Object timeSpec, List<String> timeProperties) {
List<Filter> filters = new ArrayList<>(); List<Filter> filters = new ArrayList<>();
for (String timeProperty : timeProperties) { for (String timeProperty : timeProperties) {
Expand Down Expand Up @@ -215,4 +263,12 @@ private Filter bboxFilter(Object bbox) {
throw new ServiceException( throw new ServiceException(
"Internal error, did not expect to find this value for the bbox: " + bbox); "Internal error, did not expect to find this value for the bbox: " + bbox);
} }

public TileDataRequest getTileData() {
return tileData;
}

public void setTileData(TileDataRequest tileData) {
this.tileData = tileData;
}
} }
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,14 @@
/* (c) 2018 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs3.kvp;

import org.geoserver.wfs3.TilingSchemesRequest;

public class TilingSchemesKVPReader extends BaseKvpRequestReader {

public TilingSchemesKVPReader() {
super(TilingSchemesRequest.class);
}
}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,14 @@
/* (c) 2018 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs3.kvp;

import org.geoserver.ows.kvp.IntegerKvpParser;

public class WFS3TileResolutionKvpParser extends IntegerKvpParser {

public WFS3TileResolutionKvpParser() {
super("resolution");
}
}

0 comments on commit e492eee

Please sign in to comment.