diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a7c7417fa..bfc164f81 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -3,12 +3,13 @@ name: Build and Release Snapshot
on:
push:
branches:
- - master
jobs:
build-and-release:
runs-on: ubuntu-22.04
+ if: github.ref == 'refs/heads/master'
+
steps:
- name: Checkout code
uses: actions/checkout@v3
@@ -20,8 +21,14 @@ jobs:
java-version: '11'
cache: 'maven'
server-id: ossrh
- server-username: MAVEN_USERNAME
- server-password: MAVEN_PASSWORD
+ server-username: ${{ secrets.OSSRH_USERNAME }}
+ server-password: ${{ secrets.OSSRH_TOKEN }}
+
+ - name: Run Tests
+ run: |
+ mvn --no-transfer-progress \
+ --batch-mode \
+ clean verify
- id: install-secret-key
name: Install gpg secret key
@@ -32,15 +39,35 @@ jobs:
gpg --list-secret-keys --keyid-format LONG
- name: Build and Deploy Snapshot
- env:
- MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
- MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
run: |
mvn --no-transfer-progress \
--batch-mode \
-Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} \
+ -Dossrh.username=${{ secrets.OSSRH_USERNAME }} \
+ -Dossrh.password=${{ secrets.OSSRH_TOKEN }} \
clean deploy \
-DskipTests=true \
-P release \
-Dmaven.javadoc.skip=true \
-Dgpg.skip=false
+
+ build-and-test:
+ runs-on: ubuntu-22.04
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup Java
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: 'maven'
+
+ - name: Build and Test Branch
+ run: |
+ mvn --no-transfer-progress \
+ --batch-mode \
+ clean install \
+ -Dmaven.javadoc.skip=true
diff --git a/apps/pom.xml b/apps/pom.xml
index 400b08272..15aa58895 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -7,7 +7,7 @@
org.hortonmachine
hortonmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
hm-apps
@@ -27,7 +27,7 @@
org.hortonmachine
hm-gui
- 0.10.8
+ 0.10.9-SNAPSHOT
org.mapsforge
diff --git a/dbs/pom.xml b/dbs/pom.xml
index d57d3ce8b..f812c7adb 100644
--- a/dbs/pom.xml
+++ b/dbs/pom.xml
@@ -7,7 +7,7 @@
org.hortonmachine
hortonmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
../pom.xml
diff --git a/gears/pom.xml b/gears/pom.xml
index f4e8844eb..52607bee8 100644
--- a/gears/pom.xml
+++ b/gears/pom.xml
@@ -7,7 +7,7 @@
org.hortonmachine
hortonmachine
../pom.xml
- 0.10.8
+ 0.10.9-SNAPSHOT
hm-gears
@@ -18,7 +18,7 @@
org.hortonmachine
hm-dbs
- 0.10.8
+ 0.10.9-SNAPSHOT
@@ -145,7 +145,7 @@
it.geosolutions.imageio-ext
imageio-ext-cog-rangereader-http
-
+
org.geotools
gt-imagemosaic
@@ -203,6 +203,10 @@
netcdf4
+
+ com.amazonaws
+ aws-java-sdk-core
+
diff --git a/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacAsset.java b/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacAsset.java
index bcb7ea8ed..68ec20a8a 100644
--- a/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacAsset.java
+++ b/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacAsset.java
@@ -1,7 +1,11 @@
package org.hortonmachine.gears.io.stac;
-import java.util.Iterator;
-
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.S3Object;
+import com.fasterxml.jackson.databind.JsonNode;
+import it.geosolutions.imageio.core.BasicAuthURI;
+import it.geosolutions.imageio.plugins.cog.CogImageReadParam;
+import it.geosolutions.imageioimpl.plugins.cog.*;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.hortonmachine.gears.libs.modules.HMConstants;
@@ -10,18 +14,13 @@
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import it.geosolutions.imageio.core.BasicAuthURI;
-import it.geosolutions.imageio.plugins.cog.CogImageReadParam;
-import it.geosolutions.imageioimpl.plugins.cog.CogImageInputStreamSpi;
-import it.geosolutions.imageioimpl.plugins.cog.CogImageReaderSpi;
-import it.geosolutions.imageioimpl.plugins.cog.CogSourceSPIProvider;
-import it.geosolutions.imageioimpl.plugins.cog.HttpRangeReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
/**
* An asset from a stac item.
- *
+ *
* @author Andrea Antonello (www.hydrologis.com)
*
*/
@@ -49,9 +48,8 @@ public HMStacAsset( String id, JsonNode assetNode ) {
}
if (type.toLowerCase().contains("profile=cloud-optimized")) {
JsonNode rasterBandNode = assetNode.get("raster:bands");
+ assetUrl = assetNode.get("href").textValue();
if (rasterBandNode != null && !rasterBandNode.isEmpty()) {
- assetUrl = assetNode.get("href").textValue();
-
Iterator rbIterator = rasterBandNode.elements();
while( rbIterator.hasNext() ) {
JsonNode rbNode = rbIterator.next();
@@ -64,9 +62,6 @@ public HMStacAsset( String id, JsonNode assetNode ) {
resolution = resolNode.asDouble();
}
}
- } else {
- isValid = false;
- nonValidReason = "raster bands metadata missing";
}
} else {
isValid = false;
@@ -93,23 +88,29 @@ public String toString() {
/**
* Read the asset's coverage into a local raster.
- *
+ *
* @param region and optional region to read from.
* @param user an optional user in case of authentication.
* @param password an optional password in case of authentication.
- * @return the read raster from the asset's url..
- * @throws Exception
+ * @return the read raster from the asset's url.
+ * @throws Exception
*/
- public GridCoverage2D readRaster( RegionMap region, String user, String password ) throws Exception {
+ public GridCoverage2D readRaster( RegionMap region, String user, String password, AmazonS3 s3Client ) throws Exception {
BasicAuthURI cogUri = new BasicAuthURI(assetUrl, false);
if (user != null && password != null) {
cogUri.setUser(user);
cogUri.setPassword(password);
}
- HttpRangeReader rangeReader = new HttpRangeReader(cogUri.getUri(), CogImageReadParam.DEFAULT_HEADER_LENGTH);
- CogSourceSPIProvider inputProvider = new CogSourceSPIProvider(cogUri, new CogImageReaderSpi(),
- new CogImageInputStreamSpi(), rangeReader.getClass().getName());
- GeoTiffReader reader = new GeoTiffReader(inputProvider);
+ GeoTiffReader reader;
+ if (assetUrl.startsWith("s3://")) {
+ InputStream inputProvider = readS3Raster(cogUri, s3Client);
+ reader = new GeoTiffReader(inputProvider);
+ } else {
+ RangeReader rangeReader = new HttpRangeReader(cogUri.getUri(), CogImageReadParam.DEFAULT_HEADER_LENGTH);
+ CogSourceSPIProvider inputProvider = new CogSourceSPIProvider(cogUri, new CogImageReaderSpi(),
+ new CogImageInputStreamSpi(), rangeReader.getClass().getName());
+ reader = new GeoTiffReader(inputProvider);
+ }
CoordinateReferenceSystem crs = reader.getCoordinateReferenceSystem();
GeneralParameterValue[] generalParameter = null;
@@ -120,8 +121,18 @@ public GridCoverage2D readRaster( RegionMap region, String user, String password
return coverage;
}
+ public InputStream readS3Raster(BasicAuthURI cogUri, AmazonS3 s3Client ) throws IOException {
+ String[] bucketAndObject = assetUrl.split("://")[1].split("/", 2);
+ S3Object object = s3Client.getObject(bucketAndObject[0], bucketAndObject[1]);
+ return object.getObjectContent();
+ }
+
public GridCoverage2D readRaster( RegionMap region ) throws Exception {
- return readRaster(region, null, null);
+ return readRaster(region, null, null, null );
+ }
+
+ public GridCoverage2D readRaster( RegionMap region, AmazonS3 s3Client ) throws Exception {
+ return readRaster(region, null, null, s3Client );
}
public String getId() {
diff --git a/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacCollection.java b/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacCollection.java
index a6d7a919c..2a35afc9f 100644
--- a/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacCollection.java
+++ b/gears/src/main/java/org/hortonmachine/gears/io/stac/HMStacCollection.java
@@ -1,11 +1,6 @@
package org.hortonmachine.gears.io.stac;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.stream.Collectors;
-
+import com.amazonaws.services.s3.AmazonS3;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
@@ -37,6 +32,13 @@
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
@SuppressWarnings({"rawtypes"})
/**
* A stac collection.
@@ -49,6 +51,7 @@ public class HMStacCollection {
private Collection collection;
private SearchQuery search;
private IHMProgressMonitor pm;
+ private AmazonS3 s3Client;
HMStacCollection( STACClient stacClient, Collection collection, IHMProgressMonitor pm ) {
this.stacClient = stacClient;
@@ -108,10 +111,26 @@ public HMStacCollection setTimestampFilter( Date startTimestamp, Date endTimesta
public HMStacCollection setGeometryFilter( Geometry intersectionGeometry ) {
if (search == null)
search = new SearchQuery();
+ else if (search.getBbox() != null)
+ throw new IllegalStateException("Cannot add intersects filter. Only one of either intersects or bbox may be specified");
search.setIntersects(intersectionGeometry);
return this;
}
+ /**
+ * Set the geometry bbox filter for search query
+ * @param bbox
+ * @return the current collection.
+ */
+ public HMStacCollection setBboxFilter( double[] bbox ) {
+ if (search == null)
+ search = new SearchQuery();
+ else if (search.getIntersects() != null)
+ throw new IllegalStateException("Cannot add intersects filter. Only one of either intersects or bbox may be specified");
+ search.setBbox(bbox);
+ return this;
+ }
+
/**
* Set cql filter for search query;
*
@@ -126,12 +145,21 @@ public HMStacCollection setCqlFilter( String cqlFilter ) throws CQLException {
return this;
}
+ private SimpleFeatureCollection queryFeatureCollection() throws IOException {
+ try {
+ return stacClient.search(search, STACClient.SearchMode.POST);
+ } catch (IOException e) {
+ pm.message("POST search query not supported by the endpoint. GET will be tried.");
+ }
+ return stacClient.search(search, STACClient.SearchMode.GET);
+ }
+
public List searchItems() throws Exception {
if (search == null)
search = new SearchQuery();
search.setCollections(Arrays.asList(getId()));
- SimpleFeatureCollection fc = stacClient.search(search, STACClient.SearchMode.GET);
+ SimpleFeatureCollection fc = queryFeatureCollection();
SimpleFeatureIterator iterator = fc.features();
pm.beginTask("Extracting STAC items...", -1);
List stacItems = new ArrayList<>();
@@ -164,7 +192,7 @@ public List searchItems() throws Exception {
* @return the final raster.
* @throws Exception
*/
- public static HMRaster readRasterBandOnRegion( RegionMap latLongRegionMap, String bandName, List items,
+ public HMRaster readRasterBandOnRegion( RegionMap latLongRegionMap, String bandName, List items,
boolean allowTransform, MergeMode mergeMode, IHMProgressMonitor pm ) throws Exception {
if (!allowTransform) {
diff --git a/gears/src/test/java/org/hortonmachine/gears/modules/TestHMStacCollection.java b/gears/src/test/java/org/hortonmachine/gears/modules/TestHMStacCollection.java
new file mode 100644
index 000000000..5f15feba4
--- /dev/null
+++ b/gears/src/test/java/org/hortonmachine/gears/modules/TestHMStacCollection.java
@@ -0,0 +1,107 @@
+package org.hortonmachine.gears.modules;
+
+import org.hortonmachine.gears.io.stac.HMStacCollection;
+import org.hortonmachine.gears.io.stac.HMStacItem;
+import org.hortonmachine.gears.io.stac.HMStacManager;
+import org.hortonmachine.gears.libs.monitor.DummyProgressMonitor;
+import org.hortonmachine.gears.utils.HMTestCase;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Polygon;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+
+import static org.junit.Assert.assertThrows;
+
+public class TestHMStacCollection extends HMTestCase {
+ private GeometryFactory gf = new GeometryFactory();
+ private DummyProgressMonitor pm = new DummyProgressMonitor();
+ private HMStacManager manager;
+
+ private Coordinate[] createBbox(double xmin, double ymin, double xmax, double ymax) {
+ Coordinate[] bboxCoordinates = new Coordinate[5];
+ bboxCoordinates[0] = new Coordinate(xmin, ymin);
+ bboxCoordinates[1] = new Coordinate(xmin, ymax);
+ bboxCoordinates[2] = new Coordinate(xmax, ymax);
+ bboxCoordinates[3] = new Coordinate(xmax, ymin);
+ bboxCoordinates[4] = new Coordinate(xmin, ymin);
+ return bboxCoordinates;
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ String catalogUrl = "https://planetarycomputer.microsoft.com/api/stac/v1";
+ manager = new HMStacManager(catalogUrl, pm);
+ manager.open();
+ }
+
+ public void testSearchCatalogWithValidSpatioTemporalFilters() throws Exception {
+ HMStacCollection collection = manager.getCollectionById("io-lulc-annual-v02");
+ Instant start = Instant.ofEpochMilli(1514764800000L); // 2018-01-01
+ Instant end = start.plus(Duration.ofDays(10));
+ Polygon bboxPolygon = gf.createPolygon(createBbox(0.0, 0.0, 10.0, 10.0));
+
+ List items = collection.setTimestampFilter(Date.from(start), Date.from(end))
+ .setGeometryFilter(bboxPolygon)
+ .searchItems();
+
+ assertTrue(!items.isEmpty());
+ }
+
+ public void testSearchCatalogWithInvalidTemporalFilters() throws Exception {
+ HMStacCollection collection = manager.getCollectionById("io-lulc-annual-v02");
+ Instant start = Instant.ofEpochMilli(946688400000L); // 2000-01-01, a year with no data
+ Instant end = start.plus(Duration.ofDays(10));
+ Polygon bboxPolygon = gf.createPolygon(createBbox(0.0, 0.0, 10.0, 10.0));
+
+ List items = collection.setTimestampFilter(Date.from(start), Date.from(end))
+ .setGeometryFilter(bboxPolygon)
+ .searchItems();
+
+ assertTrue(items.isEmpty());
+ }
+
+ public void testSearchCatalogWithInvalidSpatialFilters() throws Exception {
+ HMStacCollection collection = manager.getCollectionById("io-lulc-annual-v02");
+ Instant start = Instant.ofEpochMilli(1514764800000L); // 2018-01-01
+ Instant end = start.plus(Duration.ofDays(10));
+ Polygon bboxPolygon = gf.createPolygon(createBbox(190.0, 90.0, 200.0, 100.0)); // out of bounds
+
+ List items = collection.setTimestampFilter(Date.from(start), Date.from(end))
+ .setGeometryFilter(bboxPolygon)
+ .searchItems();
+
+ assertTrue(items.isEmpty());
+ }
+
+ public void testSearchCatalogUsingBbox() throws Exception {
+ HMStacCollection collection = manager.getCollectionById("io-lulc-annual-v02");
+ Instant start = Instant.ofEpochMilli(1514764800000L); // 2018-01-01
+ Instant end = start.plus(Duration.ofDays(10));
+ double[] bbox = {0.0, 0.0, 10.0, 10.0};
+
+ List items = collection.setTimestampFilter(Date.from(start), Date.from(end))
+ .setBboxFilter(bbox)
+ .searchItems();
+
+ assertTrue(!items.isEmpty());
+ }
+
+ public void testSearchThrowsExceptionUsingBothBboxAndIntersect() throws Exception {
+ HMStacCollection collection = manager.getCollectionById("io-lulc-annual-v02");
+ Instant start = Instant.ofEpochMilli(1514764800000L); // 2018-01-01
+ Instant end = start.plus(Duration.ofDays(10));
+ Polygon bboxPolygon = gf.createPolygon(createBbox(0.0, 0.0, 10.0, 10.0));
+ double[] bbox = {0.0, 0.0, 10.0, 10.0};
+
+ assertThrows(IllegalStateException.class, () -> collection.setTimestampFilter(Date.from(start), Date.from(end))
+ .setGeometryFilter(bboxPolygon)
+ .setBboxFilter(bbox)
+ .searchItems()
+ );
+ }
+}
diff --git a/gears/src/test/java/org/hortonmachine/gears/modules/TestStacAsset.java b/gears/src/test/java/org/hortonmachine/gears/modules/TestStacAsset.java
index 4ad6a3952..a57cb7804 100644
--- a/gears/src/test/java/org/hortonmachine/gears/modules/TestStacAsset.java
+++ b/gears/src/test/java/org/hortonmachine/gears/modules/TestStacAsset.java
@@ -1,12 +1,21 @@
package org.hortonmachine.gears.modules;
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.geotools.coverage.grid.GridCoverage2D;
import org.hortonmachine.gears.io.stac.HMStacAsset;
import org.hortonmachine.gears.utils.HMTestCase;
+import org.hortonmachine.gears.utils.RegionMap;
+
+import static org.junit.Assert.assertThrows;
public class TestStacAsset extends HMTestCase {
+ private ObjectMapper mapper = new ObjectMapper();
protected void setUp() throws Exception {
@@ -17,7 +26,6 @@ protected void setUp() throws Exception {
public void testCreateValidStacAsset() throws JsonProcessingException {
String assetJSON = "{\"title\":\"Band 1 (coastal) BOA reflectance\",\"type\":\"image/tiff; application=geotiff; profile=cloud-optimized\",\"roles\":[\"data\"],\"gsd\":60,\"eo:bands\":[{\"name\":\"B01\",\"common_name\":\"coastal\",\"center_wavelength\":0.4439,\"full_width_half_max\":0.027}],\"href\":\"https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/33/S/VB/2021/2/S2B_33SVB_20210221_0_L2A/B01.tif\",\"proj:shape\":[1830,1830],\"proj:transform\":[60,0,399960,0,-60,4200000,0,0,1],\"raster:bands\":[{\"data_type\":\"uint16\",\"spatial_resolution\":60,\"bits_per_sample\":15,\"nodata\":0,\"statistics\":{\"minimum\":1,\"maximum\":20567,\"mean\":2339.4759595597,\"stddev\":3026.6973619954,\"valid_percent\":99.83}}]}";
- ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(assetJSON);
HMStacAsset asset = new HMStacAsset("B01", node);
@@ -32,7 +40,6 @@ public void testCreateValidStacAsset() throws JsonProcessingException {
public void testCreateInvalidStacAssetTypeInformationNotAvailable() throws JsonProcessingException {
String assetJSON = "{\"title\":\"Band 1 (coastal) BOA reflectance\",\"roles\":[\"data\"],\"gsd\":60,\"eo:bands\":[{\"name\":\"B01\",\"common_name\":\"coastal\",\"center_wavelength\":0.4439,\"full_width_half_max\":0.027}],\"href\":\"https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/33/S/VB/2021/2/S2B_33SVB_20210221_0_L2A/B01.tif\",\"proj:shape\":[1830,1830],\"proj:transform\":[60,0,399960,0,-60,4200000,0,0,1],\"raster:bands\":[{\"data_type\":\"uint16\",\"spatial_resolution\":60,\"bits_per_sample\":15,\"nodata\":0,\"statistics\":{\"minimum\":1,\"maximum\":20567,\"mean\":2339.4759595597,\"stddev\":3026.6973619954,\"valid_percent\":99.83}}]}";
- ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(assetJSON);
HMStacAsset asset = new HMStacAsset("B01", node);
@@ -43,7 +50,6 @@ public void testCreateInvalidStacAssetTypeInformationNotAvailable() throws JsonP
public void testCreateInvalidStacAssetNotACOG() throws JsonProcessingException {
String assetJSON = "{\"title\":\"Band 1 (coastal) BOA reflectance\",\"type\":\"image/tiff;\",\"roles\":[\"data\"],\"gsd\":60,\"eo:bands\":[{\"name\":\"B01\",\"common_name\":\"coastal\",\"center_wavelength\":0.4439,\"full_width_half_max\":0.027}],\"href\":\"https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/33/S/VB/2021/2/S2B_33SVB_20210221_0_L2A/B01.tif\",\"proj:shape\":[1830,1830],\"proj:transform\":[60,0,399960,0,-60,4200000,0,0,1],\"raster:bands\":[{\"data_type\":\"uint16\",\"spatial_resolution\":60,\"bits_per_sample\":15,\"nodata\":0,\"statistics\":{\"minimum\":1,\"maximum\":20567,\"mean\":2339.4759595597,\"stddev\":3026.6973619954,\"valid_percent\":99.83}}]}";
- ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(assetJSON);
HMStacAsset asset = new HMStacAsset("B01", node);
@@ -52,15 +58,52 @@ public void testCreateInvalidStacAssetNotACOG() throws JsonProcessingException {
assertEquals("not a COG", asset.getNonValidReason());
}
- public void testCreateInvalidStacAssetRasterBandsMetadataMissing() throws JsonProcessingException {
+ public void testCreateStacAssetRasterBandsMetadataMissingIsValid() throws JsonProcessingException {
String assetJSON = "{\"title\":\"Band 1 (coastal) BOA reflectance\",\"type\":\"image/tiff; application=geotiff; profile=cloud-optimized\",\"roles\":[\"data\"],\"gsd\":60,\"eo:bands\":[{\"name\":\"B01\",\"common_name\":\"coastal\",\"center_wavelength\":0.4439,\"full_width_half_max\":0.027}],\"href\":\"https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/33/S/VB/2021/2/S2B_33SVB_20210221_0_L2A/B01.tif\",\"proj:shape\":[1830,1830],\"proj:transform\":[60,0,399960,0,-60,4200000,0,0,1],\"raster:bands\":[]}";
- ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(assetJSON);
HMStacAsset asset = new HMStacAsset("B01", node);
- assertFalse(asset.isValid());
- assertEquals("raster bands metadata missing", asset.getNonValidReason());
+ assertTrue(asset.isValid());
}
+ public void testReadRasterFromHTTP() throws Exception {
+ String assetJSON = "{\"title\":\"Band 1 (coastal) BOA reflectance\",\"type\":\"image/tiff; application=geotiff; profile=cloud-optimized\",\"roles\":[\"data\"],\"gsd\":60,\"eo:bands\":[{\"name\":\"B01\",\"common_name\":\"coastal\",\"center_wavelength\":0.4439,\"full_width_half_max\":0.027}],\"href\":\"https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/33/S/VB/2021/2/S2B_33SVB_20210221_0_L2A/B01.tif\",\"proj:shape\":[1830,1830],\"proj:transform\":[60,0,399960,0,-60,4200000,0,0,1],\"raster:bands\":[{\"data_type\":\"uint16\",\"spatial_resolution\":60,\"bits_per_sample\":15,\"nodata\":0,\"statistics\":{\"minimum\":1,\"maximum\":20567,\"mean\":2339.4759595597,\"stddev\":3026.6973619954,\"valid_percent\":99.83}}]}";
+ JsonNode node = mapper.readTree(assetJSON);
+ String assetId = "rainfall";
+ HMStacAsset hmAsset = new HMStacAsset(assetId, node);
+ RegionMap regionMap = RegionMap.fromBoundsAndGrid(1640000.0, 1640200.0, 5140000.0, 5140160.0, 20, 16);
+
+ GridCoverage2D grid = hmAsset.readRaster(regionMap);
+
+ assertNotNull(grid);
+ }
+
+ private AmazonS3 createDefaultS3Client(String region) {
+ AWSCredentials credentials = new BasicAWSCredentials(
+ "accessKey",
+ "secretKey"
+ );
+ AmazonS3 client = AmazonS3ClientBuilder
+ .standard()
+ // We use anonymized credentials for this example.
+ // For testing purposes, add your own credentials and uncomment the following line.
+ //.withCredentials(new AWSStaticCredentialsProvider(credentials))
+ .withRegion("us-west-2")
+ .build();
+ return client;
+ }
+
+ public void testReadRasterFromS3() throws Exception {
+ String assetJSON = "{\"href\":\"s3://sentinel-cogs/sentinel-s2-l2a-cogs/5/C/MK/2018/10/S2B_5CMK_20181020_0_L2A/B01.tif\",\"type\":\"image/tiff; application=geotiff; profile=cloud-optimized\",\"title\":\"rainfall\",\"eo:bands\":[{\"name\":\"rainfall\"}],\"proj:epsg\":4326,\"proj:shape\":[1600,1500],\"proj:transform\":[0.05000000074505806,0,-20,0,-0.05000000074505806,40,0,0,1],\"roles\":[\"data\"]}},\"bbox\":[-20,-40.000001192092896,55.00000111758709,40],\"stac_extensions\":[\"https://stac-extensions.github.io/eo/v1.1.0/schema.json\",\"https://stac-extensions.github.io/projection/v1.1.0/schema.json\"],\"collection\":\"rainfall_chirps_monthly\"}";
+ JsonNode node = mapper.readTree(assetJSON);
+ String assetId = "rainfall";
+ HMStacAsset hmAsset = new HMStacAsset(assetId, node);
+ RegionMap regionMap = RegionMap.fromBoundsAndGrid(1640000.0, 1640200.0, 5140000.0, 5140160.0, 20, 16);
+ AmazonS3 s3Client = createDefaultS3Client("us-west-2");
+
+ GridCoverage2D grid = hmAsset.readRaster(regionMap, s3Client);
+
+ assertNotNull(grid);
+ }
}
diff --git a/gui/pom.xml b/gui/pom.xml
index 7f13aa4bd..b96413703 100644
--- a/gui/pom.xml
+++ b/gui/pom.xml
@@ -5,7 +5,7 @@
org.hortonmachine
hortonmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
hm-gui
@@ -16,7 +16,7 @@
org.hortonmachine
hm-modules
- 0.10.8
+ 0.10.9-SNAPSHOT
diff --git a/hmachine/pom.xml b/hmachine/pom.xml
index 4821f8345..fc92dbfd2 100644
--- a/hmachine/pom.xml
+++ b/hmachine/pom.xml
@@ -6,7 +6,7 @@
org.hortonmachine
hortonmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
../pom.xml
@@ -18,7 +18,7 @@
org.hortonmachine
hm-gears
- 0.10.8
+ 0.10.9-SNAPSHOT
diff --git a/lesto/pom.xml b/lesto/pom.xml
index 08e595203..af39333ac 100644
--- a/lesto/pom.xml
+++ b/lesto/pom.xml
@@ -6,7 +6,7 @@
org.hortonmachine
hortonmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
hm-lesto
@@ -18,7 +18,7 @@
org.hortonmachine
hm-hmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
diff --git a/modules/pom.xml b/modules/pom.xml
index f86655a4e..958e69e84 100644
--- a/modules/pom.xml
+++ b/modules/pom.xml
@@ -7,7 +7,7 @@
org.hortonmachine
hortonmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
hm-modules
@@ -18,7 +18,7 @@
org.hortonmachine
hm-lesto
- 0.10.8
+ 0.10.9-SNAPSHOT
diff --git a/pom.xml b/pom.xml
index 94cdf5776..baa0afc4a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.hortonmachine
hortonmachine
- 0.10.8
+ 0.10.9-SNAPSHOT
pom
The Horton Machine
@@ -55,6 +55,7 @@
false
+ 1.12.730
@@ -397,7 +398,6 @@
imageio-ext-cog-rangereader-http
${imageio.ext.version}
-
joda-time
joda-time
@@ -894,6 +894,12 @@
test
+
+ com.amazonaws
+ aws-java-sdk-core
+ ${aws.version}
+
+
@@ -1122,6 +1128,8 @@
ossrh
https://oss.sonatype.org/
true
+ ${env.OSSRH_USERNAME}
+ ${env.OSSRH_TOKEN}