1
1
package edu .kit .datamanager .ro_crate ;
2
2
3
+ import com .fasterxml .jackson .core .TreeNode ;
3
4
import com .fasterxml .jackson .databind .JsonNode ;
4
5
import com .fasterxml .jackson .databind .ObjectMapper ;
5
6
import com .fasterxml .jackson .databind .node .ObjectNode ;
8
9
import edu .kit .datamanager .ro_crate .context .RoCrateMetadataContext ;
9
10
import edu .kit .datamanager .ro_crate .entities .AbstractEntity ;
10
11
import edu .kit .datamanager .ro_crate .entities .contextual .ContextualEntity ;
12
+ import edu .kit .datamanager .ro_crate .entities .contextual .JsonDescriptor ;
11
13
import edu .kit .datamanager .ro_crate .entities .data .DataEntity ;
12
14
import edu .kit .datamanager .ro_crate .entities .data .RootDataEntity ;
13
15
import edu .kit .datamanager .ro_crate .externalproviders .dataentities .ImportFromDataCite ;
14
16
import edu .kit .datamanager .ro_crate .objectmapper .MyObjectMapper ;
15
17
import edu .kit .datamanager .ro_crate .payload .CratePayload ;
16
18
import edu .kit .datamanager .ro_crate .payload .RoCratePayload ;
17
19
import edu .kit .datamanager .ro_crate .preview .CratePreview ;
20
+ import edu .kit .datamanager .ro_crate .special .CrateVersion ;
18
21
import edu .kit .datamanager .ro_crate .special .JsonUtilFunctions ;
19
22
import edu .kit .datamanager .ro_crate .validation .JsonSchemaValidation ;
20
23
import edu .kit .datamanager .ro_crate .validation .Validator ;
21
24
22
25
import java .io .File ;
26
+ import java .net .URI ;
23
27
import java .util .ArrayList ;
24
28
import java .util .Collection ;
29
+ import java .util .Collections ;
25
30
import java .util .List ;
31
+ import java .util .Optional ;
32
+ import java .util .stream .Collectors ;
33
+ import java .util .stream .StreamSupport ;
26
34
27
35
/**
28
36
* The class that represents a single ROCrate.
37
+ *
38
+ * To build or modify it, use a instance of {@link RoCrateBuilder}. In the case
39
+ * features of RO-Crate DRAFT specifications are needed, refer to
40
+ * {@link BuilderWithDraftFeatures} and its documentation.
29
41
*
30
42
* @author Nikola Tzotchev on 6.2.2022 г.
31
43
* @version 1
32
44
*/
33
45
public class RoCrate implements Crate {
34
46
35
- private static final String ID = "ro-crate-metadata.json" ;
36
- private static final String RO_SPEC = "https://w3id.org/ro/crate/1.1" ;
37
-
38
47
private final CratePayload roCratePayload ;
39
48
private CrateMetadataContext metadataContext ;
40
49
private CratePreview roCratePreview ;
@@ -81,7 +90,7 @@ public RoCrate() {
81
90
this .metadataContext = new RoCrateMetadataContext ();
82
91
rootDataEntity = new RootDataEntity .RootDataEntityBuilder ()
83
92
.build ();
84
- jsonDescriptor = createDefaultJsonDescriptor ();
93
+ jsonDescriptor = new JsonDescriptor ();
85
94
}
86
95
87
96
/**
@@ -95,12 +104,44 @@ public RoCrate(RoCrateBuilder roCrateBuilder) {
95
104
this .metadataContext = roCrateBuilder .metadataContext ;
96
105
this .roCratePreview = roCrateBuilder .preview ;
97
106
this .rootDataEntity = roCrateBuilder .rootDataEntity ;
98
- this .jsonDescriptor = roCrateBuilder .jsonDescriptor ;
107
+ this .jsonDescriptor = roCrateBuilder .descriptorBuilder . build () ;
99
108
this .untrackedFiles = roCrateBuilder .untrackedFiles ;
100
109
Validator defaultValidation = new Validator (new JsonSchemaValidation ());
101
110
defaultValidation .validate (this );
102
111
}
103
112
113
+ @ Override
114
+ public Optional <CrateVersion > getVersion () {
115
+ JsonNode conformsTo = this .jsonDescriptor .getProperty ("conformsTo" );
116
+ if (conformsTo .isArray ()) {
117
+ return StreamSupport .stream (conformsTo .spliterator (), false )
118
+ .filter (TreeNode ::isObject )
119
+ .map (obj -> obj .path ("@id" ).asText ())
120
+ .map (CrateVersion ::fromSpecUri )
121
+ .filter (Optional ::isPresent )
122
+ .map (Optional ::get )
123
+ .findFirst ();
124
+ } else if (conformsTo .isObject ()) {
125
+ return CrateVersion .fromSpecUri (conformsTo .get ("@id" ).asText ());
126
+ } else {
127
+ return Optional .empty ();
128
+ }
129
+ }
130
+
131
+ @ Override
132
+ public Collection <String > getProfiles () {
133
+ JsonNode conformsTo = this .jsonDescriptor .getProperty ("conformsTo" );
134
+ if (conformsTo .isArray ()) {
135
+ return StreamSupport .stream (conformsTo .spliterator (), false )
136
+ .filter (TreeNode ::isObject )
137
+ .map (obj -> obj .path ("@id" ).asText ())
138
+ .filter (txt -> !CrateVersion .fromSpecUri (txt ).isPresent ())
139
+ .collect (Collectors .toSet ());
140
+ } else {
141
+ return Collections .emptySet ();
142
+ }
143
+ }
144
+
104
145
@ Override
105
146
public String getJsonMetadata () {
106
147
ObjectMapper objectMapper = MyObjectMapper .getMapper ();
@@ -201,28 +242,20 @@ public List<File> getUntrackedFiles() {
201
242
return this .untrackedFiles ;
202
243
}
203
244
204
- protected static ContextualEntity createDefaultJsonDescriptor () {
205
- return new ContextualEntity .ContextualEntityBuilder ()
206
- .setId (ID )
207
- .addType ("CreativeWork" )
208
- .addIdProperty ("about" , "./" )
209
- .addIdProperty ("conformsTo" , RoCrate .RO_SPEC )
210
- .build ();
211
- }
212
-
213
245
/**
214
246
* The inner class builder for the easier creation of a ROCrate.
215
247
*/
216
- public static final class RoCrateBuilder {
248
+ public static class RoCrateBuilder {
217
249
218
250
CratePayload payload ;
219
251
CratePreview preview ;
220
252
CrateMetadataContext metadataContext ;
221
253
ContextualEntity license ;
222
254
RootDataEntity rootDataEntity ;
223
- ContextualEntity jsonDescriptor ;
224
255
List <File > untrackedFiles ;
225
256
257
+ JsonDescriptor .Builder descriptorBuilder = new JsonDescriptor .Builder ();
258
+
226
259
/**
227
260
* The default constructor of a builder.
228
261
*
@@ -237,7 +270,6 @@ public RoCrateBuilder(String name, String description) {
237
270
.addProperty ("name" , name )
238
271
.addProperty ("description" , description )
239
272
.build ();
240
- jsonDescriptor = RoCrate .createDefaultJsonDescriptor ();
241
273
}
242
274
243
275
/**
@@ -250,7 +282,6 @@ public RoCrateBuilder() {
250
282
this .metadataContext = new RoCrateMetadataContext ();
251
283
rootDataEntity = new RootDataEntity .RootDataEntityBuilder ()
252
284
.build ();
253
- jsonDescriptor = RoCrate .createDefaultJsonDescriptor ();
254
285
}
255
286
256
287
/**
@@ -263,8 +294,8 @@ public RoCrateBuilder(RoCrate crate) {
263
294
this .preview = crate .roCratePreview ;
264
295
this .metadataContext = crate .metadataContext ;
265
296
this .rootDataEntity = crate .rootDataEntity ;
266
- this .jsonDescriptor = crate .jsonDescriptor ;
267
297
this .untrackedFiles = crate .untrackedFiles ;
298
+ this .descriptorBuilder = new JsonDescriptor .Builder (crate );
268
299
}
269
300
270
301
/**
@@ -322,9 +353,67 @@ public RoCrateBuilder addUntrackedFile(File file) {
322
353
return this ;
323
354
}
324
355
356
+ /**
357
+ * Returns a crate with the information from this builder.
358
+ */
325
359
public RoCrate build () {
326
360
return new RoCrate (this );
327
361
}
328
362
}
329
363
364
+ /**
365
+ * Builder for Crates, supporting features which are not in a final
366
+ * specification yet.
367
+ *
368
+ * NOTE: This will change the specification version of your crate.
369
+ *
370
+ * We only add features we expect to be in the new specification in the
371
+ * end.
372
+ * In case a feature will not make it into the specification, we will mark it as
373
+ * deprecated and remove it in new major versions.
374
+ * If a feature is finalized, it will be added to the stable
375
+ * {@link RoCrateBuilder} and marked as deprecated in this class.
376
+ */
377
+ public static class BuilderWithDraftFeatures extends RoCrateBuilder {
378
+
379
+ /**
380
+ * @see RoCrateBuilder#RoCrateBuilder()
381
+ */
382
+ public BuilderWithDraftFeatures () {
383
+ super ();
384
+ }
385
+
386
+ /**
387
+ * @see RoCrateBuilder#RoCrateBuilder(String, String)
388
+ */
389
+ public BuilderWithDraftFeatures (String name , String description ) {
390
+ super ();
391
+ }
392
+
393
+ /**
394
+ * @see RoCrateBuilder#RoCrateBuilder(RoCrate)
395
+ */
396
+ public BuilderWithDraftFeatures (RoCrate crate ) {
397
+ super (crate );
398
+ this .descriptorBuilder = new JsonDescriptor .Builder (crate );
399
+ }
400
+
401
+ /**
402
+ * Indicate this crate also conforms to the given specification, in addition to
403
+ * the version this builder adds.
404
+ *
405
+ * This is helpful for profiles or other specifications the crate conforms to.
406
+ * Can be called multiple times to add more specifications.
407
+ *
408
+ * @param specification a specification or profile this crate conforms to.
409
+ * @return the builder
410
+ */
411
+ public BuilderWithDraftFeatures alsoConformsTo (URI specification ) {
412
+ descriptorBuilder
413
+ .addConformsTo (specification )
414
+ // usage of a draft feature results in draft version numbers of the crate
415
+ .setVersion (CrateVersion .LATEST_UNSTABLE );
416
+ return this ;
417
+ }
418
+ }
330
419
}
0 commit comments