11package dev .zarr .zarrjava .core ;
22
33import dev .zarr .zarrjava .ZarrException ;
4+ import dev .zarr .zarrjava .store .FilesystemStore ;
45import dev .zarr .zarrjava .store .StoreHandle ;
56import dev .zarr .zarrjava .utils .IndexingUtils ;
67import dev .zarr .zarrjava .utils .MultiArrayUtils ;
1011
1112import javax .annotation .Nonnull ;
1213import javax .annotation .Nullable ;
14+ import java .io .IOException ;
1315import java .nio .ByteBuffer ;
16+ import java .nio .file .Path ;
17+ import java .nio .file .Paths ;
1418import java .util .Arrays ;
1519import java .util .stream .Stream ;
1620
17- public interface Array {
21+ public abstract class Array extends AbstractNode {
1822
19- ArrayMetadata metadata ();
20-
21- StoreHandle storeHandle ();
23+ protected CodecPipeline codecPipeline ;
24+ public abstract ArrayMetadata metadata ();
2225
23- CodecPipeline codecPipeline ();
26+ protected Array (StoreHandle storeHandle ) throws ZarrException {
27+ super (storeHandle );
28+ }
29+
30+ /**
31+ * Opens an existing Zarr array at a specified storage location. Automatically detects the Zarr version.
32+ *
33+ * @param storeHandle the storage location of the Zarr array
34+ * @throws IOException throws IOException if the metadata cannot be read
35+ * @throws ZarrException throws ZarrException if the Zarr array cannot be opened
36+ */
37+ public static Array open (StoreHandle storeHandle ) throws IOException , ZarrException {
38+ boolean isV3 = storeHandle .resolve (ZARR_JSON ).exists ();
39+ boolean isV2 = storeHandle .resolve (ZARRAY ).exists ();
40+ if (isV3 && isV2 ) {
41+ throw new ZarrException ("Both Zarr v2 and v3 arrays found at the specified location." );
42+ } else if (isV3 ) {
43+ return dev .zarr .zarrjava .v3 .Array .open (storeHandle );
44+ } else if (isV2 ) {
45+ return dev .zarr .zarrjava .v2 .Array .open (storeHandle );
46+ } else {
47+ throw new ZarrException ("No Zarr array found at the specified location." );
48+ }
49+ }
50+ /**
51+ * Opens an existing Zarr array at a specified storage location. Automatically detects the Zarr version.
52+ *
53+ * @param path the storage location of the Zarr array
54+ * @throws IOException throws IOException if the metadata cannot be read
55+ * @throws ZarrException throws ZarrException if the Zarr array cannot be opened
56+ */
57+ public static Array open (Path path ) throws IOException , ZarrException {
58+ return open (new StoreHandle (new FilesystemStore (path )));
59+ }
60+
61+ /**
62+ * Opens an existing Zarr array at a specified storage location. Automatically detects the Zarr version.
63+ *
64+ * @param path the storage location of the Zarr array
65+ * @throws IOException throws IOException if the metadata cannot be read
66+ * @throws ZarrException throws ZarrException if the Zarr array cannot be opened
67+ */
68+ public static Array open (String path ) throws IOException , ZarrException {
69+ return open (Paths .get (path ));
70+ }
2471
2572 /**
2673 * Writes a ucar.ma2.Array into the Zarr array at a specified offset. The shape of the Zarr array
2774 * needs be large enough for the write.
2875 *
29- * @param offset the offset where to write the data
30- * @param array the data to write
76+ * @param offset the offset where to write the data
77+ * @param array the data to write
3178 * @param parallel utilizes parallelism if true
3279 */
33- default void write (long [] offset , ucar .ma2 .Array array , boolean parallel ) {
80+ public void write (long [] offset , ucar .ma2 .Array array , boolean parallel ) {
3481 ArrayMetadata metadata = metadata ();
3582 if (offset .length != metadata .ndim ()) {
3683 throw new IllegalArgumentException ("'offset' needs to have rank '" + metadata .ndim () + "'." );
@@ -42,15 +89,15 @@ default void write(long[] offset, ucar.ma2.Array array, boolean parallel) {
4289 int [] shape = array .getShape ();
4390
4491 final int [] chunkShape = metadata .chunkShape ();
45- Stream <long []> chunkStream = Arrays .stream (IndexingUtils .computeChunkCoords (metadata .shape () , chunkShape , offset , shape ));
92+ Stream <long []> chunkStream = Arrays .stream (IndexingUtils .computeChunkCoords (metadata .shape , chunkShape , offset , shape ));
4693 if (parallel ) {
4794 chunkStream = chunkStream .parallel ();
4895 }
4996 chunkStream .forEach (
5097 chunkCoords -> {
5198 try {
5299 final IndexingUtils .ChunkProjection chunkProjection =
53- IndexingUtils .computeProjection (chunkCoords , metadata .shape () , chunkShape , offset ,
100+ IndexingUtils .computeProjection (chunkCoords , metadata .shape , chunkShape , offset ,
54101 shape
55102 );
56103
@@ -82,19 +129,19 @@ default void write(long[] offset, ucar.ma2.Array array, boolean parallel) {
82129 *
83130 * @param chunkCoords The coordinates of the chunk as computed by the offset of the chunk divided
84131 * by the chunk shape.
85- * @param chunkArray The data to write into the chunk
132+ * @param chunkArray The data to write into the chunk
86133 * @throws ZarrException throws ZarrException if the write fails
87134 */
88- default void writeChunk (long [] chunkCoords , ucar .ma2 .Array chunkArray ) throws ZarrException {
135+ public void writeChunk (long [] chunkCoords , ucar .ma2 .Array chunkArray ) throws ZarrException {
89136 ArrayMetadata metadata = metadata ();
90137 String [] chunkKeys = metadata .chunkKeyEncoding ().encodeChunkKey (chunkCoords );
91- StoreHandle chunkHandle = storeHandle () .resolve (chunkKeys );
138+ StoreHandle chunkHandle = storeHandle .resolve (chunkKeys );
92139 Object parsedFillValue = metadata .parsedFillValue ();
93140
94141 if (parsedFillValue != null && MultiArrayUtils .allValuesEqual (chunkArray , parsedFillValue )) {
95142 chunkHandle .delete ();
96143 } else {
97- ByteBuffer chunkBytes = codecPipeline () .encode (chunkArray );
144+ ByteBuffer chunkBytes = codecPipeline .encode (chunkArray );
98145 chunkHandle .set (chunkBytes );
99146 }
100147 }
@@ -108,22 +155,21 @@ default void writeChunk(long[] chunkCoords, ucar.ma2.Array chunkArray) throws Za
108155 * @throws ZarrException throws ZarrException if the requested chunk is outside the array's domain or if the read fails
109156 */
110157 @ Nonnull
111- default ucar .ma2 .Array readChunk (long [] chunkCoords )
112- throws ZarrException {
158+ public ucar .ma2 .Array readChunk (long [] chunkCoords ) throws ZarrException {
113159 ArrayMetadata metadata = metadata ();
114160 if (!chunkIsInArray (chunkCoords )) {
115161 throw new ZarrException ("Attempting to read data outside of the array's domain." );
116162 }
117163
118164 final String [] chunkKeys = metadata .chunkKeyEncoding ().encodeChunkKey (chunkCoords );
119- final StoreHandle chunkHandle = storeHandle () .resolve (chunkKeys );
165+ final StoreHandle chunkHandle = storeHandle .resolve (chunkKeys );
120166
121167 ByteBuffer chunkBytes = chunkHandle .read ();
122168 if (chunkBytes == null ) {
123169 return metadata .allocateFillValueChunk ();
124170 }
125171
126- return codecPipeline () .decode (chunkBytes );
172+ return codecPipeline .decode (chunkBytes );
127173 }
128174
129175
@@ -134,7 +180,7 @@ default ucar.ma2.Array readChunk(long[] chunkCoords)
134180 *
135181 * @param array the data to write
136182 */
137- default void write (ucar .ma2 .Array array ) {
183+ public void write (ucar .ma2 .Array array ) {
138184 write (new long [metadata ().ndim ()], array );
139185 }
140186
@@ -144,20 +190,20 @@ default void write(ucar.ma2.Array array) {
144190 * Utilizes no parallelism.
145191 *
146192 * @param offset the offset where to write the data
147- * @param array the data to write
193+ * @param array the data to write
148194 */
149- default void write (long [] offset , ucar .ma2 .Array array ) {
195+ public void write (long [] offset , ucar .ma2 .Array array ) {
150196 write (offset , array , false );
151197 }
152198
153199 /**
154200 * Writes a ucar.ma2.Array into the Zarr array at the beginning of the Zarr array. The shape of
155201 * the Zarr array needs be large enough for the write.
156202 *
157- * @param array the data to write
203+ * @param array the data to write
158204 * @param parallel utilizes parallelism if true
159205 */
160- default void write (ucar .ma2 .Array array , boolean parallel ) {
206+ public void write (ucar .ma2 .Array array , boolean parallel ) {
161207 write (new long [metadata ().ndim ()], array , parallel );
162208 }
163209
@@ -168,20 +214,20 @@ default void write(ucar.ma2.Array array, boolean parallel) {
168214 * @throws ZarrException throws ZarrException if the read fails
169215 */
170216 @ Nonnull
171- default ucar .ma2 .Array read () throws ZarrException {
172- return read (new long [metadata ().ndim ()], Utils .toIntArray (metadata ().shape () ));
217+ public ucar .ma2 .Array read () throws ZarrException {
218+ return read (new long [metadata ().ndim ()], Utils .toIntArray (metadata ().shape ));
173219 }
174220
175221 /**
176222 * Reads a part of the Zarr array based on a requested offset and shape into an ucar.ma2.Array.
177223 * Utilizes no parallelism.
178224 *
179225 * @param offset the offset where to start reading
180- * @param shape the shape of the data to read
226+ * @param shape the shape of the data to read
181227 * @throws ZarrException throws ZarrException if the requested data is outside the array's domain or if the read fails
182228 */
183229 @ Nonnull
184- default ucar .ma2 .Array read (final long [] offset , final int [] shape ) throws ZarrException {
230+ public ucar .ma2 .Array read (final long [] offset , final int [] shape ) throws ZarrException {
185231 return read (offset , shape , false );
186232 }
187233
@@ -192,15 +238,15 @@ default ucar.ma2.Array read(final long[] offset, final int[] shape) throws ZarrE
192238 * @throws ZarrException throws ZarrException if the requested data is outside the array's domain or if the read fails
193239 */
194240 @ Nonnull
195- default ucar .ma2 .Array read (final boolean parallel ) throws ZarrException {
196- return read (new long [metadata ().ndim ()], Utils .toIntArray (metadata ().shape () ), parallel );
241+ public ucar .ma2 .Array read (final boolean parallel ) throws ZarrException {
242+ return read (new long [metadata ().ndim ()], Utils .toIntArray (metadata ().shape ), parallel );
197243 }
198244
199- default boolean chunkIsInArray (long [] chunkCoords ) {
245+ boolean chunkIsInArray (long [] chunkCoords ) {
200246 final int [] chunkShape = metadata ().chunkShape ();
201247 for (int dimIdx = 0 ; dimIdx < metadata ().ndim (); dimIdx ++) {
202248 if (chunkCoords [dimIdx ] < 0
203- || chunkCoords [dimIdx ] * chunkShape [dimIdx ] >= metadata ().shape () [dimIdx ]) {
249+ || chunkCoords [dimIdx ] * chunkShape [dimIdx ] >= metadata ().shape [dimIdx ]) {
204250 return false ;
205251 }
206252 }
@@ -210,23 +256,22 @@ default boolean chunkIsInArray(long[] chunkCoords) {
210256 /**
211257 * Reads a part of the Zarr array based on a requested offset and shape into an ucar.ma2.Array.
212258 *
213- * @param offset the offset where to start reading
214- * @param shape the shape of the data to read
259+ * @param offset the offset where to start reading
260+ * @param shape the shape of the data to read
215261 * @param parallel utilizes parallelism if true
216262 * @throws ZarrException throws ZarrException if the requested data is outside the array's domain or if the read fails
217263 */
218264 @ Nonnull
219- default ucar .ma2 .Array read (final long [] offset , final int [] shape , final boolean parallel ) throws ZarrException {
265+ public ucar .ma2 .Array read (final long [] offset , final int [] shape , final boolean parallel ) throws ZarrException {
220266 ArrayMetadata metadata = metadata ();
221- CodecPipeline codecPipeline = codecPipeline ();
222267 if (offset .length != metadata .ndim ()) {
223268 throw new IllegalArgumentException ("'offset' needs to have rank '" + metadata .ndim () + "'." );
224269 }
225270 if (shape .length != metadata .ndim ()) {
226271 throw new IllegalArgumentException ("'shape' needs to have rank '" + metadata .ndim () + "'." );
227272 }
228273 for (int dimIdx = 0 ; dimIdx < metadata .ndim (); dimIdx ++) {
229- if (offset [dimIdx ] < 0 || offset [dimIdx ] + shape [dimIdx ] > metadata .shape () [dimIdx ]) {
274+ if (offset [dimIdx ] < 0 || offset [dimIdx ] + shape [dimIdx ] > metadata .shape [dimIdx ]) {
230275 throw new ZarrException ("Requested data is outside of the array's domain." );
231276 }
232277 }
@@ -238,15 +283,15 @@ default ucar.ma2.Array read(final long[] offset, final int[] shape, final boolea
238283
239284 final ucar .ma2 .Array outputArray = ucar .ma2 .Array .factory (metadata .dataType ().getMA2DataType (),
240285 shape );
241- Stream <long []> chunkStream = Arrays .stream (IndexingUtils .computeChunkCoords (metadata .shape () , chunkShape , offset , shape ));
286+ Stream <long []> chunkStream = Arrays .stream (IndexingUtils .computeChunkCoords (metadata .shape , chunkShape , offset , shape ));
242287 if (parallel ) {
243288 chunkStream = chunkStream .parallel ();
244289 }
245290 chunkStream .forEach (
246291 chunkCoords -> {
247292 try {
248293 final IndexingUtils .ChunkProjection chunkProjection =
249- IndexingUtils .computeProjection (chunkCoords , metadata .shape () , chunkShape , offset ,
294+ IndexingUtils .computeProjection (chunkCoords , metadata .shape , chunkShape , offset ,
250295 shape
251296 );
252297
@@ -258,7 +303,7 @@ default ucar.ma2.Array read(final long[] offset, final int[] shape, final boolea
258303 }
259304
260305 final String [] chunkKeys = metadata .chunkKeyEncoding ().encodeChunkKey (chunkCoords );
261- final StoreHandle chunkHandle = storeHandle () .resolve (chunkKeys );
306+ final StoreHandle chunkHandle = storeHandle .resolve (chunkKeys );
262307 if (!chunkHandle .exists ()) {
263308 return ;
264309 }
@@ -281,11 +326,11 @@ default ucar.ma2.Array read(final long[] offset, final int[] shape, final boolea
281326 return outputArray ;
282327 }
283328
284- default ArrayAccessor access () {
329+ public ArrayAccessor access () {
285330 return new ArrayAccessor (this );
286331 }
287332
288- final class ArrayAccessor {
333+ public static final class ArrayAccessor {
289334 @ Nullable
290335 long [] offset ;
291336 @ Nullable
@@ -335,4 +380,4 @@ public void write(@Nonnull ucar.ma2.Array content) throws ZarrException {
335380 }
336381
337382 }
338- }
383+ }
0 commit comments