|
35 | 35 | import java.util.stream.Stream; |
36 | 36 |
|
37 | 37 | import static au.org.aodn.ogcapi.server.core.configuration.CacheConfig.CACHE_WMS_MAP_TILE; |
| 38 | +import static au.org.aodn.ogcapi.server.core.service.wms.WmsDefaultParam.WMS_LINK_MARKER; |
38 | 39 |
|
39 | 40 | @Slf4j |
40 | 41 | public class WmsServer { |
@@ -65,63 +66,90 @@ public WmsServer() { |
65 | 66 | xmlMapper.registerModule(new JavaTimeModule()); // Add JavaTimeModule |
66 | 67 | xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
67 | 68 | } |
68 | | - |
| 69 | + /** |
| 70 | + * This function is used to append the CQL filter to the geonetwork query, it will guess the correct dataTime field by |
| 71 | + * some logic, so that if user select filter by range, it works. In case of issue please debug the logic as we are |
| 72 | + * dealing with different non-standard name |
| 73 | + * @param uuid - The uuid of metadata |
| 74 | + * @param request - The request object to the map |
| 75 | + * @return - The CQL combined the wfs cql and the dateTime query. |
| 76 | + */ |
69 | 77 | protected String createCQLFilter(String uuid, FeatureRequest request) { |
| 78 | + String cql = ""; |
| 79 | + |
| 80 | + // If the metadata record have wfs url query, we will use it and analysis it and extract the CQL part if exist |
| 81 | + Optional<String> wfsUrl = wfsServer.getFeatureServerUrlByTitleOrQueryParam(uuid, request.getLayerName()); |
| 82 | + if(wfsUrl.isPresent()) { |
| 83 | + UriComponents wfsUrlComponents = UriComponentsBuilder.fromUriString(wfsUrl.get()).build(); |
| 84 | + // Extract the CQL if existing in the WFS, we need to apply it to the WMS as well |
| 85 | + if(wfsUrlComponents.getQueryParams().get("cql_filter") != null) { |
| 86 | + cql = wfsUrlComponents.getQueryParams().get("cql_filter").get(0); |
| 87 | + } |
| 88 | + else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { |
| 89 | + cql = wfsUrlComponents.getQueryParams().get("CQL_FILTER").get(0); |
| 90 | + } |
| 91 | + } |
| 92 | + |
70 | 93 | if (request.getDatetime() != null) { |
71 | 94 | // Special handle for date time field, the field name will be diff across dataset. So we need |
72 | 95 | // to look it up |
73 | | - String cql = ""; |
74 | 96 | try { |
75 | | - Optional<String> wfsUrl = wfsServer.getFeatureServerUrlByTitleOrQueryParam(uuid, request.getLayerName()); |
76 | | - if(wfsUrl.isPresent()) { |
77 | | - UriComponents wfsUrlComponents = UriComponentsBuilder.fromUriString(wfsUrl.get()).build(); |
78 | | - // Extract the CQL if existing in the WFS, we need to apply it to the WMS as well |
79 | | - if(wfsUrlComponents.getQueryParams().get("cql_filter") != null) { |
80 | | - cql = wfsUrlComponents.getQueryParams().get("cql_filter").get(0) + " AND "; |
81 | | - } |
82 | | - else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { |
83 | | - cql = wfsUrlComponents.getQueryParams().get("CQL_FILTER").get(0) + " AND "; |
84 | | - } |
85 | | - } |
86 | | - |
87 | 97 | List<DownloadableFieldModel> m = this.getDownloadableFields(uuid, request); |
88 | 98 | List<DownloadableFieldModel> target = m.stream() |
89 | 99 | .filter(value -> "dateTime".equalsIgnoreCase(value.getType())) |
90 | 100 | .toList(); |
91 | 101 |
|
92 | 102 | if (!target.isEmpty()) { |
93 | 103 |
|
| 104 | + List<DownloadableFieldModel> range; |
94 | 105 | if (target.size() > 2) { |
95 | 106 | // Try to find possible fields where it contains start end min max |
96 | | - target = target.stream() |
| 107 | + range = target.stream() |
97 | 108 | .filter(v -> Stream.of("start", "end", "min", "max").anyMatch(k -> v.getName().contains(k))) |
98 | 109 | .toList(); |
99 | | - } |
100 | 110 |
|
101 | | - if (target.size() == 2) { |
102 | | - // Due to no standard name, we try our best to guess if 2 dateTime field |
103 | | - String[] d = request.getDatetime().split("/"); |
104 | | - String guess1 = target.get(0).getName(); |
105 | | - String guess2 = target.get(1).getName(); |
106 | | - if ((guess1.contains("start") || guess1.contains("min")) && (guess2.contains("end") || guess2.contains("max"))) { |
107 | | - return String.format("CQL_FILTER=%s%s >= %s AND %s <= %s", cql, guess1, d[0], guess2, d[1]); |
108 | | - } |
109 | | - if ((guess2.contains("start") || guess2.contains("min")) && (guess1.contains("end") || guess1.contains("max"))) { |
110 | | - return String.format("CQL_FILTER=%s%s >= %s AND %s <= %s", cql, guess2, d[0], guess2, d[1]); |
| 111 | + if (range.size() == 2) { |
| 112 | + // Due to no standard name, we try our best to guess if 2 dateTime field, range mean we found start/end date |
| 113 | + String[] d = request.getDatetime().split("/"); |
| 114 | + String guess1 = target.get(0).getName(); |
| 115 | + String guess2 = target.get(1).getName(); |
| 116 | + |
| 117 | + if ((guess1.contains("start") || guess1.contains("min")) && (guess2.contains("end") || guess2.contains("max"))) { |
| 118 | + String timeCql = String.format("CQL_FILTER=%s >= %s AND %s <= %s", guess1, d[0], guess2, d[1]); |
| 119 | + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; |
| 120 | + } |
| 121 | + if ((guess2.contains("start") || guess2.contains("min")) && (guess1.contains("end") || guess1.contains("max"))) { |
| 122 | + String timeCql = String.format("CQL_FILTER=%s >= %s AND %s <= %s", guess2, d[0], guess2, d[1]); |
| 123 | + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; |
| 124 | + } |
| 125 | + return "".equalsIgnoreCase(cql) ? "" : cql; |
| 126 | + } else { |
| 127 | + // There are more than 1 dateTime field, it is not range type, so we try to guess the individual one |
| 128 | + // based on some common name. Add more if needed |
| 129 | + List<DownloadableFieldModel> individual = target.stream() |
| 130 | + .filter(v -> Stream.of("juld", "time").anyMatch(k -> v.getName().equalsIgnoreCase(k))) |
| 131 | + .toList(); |
| 132 | + |
| 133 | + if(individual.size() == 1) { |
| 134 | + log.debug("Map datetime field to name to [{}]", individual.get(0).getName()); |
| 135 | + String timeCql = String.format("CQL_FILTER=%s DURING %s", individual.get(0).getName(), request.getDatetime()); |
| 136 | + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; |
| 137 | + } |
111 | 138 | } |
112 | | - } else { |
113 | | - // Only 1 field so use it. |
114 | | - log.debug("Map datetime field to name to [{}]", target.get(0).getName()); |
115 | | - return String.format("CQL_FILTER=%s%s DURING %s", cql, target.get(0).getName(), request.getDatetime()); |
| 139 | + } |
| 140 | + else if(target.size() == 1) { |
| 141 | + log.debug("Map datetime field to name to the only dateTime field [{}]", target.get(0).getName()); |
| 142 | + String timeCql = String.format("CQL_FILTER=%s DURING %s", target.get(0).getName(), request.getDatetime()); |
| 143 | + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; |
116 | 144 | } |
117 | 145 | } |
118 | | - log.error("No date time field found from query for uuid {}, result will not be bounded by date time", uuid); |
119 | | - } catch (DownloadableFieldsNotFoundException dfnf) { |
120 | | - // Without field, we cannot create a valid CQL filte targeting a dateTime, so just return empty |
121 | | - return ""; |
| 146 | + log.error("No date time field found for uuid {}, result will not be bounded by date time even specified", uuid); |
| 147 | + } |
| 148 | + catch (DownloadableFieldsNotFoundException dfnf) { |
| 149 | + // Without field, we cannot create a valid CQL filte targeting a dateTime, so just return existing CQL if exist |
122 | 150 | } |
123 | 151 | } |
124 | | - return ""; |
| 152 | + return "".equalsIgnoreCase(cql) ? "" : String.format("CQL_FILTER=%s", cql); |
125 | 153 | } |
126 | 154 | /** |
127 | 155 | * Create the full WMS url to fetch the tiles image |
@@ -355,7 +383,7 @@ protected Optional<String> getMapServerUrl(String collectionId, FeatureRequest r |
355 | 383 | List<LinkModel> wmsLinks = model.getLinks() |
356 | 384 | .stream() |
357 | 385 | .filter(link -> link.getAiGroup() != null) |
358 | | - .filter(link -> link.getAiGroup().contains("Data Access > wms")) |
| 386 | + .filter(link -> link.getAiGroup().contains(WMS_LINK_MARKER)) |
359 | 387 | .toList(); |
360 | 388 |
|
361 | 389 | if (wmsLinks.isEmpty()) { |
|
0 commit comments