Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1c7ec8f
Ensure close manager
euskalhenriko May 4, 2026
331e52f
Better generated xtext code
euskalhenriko May 4, 2026
0943832
Add first version of predicate for assets using path expressions
euskalhenriko May 5, 2026
f48b09d
Add predicate using HMAsset attributes
euskalhenriko May 5, 2026
5c5c130
Merge branch 'develop' into feature/add-predicates-for-STAC-search
euskalhenriko May 8, 2026
689eb67
Working with import and encode, need test it
euskalhenriko May 8, 2026
06d5d51
Small improvements, still not test
euskalhenriko May 8, 2026
8653a22
adds support to get the features from stac, and to rasterize based on…
AM1729 May 9, 2026
2783aa4
Merge branch 'develop' of https://github.com/integratedmodelling/klab…
AM1729 May 9, 2026
83e4476
removes prints, and adds some sanity checks
AM1729 May 9, 2026
9a81463
fixes stac validator and importer to allow import
AM1729 May 11, 2026
a27c8de
adds conversion to str
AM1729 May 11, 2026
b453fd1
Changes to assume assets is not an array but a list of json object
euskalhenriko May 11, 2026
4a184b8
Merge branch 'feature/add-predicates-for-STAC-search' of https://gith…
AM1729 May 11, 2026
7ea3b47
adds some try/catch
AM1729 May 11, 2026
7de1fe8
fixes
AM1729 May 11, 2026
4a40970
epsg at assets getting epsg at asset level if not, then at item level
AM1729 May 11, 2026
1c853c9
finds first, and update the time check
AM1729 May 11, 2026
44b09a7
updates string conv
AM1729 May 11, 2026
4d58c7a
avoid making search twice
AM1729 May 12, 2026
e3ba3dc
fix grammar
AM1729 May 12, 2026
3a0dfa9
remove dual cli logs
AM1729 May 12, 2026
e2eea17
fail fast on resource access problems for collection
AM1729 May 12, 2026
8771797
put under a single try/catch
AM1729 May 12, 2026
7b922c1
put under a single try/catch
AM1729 May 12, 2026
57be8c6
Reorganize code for asset search in import
euskalhenriko May 12, 2026
4df97a8
Align code with changes
euskalhenriko May 12, 2026
2abae11
Rename function to be coherent
euskalhenriko May 13, 2026
8633543
Clean and format code
euskalhenriko May 13, 2026
2703a2c
Solve NPE if no asset match all the conditions
euskalhenriko May 13, 2026
3c7ed19
final fixes
AM1729 May 13, 2026
1e1c3c2
Merge branch 'HMSTACUpdates' of https://github.com/integratedmodellin…
AM1729 May 13, 2026
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 @@ -10,6 +10,11 @@ public static Set<String> readAssetNames(JSONObject assets) {
}

public static JSONObject getAsset(JSONObject assetMap, String assetId) {
return assetMap.getJSONObject(assetId);
/*
* Not failing if the assetId is not found, the reason being that in
* some collections the items have different assets, and the Asset naming related conventions that MSFT
* Planetary follows is not necessarily followed by evryone!
*/
return assetMap.optJSONObject(assetId);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.integratedmodelling.klab.stac;

import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.function.Predicate;

import org.integratedmodelling.klab.api.data.IGeometry;
import org.integratedmodelling.klab.common.Geometry;
Expand All @@ -11,11 +11,10 @@
import org.integratedmodelling.klab.exceptions.KlabResourceAccessException;
import org.integratedmodelling.klab.exceptions.KlabResourceNotFoundException;

import com.fasterxml.jackson.module.jsonSchema.types.ArraySchema.Items;

import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import kong.unirest.json.JSONArray;
import kong.unirest.json.JSONObject;

public class STACCollectionParser {
Expand All @@ -35,7 +34,7 @@ public static String readCollectionId(JSONObject collection) {
*/
public static IGeometry readGeometry(JSONObject collection) {
GeometryBuilder gBuilder = Geometry.builder();

JSONObject extent = collection.getJSONObject("extent");
List bbox = extent.getJSONObject("spatial").getJSONArray("bbox").getJSONArray(0).toList();
gBuilder.space().boundingBox(Double.valueOf(bbox.get(0).toString()), Double.valueOf(bbox.get(1).toString()),
Expand All @@ -56,26 +55,57 @@ public static IGeometry readGeometry(JSONObject collection) {
return gBuilder.build().withProjection(Projection.DEFAULT_PROJECTION_CODE).withTimeType("grid");
}

/**
* Reads the assets of a STAC collection and returns them as a JSON.
* @param collection as a JSON
* @return The asset list as a JSON
* @throws KlabResourceAccessException
*/
public static JSONObject readAssetsFromCollection(String collectionUrl, JSONObject collection) throws KlabResourceAccessException {
private static JSONObject findAsset(JSONObject assets, String assetId, Predicate<JSONObject> predicate) {
if (assets == null) {
return null;
}

if (assetId != null) {
JSONObject asset = assets.optJSONObject(assetId);
if (asset == null) {
return null;
}
JSONObject result = new JSONObject();
result.put(assetId, asset);
return result;
}

if (predicate != null) {
return assets.keySet().stream().map(key -> {
JSONObject asset = assets.optJSONObject(key);
if (asset == null || !predicate.test(asset)) {
return null;
}
JSONObject result = new JSONObject();
result.put(key, asset);
return result;
}).filter(Objects::nonNull).findFirst().orElse(null);
}

return null;
}

private static JSONObject readAssetInformationFromCollection(String collectionUrl, JSONObject collection, String assetId,
Predicate<JSONObject> predicate) throws KlabResourceAccessException {
if ((assetId == null) == (predicate == null)) {
throw new KlabResourceAccessException("Exactly one of assetId or predicate must be provided");
}
String collectionId = collection.getString("id");
String catalogUrl = STACUtils.getCatalogUrl(collectionUrl, collectionId, collection);
JSONObject catalogData = STACUtils.requestMetadata(catalogUrl, "catalog");

Optional<String> searchEndpoint = STACUtils.containsLinkTo(catalogData, "search")
Optional<String> searchEndpoint = STACUtils.containsLinkTo(catalogData, "search")
? STACUtils.getLinkTo(catalogData, "search")
: STACUtils.getLinkTo(collection, "search");

// Static catalogs should have their assets on the Collection
if (searchEndpoint.isEmpty()) {
// Check the assets
if (collection.has("assets")) {
return collection.getJSONObject("assets");
JSONObject assetInfo = findAsset(collection.optJSONObject("assets"), assetId, predicate);
if (assetInfo != null) {
return assetInfo;
}
}
// Try to get the assets from a link that has type `item`
Optional<String> itemHref = STACUtils.getLinkTo(collection, "item");
Expand All @@ -85,27 +115,74 @@ public static JSONObject readAssetsFromCollection(String collectionUrl, JSONObje
String itemUrl = itemHref.get().startsWith(".")
? collectionUrl.replace("collection.json", "") + itemHref.get().replace("./", "")
: itemHref.get();
// TODO get assets from the item
JSONObject itemData = STACUtils.requestMetadata(itemUrl, "feature");
if (itemData.has("assets")) {
return itemData.getJSONObject("assets");
JSONObject assetInfo = findAsset(itemData.optJSONObject("assets"), assetId, predicate);
if (assetInfo != null) {
return assetInfo;
}
throw new KlabResourceNotFoundException("Cannot find assets at STAC collection \"" + collectionUrl + "\"");
}

// TODO Move the query to another place.
String parameters = "?collections=" + collectionId + "&limit=1";
HttpResponse<JsonNode> response = Unirest.get(searchEndpoint.get() + parameters).asJson();
JSONObject searchPayload = new JSONObject().put("limit", 100)
.put("bbox", new JSONArray().put(-180.0).put(-90.0).put(180.0).put(90.0))
.put("collections", new JSONArray().put(collectionId));

HttpResponse<JsonNode> response = Unirest.post(searchEndpoint.get()).header("Content-Type", "application/json")
.body(searchPayload).asJson();

if (!response.isSuccess()) {
throw new KlabResourceAccessException(); //TODO set message
throw new KlabResourceAccessException("Unable to import collection, Search failed");
}

JSONObject searchResponse = response.getBody().getObject();
if (searchResponse.getJSONArray("features").length() == 0) {
throw new KlabResourceAccessException(); // TODO set message there is no feature
JSONArray features = searchResponse.optJSONArray("features");
if (features == null || features.length() == 0) {
throw new KlabResourceAccessException("No features were found in the collection to be imported");
}

return searchResponse.getJSONArray("features").getJSONObject(0).getJSONObject("assets");
for(int i = 0; i < features.length(); i++) {
JSONObject feature = features.optJSONObject(i);
if (feature == null) {
continue;
}

JSONObject assetInfo = findAsset(feature.optJSONObject("assets"), assetId, predicate);
if (assetInfo != null) {
return assetInfo;
}
}
if (assetId != null) {
throw new KlabResourceAccessException("No asset with ID \"" + assetId + "\" was found in the collection");
}

throw new KlabResourceAccessException("No asset matching the predicate was found in the collection");
}

/**
* Reads an asset from a STAC collection by asset key.
*
* @param collectionUrl URL of the STAC collection
* @param collection collection metadata as JSON
* @param assetId asset key to find inside each feature's assets object
* @return a JSONObject containing one entry: assetId -> asset JSON object
* @throws KlabResourceAccessException if the collection cannot be searched or no matching asset is found
*/
public static JSONObject readAssetInformationFromCollection(String collectionUrl, JSONObject collection, String assetId)
throws KlabResourceAccessException {
return readAssetInformationFromCollection(collectionUrl, collection, assetId, null);
}

/**
* Reads the first asset in a STAC collection whose asset JSON object matches the predicate.
*
* @param collectionUrl URL of the STAC collection
* @param collection collection metadata as JSON
* @param predicate predicate evaluated against each asset JSON object
* @return a JSONObject containing one entry: assetId -> asset JSON object
* @throws KlabResourceAccessException if the collection cannot be searched or no matching asset is found
*/
public static JSONObject readAssetInformationFromCollection(String collectionUrl, JSONObject collection,
Predicate<JSONObject> predicate) throws KlabResourceAccessException {
return readAssetInformationFromCollection(collectionUrl, collection, null, predicate);
}
}
Loading
Loading