88import java .nio .ByteBuffer ;
99import java .nio .file .Path ;
1010import java .nio .file .Paths ;
11+ import java .util .Comparator ;
1112import java .util .stream .Stream ;
1213
13- import com .fasterxml .jackson .databind .util .ByteBufferBackedInputStream ;
1414import org .apache .commons .compress .archivers .zip .*;
1515
1616import java .util .zip .CRC32 ;
1717import java .util .zip .ZipEntry ; // for STORED constant
1818
19- import static dev .zarr .zarrjava .utils .ZipUtils .getZipCommentFromBuffer ;
20-
2119
2220/** A Store implementation that buffers reads and writes and flushes them to an underlying Store as a zip file.
2321 */
24- public class BufferedZipStore implements Store , Store . ListableStore {
22+ public class BufferedZipStore extends ZipStore {
2523
26- private final StoreHandle underlyingStore ;
2724 private final Store .ListableStore bufferStore ;
2825 private String archiveComment ;
29- private boolean flushOnWrite ;
26+ private final boolean flushOnWrite ;
27+
28+ private final Comparator <String []> zipEntryComparator = (a , b ) -> {
29+ boolean aIsZarr = a .length > 0 && a [a .length - 1 ].equals ("zarr.json" );
30+ boolean bIsZarr = b .length > 0 && b [b .length - 1 ].equals ("zarr.json" );
31+ // first all zarr.json files
32+ if (aIsZarr && !bIsZarr ) {
33+ return -1 ;
34+ } else if (!aIsZarr && bIsZarr ) {
35+ return 1 ;
36+ } else if (aIsZarr && bIsZarr ) {
37+ // sort zarr.json in BFS order within same depth by lexicographical order
38+ if (a .length != b .length ) {
39+ return Integer .compare (a .length , b .length );
40+ } else {
41+ return String .join ("/" , a ).compareTo (String .join ("/" , b ));
42+ }
43+ } else {
44+ // then all other files in lexicographical order
45+ return String .join ("/" , a ).compareTo (String .join ("/" , b ));
46+ }
47+ };
3048
31- private void writeBuffer () throws IOException {
49+ private void writeBuffer () throws IOException {
3250 // create zip file bytes from buffer store and write to underlying store
3351 ByteArrayOutputStream baos = new ByteArrayOutputStream ();
3452 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream (baos )) {
3553 zos .setUseZip64 (Zip64Mode .AsNeeded );
3654 if (archiveComment != null ) {
3755 zos .setComment (archiveComment );
3856 }
39- Stream <String []> entries = bufferStore .list ().sorted (
40- (a , b ) -> {
41- boolean aIsZarr = a .length > 0 && a [a .length - 1 ].equals ("zarr.json" );
42- boolean bIsZarr = b .length > 0 && b [b .length - 1 ].equals ("zarr.json" );
43- // first all zarr.json files
44- if (aIsZarr && !bIsZarr ) {
45- return -1 ;
46- } else if (!aIsZarr && bIsZarr ) {
47- return 1 ;
48- } else if (aIsZarr && bIsZarr ) {
49- // sort zarr.json in BFS order within same depth by lexicographical order
50- if (a .length != b .length ) {
51- return Integer .compare (a .length , b .length );
52- } else {
53- return String .join ("/" , a ).compareTo (String .join ("/" , b ));
54- }
55- } else {
56- // then all other files in lexicographical order
57- return String .join ("/" , a ).compareTo (String .join ("/" , b ));
58- }
59- }
60- );
61-
62- entries .forEach (keys -> {
57+ bufferStore .list ().sorted (zipEntryComparator ).forEach (keys -> {
6358 try {
6459 if (keys == null || keys .length == 0 ) {
6560 // skip root entry
@@ -116,22 +111,32 @@ private void writeBuffer() throws IOException{
116111 underlyingStore .set (ByteBuffer .wrap (zipBytes ));
117112 }
118113
114+ public void setArchiveComment (@ Nullable String archiveComment ) throws IOException {
115+ this .archiveComment = archiveComment ;
116+ if (flushOnWrite ) {
117+ writeBuffer ();
118+ }
119+ }
120+
121+ public void deleteArchiveComment () throws IOException {
122+ this .setArchiveComment (null );
123+ }
119124
120- private void loadBuffer () throws IOException {
121- // read zip file bytes from underlying store and populate buffer store
122- ByteBuffer buffer = underlyingStore .read ();
123- if (buffer == null ) {
124- return ;
125+ /**
126+ * Loads the buffer from the underlying store zip file.
127+ */
128+ private void loadBuffer () throws IOException {
129+ String loadedArchiveComment = super .getArchiveComment ();
130+ if (loadedArchiveComment != null && this .archiveComment == null ) {
131+ // don't overwrite existing archiveComment
132+ this .archiveComment = loadedArchiveComment ;
125133 }
126- byte [] bufArray ;
127- if (buffer .hasArray ()) {
128- bufArray = buffer .array ();
129- } else {
130- bufArray = new byte [buffer .remaining ()];
131- buffer .duplicate ().get (bufArray );
134+
135+ InputStream inputStream = underlyingStore .getInputStream ();
136+ if (inputStream == null ) {
137+ return ;
132138 }
133- this .archiveComment = getZipCommentFromBuffer (bufArray );
134- try (ZipArchiveInputStream zis = new ZipArchiveInputStream (new ByteBufferBackedInputStream (buffer ))) {
139+ try (ZipArchiveInputStream zis = new ZipArchiveInputStream (inputStream )) {
135140 ZipArchiveEntry entry ;
136141 while ((entry = zis .getNextEntry ()) != null ) {
137142 if (entry .isDirectory ()) {
@@ -150,7 +155,7 @@ private void loadBuffer() throws IOException{
150155 }
151156
152157 public BufferedZipStore (@ Nonnull StoreHandle underlyingStore , @ Nonnull Store .ListableStore bufferStore , @ Nullable String archiveComment , boolean flushOnWrite ) {
153- this . underlyingStore = underlyingStore ;
158+ super ( underlyingStore ) ;
154159 this .bufferStore = bufferStore ;
155160 this .archiveComment = archiveComment ;
156161 this .flushOnWrite = flushOnWrite ;
@@ -229,6 +234,7 @@ public void flush() throws IOException {
229234 writeBuffer ();
230235 }
231236
237+ @ Override
232238 public String getArchiveComment () {
233239 return archiveComment ;
234240 }
0 commit comments