Skip to content

ChangeRequest to add blank nodes fails

It seems that the handling/preprocessing of blank nodes in ChangeRequests does not work correctly. Perhaps empty nodes in the Change object should be replaced by internal neone ids?

This could affect compatibility with other ONE-Record client/server implementations as ne-one require specific bNode IDs.

Tested with commit 0db3006bd7f3b6bc80a2f5c5cf144f87b7e08ba6 and commit 1898d22eb63b2e260807a6721e411f3d63b133f0

Steps to reproduce:

1. Create LogisticsObject

{    
    "@type": "https://onerecord.iata.org/ns/cargo#Piece",
    "@id": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a56",
    "https://onerecord.iata.org/ns/cargo#goodsDescription": "something"    
}

2a. Add Embedded Object to LogisticsObject with _:b0 (fails)

{
    "@context": {
        "cargo": "https://onerecord.iata.org/ns/cargo#",
        "api": "https://onerecord.iata.org/ns/api#"
    },
    "@type": "api:Change",
    "api:hasLogisticsObject": {
        "@id": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a56"
    },
    "api:hasDescription": "Add grossWeight",
    "api:hasOperation": [
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a56",
            "api:p": "https://onerecord.iata.org/ns/cargo#grossWeight",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "https://onerecord.iata.org/ns/cargo#Value",
                    "api:hasValue": "_:b0"
                }
            ]
        },
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "_:b0",
            "api:p": "https://onerecord.iata.org/ns/cargo#unit",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "http://www.w3.org/2001/XMLSchema#string",
                    "api:hasValue": "KGM"
                }
            ]
        },
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "_:b0",
            "api:p": "https://onerecord.iata.org/ns/cargo#value",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "http://www.w3.org/2001/XMLSchema#double",
                    "api:hasValue": "20.0"
                }
            ]
        }
    ],
    "api:hasRevision": {
        "@type": "http://www.w3.org/2001/XMLSchema#positiveInteger",
        "@value": "1"
    }
}

Result:

After accepting the ChangeRequest (e.g. by scheduled trigger):
```bash
2023-12-01 09:38:52,100 WARN  [org.ope.neo.rep.RepositoryTransaction] (vert.x-worker-thread-2) Exception during transaction, rolling back transaction: java.lang.IllegalArgumentException: IRI must be absolute
        at org.eclipse.rdf4j.model.impl.ValidatingValueFactory.createIRI(ValidatingValueFactory.java:72)
        at org.eclipse.rdf4j.model.util.Values.iri(Values.java:94)
        at org.eclipse.rdf4j.model.util.Values.iri(Values.java:80)
        at org.openlogisticsfoundation.neone.service.LogisticsObjectService.lambda$applyOperations$20(LogisticsObjectService.java:407)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
        at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1707)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
        at org.openlogisticsfoundation.neone.service.LogisticsObjectService.applyOperations(LogisticsObjectService.java:395)
        at org.openlogisticsfoundation.neone.service.LogisticsObjectService.acceptChangeRequest(LogisticsObjectService.java:317)
        at org.openlogisticsfoundation.neone.service.LogisticsObjectService.lambda$onChangeRequestUpdated$8(LogisticsObjectService.java:292)
        at org.openlogisticsfoundation.neone.repository.RepositoryTransaction.lambda$transactionallyDo$1(RepositoryTransaction.java:47)
        at org.openlogisticsfoundation.neone.repository.RepositoryTransaction.transactionallyGet(RepositoryTransaction.java:64)
        at org.openlogisticsfoundation.neone.repository.RepositoryTransaction.transactionallyDo(RepositoryTransaction.java:46)
        at org.openlogisticsfoundation.neone.repository.RepositoryTransaction_ClientProxy.transactionallyDo(Unknown Source)
        at org.openlogisticsfoundation.neone.service.LogisticsObjectService.onChangeRequestUpdated(LogisticsObjectService.java:286)
        at org.openlogisticsfoundation.neone.service.LogisticsObjectService_ClientProxy.onChangeRequestUpdated(Unknown Source)
        at org.openlogisticsfoundation.neone.service.LogisticsObjectService_VertxInvoker_onChangeRequestUpdated_4625f873faa7a096e68a815ba4134b092ba1a294.invokeBean(Unknown Source)
        at io.quarkus.vertx.runtime.EventConsumerInvoker.invoke(EventConsumerInvoker.java:45)
        at io.quarkus.vertx.runtime.VertxEventBusConsumerRecorder$3$1$2.call(VertxEventBusConsumerRecorder.java:142)
        at io.quarkus.vertx.runtime.VertxEventBusConsumerRecorder$3$1$2.call(VertxEventBusConsumerRecorder.java:138)
        at io.vertx.core.impl.ContextBase.lambda$executeBlocking$0(ContextBase.java:167)
        at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:277)
        at io.vertx.core.impl.ContextBase.lambda$internalExecuteBlocking$2(ContextBase.java:199)
        at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
        at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)

2b. Add Embedded Object to LogisticsObject with internal:b0 (works partly)

{
    "@context": {
        "cargo": "https://onerecord.iata.org/ns/cargo#",
        "api": "https://onerecord.iata.org/ns/api#"
    },
    "@type": "api:Change",
    "api:hasLogisticsObject": {
        "@id": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a57"
    },
    "api:hasDescription": "Add grossWeight",
    "api:hasOperation": [
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a57",
            "api:p": "https://onerecord.iata.org/ns/cargo#grossWeight",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "https://onerecord.iata.org/ns/cargo#Value",
                    "api:hasValue": "internal:b0"
                }
            ]
        },
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "internal:b0",
            "api:p": "https://onerecord.iata.org/ns/cargo#unit",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "http://www.w3.org/2001/XMLSchema#string",
                    "api:hasValue": "KGM"
                }
            ]
        },
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "internal:b0",
            "api:p": "https://onerecord.iata.org/ns/cargo#value",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "http://www.w3.org/2001/XMLSchema#double",
                    "api:hasValue": "20.0"
                }
            ]
        }
    ],
    "api:hasRevision": {
        "@type": "http://www.w3.org/2001/XMLSchema#positiveInteger",
        "@value": "1"
    }
}

Result:

{
    "@id": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a57",
    "@type": "Piece",
    "goodsDescription": "something",
    "grossWeight": {
        "@id": "internal:b0"
    },
    "@context": {
        "@vocab": "https://onerecord.iata.org/ns/cargo#"
    }
}

2c. Add Embedded Object to LogisticsObject with neone:12345 (works)

{
    "@context": {
        "cargo": "https://onerecord.iata.org/ns/cargo#",
        "api": "https://onerecord.iata.org/ns/api#"
    },
    "@type": "api:Change",
    "api:hasLogisticsObject": {
        "@id": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a58"
    },
    "api:hasDescription": "Add grossWeight",
    "api:hasOperation": [
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a58",
            "api:p": "https://onerecord.iata.org/ns/cargo#grossWeight",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "https://onerecord.iata.org/ns/cargo#Value",
                    "api:hasValue": "neone:12345"
                }
            ]
        },
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "neone:12345",
            "api:p": "https://onerecord.iata.org/ns/cargo#unit",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "http://www.w3.org/2001/XMLSchema#string",
                    "api:hasValue": "KGM"
                }
            ]
        },
        {
            "@type": "api:Operation",
            "api:op": {
                "@id": "api:ADD"
            },
            "api:s": "neone:12345",
            "api:p": "https://onerecord.iata.org/ns/cargo#value",
            "api:o": [
                {
                    "@type": "api:OperationObject",
                    "api:hasDatatype": "http://www.w3.org/2001/XMLSchema#double",
                    "api:hasValue": "20.0"
                }
            ]
        }
    ],
    "api:hasRevision": {
        "@type": "http://www.w3.org/2001/XMLSchema#positiveInteger",
        "@value": "1"
    }
}

Result:

{
    "@graph": [
        {
            "@id": "http://localhost:8080/logistics-objects/8d4cbec9-817a-4ab8-b07f-8802e4463a58",
            "@type": "Piece",
            "goodsDescription": "something",
            "grossWeight": {
                "@id": "neone:12345"
            }
        },
        {
            "@id": "neone:12345",
            "@type": "Value",
            "unit": "KGM",
            "value": {
                "@type": "http://www.w3.org/2001/XMLSchema#double",
                "@value": "20.0"
            }
        }
    ],
    "@context": {
        "@vocab": "https://onerecord.iata.org/ns/cargo#"
    }
}
Edited by Daniel A. Doeppner