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

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

15 Apr 2025 08:24AM UTC coverage: 86.955%. First build
#348

Pull #233

github

web-flow
Merge pull request #244 from kit-data-manager/renovate/commons-io-commons-io-2.x

chore(deps): update dependency commons-io:commons-io to v2.19.0
Pull Request #233: Version 2.1.0

521 of 659 new or added lines in 18 files covered. (79.06%)

1873 of 2154 relevant lines covered (86.95%)

0.87 hits per line

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

87.8
/src/main/java/edu/kit/datamanager/ro_crate/preview/CustomPreview.java
1
package edu.kit.datamanager.ro_crate.preview;
2

3
import com.fasterxml.jackson.databind.JsonNode;
4
import com.fasterxml.jackson.databind.ObjectMapper;
5
import edu.kit.datamanager.ro_crate.preview.model.ROCratePreviewModel;
6
import edu.kit.datamanager.ro_crate.util.ZipUtil;
7
import freemarker.template.Configuration;
8
import freemarker.template.Template;
9
import freemarker.template.TemplateException;
10
import freemarker.template.TemplateExceptionHandler;
11
import java.io.File;
12
import java.io.FileOutputStream;
13
import java.io.FileWriter;
14
import java.io.IOException;
15
import java.io.OutputStreamWriter;
16
import java.io.Writer;
17
import java.util.ArrayList;
18
import java.util.Collections;
19
import java.util.HashMap;
20
import java.util.LinkedList;
21
import java.util.List;
22
import java.util.Map;
23
import net.lingala.zip4j.ZipFile;
24
import net.lingala.zip4j.exception.ZipException;
25
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
26
import org.apache.commons.io.FileUtils;
27
import org.slf4j.Logger;
28
import org.slf4j.LoggerFactory;
29

30
/**
31
 * This class generates a custom preview without requiring external
32
 * dependencies, i.e., rochtml. Therefore, the FreeMarker template located under
33
 * resources/templates/custom_preview.ftl is used.
34
 *
35
 * @author jejkal
36
 */
37
public class CustomPreview implements CratePreview {
38

39
    private final static Logger logger = LoggerFactory.getLogger(CustomPreview.class);
1✔
40

41
    private final Configuration cfg;
42
    private Template template = null;
1✔
43

44
    public CustomPreview() {
1✔
45
        cfg = new Configuration(Configuration.VERSION_2_3_34);
1✔
46
        cfg.setClassForTemplateLoading(CustomPreview.class, "/");
1✔
47
        cfg.setDefaultEncoding("UTF-8");
1✔
48
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
1✔
49
        try {
50
            template = cfg.getTemplate("templates/custom_preview.ftl");
1✔
NEW
51
        } catch (IOException ex) {
×
NEW
52
            logger.error("Failed to read template for CustomPreview.", ex);
×
53
        }
1✔
54
    }
1✔
55

56
    private ROCratePreviewModel mapFromJson(String metadata) throws IOException {
57
        ObjectMapper mapper = new ObjectMapper();
1✔
58
        JsonNode root = (JsonNode) mapper.readValue(metadata, JsonNode.class);
1✔
59
        JsonNode graph = root.get("@graph");
1✔
60
        ROCratePreviewModel.ROCrate crate = new ROCratePreviewModel.ROCrate();
1✔
61
        List<ROCratePreviewModel.Dataset> datasets = new ArrayList<>();
1✔
62
        List<ROCratePreviewModel.File> files = new ArrayList<>();
1✔
63

64
        if (graph.isArray()) {
1✔
65

66
            for (JsonNode node : graph) {
1✔
67
                String id = node.get("@id").asText();
1✔
68
                List<String> types = new LinkedList<>();
1✔
69
                if (node.get("@type").isArray()) {
1✔
70

NEW
71
                    Collections.addAll(types, (String[]) mapper.convertValue(node.get("@type"), String[].class));
×
72
                } else {
73
                    types.add(node.get("@type").asText());
1✔
74
                }
75

76
                if (types.contains("Dataset") && "./".equals(id)) {
1✔
77
                    crate.name = node.get("name").asText();
1✔
78
                    crate.description = node.get("description") == null ? null : node.get("description").asText();
1✔
79
                    crate.type = "Dataset";
1✔
80
                    if (node.get("license") != null) {
1✔
81
                        crate.license = node.get("license").isObject() ? node.get("license").get("@id").asText() : node.get("license").asText();
1✔
82
                    }
83
                    crate.datePublished = node.get("datePublished") == null ? null : node.get("datePublished").asText();
1✔
84
                    crate.hasPart = new ArrayList<>();
1✔
85

86
                    if (node.has("hasPart")) {
1✔
87
                        for (JsonNode part : node.get("hasPart")) {
1✔
88
                            ROCratePreviewModel.Part p = new ROCratePreviewModel.Part();
1✔
89
                            if (part.isObject()) {
1✔
90
                                p.id = part.get("@id").asText();
1✔
91
                                p.name = part.get("@id").asText(); // Name will be replaced later
1✔
92
                            } else {
93
                                p.id = part.asText();
1✔
94
                            }
95
                            
96
                            crate.hasPart.add(p);
1✔
97
                        }
1✔
98
                    }
99
                } else if (types.contains("Dataset")) {
1✔
100
                    ROCratePreviewModel.Dataset dataset = new ROCratePreviewModel.Dataset();
1✔
101
                    dataset.id = id;
1✔
102
                    dataset.name = node.get("name").asText();
1✔
103
                    dataset.description = node.get("description").asText();
1✔
104
                    datasets.add(dataset);
1✔
105
                } else if (types.contains("File")) {
1✔
106
                    ROCratePreviewModel.File file = new ROCratePreviewModel.File();
1✔
107
                    file.id = id;
1✔
108
                    file.name = node.get("name") == null ? null : node.get("name").asText();
1✔
109
                    file.description = node.get("description") == null ? null : node.get("description").asText();
1✔
110
                    file.contentSize = node.get("contentSize") == null ? null : node.get("contentSize").asText();
1✔
111
                    file.encodingFormat = node.get("encodingFormat") == null ? null : node.get("encodingFormat").asText();
1✔
112
                    files.add(file);
1✔
113
                }
114
            }
1✔
115
        }
116

117
        // Update Part names using dataset and file lists
118
        if (crate.hasPart != null) {
1✔
119
            for (ROCratePreviewModel.Part part : crate.hasPart) {
1✔
120
                for (ROCratePreviewModel.Dataset dataset : datasets) {
1✔
121
                    if (dataset.id.equals(part.id) && dataset.name != null) {
1✔
122
                        part.name = dataset.name;
1✔
123
                    }
124
                }
1✔
125
                for (ROCratePreviewModel.File file : files) {
1✔
126
                    if (file.id.equals(part.id) && file.name != null) {
1✔
127
                        part.name = file.name;
1✔
128
                    }
129
                }
1✔
130
            }
1✔
131
        }
132

133
        ROCratePreviewModel model = new ROCratePreviewModel();
1✔
134
        model.crate = crate;
1✔
135
        model.datasets = datasets;
1✔
136
        model.files = files;
1✔
137
        return model;
1✔
138
    }
139

140
    @Override
141
    public void saveAllToZip(ZipFile zipFile) throws IOException {
142
        if (template == null) {
1✔
NEW
143
            throw new IOException("Preview template did not load. Unable to proceed.");
×
144
        }
145
        if (zipFile == null) {
1✔
NEW
146
            throw new IOException("Argument zipFile must not be null.");
×
147
        }
148
        try {
149
            zipFile.extractFile("ro-crate-metadata.json", "temp");
1✔
150
        } catch (ZipException ex) {
1✔
151
            throw new IOException("ro-crate-metadata.json not found in provided ZIP.", ex);
1✔
152
        }
1✔
153

154
        String metadata = FileUtils.readFileToString(new File("temp/ro-crate-metadata.json"), "UTF-8");
1✔
155
        try {
156
            Map<String, Object> dataModel = new HashMap<>();
1✔
157
            dataModel.put("crateModel", mapFromJson(metadata));
1✔
158

159
            try (Writer out = new OutputStreamWriter(new FileOutputStream("temp/ro-crate-preview.html"))) {
1✔
160
                template.process(dataModel, out);
1✔
161
                out.flush();
1✔
162
            }
163
            zipFile.addFile("temp/ro-crate-preview.html");
1✔
NEW
164
        } catch (TemplateException ex) {
×
NEW
165
            throw new IOException("Failed to generate preview.", ex);
×
166
        } finally {
167
            try {
168
                FileUtils.deleteDirectory(new File("temp"));
1✔
NEW
169
            } catch (IOException ex) {
×
170
                //ignore
171
            }
1✔
172
        }
173
    }
1✔
174

175
    @Override
176
    public void saveAllToFolder(File folder) throws IOException {
177
        if (template == null) {
1✔
NEW
178
            throw new IOException("Preview template did not load. Unable to proceed.");
×
179
        }
180
        if (folder == null || !folder.exists()) {
1✔
181
            throw new IOException("Preview target folder " + folder + " does not exist.");
1✔
182
        }
183
        String metadata = FileUtils.readFileToString(new File(folder, "ro-crate-metadata.json"), "UTF-8");
1✔
184
        try {
185
            Map<String, Object> dataModel = new HashMap<>();
1✔
186
            dataModel.put("crateModel", mapFromJson(metadata));
1✔
187
            try (Writer out = new OutputStreamWriter(new FileOutputStream(new File(folder, "ro-crate-preview.html")))) {
1✔
188
                template.process(dataModel, out);
1✔
189
                out.flush();
1✔
190
            }
NEW
191
        } catch (TemplateException ex) {
×
NEW
192
            throw new IOException("Failed to generate preview.", ex);
×
193
        }
1✔
194
    }
1✔
195

196
    @Override
197
    public void saveAllToStream(String metadata, ZipOutputStream stream) throws IOException {
198
        if (template == null) {
1✔
NEW
199
            throw new IOException("Preview template did not load. Unable to proceed.");
×
200
        }
201
        try {
202
            //prepare metadata for template
203
            Map<String, Object> dataModel = new HashMap<>();
1✔
204
            dataModel.put("crateModel", mapFromJson(metadata));
1✔
205

206
            //prepare output folder and writer
207
            FileUtils.forceMkdir(new File("temp"));
1✔
208
            //load and process template
209
            try (FileWriter writer = new FileWriter(new File("temp/ro-crate-preview.html"))) {
1✔
210
                //load and process template
211
                template.process(dataModel, writer);
1✔
212
                writer.flush();
1✔
213
            }
214

215
            ZipUtil.addFileToZipStream(stream, new File("temp/ro-crate-preview.html"), "ro-crate-preview.html");
1✔
NEW
216
        } catch (TemplateException ex) {
×
NEW
217
            throw new IOException("Failed to generate preview.", ex);
×
218
        } finally {
219
            try {
220
                FileUtils.deleteDirectory(new File("temp"));
1✔
NEW
221
            } catch (IOException ex) {
×
222
                //ignore
223
            }
1✔
224
        }
225
    }
1✔
226

227
}
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

© 2025 Coveralls, Inc