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}