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

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

19 May 2025 02:23PM UTC coverage: 90.418% (+0.2%) from 90.169%
#431

Pull #258

github

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

283 of 315 new or added lines in 25 files covered. (89.84%)

1 existing line in 1 file now uncovered.

2010 of 2223 relevant lines covered (90.42%)

0.9 hits per line

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

87.14
/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 edu.kit.datamanager.ro_crate.util.FileSystemUtil;
10
import net.lingala.zip4j.ZipFile;
11
import net.lingala.zip4j.model.ZipParameters;
12
import org.apache.commons.io.FileUtils;
13
import org.slf4j.Logger;
14
import org.slf4j.LoggerFactory;
15

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

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

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

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

49
    @Override
50
    public void save(Crate crate, String destination) throws IOException {
51
        String innerFolderName = "";
1✔
52
        if (this.createRootSubdir) {
1✔
53
            innerFolderName = FileSystemUtil.filterExtensionsFromFileName(
1✔
54
                    Path.of(destination).getFileName().toString(),
1✔
55
                    Set.of("ELN", "ZIP"));
1✔
56
            innerFolderName = FileSystemUtil.ensureTrailingSlash(innerFolderName);
1✔
57
        }
58
        try (ZipFile zipFile = new ZipFile(destination)) {
1✔
59
            saveMetadataJson(crate, zipFile, innerFolderName);
1✔
60
            saveDataEntities(crate, zipFile, innerFolderName);
1✔
61
            savePreview(crate, zipFile, innerFolderName);
1✔
62
        }
63
    }
1✔
64

65
    private void saveDataEntities(Crate crate, ZipFile zipFile, String prefix) throws IOException {
66
        for (DataEntity dataEntity : crate.getAllDataEntities()) {
1✔
67
            this.saveToZip(dataEntity, zipFile, prefix);
1✔
68
        }
1✔
69
    }
1✔
70

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

85
    private void savePreview(Crate crate, ZipFile zipFile, String prefix) throws IOException {
86
        Optional<CratePreview> preview = Optional.ofNullable(crate.getPreview());
1✔
87
        if (preview.isEmpty()) {
1✔
88
            return;
1✔
89
        }
90
        final String ID = UUID.randomUUID().toString();
1✔
91
        File tmpPreviewFolder = Path.of(TMP_DIR)
1✔
92
                .resolve(ID)
1✔
93
                .toFile();
1✔
94
        FileUtils.forceMkdir(tmpPreviewFolder);
1✔
95
        FileUtils.forceDeleteOnExit(tmpPreviewFolder);
1✔
96

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

122
    private void saveToZip(DataEntity entity, ZipFile zipFile, String prefix) throws IOException {
123
        if (entity == null || entity.getPath() == null) {
1✔
NEW
124
            return;
×
125
        }
126

127
        boolean isDirectory = entity.getPath().toFile().isDirectory();
1✔
128
        if (isDirectory) {
1✔
129
            ZipParameters parameters = new ZipParameters();
1✔
130
            parameters.setRootFolderNameInZip(prefix + entity.getId());
1✔
131
            parameters.setIncludeRootFolder(false);
1✔
132
            zipFile.addFolder(entity.getPath().toFile(), parameters);
1✔
133
        } else {
1✔
134
            ZipParameters zipParameters = new ZipParameters();
1✔
135
            zipParameters.setFileNameInZip(prefix + entity.getId());
1✔
136
            zipFile.addFile(entity.getPath().toFile(), zipParameters);
1✔
137
        }
138
    }
1✔
139
}
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