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 @@ -2,6 +2,7 @@

import au.org.aodn.ogcapi.server.core.service.CacheNoLandGeometry;
import au.org.aodn.ogcapi.server.core.service.CacheWarm;
import au.org.aodn.ogcapi.server.core.service.wfs.WfsServer;
import au.org.aodn.ogcapi.server.core.service.wms.WmsServer;
import au.org.aodn.ogcapi.server.core.util.GeometryUtils;
import org.ehcache.config.builders.*;
Expand Down Expand Up @@ -29,6 +30,7 @@ public class CacheConfig {

public static final String CACHE_WMS_MAP_TILE = "cache-wms-map_tile";
public static final String GET_CAPABILITIES_WMS_LAYERS = "get-capabilities-wms-layers";
public static final String GET_CAPABILITIES_WFS_FEATURE_TYPES = "get-capabilities-wfs-feature-types";
public static final String DOWNLOADABLE_FIELDS = "downloadable-fields";
public static final String ALL_NO_LAND_GEOMETRY = "all-noland-geometry";
public static final String ALL_PARAM_VOCABS = "parameter-vocabs";
Expand Down Expand Up @@ -103,6 +105,12 @@ public JCacheCacheManager cacheManager() throws IOException {
ResourcePoolsBuilder.heap(20)
).withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofHours(24)))
)
.withCache(GET_CAPABILITIES_WFS_FEATURE_TYPES,
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Object.class, Object.class,
ResourcePoolsBuilder.heap(20)
).withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofHours(24)))
)
.build();


Expand All @@ -119,8 +127,8 @@ public JCacheCacheManager cacheManager() throws IOException {
}

@Bean
public CacheWarm createCacheWarm(WmsServer wmsServer, CacheNoLandGeometry cacheNoLandGeometry, GeometryUtils geometryUtils) {
public CacheWarm createCacheWarm(WmsServer wmsServer, WfsServer wfsServer, CacheNoLandGeometry cacheNoLandGeometry, GeometryUtils geometryUtils) {
GeometryUtils.setSelf(geometryUtils);
return new CacheWarm(wmsServer, cacheNoLandGeometry, geometryUtils);
return new CacheWarm(wmsServer, wfsServer, cacheNoLandGeometry, geometryUtils);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public enum FeatureId {
wms_downloadable_fields("wms_downloadable_fields"), // Query field based on value from wms describe layer query
wms_map_tile("wms_map_tile"),
wms_map_feature("wms_map_feature"),
wms_layers("wms_layers"); // Get all available layers from WMS GetCapabilities
wms_layers("wms_layers"), // Get all available layers from WMS GetCapabilities
wfs_layers("wfs_layers"); // Get all available feature types from WFS GetCapabilities

public final String featureId;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package au.org.aodn.ogcapi.server.core.model.ogc.wfs;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JacksonXmlRootElement(localName = "FeatureType")
public class FeatureTypeInfo {

@JacksonXmlProperty(localName = "Name")
protected String name;

@JacksonXmlProperty(localName = "Title")
protected String title;

@JsonProperty("abstract")
@JacksonXmlProperty(localName = "Abstract")
private String abstract_;

@JacksonXmlProperty(localName = "Keywords", namespace = "http://www.opengis.net/ows/1.1")
private Keywords keywords;

@JacksonXmlProperty(localName = "DefaultCRS")
private String defaultCRS;

@JacksonXmlProperty(localName = "WGS84BoundingBox", namespace = "http://www.opengis.net/ows/1.1")
private WGS84BoundingBox wgs84BoundingBox;

@JacksonXmlProperty(localName = "MetadataURL")
private MetadataURL metadataURL;

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Keywords {
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "Keyword", namespace = "http://www.opengis.net/ows/1.1")
private List<String> keyword;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class WGS84BoundingBox {
@JacksonXmlProperty(localName = "LowerCorner", namespace = "http://www.opengis.net/ows/1.1")
private String lowerCorner;

@JacksonXmlProperty(localName = "UpperCorner", namespace = "http://www.opengis.net/ows/1.1")
private String upperCorner;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class MetadataURL {
@JacksonXmlProperty(isAttribute = true, localName = "href", namespace = "http://www.w3.org/1999/xlink")
private String href;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package au.org.aodn.ogcapi.server.core.model.ogc.wfs;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
@JacksonXmlRootElement(localName = "WFS_Capabilities", namespace = "http://www.opengis.net/wfs/2.0")
public class WfsGetCapabilitiesResponse {

@JacksonXmlProperty(localName = "FeatureTypeList")
private FeatureTypeList featureTypeList;

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class FeatureTypeList {
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "FeatureType")
private List<FeatureTypeInfo> featureTypes;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package au.org.aodn.ogcapi.server.core.service;

import au.org.aodn.ogcapi.server.core.model.StacCollectionModel;
import au.org.aodn.ogcapi.server.core.service.wfs.WfsServer;
import au.org.aodn.ogcapi.server.core.service.wms.WmsServer;
import au.org.aodn.ogcapi.server.core.util.GeometryUtils;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -10,9 +11,13 @@
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Scheduled;

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

import static au.org.aodn.ogcapi.server.core.configuration.CacheConfig.GET_CAPABILITIES_WFS_FEATURE_TYPES;
import static au.org.aodn.ogcapi.server.core.configuration.CacheConfig.GET_CAPABILITIES_WMS_LAYERS;

/**
* Some WMS server response very slow for GetCapabilities operation, so we warm some
* of those operation for the target server.
Expand All @@ -21,7 +26,7 @@
public class CacheWarm {
// Hardcode server list as not expect to change much overtime, add more if needed, the operation is
// heavy so we warm the cache when start
protected List<String> getCapabilitiesUrls = List.of(
protected List<String> getWmsCapabilitiesUrls = List.of(
"https://data.aad.gov.au/geoserver/underway/wms",
"https://www.cmar.csiro.au/geoserver/caab/wms",
"https://www.cmar.csiro.au/geoserver/ereefs/wms",
Expand All @@ -34,7 +39,18 @@ public class CacheWarm {
"https://geoserver.apps.aims.gov.au/aims/wms",
"https://geoserver.apps.aims.gov.au/reefcloud/wms"
);

// WFS server URLs for cache warming - using /ows endpoint which supports both WMS and WFS
protected List<String> getWfsCapabilitiesUrls = List.of(
"https://geoserver-123.aodn.org.au/geoserver/ows",
"https://geoserver.imas.utas.edu.au/geoserver/ows",
"https://www.cmar.csiro.au/geoserver/ows",
"https://geoserver.apps.aims.gov.au/aims/ows",
"https://data.aad.gov.au/geoserver/underway/ows"
);

protected WmsServer wmsServer;
protected WfsServer wfsServer;
protected GeometryUtils geometryUtils;
protected CacheNoLandGeometry cacheNoLandGeometry;

Expand All @@ -43,21 +59,36 @@ public class CacheWarm {
protected CacheWarm self;

public CacheWarm(WmsServer wmsServer,
WfsServer wfsServer,
CacheNoLandGeometry cacheNoLandGeometry,
GeometryUtils geometryUtils) {
this.cacheNoLandGeometry = cacheNoLandGeometry;
this.geometryUtils = geometryUtils;
this.wmsServer = wmsServer;
this.wfsServer = wfsServer;
}

/**
* Scheduled task to refresh specific keys 5 sec after starts and then every 23 hours
* Scheduled task to refresh WMS cache 5 sec after starts and then every 23 hours
*/
@Scheduled(initialDelay = 5000, fixedRate = 23 * 60 * 60 * 1000)
public void evictSpecificCacheEntries() {
// Evict specific keys one by one
getCapabilitiesUrls.forEach(url -> {
self.evictGetCapabilities(url);
self.warmGetCapabilities(url);
public void evictAndWarmWmsCache() {
// Evict and warm WMS cache entries one by one
getWmsCapabilitiesUrls.forEach(url -> {
self.evictWmsGetCapabilities(url);
self.warmWmsGetCapabilities(url);
});
}

/**
* Scheduled task to refresh WFS cache 10 sec after starts and then every 23 hours
*/
@Scheduled(initialDelay = 10000, fixedRate = 23 * 60 * 60 * 1000)
public void evictAndWarmWfsCache() {
// Evict and warm WFS cache entries one by one
getWfsCapabilitiesUrls.forEach(url -> {
self.evictWfsGetCapabilities(url);
self.warmWfsGetCapabilities(url);
});
}

Expand All @@ -71,24 +102,41 @@ public void keepWarmNoLandGeometryAndGeometryUtil() {
}


@CacheEvict(value = au.org.aodn.ogcapi.server.core.configuration.CacheConfig.GET_CAPABILITIES_WMS_LAYERS, key = "#key")
protected void evictGetCapabilities(String key){
// ==================== WMS Cache Methods ====================

@CacheEvict(value = GET_CAPABILITIES_WMS_LAYERS, key = "#key")
public void evictWmsGetCapabilities(String key) {
// @CacheEvict handles the eviction
log.info("Evicting cache {} for key {}",
au.org.aodn.ogcapi.server.core.configuration.CacheConfig.GET_CAPABILITIES_WMS_LAYERS,
key
);
log.info("Evicting WMS cache {} for key {}", GET_CAPABILITIES_WMS_LAYERS, key);
}

@Retryable(maxAttempts = 5, backoff = @Backoff(delay = 1000))
protected void warmGetCapabilities(String url) {
protected void warmWmsGetCapabilities(String url) {
try {
// Call and warm cache
wmsServer.fetchCapabilitiesLayersByUrl(url);
log.info("Cache GetCapabilities warm success for {}", url);
log.info("WMS Cache GetCapabilities warm success for {}", url);
} catch (RuntimeException rte) {
log.warn("WMS Cache GetCapabilities warm failed for {}, call will be slow", url);
}
catch(RuntimeException rte) {
log.warn("Cache GetCapabilities warm failed for {}, call will be slow", url);
}

// ==================== WFS Cache Methods ====================

@CacheEvict(value = GET_CAPABILITIES_WFS_FEATURE_TYPES, key = "#key")
public void evictWfsGetCapabilities(String key) {
// @CacheEvict handles the eviction
log.info("Evicting WFS cache {} for key {}", GET_CAPABILITIES_WFS_FEATURE_TYPES, key);
}

@Retryable(maxAttempts = 5, backoff = @Backoff(delay = 1000))
protected void warmWfsGetCapabilities(String url) {
try {
// Call and warm cache
wfsServer.fetchCapabilitiesFeatureTypesByUrl(url);
log.info("WFS Cache GetCapabilities warm success for {}", url);
} catch (RuntimeException rte) {
log.warn("WFS Cache GetCapabilities warm failed for {}, call will be slow", url);
}
}
}
Loading
Loading