Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -48,4 +48,6 @@ public class LayerInfo {

@JacksonXmlProperty(localName = "Style")
private Style style;

protected NcWmsLayerInfo ncWmsLayerInfo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package au.org.aodn.ogcapi.server.core.model.ogc.wms;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
import java.util.Map;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class NcWmsLayerInfo {

@JsonProperty("title")
private String title;

@JsonProperty("abstract")
private String abstractText;

@JsonProperty("units")
private String units;

@JsonProperty("bbox")
private List<Double> bbox;

@JsonProperty("scales")
private List<Double> scales;

@JsonProperty("palettes")
private List<String> palettes;

@JsonProperty("defaultPalette")
private String defaultPalette;

@JsonProperty("timeAxis")
private List<String> timeAxis;

@JsonProperty("elevationAxis")
private List<Double> elevationAxis;

@JsonProperty("scaleRange")
private List<Double> scaleRange;

@JsonProperty("datesWithData")
private Map<String, Map<String, List<Integer>>> datesWithData;

@JsonProperty("numColorBands")
private Integer numColorBands;

@JsonProperty("supportedStyles")
private List<String> supportedStyles;

@JsonProperty("moreInfo")
private String moreInfo;

@JsonProperty("timeAxisUnits")
private String timeAxisUnits;

@JsonProperty("nearestTimeIso")
private String nearestTimeIso;

@JsonProperty("logScaling")
private boolean logScaling;
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,11 @@ public Optional<String> getFeatureServerUrlByTitleOrQueryParam(String collection
/**
* Fuzzy match utility to compare layer names, ignoring namespace prefixes
* For example: "underway:nuyina_underway_202122020" matches "nuyina_underway_202122020"
* For example: "abc/cde" matches "abc"
*
* @param text1 - First text to compare
* @param text2 - Second text to compare
* @return true if texts match (after removing namespace prefix)
* @return true if texts match (after removing namespace prefix) and subfix
*/
protected boolean roughlyMatch(String text1, String text2) {
if (text1 == null || text2 == null) {
Expand All @@ -197,13 +198,11 @@ protected boolean roughlyMatch(String text1, String text2) {
String normalized1 = text1.contains(":") ? text1.substring(text1.indexOf(":") + 1) : text1;
String normalized2 = text2.contains(":") ? text2.substring(text2.indexOf(":") + 1) : text2;

if (normalized1.length() < normalized2.length()) {
// Swap the text so that compare startsWith using longer text.
String temp = normalized1;
normalized1 = normalized2;
normalized2 = temp;
}
return normalized1.startsWith(normalized2);
// Remove "/" and anything follows
normalized1 = normalized1.split("/")[0];
normalized2 = normalized2.split("/")[0];

return normalized1.equals(normalized2);
}
/**
* Extract typename from WFS URL query parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class WmsDefaultParam {

private Map<String, String> wms;
private Map<String, String> ncwms;
private Map<String, String> ncmetadata;

private Map<String, String> descLayer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@
import au.org.aodn.ogcapi.server.core.model.StacCollectionModel;
import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest;
import au.org.aodn.ogcapi.server.core.model.ogc.wfs.DownloadableFieldModel;
import au.org.aodn.ogcapi.server.core.model.ogc.wms.DescribeLayerResponse;
import au.org.aodn.ogcapi.server.core.model.ogc.wms.FeatureInfoResponse;
import au.org.aodn.ogcapi.server.core.model.ogc.wms.GetCapabilitiesResponse;
import au.org.aodn.ogcapi.server.core.model.ogc.wms.LayerInfo;
import au.org.aodn.ogcapi.server.core.model.ogc.wms.*;
import au.org.aodn.ogcapi.server.core.service.ElasticSearchBase;
import au.org.aodn.ogcapi.server.core.service.Search;
import au.org.aodn.ogcapi.server.core.service.wfs.WfsServer;
import au.org.aodn.ogcapi.server.core.util.RestTemplateUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -29,6 +27,7 @@

import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -56,6 +55,9 @@
@Autowired
protected WmsDefaultParam wmsDefaultParam;

@Autowired
protected ObjectMapper objectMapper;

@Lazy
@Autowired
protected WmsServer self;
Expand Down Expand Up @@ -114,8 +116,8 @@
if (range.size() == 2) {
// Due to no standard name, we try our best to guess if 2 dateTime field, range mean we found start/end date
String[] d = request.getDatetime().split("/");
String guess1 = target.get(0).getName();
String guess2 = target.get(1).getName();
String guess1 = range.get(0).getName();
String guess2 = range.get(1).getName();

if ((guess1.contains("start") || guess1.contains("min")) && (guess2.contains("end") || guess2.contains("max"))) {
String timeCql = String.format("CQL_FILTER=%s >= %s AND %s <= %s", guess1, d[0], guess2, d[1]);
Expand Down Expand Up @@ -174,6 +176,9 @@
param.putAll(wmsDefaultParam.getWms());
} else if (pathSegments.get(pathSegments.size() - 1).equalsIgnoreCase("ncwms")) {
param.putAll(wmsDefaultParam.getNcwms());
if(request.getDatetime() != null) {
param.put("TIME", request.getDatetime());
}
}

// Now we add the missing argument from the request
Expand Down Expand Up @@ -215,12 +220,23 @@
builder.queryParam(key, value);
}
});
// Cannot set cql in param as it contains value like "/" which is not allow in UriComponent checks
// but server must use "/" in param and cannot encode it to %2F, so to avoid exception in the
// build() call, we append the cql after the construction.
String target = String.join("&", builder.build().toUriString(), createCQLFilter(uuid, request));
log.debug("Url to wms geoserver {}", target);
urls.add(target);
if (pathSegments.get(pathSegments.size() - 1).equalsIgnoreCase("ncwms")) {
// ncWMS (including GeoServer extension) does not support CQL_FILTER.
// It focuses on NetCDF gridded data with parameters like TIME, ELEVATION, COLORSCALERANGE,
// STYLES (palettes), NUMCOLORBANDS. CQL_FILTER is a GeoServer vendor parameter for vector
// filtering, not implemented in ncWMS. So we only add CQL if it is WMS
String target = builder.build().toUriString();
log.debug("Url to ncWms geoserver {}", target);
urls.add(target);
}
else {
// Cannot set cql in param as it contains value like "/" which is not allow in UriComponent checks
// but server must use "/" in param and cannot encode it to %2F, so to avoid exception in the
// build() call, we append the cql after the construction.
String target = String.join("&", builder.build().toUriString(), createCQLFilter(uuid, request));
log.debug("Url to wms geoserver {}", target);
urls.add(target);
}

return urls;
}
Expand Down Expand Up @@ -494,7 +510,13 @@
log.debug("map tile request for layer name {} url {} ", request.getLayerName(), url);
ResponseEntity<byte[]> response = restTemplateUtils.handleRedirect(url, restTemplate.exchange(url, HttpMethod.GET, pretendUserEntity, byte[].class), byte[].class, pretendUserEntity);
if (response.getStatusCode().is2xxSuccessful()) {
return response.getBody();
if (response.getHeaders().getContentType() != null && response.getHeaders().getContentType().getType().equals("image")) {
return response.getBody();
}
else {
// Something wrong from the server likely syntax error
throw new URISyntaxException(response.getBody() != null ? new String(response.getBody(), StandardCharsets.UTF_8) : "", url);
}
}
}
}
Expand Down Expand Up @@ -602,16 +624,43 @@
if(filteredLayers.isEmpty() && request.getLayerName() != null) {
DescribeLayerResponse dr = describeLayer(collectionId, request);
if(dr != null) {
// That means at least layer is valid just not operational
return List.of(
// That means at least layer is valid just not works with wfs, we should keep the
// original layername instead showing the lookup name as it can be different from
// what is mentioned in the metadata which people get confused.
filteredLayers = List.of(
LayerInfo.builder()
.name(dr.getLayerDescription().getName())
.title(dr.getLayerDescription().getName())
.name(request.getLayerName())
.title(request.getLayerName())
.queryable("0")
.build()
);
}
}

// Special case for NCWMS layer where we need to call GetMetadata to find the related points for gridded data
if(mapServerUrl.get().contains("/ncwms")) {
filteredLayers.forEach(layer -> {
// For each ncwms layer, we attach the metadata
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(mapServerUrl.get());
builder.scheme("https"); // Force https

wmsDefaultParam.getNcmetadata().forEach((key, value) -> {
if (value != null) {
builder.queryParam(key, value);
}
});
builder.queryParam("layerName", layer.getName());

ResponseEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, pretendUserEntity, String.class);
if(response.getStatusCode().is2xxSuccessful()) {
try {
layer.setNcWmsLayerInfo(objectMapper.readValue(response.getBody(), NcWmsLayerInfo.class));
} catch (JsonProcessingException e) {
// Save to ignore
}
}
});
}
log.debug("Returning layers {}", filteredLayers);

return filteredLayers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public ResponseEntity<FeatureInfoResponse> getWmsMapFeature(String collectionId,
public ResponseEntity<byte[]> getWmsMapTile(String collectionId, FeatureRequest request) {
try {
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_PNG)
.body(wmsServer.getMapTile(collectionId, request));
} catch (Throwable e) {
throw new RuntimeException(e);
Expand Down
7 changes: 7 additions & 0 deletions server/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,15 @@ wms-default-param:
STYLES: ""
QUERYABLE: "true"
CRS: "EPSG:3857"
NUMCOLORBANDS: "253"
WIDTH: 256
HEIGHT: 256
ncmetadata:
SERVICE: "ncwms"
REQUEST: "GetMetadata"
VERSION: "1.3.0"
# Must be small letter item !!!
item: "layerDetails"
allow-id: # Full list
- 4402cb50-e20a-44ee-93e6-4728259250d2
- ae86e2f5-eaaf-459e-a405-e654d85adb9c
Expand Down
Loading
Loading