1010import java .io .IOException ;
1111import java .nio .ByteBuffer ;
1212import java .util .Arrays ;
13+ import java .util .HashMap ;
1314import java .util .Map ;
1415import java .util .function .Function ;
1516import java .util .stream .Collectors ;
1617import javax .annotation .Nonnull ;
18+ import javax .annotation .Nullable ;
1719import ucar .ma2 .InvalidRangeException ;
1820
1921public class Array extends Node {
@@ -28,6 +30,13 @@ protected Array(StoreHandle storeHandle, ArrayMetadata arrayMetadata)
2830 this .codecPipeline = new CodecPipeline (arrayMetadata .codecs );
2931 }
3032
33+ /**
34+ * Opens an existing Zarr array at a specified storage location.
35+ *
36+ * @param storeHandle
37+ * @throws IOException
38+ * @throws ZarrException
39+ */
3140 public static Array open (StoreHandle storeHandle ) throws IOException , ZarrException {
3241 return new Array (
3342 storeHandle ,
@@ -39,11 +48,32 @@ public static Array open(StoreHandle storeHandle) throws IOException, ZarrExcept
3948 );
4049 }
4150
51+ /**
52+ * Creates a new Zarr array with the provided metadata at a specified storage location. This
53+ * method will raise an exception if a Zarr array already exists at the specified storage
54+ * location.
55+ *
56+ * @param storeHandle
57+ * @param arrayMetadata
58+ * @throws IOException
59+ * @throws ZarrException
60+ */
4261 public static Array create (StoreHandle storeHandle , ArrayMetadata arrayMetadata )
4362 throws IOException , ZarrException {
4463 return Array .create (storeHandle , arrayMetadata , false );
4564 }
4665
66+ /**
67+ * Creates a new Zarr array with the provided metadata at a specified storage location. If
68+ * `existsOk` is false, this method will raise an exception if a Zarr array already exists at the
69+ * specified storage location.
70+ *
71+ * @param storeHandle
72+ * @param arrayMetadata
73+ * @param existsOk
74+ * @throws IOException
75+ * @throws ZarrException
76+ */
4777 public static Array create (StoreHandle storeHandle , ArrayMetadata arrayMetadata , boolean existsOk )
4878 throws IOException , ZarrException {
4979 StoreHandle metadataHandle = storeHandle .resolve (ZARR_JSON );
@@ -58,18 +88,53 @@ public static Array create(StoreHandle storeHandle, ArrayMetadata arrayMetadata,
5888 return new Array (storeHandle , arrayMetadata );
5989 }
6090
91+ /**
92+ * Creates a new Zarr array at a specified storage location. This method provides a callback that
93+ * gets an ArrayMetadataBuilder and needs to return such an ArrayMetadataBuilder. The callback can
94+ * be used to construct the metadata of the Zarr array. If `existsOk` is false, this method will
95+ * raise an exception if a Zarr array already exists at the specified storage location.
96+ *
97+ * @param storeHandle
98+ * @param arrayMetadataBuilderMapper
99+ * @param existsOk
100+ * @throws IOException
101+ * @throws ZarrException
102+ */
103+ public static Array create (StoreHandle storeHandle ,
104+ Function <ArrayMetadataBuilder , ArrayMetadataBuilder > arrayMetadataBuilderMapper ,
105+ boolean existsOk ) throws IOException , ZarrException {
106+ return Array .create (storeHandle ,
107+ arrayMetadataBuilderMapper .apply (new ArrayMetadataBuilder ()).build (), existsOk );
108+ }
109+
110+ @ Nonnull
61111 public static ArrayMetadataBuilder metadataBuilder () {
62112 return new ArrayMetadataBuilder ();
63113 }
64114
115+ @ Nonnull
65116 public static ArrayMetadataBuilder metadataBuilder (ArrayMetadata existingMetadata ) {
66117 return ArrayMetadataBuilder .fromArrayMetadata (existingMetadata );
67118 }
68119
120+ /**
121+ * Reads the entire Zarr array into an ucar.ma2.Array.
122+ *
123+ * @throws ZarrException
124+ */
125+ @ Nonnull
69126 public ucar .ma2 .Array read () throws ZarrException {
70127 return read (new long [metadata .ndim ()], Utils .toIntArray (metadata .shape ));
71128 }
72129
130+ /**
131+ * Reads a part of the Zarr array based on a requested offset and shape into an ucar.ma2.Array.
132+ *
133+ * @param offset
134+ * @param shape
135+ * @throws ZarrException
136+ */
137+ @ Nonnull
73138 public ucar .ma2 .Array read (final long [] offset , final int [] shape ) throws ZarrException {
74139 if (offset .length != metadata .ndim ()) {
75140 throw new IllegalArgumentException ("'offset' needs to have rank '" + metadata .ndim () + "'." );
@@ -105,15 +170,13 @@ public ucar.ma2.Array read(final long[] offset, final int[] shape) throws ZarrEx
105170 final StoreHandle chunkHandle = storeHandle .resolve (chunkKeys );
106171
107172 if (codecPipeline .supportsPartialDecode ()) {
108- System .out .println ("decodePartial" );
109173 final ucar .ma2 .Array chunkArray = codecPipeline .decodePartial (chunkHandle ,
110174 Utils .toLongArray (chunkProjection .chunkOffset ), chunkProjection .shape ,
111175 metadata .coreArrayMetadata );
112176 MultiArrayUtils .copyRegion (chunkArray , new int [metadata .ndim ()], outputArray ,
113177 chunkProjection .outOffset , chunkProjection .shape
114178 );
115179 } else {
116- System .out .println ("decode" );
117180 MultiArrayUtils .copyRegion (readChunk (chunkCoords ), chunkProjection .chunkOffset ,
118181 outputArray , chunkProjection .outOffset , chunkProjection .shape
119182 );
@@ -137,6 +200,14 @@ boolean chunkIsInArray(long[] chunkCoords) {
137200 return true ;
138201 }
139202
203+ /**
204+ * Reads one chunk of the Zarr array as specified by the chunk coordinates into an
205+ * ucar.ma2.Array.
206+ *
207+ * @param chunkCoords The coordinates of the chunk as computed by the offset of the chunk divided
208+ * by the chunk shape.
209+ * @throws ZarrException
210+ */
140211 @ Nonnull
141212 public ucar .ma2 .Array readChunk (long [] chunkCoords )
142213 throws ZarrException {
@@ -155,10 +226,23 @@ public ucar.ma2.Array readChunk(long[] chunkCoords)
155226 return codecPipeline .decode (chunkBytes , metadata .coreArrayMetadata );
156227 }
157228
229+ /**
230+ * Writes a ucar.ma2.Array into the Zarr array at the beginning of the Zarr array. The shape of
231+ * the Zarr array needs be large enough for the write.
232+ *
233+ * @param array
234+ */
158235 public void write (ucar .ma2 .Array array ) {
159236 write (new long [metadata .ndim ()], array );
160237 }
161238
239+ /**
240+ * Writes a ucar.ma2.Array into the Zarr array at a specified offset. The shape of the Zarr array
241+ * needs be large enough for the write.
242+ *
243+ * @param offset
244+ * @param array
245+ */
162246 public void write (long [] offset , ucar .ma2 .Array array ) {
163247 if (offset .length != metadata .ndim ()) {
164248 throw new IllegalArgumentException ("'offset' needs to have rank '" + metadata .ndim () + "'." );
@@ -200,6 +284,14 @@ public void write(long[] offset, ucar.ma2.Array array) {
200284 });
201285 }
202286
287+ /**
288+ * Writes one chunk into the Zarr array as specified by the chunk coordinates. The shape of the
289+ * Zarr array needs be large enough for the write.
290+ *
291+ * @param chunkCoords
292+ * @param chunkArray
293+ * @throws ZarrException
294+ */
203295 public void writeChunk (long [] chunkCoords , ucar .ma2 .Array chunkArray ) throws ZarrException {
204296 String [] chunkKeys = metadata .chunkKeyEncoding .encodeChunkKey (chunkCoords );
205297 StoreHandle chunkHandle = storeHandle .resolve (chunkKeys );
@@ -212,6 +304,10 @@ public void writeChunk(long[] chunkCoords, ucar.ma2.Array chunkArray) throws Zar
212304 }
213305 }
214306
307+ public ArrayAccessor access () {
308+ return new ArrayAccessor (this );
309+ }
310+
215311 private Array writeMetadata (ArrayMetadata newArrayMetadata ) throws ZarrException , IOException {
216312 ObjectMapper objectMapper = Node .makeObjectMapper ();
217313 ByteBuffer metadataBytes = ByteBuffer .wrap (objectMapper .writeValueAsBytes (newArrayMetadata ));
@@ -220,6 +316,15 @@ private Array writeMetadata(ArrayMetadata newArrayMetadata) throws ZarrException
220316 return new Array (storeHandle , newArrayMetadata );
221317 }
222318
319+ /**
320+ * Sets a new shape for the Zarr array. It only changes the metadata, no array data is modified or
321+ * deleted. This method returns a new instance of the Zarr array class and the old instance
322+ * becomes invalid.
323+ *
324+ * @param newShape
325+ * @throws ZarrException
326+ * @throws IOException
327+ */
223328 public Array resize (long [] newShape ) throws ZarrException , IOException {
224329 if (newShape .length != metadata .ndim ()) {
225330 throw new IllegalArgumentException (
@@ -232,6 +337,14 @@ public Array resize(long[] newShape) throws ZarrException, IOException {
232337 return writeMetadata (newArrayMetadata );
233338 }
234339
340+ /**
341+ * Sets the attributes of the Zarr array. It overwrites and removes any existing attributes. This
342+ * method returns a new instance of the Zarr array class and the old instance becomes invalid.
343+ *
344+ * @param newAttributes
345+ * @throws ZarrException
346+ * @throws IOException
347+ */
235348 public Array setAttributes (Map <String , Object > newAttributes ) throws ZarrException , IOException {
236349 ArrayMetadata newArrayMetadata =
237350 ArrayMetadataBuilder .fromArrayMetadata (metadata )
@@ -240,9 +353,20 @@ public Array setAttributes(Map<String, Object> newAttributes) throws ZarrExcepti
240353 return writeMetadata (newArrayMetadata );
241354 }
242355
356+ /**
357+ * Updates the attributes of the Zarr array. It provides a callback that gets the current
358+ * attributes as input and needs to return the new set of attributes. The attributes in the
359+ * callback may be mutated. This method overwrites and removes any existing attributes. This
360+ * method returns a new instance of the Zarr array class and the old instance becomes invalid.
361+ *
362+ * @param attributeMapper
363+ * @throws ZarrException
364+ * @throws IOException
365+ */
243366 public Array updateAttributes (Function <Map <String , Object >, Map <String , Object >> attributeMapper )
244367 throws ZarrException , IOException {
245- return setAttributes (attributeMapper .apply (metadata .attributes ));
368+ return setAttributes (attributeMapper .apply (new HashMap <String , Object >(metadata .attributes ) {
369+ }));
246370 }
247371
248372 @ Override
@@ -254,4 +378,56 @@ public String toString() {
254378 metadata .dataType
255379 );
256380 }
381+
382+ public static final class ArrayAccessor {
383+
384+ @ Nullable
385+ long [] offset ;
386+ @ Nullable
387+ int [] shape ;
388+ @ Nonnull
389+ Array array ;
390+
391+ private ArrayAccessor (@ Nonnull Array array ) {
392+ this .array = array ;
393+ }
394+
395+ @ Nonnull
396+ public ArrayAccessor withOffset (@ Nonnull long ... offset ) {
397+ this .offset = offset ;
398+ return this ;
399+ }
400+
401+
402+ @ Nonnull
403+ public ArrayAccessor withShape (@ Nonnull int ... shape ) {
404+ this .shape = shape ;
405+ return this ;
406+ }
407+
408+ @ Nonnull
409+ public ArrayAccessor withShape (@ Nonnull long ... shape ) {
410+ this .shape = Utils .toIntArray (shape );
411+ return this ;
412+ }
413+
414+ @ Nonnull
415+ public ucar .ma2 .Array read () throws ZarrException {
416+ if (offset == null ) {
417+ throw new ZarrException ("`offset` needs to be set." );
418+ }
419+ if (shape == null ) {
420+ throw new ZarrException ("`shape` needs to be set." );
421+ }
422+ return array .read (offset , shape );
423+ }
424+
425+ public void write (@ Nonnull ucar .ma2 .Array content ) throws ZarrException {
426+ if (offset == null ) {
427+ throw new ZarrException ("`offset` needs to be set." );
428+ }
429+ array .write (offset , content );
430+ }
431+
432+ }
257433}
0 commit comments