Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancing WMTS support #390

Merged
merged 2 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class WmtsLayerDataSource extends LayerDataSource {
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private WmtsTileGrid tileGrid;

@ElementCollection(targetClass = String.class)
@ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<String> urls;

Expand All @@ -39,6 +39,7 @@ public class WmtsLayerDataSource extends LayerDataSource {
private String projection;
private String matrixSet;
private String requestEncoding;
private String capabilitiesUrl;

/**
* Default constructor
Expand All @@ -56,7 +57,8 @@ public WmtsLayerDataSource() {
* @param requestEncoding
* @param urls
*/
public WmtsLayerDataSource(WmtsTileGrid tileGrid, String wmtsLayer, String wmtsStyle, String projection, String matrixSet, String requestEncoding, List<String> urls) {
public WmtsLayerDataSource(WmtsTileGrid tileGrid, String wmtsLayer, String wmtsStyle, String projection,
String matrixSet, String requestEncoding, List<String> urls, String capabilitiesUrl) {
this();
this.tileGrid = tileGrid;
this.wmtsLayer = wmtsLayer;
Expand All @@ -65,6 +67,7 @@ public WmtsLayerDataSource(WmtsTileGrid tileGrid, String wmtsLayer, String wmtsS
this.matrixSet = matrixSet;
this.requestEncoding = requestEncoding;
this.urls = urls;
this.capabilitiesUrl = capabilitiesUrl;
}

/**
Expand Down Expand Up @@ -165,6 +168,22 @@ public void setUrls(List<String> urls) {
this.urls = urls;
}

/**
*
* @return The capabilitiesUrl
*/
public String getCapabilitiesUrl() {
return capabilitiesUrl;
}

/**
*
* @param capabilitiesUrl The capabilitiesUrl to set
*/
public void setCapabilitiesUrl(String capabilitiesUrl) {
this.capabilitiesUrl = capabilitiesUrl;
}

/**
* @see java.lang.Object#hashCode()
* <p>
Expand All @@ -184,6 +203,7 @@ public int hashCode() {
append(getWmtsStyle()).
append(getTileGrid()).
append(getUrls()).
append(getCapabilitiesUrl()).
toHashCode();
}

Expand All @@ -210,6 +230,7 @@ public boolean equals(Object obj) {
append(getWmtsStyle(), other.getWmtsStyle()).
append(getTileGrid(), other.getTileGrid()).
append(getUrls(), other.getUrls()).
append(getCapabilitiesUrl(), other.getCapabilitiesUrl()).
isEquals();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,73 +376,52 @@ public Response interceptWmtsRequest(HttpServletRequest request, String serviceI
}

/**
* Calls the main method with empty optionals hashmap
* @param request
* @return
* @throws InterceptorException
* @throws URISyntaxException
* @throws HttpException
* @throws IOException
*/
public Response interceptGeoServerRequest(HttpServletRequest request)
throws InterceptorException, URISyntaxException, HttpException, IOException {
return interceptGeoServerRequest(request, new HashMap<String, Optional<String>>());
public Response interceptGeoServerRequest( HttpServletRequest request )
throws InterceptorException, URISyntaxException,
HttpException, IOException {
return interceptGeoServerRequest( request, Optional.empty() );
}

/**
*
* @param request
* @param optionals
* @param endpoint
* @return
* @throws InterceptorException
* @throws URISyntaxException
* @throws HttpException
* @throws IOException
*/
public Response interceptGeoServerRequest(
HttpServletRequest request,
HashMap<String, Optional<String>> optionals)
throws InterceptorException, URISyntaxException,
HttpException, IOException {
public Response interceptGeoServerRequest(HttpServletRequest request, Optional<String> endpoint)
throws InterceptorException, URISyntaxException, HttpException, IOException {

// wrap the request, we want to manipulate it
MutableHttpServletRequest mutableRequest =
new MutableHttpServletRequest(request);
if (optionals.containsKey("endpoint") && optionals.get("endpoint").isPresent()) {
mutableRequest.addParameter("CUSTOM_ENDPOINT", optionals.get("endpoint").get());
MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(request);
if (endpoint.isPresent()) {
mutableRequest.addParameter("CUSTOM_ENDPOINT", endpoint.get());
mutableRequest.addParameter("CONTEXT_PATH", request.getContextPath());
}

// check if we have a RESTful WMTS request
boolean isRestfulWmts = false;
boolean isRestfulWmtsGetFeatureinfo = false;
if (optionals.containsKey("layername") && optionals.get("layername").isPresent() &&
optionals.containsKey("style") && optionals.get("style").isPresent() &&
optionals.containsKey("tilematrixset") && optionals.get("tilematrixset").isPresent() &&
optionals.containsKey("tilematrix") && optionals.get("tilematrix").isPresent() &&
optionals.containsKey("tilerow") && optionals.get("tilerow").isPresent() &&
optionals.containsKey("tilecol") && optionals.get("tilecol").isPresent()) {
isRestfulWmts = true;
if (optionals.containsKey("j") && optionals.get("j").isPresent() &&
optionals.containsKey("i") && optionals.get("i").isPresent()) {
isRestfulWmtsGetFeatureinfo = true;
}
}
// get the OGC message information (service, request, endPoint)
OgcMessage message = getOgcMessage(mutableRequest, isRestfulWmts, isRestfulWmtsGetFeatureinfo);
OgcMessage message = getOgcMessage(mutableRequest);

// check whether WMS reflector endpoint should be called
final boolean useWmsReflector = shouldReflectEndpointBeCalled(mutableRequest, message);

// get the GeoServer base URI by the provided request
URI geoServerBaseUri = getGeoServerBaseURI(message, useWmsReflector);

// set the GeoServer base URI to the (wrapped) request
mutableRequest.setRequestURI(geoServerBaseUri);

// intercept the request (if needed)
mutableRequest = ogcMessageDistributor
.distributeToRequestInterceptor(mutableRequest, message, optionals);
mutableRequest = ogcMessageDistributor.distributeToRequestInterceptor(mutableRequest, message);

// send the request
// TODO: Move to global proxy class
Expand Down Expand Up @@ -489,14 +468,11 @@ private boolean shouldReflectEndpointBeCalled(MutableHttpServletRequest mutableR

/**
* @param mutableRequest
* @param isRestfulWmtsGetFeatureinfo
* @param isRestfulWmts
* @return
* @throws InterceptorException
* @throws IOException
*/
private OgcMessage getOgcMessage(MutableHttpServletRequest mutableRequest, boolean isRestfulWmts,
boolean isRestfulWmtsGetFeatureinfo)
private OgcMessage getOgcMessage(MutableHttpServletRequest mutableRequest)
throws InterceptorException, IOException {

LOG.trace("Building the OGC message from the given request.");
Expand All @@ -510,15 +486,24 @@ private OgcMessage getOgcMessage(MutableHttpServletRequest mutableRequest, boole
String requestEndPoint = MutableHttpServletRequest.getRequestParameterValue(
mutableRequest, OgcEnum.EndPoint.getAllValues());

if (isRestfulWmts) {
requestService = ServiceType.WMTS.toString();
String format = mutableRequest.getParameterIgnoreCase("format");
if (isRestfulWmtsGetFeatureinfo) {
requestOperation = OperationType.GET_FEATURE_INFO.toString();
} else if (format != null && format.toLowerCase(Locale.ROOT).contains("image")) {
requestOperation = OperationType.GET_TILE.toString();
} else {
requestOperation = OperationType.GET_CAPABILITIES.toString();
// always use the custom_endpoint as endpoint and not one of the other options to successfully determine
// the base URI
if (!StringUtils.isEmpty(requestService) && requestService.equalsIgnoreCase("wmts")) {
requestEndPoint = MutableHttpServletRequest.getRequestParameterValue(
mutableRequest, OgcEnum.EndPoint.CUSTOM_ENDPOINT.toString());
}

// check for RESTful WMTS request
if (StringUtils.isEmpty(requestService) && StringUtils.isEmpty(requestOperation)) {
if (WmtsUtil.isRestfulWmtsRequest(mutableRequest)) {
requestService = ServiceType.WMTS.toString();
if (WmtsUtil.isRestfulWmtsGetFeatureinfo(mutableRequest)) {
requestOperation = OperationType.GET_FEATURE_INFO.toString();
} else if (WmtsUtil.isRestfulWmtsGetTile(mutableRequest)) {
requestOperation = OperationType.GET_TILE.toString();
} else {
requestOperation = OperationType.GET_CAPABILITIES.toString();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Optional;

import static org.apache.logging.log4j.LogManager.getLogger;

Expand Down Expand Up @@ -132,35 +130,14 @@ public class OgcMessageDistributor {
@Qualifier("wpsResponseInterceptor")
private WpsResponseInterceptorInterface wpsResponseInterceptor;

/**
*
* @param request
* @param message
* @return
* @throws InterceptorException
*/
public MutableHttpServletRequest distributeToRequestInterceptor(
MutableHttpServletRequest request,
OgcMessage message) throws InterceptorException {
return distributeToRequestInterceptor(
request,
message,
new HashMap<String, Optional<String>>()
);
}

/**
* @param request
* @param message
* @param optionals
* @return
* @throws InterceptorException
*/
public MutableHttpServletRequest distributeToRequestInterceptor(
MutableHttpServletRequest request,
OgcMessage message,
HashMap<String, Optional<String>> optionals)
throws InterceptorException {
MutableHttpServletRequest request, OgcMessage message) throws InterceptorException {

if (message.isRequestAllowed()) {
LOG.debug("Request is ALLOWED, not intercepting the request.");
Expand Down Expand Up @@ -218,13 +195,9 @@ public MutableHttpServletRequest distributeToRequestInterceptor(
if (message.isWmtsGetCapabilities()) {
request = this.wmtsRequestInterceptor.interceptGetCapabilities(request);
} else if (message.isWmtsGetTile()) {
request = this.wmtsRequestInterceptor.interceptGetTile(
request,
optionals);
request = this.wmtsRequestInterceptor.interceptGetTile(request);
} else if (message.isWmtsGetFeatureInfo()) {
request = this.wmtsRequestInterceptor.interceptGetFeatureInfo(
request,
optionals);
request = this.wmtsRequestInterceptor.interceptGetFeatureInfo(request);
} else {
throw new InterceptorException(operationErrMsg);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package de.terrestris.shoguncore.util.interceptor;

import java.util.HashMap;
import java.util.Optional;

import org.springframework.stereotype.Component;

@Component
public interface WmtsRequestInterceptorInterface {

MutableHttpServletRequest interceptGetTile(MutableHttpServletRequest request, HashMap<String, Optional<String>> optionals);
MutableHttpServletRequest interceptGetTile(MutableHttpServletRequest request);

MutableHttpServletRequest interceptGetCapabilities(MutableHttpServletRequest request);

MutableHttpServletRequest interceptGetFeatureInfo(MutableHttpServletRequest request, HashMap<String, Optional<String>> optionals);
MutableHttpServletRequest interceptGetFeatureInfo(MutableHttpServletRequest request);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package de.terrestris.shoguncore.util.interceptor;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;

import java.util.Locale;
import java.util.regex.Pattern;

import static org.apache.logging.log4j.LogManager.getLogger;

/**
* @author Johannes Weskamm
* @author terrestris GmbH & Co. KG
*/
public class WmtsUtil {

/**
* The Logger.
*/
private static final Logger LOG = getLogger(WmtsUtil.class);

/**
* Check if given request is a RESTful WMTS call
* @param mutableRequest
* @return
*/
public static boolean isRestfulWmtsRequest(MutableHttpServletRequest mutableRequest) {
String url = mutableRequest.getRequestURL().toString();
String service = mutableRequest.getParameterIgnoreCase("service");
if (!StringUtils.isEmpty(service) && service.equalsIgnoreCase("wmts")) {
// looks like KVP
return false;
}
weskamm marked this conversation as resolved.
Show resolved Hide resolved
return Pattern.compile(".*/geoserver.action/.*/wmts/\\d+/(.*)").matcher(url).matches();
}

/**
* Check if given request is a RESTful GetFeatureInfo call
* @param mutableRequest
* @return
*/
public static boolean isRestfulWmtsGetFeatureinfo(MutableHttpServletRequest mutableRequest) {
if (!isRestfulWmtsRequest(mutableRequest)) {
return false;
}
String url = mutableRequest.getRequestURL().toString();
// weak test if we have at least 4 digits in the path for tilecol, tilerow, i and j
return !isRestfulWmtsGetTile(mutableRequest) &&
Pattern.compile("\\/\\d+\\/\\d+\\/\\d+\\/\\d+").matcher(url).matches();
}

/**
* Check if given request is a RESTful GetTile call
* @param mutableRequest
* @return
*/
public static boolean isRestfulWmtsGetTile(MutableHttpServletRequest mutableRequest) {
if (!isRestfulWmtsRequest(mutableRequest)) {
return false;
}
String url = mutableRequest.getRequestURL().toString();
String format = mutableRequest.getParameterIgnoreCase("format");
if (format == null) {
if (url.endsWith(".png") ||
url.endsWith(".jpg") ||
url.endsWith(".jpeg") ||
url.endsWith(".gif")) {
return true;
}
} else if (format.toLowerCase(Locale.ROOT).contains("image")) {
// GeoServer way of handling image format in RESTful requests
return true;
}
return false;
}

/**
* Return the layer id for the given request
* @param mutableRequest
* @return
*/
public static String getLayerId(MutableHttpServletRequest mutableRequest) {
try {
String part = mutableRequest.getRequestURL().toString().split("/wmts/")[1];
return part.split("/")[0];
} catch (Exception e) {
return null;
}
}
}
Loading