From 75a446fb3773c21ab7836846d624c4c59316bad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Garc=C3=ADa?= Date: Thu, 14 Nov 2024 13:34:47 +0100 Subject: [PATCH 1/5] Dataset link simplification --- .../entities/helper/DocumentLink.java | 37 +++++++++++-- .../service/ServiceDocumentLinkService.java | 55 ++++++++++++++++++- ...essor_PostProcessDatasetDocumentEvent.java | 37 +++++++++++-- 3 files changed, 118 insertions(+), 11 deletions(-) diff --git a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java index efa442a..346e4eb 100644 --- a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java +++ b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java @@ -92,8 +92,11 @@ public DocumentLink() { "OGC Web Feature Service".toLowerCase(), "OGC Web Map Service".toLowerCase(), "OGC Web Map Tile Service".toLowerCase(), + "OGC:WMS".toLowerCase(), "wms", + "OGC:WMTS".toLowerCase(), "wmts", + "OGC:WFS".toLowerCase(), "wfs", "atom", "http://www.opengeospatial.org/standards/wms", @@ -102,6 +105,33 @@ public DocumentLink() { "INSPIRE Atom".toLowerCase() }); + public static List validViewProtocols = Arrays.asList(new String[]{ + "http://www.opengis.net/def/serviceType/ogc/wms".toLowerCase(), + "http://www.opengis.net/def/serviceType/ogc/wmts".toLowerCase(), + "OGC Web Feature Service".toLowerCase(), + "OGC Web Map Service".toLowerCase(), + "OGC Web Map Tile Service".toLowerCase(), + "OGC:WMS".toLowerCase(), + "wms", + "OGC:WMTS".toLowerCase(), + "wmts", + "http://www.opengeospatial.org/standards/wms", + "http://www.opengeospatial.org/standards/wmts" + }); + + public static List validDownloadProtocols = Arrays.asList(new String[]{ + "http://www.opengis.net/def/serviceType/ogc/wfs".toLowerCase(), + "https://tools.ietf.org/html/rfc4287".toLowerCase(), + "ATOM Syndication Format".toLowerCase(), + "OGC Web Feature Service".toLowerCase(), + "OGC:WFS".toLowerCase(), + "wfs", + "atom", + "http://www.opengeospatial.org/standards/wfs", + "INSPIRE Atom".toLowerCase() + }); + + public static List validAtomProtocols = Arrays.asList(new String[]{ "https://tools.ietf.org/html/rfc4287".toLowerCase(), "ATOM Syndication Format".toLowerCase(), @@ -117,17 +147,14 @@ public DocumentLink() { }); public boolean isInspireSimplifiedLink() { - if ((rawURL == null) || (protocol == null) || (applicationProfile == null)) + if ((rawURL == null) || (protocol == null)) return false; - if (rawURL.isEmpty() || protocol.isEmpty() || applicationProfile.isEmpty()) + if (rawURL.isEmpty() || protocol.isEmpty()) return false; if (!validProtocols.contains(protocol.toLowerCase())) return false; - if (!validAppProfiles.contains(applicationProfile.toLowerCase())) - return false; - return true; } diff --git a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java index 430e00e..e20e258 100644 --- a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java +++ b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java @@ -72,11 +72,64 @@ public DatasetDocumentLink create(DatasetMetadataRecord datasetMetadataRecord, O result.setFunction(onlineResource.getFunction()); result.setOperationName(onlineResource.getOperationName()); result.setRawURL(onlineResource.getRawURL()); - result.setProtocol(onlineResource.getProtocol()); + + String protocolFromUrl = inferProtocolFromUrl(onlineResource.getRawURL()); + + if ((onlineResource.getProtocol() == null) && (protocolFromUrl != null)) { + // If no protocol defined, try to infer the protocol from the URL + result.setProtocol(protocolFromUrl); + } else { + result.setProtocol(onlineResource.getProtocol()); + + // TODO: review + // Check if protocol inferred is not the same type to the one defined in the protocol field and update it based on the URL inferred protocol + if (protocolFromUrl != null) { + boolean isDownloadProtocol = ServiceDocumentLink.validDownloadProtocols.contains(onlineResource.getProtocol().toLowerCase()); + boolean isDownloadUrlProtocol = ServiceDocumentLink.validDownloadProtocols.contains(protocolFromUrl.toLowerCase()); + boolean isViewProtocol = ServiceDocumentLink.validViewProtocols.contains(onlineResource.getProtocol().toLowerCase()); + boolean isViewUrlProtocol = ServiceDocumentLink.validViewProtocols.contains(protocolFromUrl); + + if (isDownloadProtocol) { + if (!isDownloadUrlProtocol && isViewUrlProtocol) { + result.setProtocol(protocolFromUrl); + } + } else if (isViewProtocol) { + if (!isViewUrlProtocol && isDownloadUrlProtocol) { + result.setProtocol(protocolFromUrl); + } + } + } + } + result.setApplicationProfile(onlineResource.getApplicationProfile()); result.setLinkCheckJobId(datasetMetadataRecord.getLinkCheckJobId()); return result; } + + + private String inferProtocolFromUrl(String url) { + String normalizedUrl = url.toLowerCase(); + + if (normalizedUrl.indexOf("wms") > -1) { + return "wms"; + } else if (normalizedUrl.indexOf("wmts") > -1) { + return "wmts"; + } else if (normalizedUrl.indexOf("wfs") > -1) { + return "wfs"; + } else if (normalizedUrl.indexOf("atom") > -1) { + return "atom"; + } else if (normalizedUrl.indexOf("wcs") > -1) { + return "wcs"; + } else if (normalizedUrl.indexOf("sos") > -1) { + return "sos"; + } else if (normalizedUrl.indexOf("api features") > -1) { + return "api features"; + } else if (normalizedUrl.indexOf("sensorthings") > -1) { + return "sensorthings"; + } + + return null; + } } diff --git a/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java b/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java index 2ff8816..7d0981b 100644 --- a/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java +++ b/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java @@ -323,13 +323,40 @@ private void process() { .filter(x -> (x.getCapabilitiesDocumentType() == CapabilitiesType.WFS) || (x.getCapabilitiesDocumentType() == CapabilitiesType.Atom)) .collect(Collectors.toList()); - if (!viewLinks.isEmpty()) + + if (!viewLinks.isEmpty()) { localDatasetMetadataRecord.setINDICATOR_VIEW_LINK_TO_DATA(IndicatorStatus.PASS); - if (!downloadLinks.isEmpty()) - localDatasetMetadataRecord.setINDICATOR_DOWNLOAD_LINK_TO_DATA(IndicatorStatus.PASS); + localDatasetMetadataRecord.setNumberOfViewDataLinks(viewLinks.size()); + } else { + // Dataset link simplification + if (!localDatasetMetadataRecord.getDocumentLinks().isEmpty()) { + List viewLinksMetadataOnlineResources = localDatasetMetadataRecord.getDocumentLinks().stream() + .filter(x -> (x.getLinkState().equals(LinkState.Complete) && x.getLinkHTTPStatusCode() == 200) && (DocumentLink.validViewProtocols.contains(x.getProtocol().toLowerCase()))) + .collect(Collectors.toList()); + + if (!viewLinksMetadataOnlineResources.isEmpty()) { + localDatasetMetadataRecord.setINDICATOR_VIEW_LINK_TO_DATA(IndicatorStatus.PASS); + localDatasetMetadataRecord.setNumberOfViewDataLinks(viewLinksMetadataOnlineResources.size()); + } + } + } - localDatasetMetadataRecord.setNumberOfViewDataLinks(viewLinks.size()); - localDatasetMetadataRecord.setNumberOfDownloadDataLinks(downloadLinks.size()); + if (!downloadLinks.isEmpty()) { + localDatasetMetadataRecord.setINDICATOR_DOWNLOAD_LINK_TO_DATA(IndicatorStatus.PASS); + localDatasetMetadataRecord.setNumberOfDownloadDataLinks(downloadLinks.size()); + } else { + // Dataset link simplification + if (!localDatasetMetadataRecord.getDocumentLinks().isEmpty()) { + List downloadLinksMetadataOnlineResources = localDatasetMetadataRecord.getDocumentLinks().stream() + .filter(x -> (x.getLinkState().equals(LinkState.Complete) && x.getLinkHTTPStatusCode() == 200) && (DocumentLink.validDownloadProtocols.contains(x.getProtocol().toLowerCase()))) + .collect(Collectors.toList()); + + if (!downloadLinksMetadataOnlineResources.isEmpty()) { + localDatasetMetadataRecord.setINDICATOR_DOWNLOAD_LINK_TO_DATA(IndicatorStatus.PASS); + localDatasetMetadataRecord.setNumberOfDownloadDataLinks(downloadLinksMetadataOnlineResources.size()); + } + } + } // List serviceLinks = new ArrayList<>(); // List capLinks = new ArrayList<>(); From a51830423693a69c21bf649fb7b6cbc8057971dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Garc=C3=ADa?= Date: Mon, 18 Nov 2024 14:49:22 +0100 Subject: [PATCH 2/5] Dataset link simplification - improve code comment --- .../linkchecker/service/ServiceDocumentLinkService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java index e20e258..baffacc 100644 --- a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java +++ b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/service/ServiceDocumentLinkService.java @@ -81,8 +81,12 @@ public DatasetDocumentLink create(DatasetMetadataRecord datasetMetadataRecord, O } else { result.setProtocol(onlineResource.getProtocol()); - // TODO: review - // Check if protocol inferred is not the same type to the one defined in the protocol field and update it based on the URL inferred protocol + // if the XML document's protocol isn't compatible with the actual URL + // then use the inferred URL protocol. + // Example; + // xml protocol is WMS (view) + // but, url is "...?service=WFS" (inferred url protocol is download and not view) + // then, set the protocol to Download (ignore the XML) if (protocolFromUrl != null) { boolean isDownloadProtocol = ServiceDocumentLink.validDownloadProtocols.contains(onlineResource.getProtocol().toLowerCase()); boolean isDownloadUrlProtocol = ServiceDocumentLink.validDownloadProtocols.contains(protocolFromUrl.toLowerCase()); From 6f4c9b398a11e1b9c26283cf391f5e76cb3854d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Garc=C3=ADa?= Date: Mon, 18 Nov 2024 14:59:28 +0100 Subject: [PATCH 3/5] Dataset link simplification - Document change in isInspireSimplifiedLink and simplify valid protocols lists definitions --- .../entities/helper/DocumentLink.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java index 346e4eb..1f9bc26 100644 --- a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java +++ b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java @@ -38,8 +38,11 @@ import javax.persistence.Column; import javax.persistence.MappedSuperclass; import javax.persistence.Transient; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; //Represents a link in a document @MappedSuperclass @@ -83,28 +86,6 @@ public DocumentLink() { //-- - public static List validProtocols = Arrays.asList(new String[]{ - "http://www.opengis.net/def/serviceType/ogc/wms".toLowerCase(), - "http://www.opengis.net/def/serviceType/ogc/wmts".toLowerCase(), - "http://www.opengis.net/def/serviceType/ogc/wfs".toLowerCase(), - "https://tools.ietf.org/html/rfc4287".toLowerCase(), - "ATOM Syndication Format".toLowerCase(), - "OGC Web Feature Service".toLowerCase(), - "OGC Web Map Service".toLowerCase(), - "OGC Web Map Tile Service".toLowerCase(), - "OGC:WMS".toLowerCase(), - "wms", - "OGC:WMTS".toLowerCase(), - "wmts", - "OGC:WFS".toLowerCase(), - "wfs", - "atom", - "http://www.opengeospatial.org/standards/wms", - "http://www.opengeospatial.org/standards/wmts", - "http://www.opengeospatial.org/standards/wfs", - "INSPIRE Atom".toLowerCase() - }); - public static List validViewProtocols = Arrays.asList(new String[]{ "http://www.opengis.net/def/serviceType/ogc/wms".toLowerCase(), "http://www.opengis.net/def/serviceType/ogc/wmts".toLowerCase(), @@ -131,6 +112,8 @@ public DocumentLink() { "INSPIRE Atom".toLowerCase() }); + public static List validProtocols = Stream.concat(validViewProtocols.stream(), + validDownloadProtocols.stream()).collect(Collectors.toList()); public static List validAtomProtocols = Arrays.asList(new String[]{ "https://tools.ietf.org/html/rfc4287".toLowerCase(), @@ -147,6 +130,7 @@ public DocumentLink() { }); public boolean isInspireSimplifiedLink() { + // Relax the check to process links with the applicationProfile information if ((rawURL == null) || (protocol == null)) return false; if (rawURL.isEmpty() || protocol.isEmpty()) @@ -158,6 +142,24 @@ public boolean isInspireSimplifiedLink() { return true; } + /*public boolean isInspireSimplifiedLink() { + if ((rawURL == null) || (protocol == null) || (applicationProfile == null)) + if ((rawURL == null) || (protocol == null)) + return false; + if (rawURL.isEmpty() || protocol.isEmpty() || applicationProfile.isEmpty()) + if (rawURL.isEmpty() || protocol.isEmpty()) + return false; + + if (!validProtocols.contains(protocol.toLowerCase())) + return false; + + if (!validAppProfiles.contains(applicationProfile.toLowerCase())) + return false; + + return true; + }*/ + + //-- From 70089cdb5caa69b6243015c0b0beef9385817b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Garc=C3=ADa?= Date: Fri, 29 Nov 2024 08:39:01 +0100 Subject: [PATCH 4/5] Dataset link simplification - Add WCS, SOS, SensorThings and API Features protocols --- .../entities/helper/DocumentLink.java | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java index 1f9bc26..5392813 100644 --- a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java +++ b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java @@ -87,29 +87,36 @@ public DocumentLink() { //-- public static List validViewProtocols = Arrays.asList(new String[]{ + "wms", "http://www.opengis.net/def/serviceType/ogc/wms".toLowerCase(), - "http://www.opengis.net/def/serviceType/ogc/wmts".toLowerCase(), - "OGC Web Feature Service".toLowerCase(), "OGC Web Map Service".toLowerCase(), - "OGC Web Map Tile Service".toLowerCase(), "OGC:WMS".toLowerCase(), - "wms", - "OGC:WMTS".toLowerCase(), - "wmts", "http://www.opengeospatial.org/standards/wms", + "wmts", + "http://www.opengis.net/def/serviceType/ogc/wmts".toLowerCase(), + "OGC Web Map Tile Service".toLowerCase(), + "OGC:WMTS".toLowerCase(), "http://www.opengeospatial.org/standards/wmts" }); public static List validDownloadProtocols = Arrays.asList(new String[]{ + "wfs", "http://www.opengis.net/def/serviceType/ogc/wfs".toLowerCase(), - "https://tools.ietf.org/html/rfc4287".toLowerCase(), - "ATOM Syndication Format".toLowerCase(), "OGC Web Feature Service".toLowerCase(), "OGC:WFS".toLowerCase(), - "wfs", - "atom", "http://www.opengeospatial.org/standards/wfs", - "INSPIRE Atom".toLowerCase() + "atom", + "https://tools.ietf.org/html/rfc4287".toLowerCase(), + "ATOM Syndication Format".toLowerCase(), + "INSPIRE Atom".toLowerCase(), + "wcs", + "OGC:WCS".toLowerCase(), + "api features", + "OGC - API Features".toLowerCase(), + "OGC:OGC-API-Features-items".toLowerCase(), + "sos", + "OGC:SOS".toLowerCase(), + "http://www.opengis.net/def/serviceType/ogc/sos".toLowerCase() }); public static List validProtocols = Stream.concat(validViewProtocols.stream(), From 494ff222891fc9dcef17c5b14391a0149ace4032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Garc=C3=ADa?= Date: Mon, 2 Dec 2024 15:44:16 +0100 Subject: [PATCH 5/5] Check protocol match simple values instead of exact match --- .../entities/helper/DocumentLink.java | 22 +++++++++++++++++-- ...essor_PostProcessDatasetDocumentEvent.java | 4 ++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java index 5392813..418baa4 100644 --- a/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java +++ b/services/linkchecker/src/main/java/net/geocat/database/linkchecker/entities/helper/DocumentLink.java @@ -90,6 +90,7 @@ public DocumentLink() { "wms", "http://www.opengis.net/def/serviceType/ogc/wms".toLowerCase(), "OGC Web Map Service".toLowerCase(), + "Web Map Service (WMS)".toLowerCase(), "OGC:WMS".toLowerCase(), "http://www.opengeospatial.org/standards/wms", "wmts", @@ -103,6 +104,7 @@ public DocumentLink() { "wfs", "http://www.opengis.net/def/serviceType/ogc/wfs".toLowerCase(), "OGC Web Feature Service".toLowerCase(), + "Web Feature Service (WFS)".toLowerCase(), "OGC:WFS".toLowerCase(), "http://www.opengeospatial.org/standards/wfs", "atom", @@ -111,9 +113,13 @@ public DocumentLink() { "INSPIRE Atom".toLowerCase(), "wcs", "OGC:WCS".toLowerCase(), + "http://www.opengis.net/def/serviceType/ogc/wcs".toLowerCase(), "api features", "OGC - API Features".toLowerCase(), "OGC:OGC-API-Features-items".toLowerCase(), + "HTTP:OGC:API-Features".toLowerCase(), + "http://www.opengis.net/def/interface/ogcapi-features".toLowerCase(), + "SensorThings".toLowerCase(), "sos", "OGC:SOS".toLowerCase(), "http://www.opengis.net/def/serviceType/ogc/sos".toLowerCase() @@ -136,6 +142,12 @@ public DocumentLink() { "http://inspire.ec.europa.eu/metadata-codelist/SpatialDataServiceType/view".toLowerCase() }); + public static final String VALID_PROTOCOLS_VIEW_REGEX = "(.*wms.*|.*wmts.*|.*web map service.*)"; + + public static final String VALID_PROTOCOLS_DOWNLOAD_REGEX = "(.*wfs.*|.*atom.*|.*wcs.*|.*sos.*|.*api.*feature.*|.*sensorthings.*|.*web feature service.*)"; + + public static final String VALID_PROTOCOLS_REGEX = "(.*wfs.*|.*atom.*|.*wcs.*|.*sos.*|.*api.*feature.*|.*sensorthings.*|.*wms.*|.*wmts.*|.*web map service.*|.*web feature service.*)"; + public boolean isInspireSimplifiedLink() { // Relax the check to process links with the applicationProfile information if ((rawURL == null) || (protocol == null)) @@ -143,12 +155,18 @@ public boolean isInspireSimplifiedLink() { if (rawURL.isEmpty() || protocol.isEmpty()) return false; - if (!validProtocols.contains(protocol.toLowerCase())) - return false; + if (!validProtocols.contains(protocol.toLowerCase())) { + // Check protocol match "simple" values instead of exact match + if (!protocol.toLowerCase().matches(VALID_PROTOCOLS_REGEX)) { + return false; + } + } + return true; } + /*public boolean isInspireSimplifiedLink() { if ((rawURL == null) || (protocol == null) || (applicationProfile == null)) if ((rawURL == null) || (protocol == null)) diff --git a/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java b/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java index 7d0981b..beb4df8 100644 --- a/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java +++ b/services/linkchecker/src/main/java/net/geocat/eventprocessor/processors/postprocess/EventProcessor_PostProcessDatasetDocumentEvent.java @@ -331,7 +331,7 @@ private void process() { // Dataset link simplification if (!localDatasetMetadataRecord.getDocumentLinks().isEmpty()) { List viewLinksMetadataOnlineResources = localDatasetMetadataRecord.getDocumentLinks().stream() - .filter(x -> (x.getLinkState().equals(LinkState.Complete) && x.getLinkHTTPStatusCode() == 200) && (DocumentLink.validViewProtocols.contains(x.getProtocol().toLowerCase()))) + .filter(x -> (x.getLinkState().equals(LinkState.Complete) && x.getLinkHTTPStatusCode() == 200) && (DocumentLink.validViewProtocols.contains(x.getProtocol().toLowerCase()) || x.getProtocol().toLowerCase().matches(DocumentLink.VALID_PROTOCOLS_VIEW_REGEX))) .collect(Collectors.toList()); if (!viewLinksMetadataOnlineResources.isEmpty()) { @@ -348,7 +348,7 @@ private void process() { // Dataset link simplification if (!localDatasetMetadataRecord.getDocumentLinks().isEmpty()) { List downloadLinksMetadataOnlineResources = localDatasetMetadataRecord.getDocumentLinks().stream() - .filter(x -> (x.getLinkState().equals(LinkState.Complete) && x.getLinkHTTPStatusCode() == 200) && (DocumentLink.validDownloadProtocols.contains(x.getProtocol().toLowerCase()))) + .filter(x -> (x.getLinkState().equals(LinkState.Complete) && x.getLinkHTTPStatusCode() == 200) && (DocumentLink.validDownloadProtocols.contains(x.getProtocol().toLowerCase()) || x.getProtocol().toLowerCase().matches(DocumentLink.VALID_PROTOCOLS_DOWNLOAD_REGEX))) .collect(Collectors.toList()); if (!downloadLinksMetadataOnlineResources.isEmpty()) {