Conflict when creating a LogisticsObject with linked but non-existent LogisticsObjects
If a link to a logistics object that does not yet exist is specified when creating a logistics object, the linked logistics object is created in the RDF memory, but without LogisticsObjectMetaData. This leads to a 409 conflict if an attempt is made to create the linked LogisticsObject. As it is not possible to create more than one LogisticsObject per request, the only alternative is to create one LogisticsObject, create the second LogisticsObject and then patch both to (back)link them.
This only happens if the @type of the linked object is specified, because then a https://1r.example.com/logistics-objects/8a76ed85-959e-45d5-8c42-5fd39c08efb1 rdf:type cargo:Shipment is added to the RDFstore, while if the @type is missing, only the triple https://1r.example.com/logistics-objects/1a8ded38-1804-467c-a369-81a411416b7c cargo:shipment https://1r.example.com/logistics-objects/8a76ed85-959e-45d5-8c42-5fd39c08efb1 is added.
In addition, a GET request of the second linked LogisticsObject returns 500 Internal Server Error because no metadata is provided. It might be reasonable to return 404 instead?
Examples
{
"@context": {
"@vocab": "https://onerecord.iata.org/ns/cargo#"
},
"@type": "Waybill",
"@id": "https://1r.example.com/logistics-objects/1a8ded38-1804-467c-a369-81a411416b7c"
"shipment": {
"@id": "https://1r.example.com/logistics-objects/8a76ed85-959e-45d5-8c42-5fd39c08efb1",
"@type": "Shipment"
},
"waybillNumber": "12345675",
"waybillPrefix": "020"
}
{
"@context": {
"@vocab": "https://onerecord.iata.org/ns/cargo#"
},
"@id": "https://1r.example.com/logistics-objects/8a76ed85-959e-45d5-8c42-5fd39c08efb1",
"@type": "Shipment",
"waybill": {
"@id": "https://1r.example.com/logistics-objects/1a8ded38-1804-467c-a369-81a411416b7c"
}
}
Then the creation of the shipment with logisticsObjectID https://1r.example.com/logistics-objects/8a76ed85-959e-45d5-8c42-5fd39c08efb1
results in 409 Conflict
Proposed fix
Extend checkIri in LogisticsObjectService by checking also the existence of LogisticsObjectMetadata:
private void checkIri(LogisticsObject logisticsObject, RepositoryConnection connection) {
var iri = logisticsObject.iri();
// Check for proper address path.
if (!iri.toString().contains(idProvider.getLogisticsObjectBaseIri().toString())) {
throw new InvalidAddressException(iri, idProvider.getLogisticsObjectBaseIri());
}
// Check if IRI is already taken.
Optional<LogisticsObject> entity = loRepository.findByIri(iri, connection);
// Check also if LogisticsObjectMetadata exists
Optional<LogisticsObjectMetadata> logisticsObjectMetadata = metadataRepository.getMetadataOfSubject(iri, connection);
entity.ifPresent(e -> {
logisticsObjectMetadata.ifPresent(l -> {
throw new AlreadyExistsException(e.iri().stringValue());
});
});
}