Skip to content

Commit

Permalink
Only convert submodel references to IRIs.
Browse files Browse the repository at this point in the history
  • Loading branch information
kenwenzel committed Dec 13, 2024
1 parent 888d35d commit 1341408
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static Value toRdfValue(Object value, ValueFactory vf) {
if (id != Record.NULL) {
idStr = id.getValue() != null ? id.getValue().toString() : null;
}
if (idStr == null && "ModelReference".equals(r.first(URIs.createURI(AAS_NAMESPACE + "type")).getValue())) {
if (idStr == null) {
URI keysProperty = URIs.createURI(AAS_NAMESPACE + "keys");
Record keys = r.first(keysProperty);
Record firstKey = null;
Expand All @@ -55,10 +55,14 @@ static Value toRdfValue(Object value, ValueFactory vf) {
}
}

if (type != null && idStr != null) {
// System.out.println("ref: " + "urn:aas:" + type + ":" + idStr);
return vf.createIRI("urn:aas:" + type + ":" +
Base64.getEncoder().encodeToString(idStr.getBytes(StandardCharsets.UTF_8)));
if (idStr != null) {
switch (type) {
case "Submodel":
return vf.createIRI("urn:aas:" + type + ":" +
Base64.getEncoder().encodeToString(idStr.getBytes(StandardCharsets.UTF_8)));
default:
// do not convert the reference to an IRI
}
}
}

Expand All @@ -77,11 +81,13 @@ static Value toRdfValue(Object value, ValueFactory vf) {
}
}

if (type != null) {
String iriStr = "urn:aas:" + type + ":" +
Base64.getEncoder().encodeToString(idStr.getBytes(StandardCharsets.UTF_8));
// System.out.println("with value: " + iriStr);
return IRIWithValue.create(iriStr, value);
switch (type) {
case "Submodel":
String iriStr = "urn:aas:" + type + ":" +
Base64.getEncoder().encodeToString(idStr.getBytes(StandardCharsets.UTF_8));
return IRIWithValue.create(iriStr, value);
default:
// do not convert the reference to an IRI
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

public class AasFederatedService implements FederatedService {
Expand All @@ -34,14 +33,18 @@ public class AasFederatedService implements FederatedService {
Supplier<ExecutorService> executorService;

public AasFederatedService(String endpoint, Supplier<ExecutorService> executorService) {
this.client = new AasClient(endpoint);
this(new AasClient(endpoint), executorService);
}

public AasFederatedService(AasClient client, Supplier<ExecutorService> executorService) {
this.client = client;
this.executorService = executorService;
}

@Override
public boolean ask(Service service, BindingSet bindings, String baseUri) throws QueryEvaluationException {
final CloseableIteration<BindingSet, QueryEvaluationException> iter = evaluate(service,
new SingletonIteration<>(bindings), baseUri);
new SingletonIteration<>(bindings), baseUri);
try {
while (iter.hasNext()) {
BindingSet bs = iter.next();
Expand All @@ -56,8 +59,8 @@ public boolean ask(Service service, BindingSet bindings, String baseUri) throws

@Override
public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Service service,
CloseableIteration<BindingSet, QueryEvaluationException> bindings, String baseUri)
throws QueryEvaluationException {
CloseableIteration<BindingSet, QueryEvaluationException> bindings, String baseUri)
throws QueryEvaluationException {
if (!bindings.hasNext()) {
return new EmptyIteration<>();
}
Expand Down Expand Up @@ -116,9 +119,9 @@ public boolean isInitialized() {

@Override
public CloseableIteration<BindingSet, QueryEvaluationException> select(Service service,
final Set<String> projectionVars, BindingSet bindings, String baseUri) throws QueryEvaluationException {
final Set<String> projectionVars, BindingSet bindings, String baseUri) throws QueryEvaluationException {
final CloseableIteration<BindingSet, QueryEvaluationException> iter = evaluate(service,
new SingletonIteration<>(bindings), baseUri);
new SingletonIteration<>(bindings), baseUri);
if (service.getBindingNames().equals(projectionVars)) {
return iter;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.github.linkedfactory.core.rdf4j.aas;

import io.github.linkedfactory.core.rdf4j.common.BaseFederatedServiceResolver;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.eclipse.rdf4j.query.algebra.evaluation.federation.FederatedService;
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.sail.memory.MemoryStore;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

/**
* Tests for extraction data from AAS shells and submodels via SPARQL.
*/
public class AasServiceTest extends Mockito {
static String toResponse(String json) {
return String.format("{\"result\": [%s]}", json);
}

@Test
public void testPropertyExtractionByIdShort() throws Exception {
var mockedHttpClient = mock(CloseableHttpClient.class);
var statusLine = mock(StatusLine.class);
when(statusLine.getStatusCode()).thenReturn(200);

var shellsResponse = mock(CloseableHttpResponse.class);
when(shellsResponse.getStatusLine()).thenReturn(statusLine);
when(shellsResponse.getEntity()).thenReturn(new StringEntity(
toResponse(new String(getClass().getResourceAsStream("/aas/AAS_Motor_1_Type_shell.json").readAllBytes())))
);
when(mockedHttpClient.execute(argThat(httpUriRequest ->
httpUriRequest != null && httpUriRequest.getURI().toString().contains("/shells")))).thenReturn(shellsResponse);
var submodelResponse = mock(CloseableHttpResponse.class);
when(submodelResponse.getStatusLine()).thenReturn(statusLine);
when(submodelResponse.getEntity()).thenReturn(new StringEntity(
new String(getClass().getResourceAsStream("/aas/AAS_Motor_1_Type_Submodel_TechnicalData.json").readAllBytes()))
);
when(mockedHttpClient.execute(argThat(httpUriRequest ->
httpUriRequest != null && httpUriRequest.getURI().toString().contains("/submodels/")))).thenReturn(submodelResponse);

var client = new AasClient("http://example.org/") {
@Override
protected CloseableHttpClient createHttpClient() {
return mockedHttpClient;
}
};

var memoryStore = new MemoryStore();
var repo = new SailRepository(memoryStore);
repo.setFederatedServiceResolver(new BaseFederatedServiceResolver() {
public FederatedService createService(String url) {
return new AasFederatedService(client, this::getExecutorService);
}
});
repo.init();

try {
try (var conn = repo.getConnection()) {
var query = conn.prepareTupleQuery("prefix aas: <https://admin-shell.io/aas/3/0/> " +
"select * {" +
"service <aas-api:http://aasx-server:5001> {" +
"<aas-api:endpoint> <aas-api:shells> ?shell ." +
" ?shell aas:idShort ?shellId ." +
" ?shell aas:submodels ?sm." +
" ?sm aas:semanticId/aas:keys/aas:value \"https://admin-shell.io/ZVEI/TechnicalData/Submodel/1/2\"." +
" ?sm (!<:>)+ ?element ." +
" { ?element a aas:Property } union { ?element a aas:MultiLanguageProperty }\n" +
" ?element aas:idShort \"ProductClassId\" ; " +
" aas:valueId/aas:keys/aas:value ?productClassId." +
"}" +
"}");
try (var result = query.evaluate()) {
Assert.assertTrue(result.hasNext());
while (result.hasNext()) {
var bindings = result.next();
Assert.assertEquals("0173-1#01-BAB253#016",
bindings.getValue("productClassId").stringValue());
}
}
}
} finally {
repo.shutDown();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
{
"idShort": "TechnicalData",
"id": "https://eplan.com/example/sm/motor/technicaldata_4",
"kind": "Instance",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "https://admin-shell.io/ZVEI/TechnicalData/Submodel/1/2"
}
]
},
"submodelElements": [
{
"idShort": "GeneralInformation",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "ConceptDescription",
"value": "https://admin-shell.io/ZVEI/TechnicalData/GeneralInformation/1/1"
}
]
},
"value": [
{
"idShort": "ManufacturerName",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "0173-1#02-AAO677#002"
}
]
},
"valueType": "xs:string",
"value": "SEW",
"modelType": "Property"
},
{
"idShort": "ManufacturerArticleNumber",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "0173-1#02-AAO676#003"
}
]
},
"valueType": "xs:string",
"value": "SEW.K19DRS71M4/TH",
"modelType": "Property"
},
{
"idShort": "ManufacturerLogo",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "https://admin-shell.io/ZVEI/TechnicalData/ManufacturerLogo/1/1"
}
]
},
"contentType": "",
"modelType": "File"
},
{
"idShort": "ManufacturerProductDesignation",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "0173-1#02-AAW338#001 "
}
]
},
"value": [
{
"language": "de",
"text": "MotorProtectionCircuitBreaker zum Schutz von Motoren"
}
],
"modelType": "MultiLanguageProperty"
},
{
"idShort": "ManufacturerOrderCode",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "0173-1#02-AAO227#002"
}
]
},
"valueType": "xs:string",
"value": "K19DRS71M4/TH",
"modelType": "Property"
},
{
"idShort": "ProductImage",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "https://admin-shell.io/ZVEI/TechnicalData/ProductImage/1/1"
}
]
},
"contentType": "",
"modelType": "File"
}
],
"modelType": "SubmodelElementCollection"
},
{
"idShort": "ProductClassifications",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "ConceptDescription",
"value": "https://admin-shell.io/ZVEI/TechnicalData/ProductClassifications/1/1"
}
]
},
"value": [
{
"idShort": "ProductClassificationItem",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "ConceptDescription",
"value": "https://admin-shell.io/ZVEI/TechnicalData/ProductClassificationItem/1/1"
}
]
},
"value": [
{
"idShort": "ProductClassificationSystem",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "ConceptDescription",
"value": "https://admin-shell.io/ZVEI/TechnicalData/ProductClassificationSystem/1/1"
}
]
},
"valueType": "xs:string",
"value": "ECLASS",
"modelType": "Property"
},
{
"idShort": "ClassificationSystemVersion",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "ConceptDescription",
"value": "https://admin-shell.io/ZVEI/TechnicalData/ClassificationSystemVersion/1/1"
}
]
},
"valueType": "xs:string",
"value": "13.0",
"modelType": "Property"
},
{
"idShort": "ProductClassId",
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "ConceptDescription",
"value": "https://admin-shell.io/ZVEI/TechnicalData/ProductClassId/1/1"
}
]
},
"valueType": "xs:string",
"value": "27-02-22-90 High voltage three-phase current asynchronous motor (unspecified)",
"valueId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "0173-1#01-BAB253#016"
}
]
},
"modelType": "Property"
}
],
"modelType": "SubmodelElementCollection"
}
],
"modelType": "SubmodelElementCollection"
}
],
"modelType": "Submodel"
}
Loading

0 comments on commit 1341408

Please sign in to comment.