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

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

01 Apr 2025 01:45PM UTC coverage: 88.589%. First build
#323

Pull #233

github

ThomasJejkal
Added zip stream writer, minor cleanup
Pull Request #233: CI trigger adjustments

34 of 82 new or added lines in 4 files covered. (41.46%)

1607 of 1814 relevant lines covered (88.59%)

0.89 hits per line

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

74.55
/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataEntity.java
1
package edu.kit.datamanager.ro_crate.entities.data;
2

3
import com.fasterxml.jackson.annotation.JsonIgnore;
4

5
import edu.kit.datamanager.ro_crate.entities.AbstractEntity;
6
import edu.kit.datamanager.ro_crate.entities.contextual.ContextualEntity;
7
import static edu.kit.datamanager.ro_crate.special.IdentifierUtils.isUrl;
8

9
import java.io.File;
10
import java.io.FileInputStream;
11
import java.io.IOException;
12
import java.io.InputStream;
13
import java.net.URI;
14
import java.nio.file.Path;
15
import java.util.ArrayList;
16
import java.util.List;
17
import net.lingala.zip4j.ZipFile;
18
import net.lingala.zip4j.exception.ZipException;
19
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
20
import net.lingala.zip4j.model.ZipParameters;
21
import org.apache.commons.io.FileUtils;
22

23
/**
24
 * The base class of every data entity.
25
 *
26
 * @author Nikola Tzotchev on 4.2.2022 г.
27
 * @version 1
28
 */
29
public class DataEntity extends AbstractEntity {
30

31
    @JsonIgnore
32
    private Path path;
33

34
    /**
35
     * The constructor that takes an DataEntity builder and instantiates the
36
     * entity.
37
     *
38
     * @param entityBuilder the builder passed as argument.
39
     */
40
    public DataEntity(AbstractDataEntityBuilder<?> entityBuilder) {
41
        super(entityBuilder);
1✔
42
        if (!entityBuilder.authors.isEmpty()) {
1✔
43
            this.addIdListProperties("author", entityBuilder.authors);
1✔
44
        }
45
        this.path = entityBuilder.location;
1✔
46
    }
1✔
47

48
    /**
49
     * Adds an author ID to the entity.
50
     *
51
     * Calling this multiple times will add multiple author IDs.
52
     *
53
     * @param id the identifier of the author.
54
     */
55
    public void addAuthorId(String id) {
56
        this.addIdProperty("author", id);
×
57
    }
×
58

59
    /**
60
     * If the data entity contains a physical file. This method will write it
61
     * when the crate is being written to a zip archive.
62
     *
63
     * @param zipFile the zipFile where it should be written.
64
     * @throws ZipException when something goes wrong with the writing to the
65
     * zip file.
66
     */
67
    public void saveToZip(ZipFile zipFile) throws ZipException {
68
        if (this.path != null) {
1✔
69
            ZipParameters zipParameters = new ZipParameters();
1✔
70
            zipParameters.setFileNameInZip(this.getId());
1✔
71
            zipFile.addFile(this.path.toFile(), zipParameters);
1✔
72
        }
73
    }
1✔
74

75
    /**
76
     * If the data entity contains a physical file. This method will write it
77
     * when the crate is being written to a zip archive.
78
     *
79
     * @param zipStream The zip output stream where it should be written.
80
     * @throws ZipException when something goes wrong with the writing to the
81
     * zip file.
82
     * @throws IOException If opening the file input stream fails.
83
     */
84
    public void saveToStream(ZipOutputStream zipStream) throws ZipException, IOException {
NEW
85
        if (this.path != null) {
×
NEW
86
            byte[] buff = new byte[4096];
×
87
            int readLen;
NEW
88
            ZipParameters zipParameters = new ZipParameters();
×
NEW
89
            zipParameters.setFileNameInZip(this.getId());
×
NEW
90
            zipStream.putNextEntry(zipParameters);
×
NEW
91
            try (InputStream inputStream = new FileInputStream(this.path.toFile())) {
×
NEW
92
                while ((readLen = inputStream.read(buff)) != -1) {
×
NEW
93
                    zipStream.write(buff, 0, readLen);
×
94
                }
95
            }
NEW
96
            zipStream.closeEntry();
×
97
        }
NEW
98
    }
×
99

100
    /**
101
     * If the data entity contains a physical file. This method will write it
102
     * when the crate is being written to a folder.
103
     *
104
     * @param file the folder location where the entity should be written.
105
     * @throws IOException if something goes wrong with the writing.
106
     */
107
    public void savetoFile(File file) throws IOException {
108
        if (this.getPath() != null) {
1✔
109
            if (this.getPath().toFile().isDirectory()) {
1✔
110
                FileUtils.copyDirectory(this.getPath().toFile(), file.toPath().resolve(this.getId()).toFile());
1✔
111
            } else {
112
                FileUtils.copyFile(this.getPath().toFile(), file.toPath().resolve(this.getId()).toFile());
1✔
113
            }
114
        }
115
    }
1✔
116

117
    @JsonIgnore
118
    public Path getPath() {
119
        return path;
1✔
120
    }
121

122
    abstract static class AbstractDataEntityBuilder<T extends AbstractDataEntityBuilder<T>> extends
1✔
123
            AbstractEntityBuilder<T> {
124

125
        private Path location;
126
        private List<String> authors = new ArrayList<>();
1✔
127

128
        /**
129
         * Sets the location of the data entity.
130
         *
131
         * If the ID has not been set manually in beforehand, it will be derived
132
         * from the path. Use {@link #setId(String)} to override it or set it in
133
         * beforehand. Note that another call of {@link #setLocation(Path)} will
134
         * not override the ID as it has been set by the previous call!
135
         *
136
         * @param path the location of the data. May be null, in which case
137
         * nothing happens.
138
         * @return this builder
139
         */
140
        public T setLocation(Path path) {
141
            if (path != null) {
1✔
142
                if (this.getId() == null) {
1✔
143
                    this.setId(path.getFileName().toString());
1✔
144
                }
145
                this.location = path;
1✔
146
            }
147
            return self();
1✔
148
        }
149

150
        /**
151
         * A variant of {@link #setLocation(Path)} which may throw exceptions.
152
         *
153
         * @param path the location of the data
154
         * @return this builder
155
         * @throws IllegalArgumentException if path is null
156
         */
157
        public T setLocationWithExceptions(Path path) throws IllegalArgumentException {
158
            if (path == null) {
1✔
159
                throw new IllegalArgumentException("The given path should not be null.");
×
160
            }
161
            return setLocation(path);
1✔
162
        }
163

164
        /**
165
         * Same as {@link #setLocation(Path)} but instead of associating this
166
         * entity with a file, it will point to some place on the internet.
167
         *
168
         * Via the specification, this means the uri will be set as the ID. This
169
         * call is therefore equivalent to {@link #setId(String)}.
170
         *
171
         * @param uri the URI, should point at the data reachable on the
172
         * internet.
173
         * @return this builder
174
         */
175
        public T setLocation(URI uri) {
176
            if (uri != null && this.getId() == null) {
1✔
177
                this.setId(uri.toString());
1✔
178
            }
179
            return self();
1✔
180
        }
181

182
        /**
183
         * A variant of {@link #setLocation(URI)} which may throw exceptions.
184
         *
185
         * @param uri the given uri
186
         * @return this builder
187
         * @throws IllegalArgumentException if uri is null or not a valid URL
188
         */
189
        public T setLocationWithExceptions(URI uri) throws IllegalArgumentException {
190
            if (!isUrl(uri.toString())) {
1✔
191
                throw new IllegalArgumentException("This Data Entity remote ID does not resolve to a valid URL.");
1✔
192
            }
193
            return setLocation(uri);
×
194
        }
195

196
        public T setLicense(String id) {
197
            this.addIdProperty("license", id);
1✔
198
            return self();
1✔
199
        }
200

201
        public T setLicense(ContextualEntity license) {
202
            this.addIdProperty("license", license.getId());
1✔
203
            return self();
1✔
204
        }
205

206
        public T addAuthor(String id) {
207
            this.authors.add(id);
1✔
208
            return self();
1✔
209
        }
210

211
        public T setContentLocation(String id) {
212
            this.addIdProperty("contentLocation", id);
1✔
213
            return self();
1✔
214
        }
215

216
        @Override
217
        public abstract DataEntity build();
218
    }
219

220
    /**
221
     * Data Entity builder class that allows for easier data entity creation.
222
     *
223
     * If not explicitly mentioned, all methods avoid Exceptions and will
224
     * silently ignore null-parameters, in which case nothing will happen. Use
225
     * the available *WithExceptions-methods in case you need them.
226
     */
227
    public static final class DataEntityBuilder extends AbstractDataEntityBuilder<DataEntityBuilder> {
1✔
228

229
        @Override
230
        public DataEntityBuilder self() {
231
            return this;
1✔
232
        }
233

234
        @Override
235
        public DataEntity build() {
236
            return new DataEntity(this);
1✔
237
        }
238
    }
239
}
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