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

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

29 Apr 2025 01:00PM UTC coverage: 86.311%. First build
#378

Pull #233

github

web-flow
Merge pull request #253 from kit-data-manager/fix-renaming-of-data-set-entities

Fix renaming of data set entities
Pull Request #233: Version 2.1.0

598 of 763 new or added lines in 29 files covered. (78.37%)

1879 of 2177 relevant lines covered (86.31%)

0.86 hits per line

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

80.83
/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.util.ZipUtil;
6
import freemarker.template.Configuration;
7
import freemarker.template.Template;
8
import freemarker.template.TemplateException;
9
import freemarker.template.TemplateExceptionHandler;
10
import java.io.File;
11
import java.io.FileOutputStream;
12
import java.io.FileWriter;
13
import java.io.IOException;
14
import java.io.OutputStreamWriter;
15
import java.io.Writer;
16
import java.util.ArrayList;
17
import java.util.Collections;
18
import java.util.HashMap;
19
import java.util.LinkedList;
20
import java.util.List;
21
import java.util.Map;
22
import net.lingala.zip4j.ZipFile;
23
import net.lingala.zip4j.exception.ZipException;
24
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
25
import org.apache.commons.io.FileUtils;
26
import org.slf4j.Logger;
27
import org.slf4j.LoggerFactory;
28

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

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

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

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

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

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

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

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

75
                if (types.contains("Dataset") && "./".equals(id)) {
1✔
76
                    crate.name = node.path("name").asText();
1✔
77
                    crate.description = node.path("description").asText(null);
1✔
78
                    crate.type = "Dataset";
1✔
79
                    crate.license = node.path("license").path("@id").asText(node.path("license").asText(null));
1✔
80
                    crate.datePublished = node.path("datePublished").asText(null);
1✔
81
                    crate.hasPart = new ArrayList<>();
1✔
82

83
                    for (JsonNode part : node.path("hasPart")) {
1✔
84
                        CustomPreviewModel.Part p = new CustomPreviewModel.Part();
1✔
85
                        String tmpId = part.path("@id").asText(part.asText());
1✔
86
                        p.id = tmpId;
1✔
87
                        p.name = tmpId; // Name will be replaced later
1✔
88
                        crate.hasPart.add(p);
1✔
89
                    }
1✔
90
                } else if (types.contains("Dataset")) {
1✔
NEW
91
                    CustomPreviewModel.Dataset dataset = new CustomPreviewModel.Dataset();
×
NEW
92
                    dataset.id = id;
×
NEW
93
                    dataset.name = node.path("name").asText();
×
NEW
94
                    dataset.description = node.path("description").asText();
×
NEW
95
                    datasets.add(dataset);
×
96
                } else if (types.contains("File")) {
1✔
97
                    CustomPreviewModel.File file = new CustomPreviewModel.File();
1✔
98
                    file.id = id;
1✔
99
                    file.name = node.path("name").asText(null);
1✔
100
                    file.description = node.path("description").asText(null);
1✔
101
                    file.contentSize = node.path("contentSize").asText(null);
1✔
102
                    file.encodingFormat = node.path("encodingFormat").asText(null);
1✔
103
                    files.add(file);
1✔
104
                }
105
            }
1✔
106
        }
107

108
        // Update Part names using dataset and file lists
109
        if (crate.hasPart != null) {
1✔
110
            for (CustomPreviewModel.Part part : crate.hasPart) {
1✔
111
                for (CustomPreviewModel.Dataset dataset : datasets) {
1✔
NEW
112
                    if (dataset.id.equals(part.id) && dataset.name != null) {
×
NEW
113
                        part.name = dataset.name;
×
114
                    }
NEW
115
                }
×
116
                for (CustomPreviewModel.File file : files) {
1✔
117
                    if (file.id.equals(part.id) && file.name != null) {
1✔
118
                        part.name = file.name;
1✔
119
                    }
120
                }
1✔
121
            }
1✔
122
        }
123

124
        CustomPreviewModel model = new CustomPreviewModel();
1✔
125
        model.crate = crate;
1✔
126
        model.datasets = datasets;
1✔
127
        model.files = files;
1✔
128
        return model;
1✔
129
    }
130

131
    @Override
132
    public void saveAllToZip(ZipFile zipFile) throws IOException {
133
        if (template == null) {
1✔
NEW
134
            throw new IOException("Preview template did not load. Unable to proceed.");
×
135
        }
136
        if (zipFile == null) {
1✔
NEW
137
            throw new IOException("Argument zipFile must not be null.");
×
138
        }
139
        try {
140
            zipFile.extractFile("ro-crate-metadata.json", "temp");
1✔
141
        } catch (ZipException ex) {
1✔
142
            throw new IOException("ro-crate-metadata.json not found in provided ZIP.", ex);
1✔
143
        }
1✔
144

145
        String metadata = FileUtils.readFileToString(new File("temp/ro-crate-metadata.json"), "UTF-8");
1✔
146
        try {
147
            Map<String, Object> dataModel = new HashMap<>();
1✔
148
            dataModel.put("crateModel", mapFromJson(metadata));
1✔
149

150
            try (Writer out = new OutputStreamWriter(new FileOutputStream("temp/ro-crate-preview.html"))) {
1✔
151
                template.process(dataModel, out);
1✔
152
                out.flush();
1✔
153
            }
154
            zipFile.addFile("temp/ro-crate-preview.html");
1✔
NEW
155
        } catch (TemplateException ex) {
×
NEW
156
            throw new IOException("Failed to generate preview.", ex);
×
157
        } finally {
158
            try {
159
                FileUtils.deleteDirectory(new File("temp"));
1✔
NEW
160
            } catch (IOException ex) {
×
161
                //ignore
162
            }
1✔
163
        }
164
    }
1✔
165

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

187
    @Override
188
    public void saveAllToStream(String metadata, ZipOutputStream stream) throws IOException {
189
        if (template == null) {
1✔
NEW
190
            throw new IOException("Preview template did not load. Unable to proceed.");
×
191
        }
192
        try {
193
            //prepare metadata for template
194
            Map<String, Object> dataModel = new HashMap<>();
1✔
195
            dataModel.put("crateModel", mapFromJson(metadata));
1✔
196

197
            //prepare output folder and writer
198
            FileUtils.forceMkdir(new File("temp"));
1✔
199
            //load and process template
200
            try (FileWriter writer = new FileWriter(new File("temp/ro-crate-preview.html"))) {
1✔
201
                //load and process template
202
                template.process(dataModel, writer);
1✔
203
                writer.flush();
1✔
204
            }
205

206
            ZipUtil.addFileToZipStream(stream, new File("temp/ro-crate-preview.html"), "ro-crate-preview.html");
1✔
NEW
207
        } catch (TemplateException ex) {
×
NEW
208
            throw new IOException("Failed to generate preview.", ex);
×
209
        } finally {
210
            try {
211
                FileUtils.deleteDirectory(new File("temp"));
1✔
NEW
212
            } catch (IOException ex) {
×
213
                //ignore
214
            }
1✔
215
        }
216
    }
1✔
217

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