Skip to content

Commit 55648fd

Browse files
committed
feat: create provenance entity per library version and keep old ones
1 parent 501060d commit 55648fd

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
lines changed

src/main/java/edu/kit/datamanager/ro_crate/writer/ProvenanceManager.java

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import edu.kit.datamanager.ro_crate.util.VersionProvider;
77

88
import java.time.Instant;
9-
import java.util.UUID;
109

1110
import static edu.kit.datamanager.ro_crate.entities.contextual.ContextualEntity.ContextualEntityBuilder;
1211

@@ -15,7 +14,18 @@
1514
* Handles the creation and updating of ro-crate-java entity and its actions.
1615
*/
1716
class ProvenanceManager {
18-
private static final String RO_CRATE_JAVA_ID = "#ro-crate-java";
17+
private record IdPrefix(String prefix) {
18+
public String withSuffix(String suffix) {
19+
return prefix + "-" + suffix;
20+
}
21+
22+
@Override
23+
public String toString() {
24+
return prefix;
25+
}
26+
}
27+
28+
private static final IdPrefix RO_CRATE_JAVA_ID = new IdPrefix("#ro-crate-java");
1929

2030
protected VersionProvider versionProvider;
2131

@@ -35,47 +45,52 @@ public ProvenanceManager(VersionProvider versionProvider) {
3545
this.versionProvider = versionProvider;
3646
}
3747

48+
public String getLibraryId() {
49+
return RO_CRATE_JAVA_ID.withSuffix(versionProvider.getVersion().toLowerCase());
50+
}
51+
3852
void addProvenanceInformation(Crate crate) {
3953
// Determine if this is the first write
40-
boolean isFirstWrite = !crate.getJsonMetadata().contains(RO_CRATE_JAVA_ID) && !crate.isImported();
54+
boolean isFirstWrite = crate.getAllContextualEntities().stream().noneMatch(
55+
entity -> entity.getId().startsWith(RO_CRATE_JAVA_ID.toString()))
56+
&& !crate.isImported();
57+
58+
String libraryId = this.getLibraryId();
4159

4260
// Create action entity first
43-
String actionId = "#" + UUID.randomUUID();
44-
ContextualEntity actionEntity = createActionEntity(actionId, isFirstWrite);
61+
ContextualEntity actionEntity = createActionEntity(isFirstWrite, libraryId);
4562

4663
// Create or update ro-crate-java entity
47-
ContextualEntity roCrateJavaEntity = buildRoCrateJavaEntity(crate, actionId, isFirstWrite);
64+
ContextualEntity roCrateJavaEntity = buildRoCrateJavaEntity(crate, actionEntity.getId(), libraryId);
4865

4966
// Add entities to crate
5067
crate.addContextualEntity(roCrateJavaEntity);
5168
crate.addContextualEntity(actionEntity);
5269
}
5370

54-
private ContextualEntity createActionEntity(String actionId, boolean isFirstWrite) {
71+
private ContextualEntity createActionEntity(boolean isFirstWrite, String libraryId) {
5572
return new ContextualEntityBuilder()
56-
.setId(actionId)
5773
.addType(isFirstWrite ? "CreateAction" : "UpdateAction")
5874
.addProperty("startTime", Instant.now().toString())
59-
.addIdProperty("agent", RO_CRATE_JAVA_ID)
75+
.addIdProperty("agent", libraryId)
6076
.build();
6177
}
6278

6379
private ContextualEntity buildRoCrateJavaEntity(
6480
Crate crate,
6581
String newActionId,
66-
boolean isFirstWrite
82+
String libraryId
6783
) {
84+
String version = this.versionProvider.getVersion();
6885
ContextualEntity self = crate.getAllContextualEntities().stream()
69-
.filter(contextualEntity -> RO_CRATE_JAVA_ID.equals(contextualEntity.getId()))
86+
.filter(contextualEntity -> libraryId.equals(contextualEntity.getId()))
7087
.findFirst()
7188
.orElseGet(() -> {
72-
String version = this.versionProvider.getVersion();
7389
return new ContextualEntityBuilder()
74-
.setId(RO_CRATE_JAVA_ID)
90+
.setId(libraryId)
7591
.addType("SoftwareApplication")
7692
.addProperty("name", "ro-crate-java")
7793
.addProperty("url", "https://github.com/kit-data-manager/ro-crate-java")
78-
// TODO read software version and version from gradle (write into resources properties file when building and read it from there)
7994
.addProperty("version", version)
8095
.addProperty("softwareVersion", version)
8196
.addProperty("license", "Apache-2.0")

src/test/java/edu/kit/datamanager/ro_crate/writer/RoCrateMetadataGenerationTest.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020

2121
class RoCrateMetadataGenerationTest {
2222

23+
private final String currentVersionId = new ProvenanceManager().getLibraryId();
24+
private final String oldVersionId = new ProvenanceManager(() -> "1.0.0").getLibraryId();
25+
private final String newVersionId = new ProvenanceManager(() -> "2.5.3").getLibraryId();
26+
2327
private final ObjectMapper objectMapper = new ObjectMapper();
2428
private Validator validator;
2529

@@ -55,7 +59,7 @@ void should_ContainRoCrateJavaEntities_When_WritingEmptyCrate(@TempDir Path temp
5559
JsonNode graph = rootNode.get("@graph");
5660

5761
// Find ro-crate-java entity
58-
JsonNode roCrateJavaEntity = findEntityById(graph, "#ro-crate-java");
62+
JsonNode roCrateJavaEntity = findEntityById(graph, this.currentVersionId);
5963
assertNotNull(roCrateJavaEntity, "ro-crate-java entity should exist");
6064
assertEquals("SoftwareApplication", roCrateJavaEntity.get("@type").asText(),
6165
"ro-crate-java should be of type SoftwareApplication");
@@ -64,7 +68,7 @@ void should_ContainRoCrateJavaEntities_When_WritingEmptyCrate(@TempDir Path temp
6468
JsonNode createActionEntity = findEntityByType(graph, "CreateAction");
6569
assertNotNull(createActionEntity, "CreateAction entity should exist");
6670
assertNotNull(createActionEntity.get("startTime"), "CreateAction should have startTime");
67-
assertEquals("#ro-crate-java", createActionEntity.get("agent").get("@id").asText(),
71+
assertEquals(this.currentVersionId, createActionEntity.get("agent").get("@id").asText(),
6872
"CreateAction should reference ro-crate-java as agent");
6973
}
7074

@@ -86,7 +90,7 @@ void should_HaveRequiredPropertiesInRoCrateJavaEntity_When_WritingCrate(@TempDir
8690

8791
// Parse metadata file
8892
JsonNode rootNode = objectMapper.readTree(metadata);
89-
JsonNode roCrateJavaEntity = findEntityById(rootNode.get("@graph"), "#ro-crate-java");
93+
JsonNode roCrateJavaEntity = findEntityById(rootNode.get("@graph"), this.currentVersionId);
9094

9195
assertNotNull(roCrateJavaEntity, "ro-crate-java entity should exist");
9296
assertEquals("ro-crate-java", roCrateJavaEntity.get("name").asText(),
@@ -119,7 +123,7 @@ void should_HaveBidirectionalRelation_Between_RoCrateJavaAndItsAction(@TempDir P
119123
JsonNode graph = rootNode.get("@graph");
120124

121125
// Get both entities
122-
JsonNode roCrateJavaEntity = findEntityById(graph, "#ro-crate-java");
126+
JsonNode roCrateJavaEntity = findEntityById(graph, this.currentVersionId);
123127
JsonNode createActionEntity = findEntityByType(graph, "CreateAction");
124128

125129
assertNotNull(roCrateJavaEntity, "ro-crate-java entity should exist");
@@ -128,7 +132,7 @@ void should_HaveBidirectionalRelation_Between_RoCrateJavaAndItsAction(@TempDir P
128132
// Test CreateAction -> ro-crate-java reference
129133
JsonNode agentRef = createActionEntity.get("agent");
130134
assertNotNull(agentRef, "CreateAction should have agent property");
131-
assertEquals("#ro-crate-java", agentRef.get("@id").asText(),
135+
assertEquals(this.currentVersionId, agentRef.get("@id").asText(),
132136
"CreateAction's agent should reference ro-crate-java");
133137

134138
// Test ro-crate-java -> CreateAction reference
@@ -162,7 +166,7 @@ void should_AccumulateActions_When_WritingMultipleTimes(@TempDir Path tempDir) t
162166
JsonNode graph = rootNode.get("@graph");
163167

164168
// Get ro-crate-java entity
165-
JsonNode roCrateJavaEntity = findEntityById(graph, "#ro-crate-java");
169+
JsonNode roCrateJavaEntity = findEntityById(graph, this.currentVersionId);
166170
assertNotNull(roCrateJavaEntity, "ro-crate-java entity should exist");
167171

168172
// Verify actions array exists and has three entries
@@ -183,14 +187,14 @@ void should_AccumulateActions_When_WritingMultipleTimes(@TempDir Path tempDir) t
183187

184188
// Verify CreateAction properties
185189
assertNotNull(createAction.get("startTime"), "CreateAction should have startTime");
186-
assertEquals("#ro-crate-java", createAction.get("agent").get("@id").asText(),
190+
assertEquals(this.currentVersionId, createAction.get("agent").get("@id").asText(),
187191
"CreateAction should reference ro-crate-java as agent");
188192

189193
// Verify UpdateAction properties
190194
for (JsonNode updateAction : updateActions) {
191195
assertNotNull(updateAction.get("startTime"),
192196
"UpdateAction should have startTime");
193-
assertEquals("#ro-crate-java", updateAction.get("agent").get("@id").asText(),
197+
assertEquals(this.currentVersionId, updateAction.get("agent").get("@id").asText(),
194198
"UpdateAction should reference ro-crate-java as agent");
195199
}
196200

@@ -222,7 +226,7 @@ void should_HaveValidVersionFormat_When_WritingCrate(@TempDir Path tempDir) thro
222226

223227
// Parse metadata file
224228
JsonNode rootNode = objectMapper.readTree(metadata);
225-
JsonNode roCrateJavaEntity = findEntityById(rootNode.get("@graph"), "#ro-crate-java");
229+
JsonNode roCrateJavaEntity = findEntityById(rootNode.get("@graph"), this.currentVersionId);
226230

227231
// Version format validation
228232
@SuppressWarnings("DataFlowIssue")
@@ -256,7 +260,7 @@ void should_HaveCompleteMetadata_When_WritingCrate(@TempDir Path tempDir) throws
256260

257261
// Parse metadata file
258262
JsonNode rootNode = objectMapper.readTree(metadata);
259-
JsonNode roCrateJavaEntity = findEntityById(rootNode.get("@graph"), "#ro-crate-java");
263+
JsonNode roCrateJavaEntity = findEntityById(rootNode.get("@graph"), this.currentVersionId);
260264

261265
// Required properties with specific values
262266
assertEquals("ro-crate-java", roCrateJavaEntity.get("name").asText(),
@@ -301,7 +305,7 @@ void should_AddProvenanceInfo_When_ModifyingExistingCrateWithoutProvenance(@Temp
301305

302306
JsonNode originalRoot = objectMapper.readTree(originalMetadata);
303307
JsonNode originalGraph = originalRoot.get("@graph");
304-
assertNull(findEntityById(originalGraph, "#ro-crate-java"),
308+
assertNull(findEntityById(originalGraph, this.currentVersionId),
305309
"Original crate should not have ro-crate-java entity");
306310
assertNull(findEntityByType(originalGraph, "CreateAction"),
307311
"Original crate should not have CreateAction");
@@ -326,7 +330,7 @@ void should_AddProvenanceInfo_When_ModifyingExistingCrateWithoutProvenance(@Temp
326330
JsonNode modifiedGraph = modifiedRoot.get("@graph");
327331

328332
// Verify ro-crate-java entity was added
329-
JsonNode roCrateJavaEntity = findEntityById(modifiedGraph, "#ro-crate-java");
333+
JsonNode roCrateJavaEntity = findEntityById(modifiedGraph, this.currentVersionId);
330334
assertNotNull(roCrateJavaEntity, "ro-crate-java entity should be added");
331335

332336
// Should only have UpdateAction, no CreateAction
@@ -339,7 +343,7 @@ void should_AddProvenanceInfo_When_ModifyingExistingCrateWithoutProvenance(@Temp
339343
// Verify update action properties
340344
assertNotNull(updateAction.get("startTime"),
341345
"UpdateAction should have startTime");
342-
assertEquals("#ro-crate-java",
346+
assertEquals(this.currentVersionId,
343347
updateAction.get("agent").get("@id").asText(),
344348
"UpdateAction should reference ro-crate-java as agent");
345349

@@ -390,7 +394,7 @@ void should_PreserveExistingProvenance_When_ModifyingCrate(@TempDir Path tempDir
390394
"Update should be after creation");
391395

392396
// Verify ro-crate-java entity references both actions
393-
JsonNode roCrateJavaEntity = findEntityById(graph, "#ro-crate-java");
397+
JsonNode roCrateJavaEntity = findEntityById(graph, this.currentVersionId);
394398
//noinspection DataFlowIssue
395399
assertTrue(roCrateJavaEntity.get("Action").isArray(),
396400
"ro-crate-java should have an array of actions");

0 commit comments

Comments
 (0)