diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..2579abb7 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Format source code according to checkstyle configuration +a5da2cad2e1f73c18df90bbfbe5d06f2bbd3357e diff --git a/build.gradle b/build.gradle index 9bbbaee6..78270ef6 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java-library' id 'eclipse' id 'maven-publish' + id 'checkstyle' } group = 'com.glencoesoftware.omero' @@ -87,3 +88,7 @@ jar { ) } } + +checkstyle { + toolVersion = "10.26.1" +} diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 00000000..b10ab4ca --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/glencoesoftware/omero/zarr/OmeroAmazonS3ClientFactory.java b/src/main/java/com/glencoesoftware/omero/zarr/OmeroAmazonS3ClientFactory.java index 9a85a081..f078056b 100644 --- a/src/main/java/com/glencoesoftware/omero/zarr/OmeroAmazonS3ClientFactory.java +++ b/src/main/java/com/glencoesoftware/omero/zarr/OmeroAmazonS3ClientFactory.java @@ -15,14 +15,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -package com.glencoesoftware.omero.zarr; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import org.slf4j.LoggerFactory; +package com.glencoesoftware.omero.zarr; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.AWSCredentialsProviderChain; @@ -36,7 +30,15 @@ import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.util.AwsHostNameUtils; import com.upplication.s3fs.AmazonS3ClientFactory; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import org.slf4j.LoggerFactory; +/** + * Subclass which maps an URI into a set of credentials to use for the client. + */ public class OmeroAmazonS3ClientFactory extends AmazonS3ClientFactory { private static final org.slf4j.Logger log = @@ -48,11 +50,11 @@ public class OmeroAmazonS3ClientFactory extends AmazonS3ClientFactory { protected AWSCredentialsProvider getCredentialsProvider(Properties props) { // If AWS Environment or System Properties are set, throw an exception // so users will know they are not supported - if (System.getenv("AWS_ACCESS_KEY_ID") != null || - System.getenv("AWS_SECRET_ACCESS_KEY") != null || - System.getenv("AWS_SESSION_TOKEN") != null || - System.getProperty("aws.accessKeyId") != null || - System.getProperty("aws.secretAccessKey") != null) { + if (System.getenv("AWS_ACCESS_KEY_ID") != null + || System.getenv("AWS_SECRET_ACCESS_KEY") != null + || System.getenv("AWS_SESSION_TOKEN") != null + || System.getProperty("aws.accessKeyId") != null + || System.getProperty("aws.secretAccessKey") != null) { throw new RuntimeException("AWS credentials supplied by environment variables" + " or Java system properties are not supported." + " Please use either named profiles or instance" @@ -77,6 +79,7 @@ protected AWSCredentialsProvider getCredentialsProvider(Properties props) { /** * Retrieves the bucket name from a given URI. + * * @param uri The URI to handle * @return The bucket name */ @@ -90,6 +93,7 @@ private String getBucketFromUri(URI uri) { /** * Retrieves the region from a given URI. + * * @param uri The URI to handle * @return The region */ @@ -103,6 +107,7 @@ private String getRegionFromUri(URI uri) { /** * Retrieves the endpoint from a given URI. + * * @param uri The URI to handle * @return The endpoint */ @@ -112,7 +117,7 @@ public String getEndPointFromUri(URI uri) { @Override public synchronized AmazonS3 getAmazonS3(URI uri, Properties props) { - //Check if we have a S3 client for this bucket + // Check if we have a S3 client for this bucket String bucket = getBucketFromUri(uri); if (bucketClientMap.containsKey(bucket)) { log.info("Found bucket " + bucket); @@ -120,11 +125,12 @@ public synchronized AmazonS3 getAmazonS3(URI uri, Properties props) { } log.info("Creating client for bucket " + bucket); AmazonS3 client = AmazonS3ClientBuilder.standard() - .withCredentials(getCredentialsProvider(props)) - .withClientConfiguration(getClientConfiguration(props)) - .withMetricsCollector(getRequestMetricsCollector(props)) - .withEndpointConfiguration(new EndpointConfiguration(getEndPointFromUri(uri), getRegionFromUri(uri))) - .build(); + .withCredentials(getCredentialsProvider(props)) + .withClientConfiguration(getClientConfiguration(props)) + .withMetricsCollector(getRequestMetricsCollector(props)) + .withEndpointConfiguration( + new EndpointConfiguration(getEndPointFromUri(uri), getRegionFromUri(uri))) + .build(); bucketClientMap.put(bucket, client); return client; } diff --git a/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3FileSystem.java b/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3FileSystem.java index c4f02d1a..2af84c49 100644 --- a/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3FileSystem.java +++ b/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3FileSystem.java @@ -15,16 +15,18 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -package com.glencoesoftware.omero.zarr; -import java.io.IOException; +package com.glencoesoftware.omero.zarr; import com.amazonaws.services.s3.AmazonS3; import com.upplication.s3fs.S3FileSystem; import com.upplication.s3fs.S3FileSystemProvider; +import java.io.IOException; +/** Subclass of S3FileSystem with performance optimizations. */ public class OmeroS3FileSystem extends S3FileSystem { + /** Default constructor. */ public OmeroS3FileSystem(S3FileSystemProvider provider, String key, AmazonS3 client, String endpoint) { super(provider, key, client, endpoint); @@ -32,11 +34,11 @@ public OmeroS3FileSystem(S3FileSystemProvider provider, String key, @Override public void close() throws IOException { - //No-op + // No-op } @Override public boolean isOpen() { - return true; //Not possible to be closed + return true; // Not possible to be closed } } diff --git a/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3ReadOnlySeekableByteChannel.java b/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3ReadOnlySeekableByteChannel.java index 8dbc1671..8fd8e1c3 100644 --- a/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3ReadOnlySeekableByteChannel.java +++ b/src/main/java/com/glencoesoftware/omero/zarr/OmeroS3ReadOnlySeekableByteChannel.java @@ -15,9 +15,14 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -package com.glencoesoftware.omero.zarr; +package com.glencoesoftware.omero.zarr; +import com.amazonaws.services.s3.model.GetObjectRequest; +import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.s3.model.S3ObjectInputStream; +import com.upplication.s3fs.S3Path; +import com.upplication.s3fs.S3ReadOnlySeekableByteChannel; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -32,14 +37,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; - import org.perf4j.slf4j.Slf4JStopWatch; -import com.amazonaws.services.s3.model.GetObjectRequest; -import com.amazonaws.services.s3.model.S3Object; -import com.amazonaws.services.s3.model.S3ObjectInputStream; -import com.upplication.s3fs.S3Path; -import com.upplication.s3fs.S3ReadOnlySeekableByteChannel; /** * Overridden, hybrid version of the implementation from @@ -61,15 +60,15 @@ public class OmeroS3ReadOnlySeekableByteChannel implements SeekableByteChannel { * entire object in full from S3 without checks for length during * object construction. */ - public OmeroS3ReadOnlySeekableByteChannel(S3Path path, Set options) throws IOException { + public OmeroS3ReadOnlySeekableByteChannel(S3Path path, Set options) + throws IOException { this.options = Collections.unmodifiableSet(new HashSet<>(options)); - if ( - this.options.contains(StandardOpenOption.WRITE) || - this.options.contains(StandardOpenOption.CREATE) || - this.options.contains(StandardOpenOption.CREATE_NEW) || - this.options.contains(StandardOpenOption.APPEND) - ) { + if (this.options.contains(StandardOpenOption.WRITE) + || this.options.contains(StandardOpenOption.CREATE) + || this.options.contains(StandardOpenOption.CREATE_NEW) + || this.options.contains(StandardOpenOption.APPEND) + ) { throw new ReadOnlyFileSystemException(); } @@ -92,10 +91,10 @@ public OmeroS3ReadOnlySeekableByteChannel(S3Path path, Set // the stream closed as quickly as possible. See // https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/S3Object.html#getObjectContent-- try (S3ObjectInputStream s3Stream = s3Object.getObjectContent()) { - byte[] read_buf = new byte[1024*1024]; - int read_len = 0; - while ((read_len = s3Stream.read(read_buf)) > 0) { - outputStream.write(read_buf, 0, read_len); + byte[] readBuf = new byte[1024 * 1024]; + int readLen = 0; + while ((readLen = s3Stream.read(readBuf)) > 0) { + outputStream.write(readBuf, 0, readLen); } } this.data = outputStream.toByteArray(); @@ -124,7 +123,9 @@ public boolean isOpen() { * private visibility. */ @Override - public long position() { return position; } + public long position() { + return position; + } /** * Overridden, hybrid version of the implementation from @@ -133,8 +134,7 @@ public boolean isOpen() { */ @Override public SeekableByteChannel position(long targetPosition) - throws IOException - { + throws IOException { throw new UnsupportedOperationException(); } diff --git a/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelBuffer.java b/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelBuffer.java index 4ff6b989..4cd2bee7 100644 --- a/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelBuffer.java +++ b/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelBuffer.java @@ -18,6 +18,10 @@ package com.glencoesoftware.omero.zarr; +import com.bc.zarr.DataType; +import com.bc.zarr.ZarrArray; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; import java.awt.Dimension; import java.io.IOException; import java.nio.BufferOverflowException; @@ -31,22 +35,18 @@ import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.stream.IntStream; - -import org.slf4j.LoggerFactory; - -import com.bc.zarr.DataType; -import com.bc.zarr.ZarrArray; -import com.github.benmanes.caffeine.cache.AsyncLoadingCache; -import com.github.benmanes.caffeine.cache.Caffeine; - import loci.formats.FormatTools; import ome.io.nio.DimensionsOutOfBoundsException; import ome.io.nio.PixelBuffer; import ome.io.nio.RomioPixelBuffer; import ome.model.core.Pixels; import ome.util.PixelData; +import org.slf4j.LoggerFactory; import ucar.ma2.InvalidRangeException; +/** + * Subclass of ome.io.nio.PixelBuffer handling OME-Zarr data. + **/ public class ZarrPixelBuffer implements PixelBuffer { private static final org.slf4j.Logger log = @@ -55,25 +55,25 @@ public class ZarrPixelBuffer implements PixelBuffer { /** Reference to the pixels. */ private final Pixels pixels; - /** Root of the OME-NGFF multiscale we are operating on */ + /** Root of the OME-NGFF multiscale we are operating on. */ private final Path root; - /** Requested resolution level */ + /** Requested resolution level. */ private int resolutionLevel; - /** Total number of resolution levels */ + /** Total number of resolution levels. */ private final int resolutionLevels; - /** Max Plane Width */ + /** Max Plane Width. */ private final Integer maxPlaneWidth; - /** Max Plane Height */ + /** Max Plane Height. */ private final Integer maxPlaneHeight; - /** Zarr attributes present on the root group */ + /** Zarr attributes present on the root group. */ private final Map rootGroupAttributes; - /** Zarr array corresponding to the current resolution level */ + /** Zarr array corresponding to the current resolution level. */ private ZarrArray array; /** @@ -82,34 +82,32 @@ public class ZarrPixelBuffer implements PixelBuffer { */ private Map zIndexMap; - /** { resolutionLevel, z, c, t, x, y, w, h } vs. tile byte array cache */ + /** { resolutionLevel, z, c, t, x, y, w, h } vs. tile byte array cache. */ private final AsyncLoadingCache, byte[]> tileCache; - /** Whether or not the Zarr is on S3 or similar */ + /** Whether or not the Zarr is on S3 or similar. */ private final boolean isRemote; - /** Root path vs. metadata cache */ + /** Root path vs. metadata cache. */ private final AsyncLoadingCache> zarrMetadataCache; - /** Array path vs. ZarrArray cache */ + /** Array path vs. ZarrArray cache. */ private final AsyncLoadingCache zarrArrayCache; - /** Supported axes, X and Y are essential */ + /** Supported axes, X and Y are essential. */ public enum Axis { X, Y, Z, C, T; } - /** Maps axes to their corresponding indexes */ + /** Maps axes to their corresponding indexes. */ private Map axesOrder; /** - * Default constructor + * Default constructor. + * * @param pixels Pixels metadata for the pixel buffer * @param root The root of this buffer - * @param maxTileLength Maximum tile length that can be used during - * read operations - * @throws IOException */ public ZarrPixelBuffer(Pixels pixels, Path root, Integer maxPlaneWidth, Integer maxPlaneHeight, @@ -121,10 +119,10 @@ public ZarrPixelBuffer(Pixels pixels, Path root, Integer maxPlaneWidth, this.root = root; this.zarrMetadataCache = zarrMetadataCache; this.zarrArrayCache = zarrArrayCache; - this.isRemote = root.toString().startsWith("s3://")? true : false; + this.isRemote = root.toString().startsWith("s3://") ? true : false; try { rootGroupAttributes = this.zarrMetadataCache.get(this.root).get(); - } catch (ExecutionException|InterruptedException e) { + } catch (ExecutionException | InterruptedException e) { throw new IOException(e); } if (!rootGroupAttributes.containsKey("multiscales")) { @@ -162,6 +160,7 @@ public ZarrPixelBuffer(Pixels pixels, Path root, Integer maxPlaneWidth, /** * Get Bio-Formats/OMERO pixels type for buffer. + * * @return See above. */ public int getPixelsType() { @@ -191,11 +190,11 @@ public int getPixelsType() { /** * Calculates the pixel length of a given NumPy like "shape". + * * @param shape the NumPy like "shape" to calculate the length of * @return See above - * @see - * numpy.shape documentation + * @see numpy.shape + * documentation */ private long length(int[] shape) { return IntStream.of(shape) @@ -269,7 +268,7 @@ private void read(byte[] buffer, int[] shape, int[] offset) default: throw new IllegalArgumentException( "Data type " + dataType + " not supported"); - } + } } } catch (InvalidRangeException e) { log.error("Error reading Zarr data", e); @@ -294,8 +293,8 @@ private PixelData toPixelData(byte[] buffer) { /** * Retrieves the array chunk sizes of all subresolutions of this multiscale * buffer. + * * @return See above. - * @throws IOException */ public int[][] getChunks() throws IOException { List> datasets = getDatasets(); @@ -312,6 +311,7 @@ public int[][] getChunks() throws IOException { /** * Retrieves the datasets metadata of the first multiscale from the root * group attributes. + * * @return See above. * @see #getRootGroupAttributes() * @see #getMultiscalesMetadata() @@ -322,7 +322,8 @@ public List> getDatasets() { } /** - * Retrieves the axes order of the first multiscale + * Retrieves the axes order of the first multiscale. + * * @return See above. */ public Map getAxesOrder() { @@ -330,7 +331,8 @@ public Map getAxesOrder() { return axesOrder; } axesOrder = new HashMap(); - List> axesData = (List>) getMultiscalesMetadata().get(0).get("axes"); + List> axesData = + (List>) getMultiscalesMetadata().get(0).get("axes"); if (axesData == null) { log.warn("No axes metadata found, defaulting to standard axes TCZYX"); axesOrder.put(Axis.T, 0); @@ -345,7 +347,8 @@ public Map getAxesOrder() { try { axesOrder.put(Axis.valueOf(name), i); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid axis name (only T,C,Z,Y,X are supported): " + name); + throw new IllegalArgumentException( + "Invalid axis name (only T,C,Z,Y,X are supported): " + name); } } } @@ -357,6 +360,7 @@ public Map getAxesOrder() { /** * Retrieves the multiscales metadata from the root group attributes. + * * @return See above. * @see #getRootGroupAttributes() * @see #getDatasets() @@ -368,6 +372,7 @@ public List> getMultiscalesMetadata() { /** * Returns the current Zarr root group attributes for this buffer. + * * @return See above. * @see #getMultiscalesMetadata() * @see #getDatasets() @@ -385,6 +390,7 @@ public void close() throws IOException { /** * Implemented as specified by {@link PixelBuffer} I/F. + * * @see PixelBuffer#checkBounds(Integer, Integer, Integer, Integer, Integer) */ @Override @@ -416,6 +422,9 @@ public void checkBounds(Integer x, Integer y, Integer z, Integer c, } } + /** + * Checks the shape to read does not exceed the maximum plane size. + **/ public void checkReadSize(int[] shape) { long length = length(shape); long maxLength = maxPlaneWidth * maxPlaneHeight; @@ -522,14 +531,14 @@ public PixelData getTile( Integer z, Integer c, Integer t, Integer x, Integer y, Integer w, Integer h) throws IOException { - //Check origin indices > 0 + // Check origin indices > 0 checkBounds(x, y, z, c, t); - //Check check bottom-right of tile in bounds + // Check check bottom-right of tile in bounds checkBounds(x + w - 1, y + h - 1, z, c, t); - //Check planar read size (sizeX and sizeY only), essential that this - //happens before the similar check in read(). Otherwise we will - //potentially allocate massive inner buffers in the tile cache - //asynchronous entry builder that will never be used. + // Check planar read size (sizeX and sizeY only), essential that this + // happens before the similar check in read(). Otherwise we will + // potentially allocate massive inner buffers in the tile cache + // asynchronous entry builder that will never be used. checkReadSize(new int[] { w, h }); List> keys = new ArrayList>(); @@ -537,7 +546,7 @@ public PixelData getTile( List channels = Arrays.asList(new Integer[] { c }); if (getSizeC() == 3 && isRemote) { // Guessing that we are in RGB mode - channels = Arrays.asList(new Integer[] { 0, 1 ,2 }); + channels = Arrays.asList(new Integer[] { 0, 1, 2 }); } for (Integer channel : channels) { List v = Arrays.asList( @@ -561,9 +570,9 @@ public byte[] getTileDirect( Integer z, Integer c, Integer t, Integer x, Integer y, Integer w, Integer h, byte[] buffer) throws IOException { try { - //Check origin indices > 0 + // Check origin indices > 0 checkBounds(x, y, z, c, t); - //Check check bottom-right of tile in bounds + // Check check bottom-right of tile in bounds checkBounds(x + w - 1, y + h - 1, z, c, t); int[] shape = new int[axesOrder.size()]; @@ -680,9 +689,9 @@ public byte[] getStackDirect(Integer c, Integer t, byte[] buffer) int w = getSizeX(); int h = getSizeY(); - //Check origin indices > 0 + // Check origin indices > 0 checkBounds(x, y, z, c, t); - //Check check bottom-right of tile in bounds + // Check check bottom-right of tile in bounds checkBounds(x + w - 1, y + h - 1, z, c, t); int[] shape = new int[axesOrder.size()]; @@ -727,9 +736,9 @@ public byte[] getTimepointDirect(Integer t, byte[] buffer) int w = getSizeX(); int h = getSizeY(); - //Check origin indices > 0 + // Check origin indices > 0 checkBounds(x, y, z, c, t); - //Check check bottom-right of tile in bounds + // Check check bottom-right of tile in bounds checkBounds(x + w - 1, y + h - 1, z, c, t); int[] shape = new int[axesOrder.size()]; @@ -828,8 +837,8 @@ public void setTimepoint(byte[] buffer, Integer t) @Override public byte[] calculateMessageDigest() throws IOException { throw new UnsupportedOperationException( - "Zarr pixel buffer does not support message digest " + - "calculation"); + "Zarr pixel buffer does not support message digest " + + "calculation"); } @Override @@ -877,6 +886,8 @@ public int getSizeZ() { } /** + * Returns the real Z size for the current resolution level. + * * @return Z size of the current underlying Zarr array */ private int getTrueSizeZ() { @@ -930,8 +941,7 @@ public void setResolutionLevel(int resolutionLevel) { if (zIndexMap == null) { zIndexMap = new HashMap(); - } - else { + } else { zIndexMap.clear(); } try { diff --git a/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelsService.java b/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelsService.java index 4a3ef1a8..d34e0c16 100644 --- a/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelsService.java +++ b/src/main/java/com/glencoesoftware/omero/zarr/ZarrPixelsService.java @@ -18,6 +18,12 @@ package com.glencoesoftware.omero.zarr; +import com.bc.zarr.ZarrArray; +import com.bc.zarr.ZarrGroup; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.google.common.base.Splitter; +import com.upplication.s3fs.OmeroS3FilesystemProvider; import java.io.File; import java.io.IOException; import java.net.URI; @@ -28,18 +34,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; - -import org.perf4j.StopWatch; -import org.perf4j.slf4j.Slf4JStopWatch; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Splitter; -import com.upplication.s3fs.OmeroS3FilesystemProvider; -import com.bc.zarr.ZarrArray; -import com.bc.zarr.ZarrGroup; -import com.github.benmanes.caffeine.cache.AsyncLoadingCache; -import com.github.benmanes.caffeine.cache.Caffeine; - import ome.api.IQuery; import ome.conditions.LockTimeout; import ome.io.nio.BackOff; @@ -51,11 +45,15 @@ import ome.model.core.Pixels; import ome.model.meta.ExternalInfo; import ome.model.roi.Mask; +import org.perf4j.StopWatch; +import org.perf4j.slf4j.Slf4JStopWatch; +import org.slf4j.LoggerFactory; /** * Subclass which overrides series retrieval to avoid the need for * an injected {@link IQuery}. - * @author Chris Allan + * + * @author Chris Allan * */ public class ZarrPixelsService extends ome.io.nio.PixelsService { @@ -66,25 +64,26 @@ public class ZarrPixelsService extends ome.io.nio.PixelsService { public static final String NGFF_ENTITY_TYPE = "com.glencoesoftware.ngff:multiscales"; public static final long NGFF_ENTITY_ID = 3; - /** Max Plane Width */ + /** Max Plane Width. */ protected final Integer maxPlaneWidth; - /** Max Plane Height */ + /** Max Plane Height. */ protected final Integer maxPlaneHeight; - /** Zarr metadata and array cache size */ + /** Zarr metadata and array cache size. */ private final long zarrCacheSize; - /** Copy of private IQuery also provided to ome.io.nio.PixelsService */ + /** Copy of private IQuery also provided to ome.io.nio.PixelsService. */ private final IQuery iQuery; - /** Root path vs. metadata cache */ + /** Root path vs. metadata cache. */ private final AsyncLoadingCache> zarrMetadataCache; /** Array path vs. ZarrArray cache */ private final AsyncLoadingCache zarrArrayCache; + /** Default constructor. */ public ZarrPixelsService( String path, boolean isReadOnlyRepo, File memoizerDirectory, long memoizerWait, FilePathResolver resolver, BackOff backOff, @@ -110,9 +109,9 @@ public ZarrPixelsService( /** * Retrieves Zarr metadata from a given path. - * @param root path to get Zarr metadata from + * + * @param path path to get Zarr metadata from * @return See above. - * @throws IOException */ public static Map getZarrMetadata(Path path) throws IOException { @@ -124,9 +123,9 @@ public static Map getZarrMetadata(Path path) /** * Opens a Zarr array at a given path. - * @param root path to open a Zarr array from + * + * @param path path to open a Zarr array from * @return See above. - * @throws IOException */ public static ZarrArray getZarrArray(Path path) throws IOException { return ZarrArray.open(path); @@ -134,11 +133,11 @@ public static ZarrArray getZarrArray(Path path) throws IOException { /** * Converts an NGFF root string to a path, initializing a {@link FileSystem} - * if required + * if required. + * * @param ngffDir NGFF directory root * @return Fully initialized path or null if the NGFF root - * directory has not been specified in configuration. - * @throws IOException + * directory has not been specified in configuration. */ public static Path asPath(String ngffDir) throws IOException { if (ngffDir.isEmpty()) { @@ -189,25 +188,27 @@ public static Path asPath(String ngffDir) throws IOException { /** * Retrieve {@link Mask} or {@link Image} URI stored under {@link ExternalInfo}. + * * @param object loaded {@link Mask} or {@link Image} to check for a URI * @return the value of {@link ExternalInfo.lsid}, null if the object - * does not have an {@link ExternalInfo} with a valid {@link ExternalInfo.lsid} atttribute - * or if {@link ExternalInfo.entityType} is not equal to {@link NGFF_ENTITY_TYPE} or if - * {@link ExternalInfo.entityId} is not equal to {@link NGFF_ENTITY_ID}. + * does not have an {@link ExternalInfo} with a valid {@link ExternalInfo.lsid} atttribute + * or if {@link ExternalInfo.entityType} is not equal to {@link NGFF_ENTITY_TYPE} or if + * {@link ExternalInfo.entityId} is not equal to {@link NGFF_ENTITY_ID}. */ public String getUri(IObject object) { return getUri(object, NGFF_ENTITY_TYPE, NGFF_ENTITY_ID); } /** - * Retrieve {@link Mask} or {@link Image} URI stored under {@link ExternalInfo} + * Retrieve {@link Mask} or {@link Image} URI stored under {@link ExternalInfo}. + * * @param object loaded {@link Mask} or {@link Image} to check for a URI * @param targetEntityType expected entityType in the object {@link ExternalInfo} * @param targetEntityId expected entityType in the object {@link ExternalInfo} * @return the value of {@link ExternalInfo.lsid}, null if the object - * does not have an {@link ExternalInfo} with a valid {@link ExternalInfo.lsid} atttribute - * or if {@link ExternalInfo.entityType} is not equal to targetEntityType or if - * {@link ExternalInfo.entityId} is not equal to targetEntityId . + * does not have an {@link ExternalInfo} with a valid {@link ExternalInfo.lsid} atttribute + * or if {@link ExternalInfo.entityType} is not equal to targetEntityType or if + * {@link ExternalInfo.entityId} is not equal to targetEntityId . */ public String getUri(IObject object, String targetEntityType, Long targetEntityId) { ExternalInfo externalInfo = object.getDetails().getExternalInfo(); @@ -259,6 +260,7 @@ public String getUri(IObject object, String targetEntityType, Long targetEntityI /** * Retrieve the {@link Image} for a particular set of pixels. Where * possible, does not initiate a query. + * * @param pixels Pixels set to retrieve the {@link Image} for. * @return See above. */ @@ -273,9 +275,10 @@ protected Image getImage(Pixels pixels) { /** * Retrieves the series for a given set of pixels. Where possible, does not * initiate a query. + * * @param pixels Set of pixels to return the series for. * @return The series as specified by the pixels parameters or - * 0 (the first series). + * 0 (the first series). */ @Override protected int getSeries(Pixels pixels) { @@ -288,9 +291,9 @@ protected int getSeries(Pixels pixels) { /** * Returns a label image NGFF pixel buffer if it exists. + * * @param mask Mask to retrieve a pixel buffer for. * @return A pixel buffer instance. - * @throws IOException */ public ZarrPixelBuffer getLabelImagePixelBuffer(Mask mask) throws IOException { @@ -312,11 +315,12 @@ pixels, asPath(root), maxPlaneWidth, maxPlaneHeight, /** * Creates an NGFF pixel buffer for a given set of pixels. + * * @param pixels Pixels set to retrieve a pixel buffer for. - * true opens as read-write, false opens as - * read-only. + * true opens as read-write, false opens as + * read-only. * @return An NGFF pixel buffer instance or null if one cannot - * be found. + * be found. */ protected ZarrPixelBuffer createOmeNgffPixelBuffer(Pixels pixels) { StopWatch t0 = new Slf4JStopWatch("createOmeNgffPixelBuffer()"); @@ -326,7 +330,7 @@ protected ZarrPixelBuffer createOmeNgffPixelBuffer(Pixels pixels) { if (uri == null) { // Quick exit if we think we're OME-NGFF but there is no URI if (image.getFormat() != null && "OMEXML".equals(image.getFormat().getValue())) { - throw new LockTimeout("Import in progress.", 15*1000, 0); + throw new LockTimeout("Import in progress.", 15 * 1000, 0); } log.debug("No OME-NGFF root"); return null; @@ -341,8 +345,8 @@ protected ZarrPixelBuffer createOmeNgffPixelBuffer(Pixels pixels) { return v; } catch (Exception e) { log.warn( - "Getting OME-NGFF pixel buffer failed - " + - "attempting to get local data", e); + "Getting OME-NGFF pixel buffer failed - " + + "attempting to get local data", e); } } catch (IOException e1) { log.debug( @@ -358,10 +362,11 @@ protected ZarrPixelBuffer createOmeNgffPixelBuffer(Pixels pixels) { * Returns a pixel buffer for a given set of pixels. Either an NGFF pixel * buffer, a proprietary ROMIO pixel buffer or a specific pixel buffer * implementation. + * * @param pixels Pixels set to retrieve a pixel buffer for. * @param write Whether or not to open the pixel buffer as read-write. - * true opens as read-write, false opens as - * read-only. + * true opens as read-write, false opens as + * read-only. * @return A pixel buffer instance. */ @Override diff --git a/src/main/java/com/upplication/s3fs/OmeroS3FilesystemProvider.java b/src/main/java/com/upplication/s3fs/OmeroS3FilesystemProvider.java index fe85c30a..ce232a34 100644 --- a/src/main/java/com/upplication/s3fs/OmeroS3FilesystemProvider.java +++ b/src/main/java/com/upplication/s3fs/OmeroS3FilesystemProvider.java @@ -15,11 +15,17 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + package com.upplication.s3fs; import static com.upplication.s3fs.AmazonS3Factory.ACCESS_KEY; import static com.upplication.s3fs.AmazonS3Factory.SECRET_KEY; +import com.glencoesoftware.omero.zarr.OmeroAmazonS3ClientFactory; +import com.glencoesoftware.omero.zarr.OmeroS3FileSystem; +import com.glencoesoftware.omero.zarr.OmeroS3ReadOnlySeekableByteChannel; +import com.google.common.base.Preconditions; +import com.upplication.s3fs.attribute.S3BasicFileAttributes; import java.io.IOException; import java.net.URI; import java.nio.channels.SeekableByteChannel; @@ -35,12 +41,8 @@ import java.util.Properties; import java.util.Set; -import com.glencoesoftware.omero.zarr.OmeroAmazonS3ClientFactory; -import com.glencoesoftware.omero.zarr.OmeroS3FileSystem; -import com.glencoesoftware.omero.zarr.OmeroS3ReadOnlySeekableByteChannel; -import com.google.common.base.Preconditions; -import com.upplication.s3fs.attribute.S3BasicFileAttributes; +/** Subclass of S3FileSystemProvider with performance optimizations. */ public class OmeroS3FilesystemProvider extends S3FileSystemProvider { /** @@ -67,7 +69,9 @@ public FileSystem newFileSystem(URI uri, Map env) { private void validateProperties(Properties props) { Preconditions.checkArgument( (props.getProperty(ACCESS_KEY) == null && props.getProperty(SECRET_KEY) == null) - || (props.getProperty(ACCESS_KEY) != null && props.getProperty(SECRET_KEY) != null), "%s and %s should both be provided or should both be omitted", + || (props.getProperty(ACCESS_KEY) != null + && props.getProperty(SECRET_KEY) != null), + "%s and %s should both be provided or should both be omitted", ACCESS_KEY, SECRET_KEY); } @@ -98,7 +102,8 @@ private Properties getProperties(URI uri, Map env) { */ @Override public S3FileSystem createFileSystem(URI uri, Properties props) { - return new OmeroS3FileSystem(this, getFileSystemKey(uri, props), getAmazonS3(uri, props), uri.getHost()); + return new OmeroS3FileSystem( + this, getFileSystemKey(uri, props), getAmazonS3(uri, props), uri.getHost()); } /** @@ -139,13 +144,16 @@ public boolean exists(S3Path path) { * {@link OmeroS3ReadOnlySeekableByteChannel}. */ @Override - public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) throws IOException { + public SeekableByteChannel newByteChannel( + Path path, Set options, FileAttribute... attrs) + throws IOException { S3Path s3Path = toS3Path(path); if (options.isEmpty() || options.contains(StandardOpenOption.READ)) { - if (options.contains(StandardOpenOption.WRITE)) + if (options.contains(StandardOpenOption.WRITE)) { throw new UnsupportedOperationException( "Can't read and write one on channel" ); + } return new OmeroS3ReadOnlySeekableByteChannel(s3Path, options); } else { return new S3SeekableByteChannel(s3Path, options); @@ -157,7 +165,8 @@ public SeekableByteChannel newByteChannel(Path path, Set o * due to its private visibility. */ private S3Path toS3Path(Path path) { - Preconditions.checkArgument(path instanceof S3Path, "path must be an instance of %s", S3Path.class.getName()); + Preconditions.checkArgument(path instanceof S3Path, + "path must be an instance of %s", S3Path.class.getName()); return (S3Path) path; } @@ -168,9 +177,11 @@ private S3Path toS3Path(Path path) { * read-only attributes for every file. */ @Override - public A readAttributes(Path path, Class type, LinkOption... options) throws IOException { + public A readAttributes( + Path path, Class type, LinkOption... options) throws IOException { S3Path s3path = (S3Path) path; - BasicFileAttributes attrs = new S3BasicFileAttributes(s3path.getKey(), null, 0, true, false); + BasicFileAttributes attrs = new S3BasicFileAttributes( + s3path.getKey(), null, 0, true, false); return type.cast(attrs); } } diff --git a/src/test/java/com/glencoesoftware/omero/zarr/TestZarr.java b/src/test/java/com/glencoesoftware/omero/zarr/TestZarr.java index 5b493fad..952ef294 100644 --- a/src/test/java/com/glencoesoftware/omero/zarr/TestZarr.java +++ b/src/test/java/com/glencoesoftware/omero/zarr/TestZarr.java @@ -19,6 +19,17 @@ package com.glencoesoftware.omero.zarr; +import com.bc.zarr.ArrayParams; +import com.bc.zarr.DataType; +import com.bc.zarr.DimensionSeparator; +import com.bc.zarr.ZarrArray; +import com.bc.zarr.ZarrGroup; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -30,24 +41,11 @@ import java.util.Map; import java.util.OptionalInt; import java.util.Random; - -import com.bc.zarr.ArrayParams; -import com.bc.zarr.DataType; -import com.bc.zarr.DimensionSeparator; -import com.bc.zarr.ZarrArray; -import com.bc.zarr.ZarrGroup; - import ucar.ma2.InvalidRangeException; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; - /** - * TestZarr is a utility class for creating and populating a Zarr with different number and order of dimensions. + * TestZarr is a utility class for creating and populating a Zarr with different number and + * order of dimensions. */ public class TestZarr { @@ -71,26 +69,16 @@ public class TestZarr { /** * Create a new TestZarr object with default values. - * @throws IOException */ public TestZarr() throws IOException { } /** * Create a new TestZarr object with custom values. - * @param sizeX - * @param sizeY - * @param sizeZ - * @param sizeT - * @param sizeC - * @param order - * @param path - * @param dataType - * @param overwrite - * @throws IOException */ - public TestZarr(int sizeX, int sizeY, int sizeZ, int sizeT, int sizeC, - String order, String path, DataType dataType, boolean overwrite) throws IOException { + public TestZarr(int sizeX, int sizeY, int sizeZ, int sizeT, int sizeC, + String order, String path, DataType dataType, boolean overwrite) + throws IOException { this.sizeX = sizeX; this.sizeY = sizeY; this.sizeZ = sizeZ; @@ -104,15 +92,13 @@ public TestZarr(int sizeX, int sizeY, int sizeZ, int sizeT, int sizeC, /** * Initialize the Zarr array. - * @return - * @throws IOException */ public TestZarr init() throws IOException { if (order == null || order.isEmpty()) { throw new IllegalArgumentException("Order must specified."); } this.order = this.order.toUpperCase(); - if (!order.contains("X") || !order.contains("Y") ) { + if (!order.contains("X") || !order.contains("Y")) { throw new IllegalArgumentException("Order must contain X and Y"); } if (!order.contains("C")) { @@ -133,34 +119,37 @@ public TestZarr init() throws IOException { if (sizeT == 0) { this.order = order.replace("T", ""); } - int[] shape = new int[order.length()]; - if (order.contains("C")) + int[] shape = new int[order.length()]; + if (order.contains("C")) { shape[order.indexOf("C")] = sizeC; - if (order.contains("T")) + } + if (order.contains("T")) { shape[order.indexOf("T")] = sizeT; - if (order.contains("Z")) + } + if (order.contains("Z")) { shape[order.indexOf("Z")] = sizeZ; + } shape[order.indexOf("Y")] = sizeY; shape[order.indexOf("X")] = sizeX; if (Files.exists(path)) { if (overwrite) { Files.walk(path) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); } else { throw new IOException("Path already exists"); } } - Path series_path = path.resolve("0"); // image 0 (one image) - Path img_path = series_path.resolve("0"); // resolution 0 (one resolution) + Path seriesPath = path.resolve("0"); // image 0 (one image) + Path imgPath = seriesPath.resolve("0"); // resolution 0 (one resolution) // Create parent directories if they don't exist - Files.createDirectories(img_path.getParent()); + Files.createDirectories(imgPath.getParent()); - array = ZarrArray.create(img_path, new ArrayParams() + array = ZarrArray.create(imgPath, new ArrayParams() .shape(shape) .dataType(dataType) .dimensionSeparator(DimensionSeparator.SLASH) @@ -169,34 +158,31 @@ public TestZarr init() throws IOException { } /** - * Fill the Zarr array with pixel data - * @return - * @throws IOException - * @throws InvalidRangeException + * Fill the Zarr array with pixel data. */ public TestZarr createImage() throws IOException, InvalidRangeException { for (int c = 0; c < Math.max(1, sizeC); c++) { for (int t = 0; t < Math.max(1, sizeT); t++) { for (int z = 0; z < Math.max(1, sizeZ); z++) { - byte[] plane = generateGreyscaleImageWithText(c, z, t); int[] sh = new int[order.length()]; int[] off = new int[order.length()]; - if (order.contains("C")) + if (order.contains("C")) { sh[order.indexOf("C")] = 1; - if (order.contains("T")) + off[order.indexOf("C")] = c; + } + if (order.contains("T")) { sh[order.indexOf("T")] = 1; - if (order.contains("Z")) + off[order.indexOf("T")] = t; + } + if (order.contains("Z")) { sh[order.indexOf("Z")] = 1; + off[order.indexOf("Z")] = z; + } sh[order.indexOf("Y")] = sizeY; sh[order.indexOf("X")] = sizeX; - if (order.contains("C")) - off[order.indexOf("C")] = c; - if (order.contains("T")) - off[order.indexOf("T")] = t; - if (order.contains("Z")) - off[order.indexOf("Z")] = z; off[order.indexOf("Y")] = 0; off[order.indexOf("X")] = 0; + byte[] plane = generateGreyscaleImageWithText(c, z, t); array.write(plane, sh, off); } } @@ -206,8 +192,6 @@ public TestZarr createImage() throws IOException, InvalidRangeException { /** * Save the image metadata to the Zarr file. - * @return - * @throws IOException */ public TestZarr createMetadata() throws IOException { List> axes = new ArrayList<>(); @@ -229,7 +213,6 @@ public TestZarr createMetadata() throws IOException { axes.add(axisObj); } - List> datasets = new ArrayList<>(); Map resObj = new HashMap<>(); resObj.put("path", "0"); List> transforms = new ArrayList<>(); @@ -238,6 +221,7 @@ public TestZarr createMetadata() throws IOException { trans.put("scale", new int[] {1, 1, 1, 1, 1}); transforms.add(trans); resObj.put("coordinateTransformations", transforms); + List> datasets = new ArrayList<>(); datasets.add(resObj); List msArray = new ArrayList<>(); @@ -245,14 +229,14 @@ public TestZarr createMetadata() throws IOException { msData.put("axes", axes); msData.put("datasets", datasets); msArray.add(msData); - Path series_path = path.resolve("0"); // image 0 (one image) + Path seriesPath = path.resolve("0"); // image 0 (one image) // Create the series directory if it doesn't exist - Files.createDirectories(series_path); + Files.createDirectories(seriesPath); // Create a new ZarrGroup instead of trying to open an existing one - ZarrGroup z = ZarrGroup.create(series_path); - Map attrs = new HashMap(); + ZarrGroup z = ZarrGroup.create(seriesPath); + Map attrs = new HashMap(); attrs.put("multiscales", msArray); z.writeAttributes(attrs); @@ -262,6 +246,7 @@ public TestZarr createMetadata() throws IOException { /** * Generates a grayscale image with text. * The background is black (0) and the text is white (255). + * * @return byte array containing the grayscale image data */ public byte[] generateGreyscaleImageWithText(int c, int z, int t) { @@ -271,7 +256,8 @@ public byte[] generateGreyscaleImageWithText(int c, int z, int t) { // Set rendering hints for better text quality g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + g2d.setRenderingHint( + RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); // Fill background with black g2d.setColor(Color.BLACK); @@ -290,7 +276,8 @@ public byte[] generateGreyscaleImageWithText(int c, int z, int t) { // Generate random position for text, ensuring it fits within the image Random random = new Random(); int x = textX.isPresent() ? textX.getAsInt() : random.nextInt(sizeX - textWidth); - int y = textY.isPresent() ? textY.getAsInt() : random.nextInt(sizeY - textHeight) + g2d.getFontMetrics().getAscent(); + int y = textY.isPresent() ? textY.getAsInt() + : random.nextInt(sizeY - textHeight) + g2d.getFontMetrics().getAscent(); // Draw the text g2d.drawString(planeText, x, y); @@ -305,6 +292,7 @@ public int getSizeX() { return sizeX; } + /** Set the X dimension size. */ public TestZarr setSizeX(int sizeX) { this.sizeX = sizeX; return this; @@ -314,6 +302,7 @@ public int getSizeY() { return sizeY; } + /** Set the Y dimension size. */ public TestZarr setSizeY(int sizeY) { this.sizeY = sizeY; return this; @@ -323,6 +312,7 @@ public int getSizeZ() { return sizeZ; } + /** Set the Z dimension size. */ public TestZarr setSizeZ(int sizeZ) { this.sizeZ = sizeZ; return this; @@ -332,6 +322,7 @@ public int getSizeT() { return sizeT; } + /** Set the T dimension size. */ public TestZarr setSizeT(int sizeT) { this.sizeT = sizeT; return this; @@ -341,6 +332,7 @@ public int getSizeC() { return sizeC; } + /** Set the C dimension size. */ public TestZarr setSizeC(int sizeC) { this.sizeC = sizeC; return this; @@ -354,8 +346,6 @@ public String getOrder() { * Set the order of the dimensions. * Note: Reverse of ome.model.enums.DimensionOrder, * e.g. DimensionOrder.XYZCT -> use "TCZYX" - * @param order - * @return */ public TestZarr setOrder(String order) { this.order = order; @@ -366,6 +356,7 @@ public Path getPath() { return path; } + /** Set the dataset path. */ public TestZarr setPath(Path path) { this.path = path; return this; @@ -375,6 +366,7 @@ public DataType getDataType() { return dataType; } + /** Set the data type. */ public TestZarr setDataType(DataType dataType) { this.dataType = dataType; return this; @@ -384,6 +376,7 @@ public ZarrArray getArray() { return array; } + /** Set whether the dataset can be ovewritten.*/ public TestZarr setOverwrite(boolean b) { this.overwrite = b; return this; @@ -397,16 +390,19 @@ public String getText() { return text; } + /** Set the text. */ public TestZarr setText(String text) { this.text = text; return this; } + /** Set the X location of the text. */ public TestZarr setTextX(int textX) { this.textX = OptionalInt.of(textX); return this; } + /** Set the Y location of the text. */ public TestZarr setTextY(int textY) { this.textY = OptionalInt.of(textY); return this; diff --git a/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java b/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java index 23150c72..b11ddb51 100644 --- a/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java +++ b/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java @@ -18,6 +18,12 @@ package com.glencoesoftware.omero.zarr; +import com.bc.zarr.ZarrArray; +import com.bc.zarr.ZarrGroup; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.glencoesoftware.bioformats2raw.Converter; +import com.glencoesoftware.omero.zarr.ZarrPixelBuffer.Axis; import java.awt.Dimension; import java.io.File; import java.io.IOException; @@ -33,19 +39,6 @@ import java.util.List; import java.util.Map; import java.util.stream.IntStream; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import com.glencoesoftware.omero.zarr.ZarrPixelBuffer.Axis; - -import com.bc.zarr.ZarrArray; -import com.bc.zarr.ZarrGroup; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.benmanes.caffeine.cache.Caffeine; -import com.glencoesoftware.bioformats2raw.Converter; - import loci.formats.FormatTools; import loci.formats.in.FakeReader; import ome.io.nio.DimensionsOutOfBoundsException; @@ -53,16 +46,22 @@ import ome.model.enums.DimensionOrder; import ome.model.enums.PixelsType; import ome.util.PixelData; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; import picocli.CommandLine; import ucar.ma2.Array; import ucar.ma2.DataType; import ucar.ma2.InvalidRangeException; +/** Unit tests for ZarrPixelBuffer. */ public class ZarrPixelBufferTest { @Rule public TemporaryFolder tmpDir = new TemporaryFolder(); + /** Constructor. */ public ZarrPixelBuffer createPixelBuffer( Pixels pixels, Path path, Integer maxPlaneWidth, Integer maxPlaneHeight) throws IOException { @@ -82,7 +81,7 @@ public ZarrPixelBuffer createPixelBuffer( * * @param additionalArgs CLI arguments as needed beyond "input output" */ - void assertBioFormats2Raw(Path input, Path output, String...additionalArgs) + void assertBioFormats2Raw(Path input, Path output, String... additionalArgs) throws IOException { List args = new ArrayList( Arrays.asList(new String[] { "--compression", "null" })); @@ -105,11 +104,11 @@ void assertBioFormats2Raw(Path input, Path output, String...additionalArgs) } } - static Path fake(String...args) { - Assert.assertTrue(args.length %2 == 0); + static Path fake(String... args) { + Assert.assertTrue(args.length % 2 == 0); Map options = new HashMap(); for (int i = 0; i < args.length; i += 2) { - options.put(args[i], args[i+1]); + options.put(args[i], args[i + 1]); } return fake(options); } @@ -120,24 +119,22 @@ static Path fake(Map options) { /** * Create a Bio-Formats fake INI file to use for testing. + * * @param options map of the options to assign as part of the fake filename - * from the allowed keys + * from the allowed keys * @param series map of the integer series index and options map (same format - * as options to add to the fake INI content - * @see https://docs.openmicroscopy.org/bio-formats/6.4.0/developers/ - * generating-test-images.html#key-value-pairs + * as options to add to the fake INI content + * @see fake file specification * @return path to the fake INI file that has been created */ static Path fake(Map options, - Map> series) - { + Map> series) { return fake(options, series, null); } static Path fake(Map options, Map> series, - Map originalMetadata) - { + Map originalMetadata) { StringBuilder sb = new StringBuilder(); sb.append("image"); if (options != null) { @@ -173,10 +170,10 @@ static Path fake(Map options, String iniPath = iniAsFile.getAbsolutePath(); String fakePath = iniPath.substring(0, iniPath.length() - 4); Path fake = Paths.get(fakePath); - File fakeAsFile = fake.toFile(); Files.write(fake, new byte[]{}); Files.write(ini, lines); iniAsFile.deleteOnExit(); + File fakeAsFile = fake.toFile(); fakeAsFile.deleteOnExit(); return ini; } catch (IOException e) { @@ -184,6 +181,7 @@ static Path fake(Map options, } } + /** Write Zarr multiscales attributes. */ public Path writeTestZarr( int sizeT, int sizeC, @@ -193,7 +191,7 @@ public Path writeTestZarr( String pixelType, int resolutions) throws IOException { - Path input = fake( + Path input = fake( "sizeT", Integer.toString(sizeT), "sizeC", Integer.toString(sizeC), "sizeZ", Integer.toString(sizeZ), @@ -204,7 +202,6 @@ public Path writeTestZarr( Path output = tmpDir.getRoot().toPath().resolve("output.zarr"); assertBioFormats2Raw(input, output); - List msArray = new ArrayList<>(); Map msData = new HashMap<>(); Map msMetadata = new HashMap<>(); msMetadata.put("method", "loci.common.image.SimpleImageScaler"); @@ -212,14 +209,15 @@ public Path writeTestZarr( msData.put("metadata", msMetadata); msData.put("datasets", getDatasets(resolutions)); msData.put("version", "0.1"); + List msArray = new ArrayList<>(); msArray.add(msData); ZarrGroup z = ZarrGroup.open(output.resolve("0")); - Map attrs = new HashMap(); + Map attrs = new HashMap(); attrs.put("multiscales", msArray); z.writeAttributes(attrs); return output; - } + } List> getDatasets(int resolutions) { List> datasets = new ArrayList<>(); @@ -261,7 +259,7 @@ public void testGetChunks() throws IOException { new int[] {1, 1, 1, 256, 1024}, new int[] {1, 1, 1, 128, 512} }; - for(int i = 0; i < chunks.length; i++) { + for (int i = 0; i < chunks.length; i++) { Assert.assertTrue(Arrays.equals( chunks[i], expectedChunks[i])); } @@ -283,8 +281,8 @@ public void testGetDatasets() throws IOException { resolutions); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { - List> datasets = zpbuf.getDatasets(); - List> expectedDatasets = getDatasets(3); + List> datasets = zpbuf.getDatasets(); + List> expectedDatasets = getDatasets(3); for (int i = 0; i < datasets.size(); i++) { Assert.assertEquals(datasets.get(i), expectedDatasets.get(i)); } @@ -346,11 +344,11 @@ public void testGetTile() throws IOException, InvalidRangeException { Path output = writeTestZarr( sizeT, sizeC, sizeZ, sizeY, sizeX, "int32", resolutions); ZarrArray test = ZarrArray.open(output.resolve("0").resolve("0")); - int[] data = new int[2*3*4*5*6]; - for (int i = 0; i < 2*3*4*5*6; i++) { + int[] data = new int[2 * 3 * 4 * 5 * 6]; + for (int i = 0; i < 2 * 3 * 4 * 5 * 6; i++) { data[i] = i; } - test.write(data, new int[] {2,3,4,5,6}, new int[] {0,0,0,0,0}); + test.write(data, new int[] {2, 3, 4, 5, 6}, new int[] {0, 0, 0, 0, 0}); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { PixelData pixelData = zpbuf.getTile(0, 0, 0, 0, 0, 2, 2); @@ -365,7 +363,7 @@ public void testGetTile() throws IOException, InvalidRangeException { bb = pixelData.getData(); bb.order(ByteOrder.BIG_ENDIAN); ib = bb.asIntBuffer(); - Assert.assertEquals(ib.get(0), 517);//360(6*5*4*3) + 120(6*5*4) + 30(6*5) + 6 + 1 + Assert.assertEquals(ib.get(0), 517); // 360(6*5*4*3) + 120(6*5*4) + 30(6*5) + 6 + 1 Assert.assertEquals(ib.get(1), 518); Assert.assertEquals(ib.get(2), 523); Assert.assertEquals(ib.get(3), 524); @@ -390,13 +388,13 @@ private byte[] getStack( byte[] timepoint, int c, int sizeC, int sizeZ, int sizeX, int sizeY, String order) { // XXX: Is not data type agnostic, expects signed 32-bit integer pixels - int bytesPerPixel = 4; int[] shape = new int[4]; String shapeorder = order.replace("T", ""); shape[shapeorder.indexOf('C')] = sizeC; shape[shapeorder.indexOf('Z')] = sizeZ; shape[shapeorder.indexOf('Y')] = sizeY; shape[shapeorder.indexOf('X')] = sizeX; + int bytesPerPixel = 4; int size = IntStream.of(new int[] {sizeZ, sizeY, sizeX, bytesPerPixel}) .reduce(1, Math::multiplyExact); Array array = asArray(timepoint, shape).slice(shapeorder.indexOf('C'), c); @@ -414,12 +412,12 @@ private byte[] getPlane( private byte[] getPlane( byte[] stack, int z, int sizeZ, int sizeX, int sizeY, String order) { // XXX: Is not data type agnostic, expects signed 32-bit integer pixels - int bytesPerPixel = 4; String shapeorder = order.replace("T", "").replace("C", ""); int[] shape = new int[3]; shape[shapeorder.indexOf('Z')] = sizeZ; shape[shapeorder.indexOf('Y')] = sizeY; shape[shapeorder.indexOf('X')] = sizeX; + int bytesPerPixel = 4; int size = IntStream.of(new int[] {sizeY, sizeX, bytesPerPixel}) .reduce(1, Math::multiplyExact); Array array = asArray(stack, shape).slice(shapeorder.indexOf('Z'), z); @@ -518,11 +516,11 @@ public void testGetTileLargerThanImage() sizeT, sizeC, sizeZ, sizeY, sizeX, "int32", resolutions); ZarrArray test = ZarrArray.open(output.resolve("0").resolve("0")); - int[] data = new int[2*3*4*5*6]; - for (int i = 0; i < 2*3*4*5*6; i++) { + int[] data = new int[2 * 3 * 4 * 5 * 6]; + for (int i = 0; i < 2 * 3 * 4 * 5 * 6; i++) { data[i] = i; } - test.write(data, new int[] {2,3,4,5,6}, new int[] {0,0,0,0,0}); + test.write(data, new int[] {2, 3, 4, 5, 6}, new int[] {0, 0, 0, 0, 0}); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { zpbuf.setResolutionLevel(0); @@ -555,13 +553,13 @@ public void testTileIntegerOverflow() // Hack the .zarray so we can appear as though we have more data than // we actually have written above. ObjectMapper mapper = new ObjectMapper(); - HashMap zArray = mapper.readValue( + HashMap arrayAttrs = mapper.readValue( Files.readAllBytes(output.resolve("0/0/.zarray")), HashMap.class); - List shape = (List) zArray.get("shape"); + List shape = (List) arrayAttrs.get("shape"); shape.set(3, 50000); shape.set(4, 50000); - mapper.writeValue(output.resolve("0/0/.zarray").toFile(), zArray); + mapper.writeValue(output.resolve("0/0/.zarray").toFile(), arrayAttrs); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 32, 32)) { zpbuf.getTile(0, 0, 0, 0, 0, 50000, 50000); @@ -801,20 +799,20 @@ public void testDownsampledZ() throws IOException { sizeT, sizeC, sizeZ, sizeY, sizeX, "uint8", resolutions); // Hack the .zarray to hide Z sections in lower resolutions - for (int r=1; r zArray = mapper.readValue( + HashMap arrayAttrs = mapper.readValue( Files.readAllBytes(output.resolve("0/" + r + "/.zarray")), HashMap.class); - List shape = (List) zArray.get("shape"); + List shape = (List) arrayAttrs.get("shape"); shape.set(2, sizeZ / (int) Math.pow(2, r)); - mapper.writeValue(output.resolve("0/" + r + "/.zarray").toFile(), zArray); + mapper.writeValue(output.resolve("0/" + r + "/.zarray").toFile(), arrayAttrs); } try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), sizeX, sizeY)) { // get the last Z section, for each resolution level - for (int r=0; r axes = zpbuf.getAxesOrder(); - Assert.assertEquals(0, axes.get(Axis.T).intValue()); - Assert.assertEquals(1, axes.get(Axis.C).intValue()); - Assert.assertEquals(2, axes.get(Axis.Z).intValue()); - Assert.assertEquals(3, axes.get(Axis.Y).intValue()); - Assert.assertEquals(4, axes.get(Axis.X).intValue()); - Assert.assertEquals(sizeT, zpbuf.getSizeT()); - Assert.assertEquals(sizeC, zpbuf.getSizeC()); - Assert.assertEquals(sizeZ, zpbuf.getSizeZ()); - Assert.assertEquals(sizeY, zpbuf.getSizeY()); - Assert.assertEquals(sizeX, zpbuf.getSizeX()); + Map axes = zpbuf.getAxesOrder(); + Assert.assertEquals(0, axes.get(Axis.T).intValue()); + Assert.assertEquals(1, axes.get(Axis.C).intValue()); + Assert.assertEquals(2, axes.get(Axis.Z).intValue()); + Assert.assertEquals(3, axes.get(Axis.Y).intValue()); + Assert.assertEquals(4, axes.get(Axis.X).intValue()); + Assert.assertEquals(sizeT, zpbuf.getSizeT()); + Assert.assertEquals(sizeC, zpbuf.getSizeC()); + Assert.assertEquals(sizeZ, zpbuf.getSizeZ()); + Assert.assertEquals(sizeY, zpbuf.getSizeY()); + Assert.assertEquals(sizeX, zpbuf.getSizeX()); } } @Test - public void test_XYCTZ() throws IOException, InvalidRangeException { + public void testXYCTZ() throws IOException, InvalidRangeException { testDimensions(512, 1024, 2, 3, 4); } @Test - public void test_XYCT() throws IOException, InvalidRangeException { + public void testXYCT() throws IOException, InvalidRangeException { testDimensions(512, 1024, 0, 3, 4); } @Test - public void test_XYCZ() throws IOException, InvalidRangeException { + public void testXYCZ() throws IOException, InvalidRangeException { testDimensions(512, 1024, 2, 3, 0); } @Test - public void test_XYTZ() throws IOException, InvalidRangeException { + public void testXYTZ() throws IOException, InvalidRangeException { testDimensions(512, 1024, 2, 0, 4); } @Test - public void test_XYZ() throws IOException, InvalidRangeException { + public void testXYZ() throws IOException, InvalidRangeException { testDimensions(512, 1024, 2, 0, 0); } @Test - public void test_XYT() throws IOException, InvalidRangeException { + public void testXYT() throws IOException, InvalidRangeException { testDimensions(512, 1024, 0, 0, 4); } @Test - public void test_XYC() throws IOException, InvalidRangeException { + public void testXYC() throws IOException, InvalidRangeException { testDimensions(512, 1024, 0, 3, 0); } @Test - public void test_XY() throws IOException, InvalidRangeException { + public void testXY() throws IOException, InvalidRangeException { testDimensions(512, 1024, 0, 0, 0); } @Test - public void test_Order_XYCTZ() throws IOException, InvalidRangeException { + public void testOrderXYCTZ() throws IOException, InvalidRangeException { testOrder(DimensionOrder.VALUE_XYCTZ); } @Test - public void test_Order_XYCZT() throws IOException, InvalidRangeException { + public void testOrderXYCZT() throws IOException, InvalidRangeException { testOrder(DimensionOrder.VALUE_XYCZT); } @Test - public void test_Order_XYTCZ() throws IOException, InvalidRangeException { + public void testOrderXYTCZ() throws IOException, InvalidRangeException { testOrder(DimensionOrder.VALUE_XYTCZ); } @Test - public void test_Order_XYTZC() throws IOException, InvalidRangeException { + public void testOrderXYTZC() throws IOException, InvalidRangeException { testOrder(DimensionOrder.VALUE_XYTZC); } @Test - public void test_Order_XYZCT() throws IOException, InvalidRangeException { + public void testOrderXYZCT() throws IOException, InvalidRangeException { testOrder(DimensionOrder.VALUE_XYZCT); } @Test - public void test_Order_XYZTC() throws IOException, InvalidRangeException { + public void testOrderXYZTC() throws IOException, InvalidRangeException { testOrder(DimensionOrder.VALUE_XYZTC); } @@ -1002,27 +1000,27 @@ private void testOrder(String order) throws IOException, InvalidRangeException { .createMetadata(); Pixels pixels = new Pixels( - null, null, testZarr.getSizeX(), testZarr.getSizeY(), testZarr.getSizeZ(), testZarr.getSizeC(), testZarr.getSizeT(), "", new DimensionOrder(order)); - - try (ZarrPixelBuffer zpbuf = - createPixelBuffer(pixels, testZarrPath.resolve("0"), testZarr.getSizeX(), testZarr.getSizeY())) { - Map axes = zpbuf.getAxesOrder(); - Assert.assertEquals(4 - order.indexOf("Z"), axes.get(Axis.Z).intValue()); - Assert.assertEquals(4 - order.indexOf("T"), axes.get(Axis.T).intValue()); - Assert.assertEquals(4 - order.indexOf("C"), axes.get(Axis.C).intValue()); - Assert.assertEquals(4 - order.indexOf("Y"), axes.get(Axis.Y).intValue()); - Assert.assertEquals(4 - order.indexOf("X"), axes.get(Axis.X).intValue()); - Assert.assertEquals(testZarr.getSizeT(), zpbuf.getSizeT()); - Assert.assertEquals(testZarr.getSizeC(), zpbuf.getSizeC()); - Assert.assertEquals(testZarr.getSizeZ(), zpbuf.getSizeZ()); - Assert.assertEquals(testZarr.getSizeY(), zpbuf.getSizeY()); - Assert.assertEquals(testZarr.getSizeX(), zpbuf.getSizeX()); + null, null, testZarr.getSizeX(), testZarr.getSizeY(), testZarr.getSizeZ(), + testZarr.getSizeC(), testZarr.getSizeT(), "", new DimensionOrder(order)); + + try (ZarrPixelBuffer zpbuf = createPixelBuffer( + pixels, testZarrPath.resolve("0"), testZarr.getSizeX(), testZarr.getSizeY())) { + Map axes = zpbuf.getAxesOrder(); + Assert.assertEquals(4 - order.indexOf("Z"), axes.get(Axis.Z).intValue()); + Assert.assertEquals(4 - order.indexOf("T"), axes.get(Axis.T).intValue()); + Assert.assertEquals(4 - order.indexOf("C"), axes.get(Axis.C).intValue()); + Assert.assertEquals(4 - order.indexOf("Y"), axes.get(Axis.Y).intValue()); + Assert.assertEquals(4 - order.indexOf("X"), axes.get(Axis.X).intValue()); + Assert.assertEquals(testZarr.getSizeT(), zpbuf.getSizeT()); + Assert.assertEquals(testZarr.getSizeC(), zpbuf.getSizeC()); + Assert.assertEquals(testZarr.getSizeZ(), zpbuf.getSizeZ()); + Assert.assertEquals(testZarr.getSizeY(), zpbuf.getSizeY()); + Assert.assertEquals(testZarr.getSizeX(), zpbuf.getSizeX()); } } - private void testDimensions(int sizeX, int sizeY, int sizeZ, int sizeC, int sizeT) throws IOException, InvalidRangeException { - int textX = 10; - int textY = 10; + private void testDimensions(int sizeX, int sizeY, int sizeZ, int sizeC, int sizeT) + throws IOException, InvalidRangeException { String order = DimensionOrder.VALUE_XYZCT; if (sizeT == 0) { @@ -1035,6 +1033,8 @@ private void testDimensions(int sizeX, int sizeY, int sizeZ, int sizeC, int size order.replace("C", ""); } + int textX = 10; + int textY = 10; Path testZarrPath = tmpDir.getRoot().toPath().resolve("test.zarr"); TestZarr testZarr = new TestZarr() .setPath(testZarrPath) @@ -1061,7 +1061,8 @@ null, new PixelsType(PixelsType.VALUE_INT32), int expectedTests = pixC * pixT * pixZ; int testCount = 0; - try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, testZarrPath.resolve("0"), sizeX, sizeY)) { + try (ZarrPixelBuffer zpbuf = createPixelBuffer( + pixels, testZarrPath.resolve("0"), sizeX, sizeY)) { for (int t = 0; t < Math.max(sizeT, 1); t++) { for (int z = 0; z < Math.max(sizeZ, 1); z++) { for (int c = 0; c < Math.max(sizeC, 1); c++) { diff --git a/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelsServiceTest.java b/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelsServiceTest.java index d14f104e..6d96c506 100644 --- a/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelsServiceTest.java +++ b/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelsServiceTest.java @@ -18,17 +18,15 @@ package com.glencoesoftware.omero.zarr; -import java.io.IOException; +import static omero.rtypes.rdouble; +import static omero.rtypes.rlong; +import static omero.rtypes.rstring; + +import com.glencoesoftware.omero.zarr.ZarrPixelsService; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.util.UUID; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.glencoesoftware.omero.zarr.ZarrPixelsService; - import omero.ApiUsageException; import omero.model.ExternalInfo; import omero.model.ExternalInfoI; @@ -38,36 +36,38 @@ import omero.model.Mask; import omero.model.MaskI; import omero.util.IceMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; -import static omero.rtypes.rdouble; -import static omero.rtypes.rlong; -import static omero.rtypes.rstring; - +/** Unit test for ZarrPixelsService. */ public class ZarrPixelsServiceTest { - private ZarrPixelsService pixelsService; - private String uuid = UUID.randomUUID().toString(); - private String imageUri = "/data/ngff/image.zarr"; - private String labelUri = imageUri + "/0/labels/" + uuid; - private Image image; - private Mask mask; - private ome.model.IObject object; - private String ENTITY_TYPE = "com.glencoesoftware.ngff:multiscales"; - private long ENTITY_ID = 3; - - @Before - public void setUp() throws IOException { - File pixelsDir = Files.createTempDirectory("pixels").toFile(); - pixelsDir.deleteOnExit(); - File memoDir = Files.createTempDirectory("memoizer").toFile(); - memoDir.deleteOnExit(); - pixelsService = new ZarrPixelsService( - pixelsDir.getAbsolutePath(), false, memoDir, 0L, null, null, null, null, 0, 0, 0); - mask = new MaskI(); - image = new ImageI(); - } - - private void addExternalInfo(IObject object, Long entityId, String entityType, String lsid, String uuid) { + private ZarrPixelsService pixelsService; + private String uuid = UUID.randomUUID().toString(); + private String imageUri = "/data/ngff/image.zarr"; + private String labelUri = imageUri + "/0/labels/" + uuid; + private Image image; + private Mask mask; + private ome.model.IObject object; + private static final String ENTITY_TYPE = "com.glencoesoftware.ngff:multiscales"; + private static final long ENTITY_ID = 3; + + /** Initializes a ZarrPixelsService with temporary directories. */ + @Before + public void setUp() throws IOException { + File pixelsDir = Files.createTempDirectory("pixels").toFile(); + pixelsDir.deleteOnExit(); + File memoDir = Files.createTempDirectory("memoizer").toFile(); + memoDir.deleteOnExit(); + pixelsService = new ZarrPixelsService( + pixelsDir.getAbsolutePath(), false, memoDir, 0L, null, null, null, null, 0, 0, 0); + mask = new MaskI(); + image = new ImageI(); + } + + private void addExternalInfo( + IObject object, Long entityId, String entityType, String lsid, String uuid) { ExternalInfo externalInfo = new ExternalInfoI(); externalInfo.setEntityId(rlong(entityId)); externalInfo.setEntityType(rstring(entityType)); @@ -78,85 +78,85 @@ private void addExternalInfo(IObject object, Long entityId, String entityType, S externalInfo.setUuid(rstring(uuid)); } object.getDetails().setExternalInfo(externalInfo); - } - - @Test - public void testDefault() throws ApiUsageException, IOException { - addExternalInfo(mask, ENTITY_ID, ENTITY_TYPE, labelUri, uuid); - object = (ome.model.roi.Mask) new IceMapper().reverse(mask); - Assert.assertEquals(pixelsService.getUri(object), labelUri); - Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), labelUri); - - addExternalInfo(image, ENTITY_ID, ENTITY_TYPE, imageUri, uuid); - object = (ome.model.core.Image) new IceMapper().reverse(image); - Assert.assertEquals(pixelsService.getUri(object), imageUri); - Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), imageUri); - } - - @Test - public void testGetUriNoExternalInfo() throws ApiUsageException, IOException { - object = (ome.model.roi.Mask) new IceMapper().reverse(mask); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - - object = (ome.model.core.Image) new IceMapper().reverse(image); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - } - - @Test - public void testGetUriNoUuid() throws ApiUsageException, IOException { - addExternalInfo(mask, ENTITY_ID, ENTITY_TYPE, labelUri, null); - object = (ome.model.roi.Mask) new IceMapper().reverse(mask); - Assert.assertEquals(pixelsService.getUri(object), labelUri); - Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), labelUri); - - addExternalInfo(image, ENTITY_ID, ENTITY_TYPE, imageUri, null); - object = (ome.model.core.Image) new IceMapper().reverse(image); - Assert.assertEquals(pixelsService.getUri(object), imageUri); - Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), imageUri); - } - - @Test - public void testGetUriNoLsid() throws ApiUsageException, IOException { - addExternalInfo(mask, ENTITY_ID, ENTITY_TYPE, null, uuid); - object = (ome.model.roi.Mask) new IceMapper().reverse(mask); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - - addExternalInfo(image, ENTITY_ID, ENTITY_TYPE, null, uuid); - object = (ome.model.core.Image) new IceMapper().reverse(image); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - } - - @Test - public void testGetUriWrongEntityType() throws ApiUsageException, IOException { - addExternalInfo(mask, ENTITY_ID, "multiscales", labelUri, uuid); - object = (ome.model.roi.Mask) new IceMapper().reverse(mask); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - Assert.assertEquals(pixelsService.getUri(object, "multiscales", ENTITY_ID), labelUri); - - addExternalInfo(image, ENTITY_ID, "multiscales", imageUri, uuid); - object = (ome.model.core.Image) new IceMapper().reverse(image); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - Assert.assertEquals(pixelsService.getUri(object, "multiscales", ENTITY_ID), imageUri); - } - - @Test - public void testGetUriWrongEntityId() throws ApiUsageException, IOException { - addExternalInfo(mask, 1L, ENTITY_TYPE, labelUri, uuid); - object = (ome.model.roi.Mask) new IceMapper().reverse(mask); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, 1L), labelUri); - - addExternalInfo(image, 1L, ENTITY_TYPE, imageUri, uuid); - object = (ome.model.core.Image) new IceMapper().reverse(image); - Assert.assertNull(pixelsService.getUri(object)); - Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); - Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, 1L), imageUri); - } + } + + @Test + public void testDefault() throws ApiUsageException, IOException { + addExternalInfo(mask, ENTITY_ID, ENTITY_TYPE, labelUri, uuid); + object = (ome.model.roi.Mask) new IceMapper().reverse(mask); + Assert.assertEquals(pixelsService.getUri(object), labelUri); + Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), labelUri); + + addExternalInfo(image, ENTITY_ID, ENTITY_TYPE, imageUri, uuid); + object = (ome.model.core.Image) new IceMapper().reverse(image); + Assert.assertEquals(pixelsService.getUri(object), imageUri); + Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), imageUri); + } + + @Test + public void testGetUriNoExternalInfo() throws ApiUsageException, IOException { + object = (ome.model.roi.Mask) new IceMapper().reverse(mask); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + + object = (ome.model.core.Image) new IceMapper().reverse(image); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + } + + @Test + public void testGetUriNoUuid() throws ApiUsageException, IOException { + addExternalInfo(mask, ENTITY_ID, ENTITY_TYPE, labelUri, null); + object = (ome.model.roi.Mask) new IceMapper().reverse(mask); + Assert.assertEquals(pixelsService.getUri(object), labelUri); + Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), labelUri); + + addExternalInfo(image, ENTITY_ID, ENTITY_TYPE, imageUri, null); + object = (ome.model.core.Image) new IceMapper().reverse(image); + Assert.assertEquals(pixelsService.getUri(object), imageUri); + Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID), imageUri); + } + + @Test + public void testGetUriNoLsid() throws ApiUsageException, IOException { + addExternalInfo(mask, ENTITY_ID, ENTITY_TYPE, null, uuid); + object = (ome.model.roi.Mask) new IceMapper().reverse(mask); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + + addExternalInfo(image, ENTITY_ID, ENTITY_TYPE, null, uuid); + object = (ome.model.core.Image) new IceMapper().reverse(image); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + } + + @Test + public void testGetUriWrongEntityType() throws ApiUsageException, IOException { + addExternalInfo(mask, ENTITY_ID, "multiscales", labelUri, uuid); + object = (ome.model.roi.Mask) new IceMapper().reverse(mask); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + Assert.assertEquals(pixelsService.getUri(object, "multiscales", ENTITY_ID), labelUri); + + addExternalInfo(image, ENTITY_ID, "multiscales", imageUri, uuid); + object = (ome.model.core.Image) new IceMapper().reverse(image); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + Assert.assertEquals(pixelsService.getUri(object, "multiscales", ENTITY_ID), imageUri); + } + + @Test + public void testGetUriWrongEntityId() throws ApiUsageException, IOException { + addExternalInfo(mask, 1L, ENTITY_TYPE, labelUri, uuid); + object = (ome.model.roi.Mask) new IceMapper().reverse(mask); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, 1L), labelUri); + + addExternalInfo(image, 1L, ENTITY_TYPE, imageUri, uuid); + object = (ome.model.core.Image) new IceMapper().reverse(image); + Assert.assertNull(pixelsService.getUri(object)); + Assert.assertNull(pixelsService.getUri(object, ENTITY_TYPE, ENTITY_ID)); + Assert.assertEquals(pixelsService.getUri(object, ENTITY_TYPE, 1L), imageUri); + } }