• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kit-data-manager / ro-crate-java / #430

19 May 2025 01:23PM UTC coverage: 90.495% (+0.3%) from 90.169%
#430

Pull #258

github

web-flow
Merge b22e70bd8 into 810d1995c
Pull Request #258: Support .ELN-style crates in all zip readers and writers

276 of 305 new or added lines in 21 files covered. (90.49%)

1 existing line in 1 file now uncovered.

2009 of 2220 relevant lines covered (90.5%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.84
/src/main/java/edu/kit/datamanager/ro_crate/writer/WriteZipStrategy.java
1
package edu.kit.datamanager.ro_crate.writer;
2

3
import com.fasterxml.jackson.databind.JsonNode;
4
import com.fasterxml.jackson.databind.ObjectMapper;
5
import edu.kit.datamanager.ro_crate.Crate;
6
import edu.kit.datamanager.ro_crate.entities.data.DataEntity;
7
import edu.kit.datamanager.ro_crate.objectmapper.MyObjectMapper;
8
import edu.kit.datamanager.ro_crate.preview.CratePreview;
9
import net.lingala.zip4j.ZipFile;
10
import net.lingala.zip4j.model.ZipParameters;
11
import org.apache.commons.io.FileUtils;
12
import org.slf4j.Logger;
13
import org.slf4j.LoggerFactory;
14

15
import java.io.ByteArrayInputStream;
16
import java.io.File;
17
import java.io.IOException;
18
import java.io.InputStream;
19
import java.nio.charset.StandardCharsets;
20
import java.nio.file.Path;
21
import java.util.Optional;
22
import java.util.UUID;
23
import java.util.regex.Matcher;
24

25
/**
26
 * Implementation of the writing strategy to provide a way of writing crates to
27
 * a zip archive.
28
 */
29
public class WriteZipStrategy implements
1✔
30
        GenericWriterStrategy<String>,
31
        ElnFormatWriter<String>
32
{
33
    private static final Logger logger = LoggerFactory.getLogger(WriteZipStrategy.class);
1✔
34

35
    /**
36
     * Defines if the zip file will directly contain the crate,
37
     * or if it will contain a subdirectory with the crate.
38
     */
39
    protected boolean createRootSubdir = false;
1✔
40

41
    @Override
42
    public ElnFormatWriter<String> usingElnStyle() {
43
        this.createRootSubdir = true;
1✔
44
        return this;
1✔
45
    }
46

47
    @Override
48
    public void save(Crate crate, String destination) throws IOException {
49
        String innerFolderName = "";
1✔
50
        if (this.createRootSubdir) {
1✔
51
            String dot = Matcher.quoteReplacement(".");
1✔
52
            String end = Matcher.quoteReplacement("$");
1✔
53
            innerFolderName = Path.of(destination).getFileName()
1✔
54
                    .toString()
1✔
55
                    // remove .zip or .eln from the end of the file name
56
                    // (?i) removes case sensitivity
57
                    .replaceFirst("(?i)" + dot + "zip" + end, "")
1✔
58
                    .replaceFirst("(?i)" + dot + "eln" + end, "");
1✔
59
            if (!innerFolderName.endsWith("/")) {
1✔
60
                innerFolderName += "/";
1✔
61
            }
62
        }
63
        try (ZipFile zipFile = new ZipFile(destination)) {
1✔
64
            saveMetadataJson(crate, zipFile, innerFolderName);
1✔
65
            saveDataEntities(crate, zipFile, innerFolderName);
1✔
66
            savePreview(crate, zipFile, innerFolderName);
1✔
67
        }
68
    }
1✔
69

70
    private void saveDataEntities(Crate crate, ZipFile zipFile, String prefix) throws IOException {
71
        for (DataEntity dataEntity : crate.getAllDataEntities()) {
1✔
72
            this.saveToZip(dataEntity, zipFile, prefix);
1✔
73
        }
1✔
74
    }
1✔
75

76
    private void saveMetadataJson(Crate crate, ZipFile zipFile, String prefix) throws IOException {
77
        // write the metadata.json file
78
        ZipParameters zipParameters = new ZipParameters();
1✔
79
        zipParameters.setFileNameInZip(prefix + "ro-crate-metadata.json");
1✔
80
        ObjectMapper objectMapper = MyObjectMapper.getMapper();
1✔
81
        // we create an JsonNode only to have the file written pretty
82
        JsonNode node = objectMapper.readTree(crate.getJsonMetadata());
1✔
83
        String str = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
1✔
84
        try (InputStream inputStream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8))) {
1✔
85
            // write the ro-crate-metadata
86
            zipFile.addStream(inputStream, zipParameters);
1✔
87
        }
88
    }
1✔
89

90
    private void savePreview(Crate crate, ZipFile zipFile, String prefix) throws IOException {
91
        Optional<CratePreview> preview = Optional.ofNullable(crate.getPreview());
1✔
92
        if (preview.isEmpty()) {
1✔
93
            return;
1✔
94
        }
95
        final String ID = UUID.randomUUID().toString();
1✔
96
        File tmpPreviewFolder = Path.of("./.tmp/ro-crate-java/writer-zipStrategy/")
1✔
97
                .resolve(ID)
1✔
98
                .toFile();
1✔
99
        FileUtils.forceMkdir(tmpPreviewFolder);
1✔
100
        FileUtils.forceDeleteOnExit(tmpPreviewFolder);
1✔
101

102
        preview.get().generate(crate, tmpPreviewFolder);
1✔
103
        String[] paths = tmpPreviewFolder.list();
1✔
104
        if (paths == null) {
1✔
NEW
105
            throw new IOException("No files found in temporary folder");
×
106
        }
107
        for (String path : paths) {
1✔
108
            File file = tmpPreviewFolder.toPath().resolve(path).toFile();
1✔
109
            if (file.isDirectory()) {
1✔
NEW
110
                ZipParameters parameters = new ZipParameters();
×
NEW
111
                parameters.setRootFolderNameInZip(prefix + path);
×
NEW
112
                parameters.setIncludeRootFolder(false);
×
NEW
113
                zipFile.addFolder(file, parameters);
×
NEW
114
            } else {
×
115
                ZipParameters zipParameters = new ZipParameters();
1✔
116
                zipParameters.setFileNameInZip(prefix + path);
1✔
117
                zipFile.addFile(file, zipParameters);
1✔
118
            }
119
        }
120
        try {
121
            FileUtils.forceDelete(tmpPreviewFolder);
1✔
NEW
122
        } catch (IOException e) {
×
NEW
123
            logger.error("Could not delete temporary preview folder: {}", tmpPreviewFolder);
×
124
        }
1✔
125
    }
1✔
126

127
    private void saveToZip(DataEntity entity, ZipFile zipFile, String prefix) throws IOException {
128
        if (entity == null || entity.getPath() == null) {
1✔
NEW
129
            return;
×
130
        }
131

132
        boolean isDirectory = entity.getPath().toFile().isDirectory();
1✔
133
        if (isDirectory) {
1✔
134
            ZipParameters parameters = new ZipParameters();
1✔
135
            parameters.setRootFolderNameInZip(prefix + entity.getId());
1✔
136
            parameters.setIncludeRootFolder(false);
1✔
137
            zipFile.addFolder(entity.getPath().toFile(), parameters);
1✔
138
        } else {
1✔
139
            ZipParameters zipParameters = new ZipParameters();
1✔
140
            zipParameters.setFileNameInZip(prefix + entity.getId());
1✔
141
            zipFile.addFile(entity.getPath().toFile(), zipParameters);
1✔
142
        }
143
    }
1✔
144
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc