Skip to content

Add support for opening OME-Zarr datasets in public S3 stores - #84

Merged
stefanhahmann merged 20 commits into
mainfrom
add-s3-support
Aug 11, 2026
Merged

Add support for opening OME-Zarr datasets in public S3 stores#84
stefanhahmann merged 20 commits into
mainfrom
add-s3-support

Conversation

@stefanhahmann

@stefanhahmann stefanhahmann commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Enables opening s3://bucket/path URIs in both the ZarrJava and N5 backends.

What's included:

  • Accept s3:// URIs in ClipboardUtils and skip the isZarr() probe for them (which would require a short-lived S3 client just for detection)
  • ZarrJavaPyramidBackend: builds an AWS SDK S3Client (default region US_EAST_1; standard AWS credential chain with an anonymous-credentials fallback) and constructs a zarr-java S3Store from the URI's host and path. The AWS SDK ships transitively with zarr-java.
  • N5PyramidBackend: relies on N5Factory's existing S3 support (via n5-aws-s3), only passing Region.US_EAST_1 as the default region so environments without ~/.aws/config still work. The n5-aws-s3 dependency was added to the ome-zarr-n5 module.

Error handling:

  • Store-access failures (S3 auth failures, missing buckets, network errors, …) are RuntimeExceptions that previously escaped every catch block and surfaced as an unhandled exception in Fiji. Each backend now wraps them, in load(), into a backend-agnostic StoreAccessException (added to ome-zarr-imglib2): ZarrJavaPyramidBackend wraps zarr-java's StoreException, N5PyramidBackend wraps N5's N5Exception thrown while opening the reader / reading multiscale metadata.
  • The Fiji opener (ZarrOpener) catches the single StoreAccessException and reports it as a user-facing error. This keeps the Fiji layer decoupled from the concrete backends.

Authentication:

  • Works with public (anonymous) buckets and with private buckets whose credentials are available through the standard AWS chain (~/.aws/credentials, AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY env vars, or instance role credentials).

Not yet included:

  • No UI to enter an S3 URI, bucket, region, or credentials. Users must paste an s3:// URI via the existing clipboard/drag-and-drop path.

  • There is currently no API to inject custom credentials programmatically.

  • Can be tested with this URI from the open organelle project: s3://janelia-cosem-datasets/jrc_mus-choroid-plexus-3/jrc_mus-choroid-plexus-3.zarr/recon-1/em/fibsem-uint8

@stefanhahmann stefanhahmann changed the title Add S3 support for opening OME-Zarr datasets Add support for opening OME-Zarr datasets in public S3 stores May 27, 2026
@stefanhahmann stefanhahmann self-assigned this May 27, 2026
@sonarqubecloud

Copy link
Copy Markdown

@stefanhahmann
stefanhahmann requested a review from xulman June 12, 2026 07:51
xulman
xulman previously approved these changes Jun 15, 2026

@xulman xulman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. Thanks.

One of the tests caught my attention, and I was "complaining" that perhaps we could reuse code and maybe even shorten/simplify the (testing) codebase?

Also, I'm thinking if it would be possible to make N5 and ZarrJava throw the same exception. Or is our layer swallowing them and re-sending further to a client code under one common exception?

Comment thread src/main/java/sc/fiji/ome/zarr/pyramid/backend/n5/N5PyramidBackend.java Outdated
Comment thread ome-zarr-fiji-ui/src/test/java/ome/zarr/fijiui/open/ZarrOpenActionsTest.java Outdated
@stefanhahmann
stefanhahmann force-pushed the add-s3-support branch 7 times, most recently from 3435f87 to 3666ab3 Compare August 5, 2026 12:07
@stefanhahmann

Copy link
Copy Markdown
Collaborator Author

Also, I'm thinking if it would be possible to make N5 and ZarrJava throw the same exception. Or is our layer swallowing them and re-sending further to a client code under one common exception?

This is now the case. Both backends translate their native store-open failures into a single backend-agnostic exception, StoreAccessException (in the ome-zarr-imglib2 API module):

The Fiji opener (ZarrOpener) then catches just that one type and surfaces it as a user-facing error.

stefanhahmann and others added 13 commits August 6, 2026 16:13
Previously any URI with a scheme other than http, https, or file was rejected. Accept s3:// as a supported scheme so S3 dataset URIs can be
pasted from the clipboard.
Add an s3:// branch that constructs an S3Store
using S3Client.create() and bucket/key parsed directly from the URI host and path. An empty key prefix is passed as null to avoid a leading slash in resolved S3 object keys.

The N5PyramidBackend already handles S3 through N5Factory and required no changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Probing would create a short-lived S3Client just for detection. The open
path creates the client it needs anyway and reports a clear error if the
location is not OME-Zarr, so the probe is skipped for s3:// URIs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
S3Client.create() requires credentials to be configured externally,
blocking access to public datasets for users without ~/.aws/credentials
or environment variables set. Using a credentials chain that tries the
default providers first and falls back to AnonymousCredentialsProvider
mirrors in the n5 backend.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both are RuntimeExceptions thrown on store-access failures (S3 auth
failures, missing buckets, network errors) that previously escaped every
catch block in openImage() and surfaced as unhandled exceptions in Fiji.
Now caught and shown as a user-facing error with the store message.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set Region.US_EAST_1 as the default S3 region in both N5PyramidBackend
and ZarrJavaPyramidBackend so that environments without ~/.aws/config
(e.g. CI) can open public S3-hosted OME-Zarr datasets without an
"Unable to load region" SDK error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add openImageFromS3 integration test that exercises the full metadata
loading pipeline for both backends against a public Janelia OpenOrganelle
dataset. Uses openImage() and counting pattern instead of opening in
ImageJ/BDV to avoid tile downloads (to not slow the test down even more)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests that both backends report a user-facing error via the error handler
when S3 store access fails. The ZARR_JAVA variant mocks ZarrJavaPyramidBackend
to throw StoreException; the N5 variant relies on N5Exception.N5IOException
being thrown immediately (local failure, no network needed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ZarrOpener (ome-zarr-fiji) is decoupled from the concrete backends, so it
cannot catch zarr-java's StoreException directly.

This commit introduces a new class StoreAccessException (ome-zarr-imglib2)
Each backend's load() wraps its native store-open failure into it (zarr-java's StoreException, N5's N5Exception), and ZarrOpener catches that single type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the openImage() methods from ZarrOpener and ZarrOpenActions.
Success tests now load via ZarrOpener.getContents() (no UI)
Rejection tests use the real openIJWithImage(), which is window-free on failure paths.
Removes the race condition where OpenResolutionLevelCommand saw no active
pyramidal until the async AWT focus event arrived (sometimes failed in the CI under load).
Synchronous active-pyramidal registration makes the EDT flush obsolete.
xulman
xulman previously approved these changes Aug 11, 2026
Comment thread ome-zarr-fiji-ui/src/main/java/ome/zarr/fijiui/util/ClipboardUtils.java Outdated
Comment thread ome-zarr-fiji-ui/src/test/java/ome/zarr/fijiui/open/ZarrOpenActionsTest.java Outdated
S3Store reported S3 errors as the AWS SDK's unchecked SdkException, which
escaped the StoreException-only catch and surfaced unhandled in Fiji. Catch
both exception types now and drop the MockedConstruction from
storeAccessErrorIsReportedToErrorHandler so ZARR_JAVA exercises the same
real path as N5.
@sonarqubecloud

Copy link
Copy Markdown

@stefanhahmann
stefanhahmann merged commit 2940dfb into main Aug 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants