From 9d75886951cc95a39182879ff356bc8d1b5dcfb1 Mon Sep 17 00:00:00 2001 From: mateusmolina Date: Mon, 9 Dec 2024 09:37:43 +0100 Subject: [PATCH 1/6] bump: Aas4j to version 1.0.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2b32c14eb..c806de04e 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ linux/amd64, linux/arm64, linux/arm/v7 8081 8081 - 1.0.2 + 1.0.3 From 8197a438beadd77bc595ef0b03c1c5980bb48a49 Mon Sep 17 00:00:00 2001 From: mateusmolina Date: Mon, 9 Dec 2024 09:58:38 +0100 Subject: [PATCH 2/6] refactor: extract OperationRequest handling to own class --- .../SubmodelRepositoryApiHTTPController.java | 26 +----- .../operation/OperationRequestExecutor.java | 79 +++++++++++++++++++ .../SubmodelServiceHTTPApiController.java | 31 +------- 3 files changed, 87 insertions(+), 49 deletions(-) create mode 100644 basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java index 645486669..109e5d4fa 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java @@ -48,6 +48,8 @@ import org.eclipse.digitaltwin.basyx.http.pagination.Base64UrlEncodedCursor; import org.eclipse.digitaltwin.basyx.http.pagination.PagedResult; import org.eclipse.digitaltwin.basyx.http.pagination.PagedResultPagingMetadata; +import org.eclipse.digitaltwin.basyx.operation.OperationRequestExecutor; +import org.eclipse.digitaltwin.basyx.operation.OperationRequestExecutor.Invokable; import org.eclipse.digitaltwin.basyx.pagination.GetSubmodelElementsResult; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository; import org.eclipse.digitaltwin.basyx.submodelrepository.http.pagination.GetSubmodelsResult; @@ -283,28 +285,8 @@ private ResponseEntity handleSubmodelElementValueNormalGetReque @Override public ResponseEntity invokeOperationSubmodelRepo(Base64UrlEncodedIdentifier submodelIdentifier, String idShortPath, @Valid OperationRequest body, @Valid Boolean async) { - List inVars = new ArrayList<>(); - inVars.addAll(body.getInputArguments()); - inVars.addAll(body.getInoutputArguments()); - - List result = Arrays.asList(repository.invokeOperation(submodelIdentifier.getIdentifier(), idShortPath, inVars.toArray(new OperationVariable[0]))); - - List outVars = new ArrayList<>(result); - List inoutputVars = new ArrayList<>(); - - if (!body.getInoutputArguments().isEmpty()) { - List inoutputVarsIdShorts = body.getInoutputArguments().stream().map(OperationVariable::getValue).map(SubmodelElement::getIdShort).toList(); - - inoutputVars = result.stream().filter(opVar -> inoutputVarsIdShorts.contains(opVar.getValue().getIdShort())).toList(); - - outVars.removeAll(inoutputVars); - } - - return ResponseEntity.ok(createOperationResult(outVars, inoutputVars)); - } - - private OperationResult createOperationResult(List outputVars, List inoutputVars) { - return new DefaultOperationResult.Builder().outputArguments(outputVars).inoutputArguments(inoutputVars).build(); + Invokable invokable = inArgs -> repository.invokeOperation(submodelIdentifier.getIdentifier(), idShortPath, inArgs); + return ResponseEntity.ok(OperationRequestExecutor.executeOperationRequestSynchronously(invokable, body)); } private String getEncodedCursorFromCursorResult(CursorResult cursorResult) { diff --git a/basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java b/basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java new file mode 100644 index 000000000..36c00db50 --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (C) 2023 the Eclipse BaSyx Authors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + ******************************************************************************/ + +package org.eclipse.digitaltwin.basyx.operation; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.digitaltwin.aas4j.v3.model.OperationRequest; +import org.eclipse.digitaltwin.aas4j.v3.model.OperationResult; +import org.eclipse.digitaltwin.aas4j.v3.model.OperationVariable; +import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultOperationResult; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService; + +/** + * Executes an Operation Request + * + * @author mateusmolina + */ +public class OperationRequestExecutor { + + private OperationRequestExecutor() { + } + + public static OperationResult executeOperationRequestSynchronously(Invokable invokable, OperationRequest request) { + List inVars = new ArrayList<>(); + inVars.addAll(request.getInputArguments()); + inVars.addAll(request.getInoutputArguments()); + + List result = Arrays.asList(invokable.invoke(inVars.toArray(new OperationVariable[0]))); + + List outVars = new ArrayList<>(result); + List inoutputVars = new ArrayList<>(); + + if (!request.getInoutputArguments().isEmpty()) { + List inoutputVarsIdShorts = request.getInoutputArguments().stream().map(OperationVariable::getValue).map(SubmodelElement::getIdShort).toList(); + + inoutputVars = result.stream().filter(opVar -> inoutputVarsIdShorts.contains(opVar.getValue().getIdShort())).toList(); + + outVars.removeAll(inoutputVars); + } + + return createSuccessOperationResult(outVars, inoutputVars); + } + + private static OperationResult createSuccessOperationResult(List outputVars, List inoutputVars) { + return new DefaultOperationResult.Builder().success(true).outputArguments(outputVars).inoutputArguments(inoutputVars).build(); + } + + @FunctionalInterface + public interface Invokable { + OperationVariable[] invoke(OperationVariable[] arguments); + } + +} diff --git a/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java b/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java index 66498d924..03ab13a15 100644 --- a/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java +++ b/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java @@ -27,16 +27,12 @@ import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.model.OperationRequest; import org.eclipse.digitaltwin.aas4j.v3.model.OperationResult; -import org.eclipse.digitaltwin.aas4j.v3.model.OperationVariable; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; -import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultOperationResult; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementNotAFileException; import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; @@ -45,6 +41,8 @@ import org.eclipse.digitaltwin.basyx.http.pagination.Base64UrlEncodedCursor; import org.eclipse.digitaltwin.basyx.http.pagination.PagedResult; import org.eclipse.digitaltwin.basyx.http.pagination.PagedResultPagingMetadata; +import org.eclipse.digitaltwin.basyx.operation.OperationRequestExecutor; +import org.eclipse.digitaltwin.basyx.operation.OperationRequestExecutor.Invokable; import org.eclipse.digitaltwin.basyx.pagination.GetSubmodelElementsResult; import org.eclipse.digitaltwin.basyx.serialization.SubmodelMetadataUtil; import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService; @@ -236,30 +234,9 @@ public ResponseEntity patchSubmodelValueOnly(@Parameter(in = ParameterIn.D public ResponseEntity invokeOperation( @Parameter(in = ParameterIn.PATH, description = "IdShort path to the submodel element (dot-separated)", required = true, schema = @Schema()) @PathVariable("idShortPath") String idShortPath, @Parameter(in = ParameterIn.DEFAULT, description = "Operation request object", required = true, schema = @Schema()) @Valid @RequestBody OperationRequest body) { - List inVars = new ArrayList<>(); - inVars.addAll(body.getInputArguments()); - inVars.addAll(body.getInoutputArguments()); - List result = Arrays.asList(service.invokeOperation(idShortPath, inVars.toArray(new OperationVariable[0]))); - - List outVars = new ArrayList<>(result); - List inoutputVars = new ArrayList<>(); - - if (!body.getInoutputArguments().isEmpty()) { - List inoutputVarsIdShorts = body.getInoutputArguments().stream().map(OperationVariable::getValue).map(SubmodelElement::getIdShort).toList(); - - inoutputVars = result.stream().filter(opVar -> inoutputVarsIdShorts.contains(opVar.getValue().getIdShort())).toList(); - - outVars.removeAll(inoutputVars); - } - - return ResponseEntity.ok(createOperationResult(outVars, inoutputVars)); - } - - private OperationResult createOperationResult(List outputVars, List inoutputVars) { - return new DefaultOperationResult.Builder() - .outputArguments(outputVars).inoutputArguments(inoutputVars) - .build(); + Invokable invokable = inArgs -> service.invokeOperation(idShortPath, inArgs); + return ResponseEntity.ok(OperationRequestExecutor.executeOperationRequestSynchronously(invokable, body)); } private String getEncodedCursorFromCursorResult(CursorResult cursorResult) { From 4d4f9400b9f3729208e1afc46340a494229a4485 Mon Sep 17 00:00:00 2001 From: mateusmolina Date: Mon, 9 Dec 2024 10:00:24 +0100 Subject: [PATCH 3/6] test: add success fields to test results --- .../src/test/resources/operation/result-inout.json | 1 + .../src/test/resources/operation/result.json | 1 + 2 files changed, 2 insertions(+) diff --git a/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result-inout.json b/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result-inout.json index 3aa563302..19b9d9bdc 100644 --- a/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result-inout.json +++ b/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result-inout.json @@ -1,4 +1,5 @@ { + "success": true, "inoutputArguments": [ { "value": { diff --git a/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result.json b/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result.json index 7a48f8c6a..20cf503ca 100644 --- a/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result.json +++ b/basyx.submodelservice/basyx.submodelservice-http/src/test/resources/operation/result.json @@ -1,4 +1,5 @@ { + "success": true, "outputArguments": [ { "value": { From a131eb20c864226aadee0f1fea5cbff526e76e6c Mon Sep 17 00:00:00 2001 From: mateusmolina Date: Mon, 9 Dec 2024 10:03:42 +0100 Subject: [PATCH 4/6] chore: bump license header year --- .../digitaltwin/basyx/operation/OperationRequestExecutor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java b/basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java index 36c00db50..397f55c07 100644 --- a/basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java +++ b/basyx.submodelservice/basyx.submodelservice-core/src/main/java/org/eclipse/digitaltwin/basyx/operation/OperationRequestExecutor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors + * Copyright (C) 2024 the Eclipse BaSyx Authors * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -34,7 +34,6 @@ import org.eclipse.digitaltwin.aas4j.v3.model.OperationVariable; import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultOperationResult; -import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService; /** * Executes an Operation Request From b5c5f113ca0d2aa1f75dfb4e5e50f8a48f302ece Mon Sep 17 00:00:00 2001 From: mateusmolina Date: Mon, 9 Dec 2024 10:07:09 +0100 Subject: [PATCH 5/6] chore: add todo for async op execution support --- .../http/SubmodelRepositoryApiHTTPController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java index 109e5d4fa..e7767121a 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java @@ -285,6 +285,10 @@ private ResponseEntity handleSubmodelElementValueNormalGetReque @Override public ResponseEntity invokeOperationSubmodelRepo(Base64UrlEncodedIdentifier submodelIdentifier, String idShortPath, @Valid OperationRequest body, @Valid Boolean async) { + + // TODO: #566 Add async operation execution support to + // SubmodelRepositoryController + Invokable invokable = inArgs -> repository.invokeOperation(submodelIdentifier.getIdentifier(), idShortPath, inArgs); return ResponseEntity.ok(OperationRequestExecutor.executeOperationRequestSynchronously(invokable, body)); } From 1dd3065f559ebd6c4f4e8e6ba839266ee3693a9d Mon Sep 17 00:00:00 2001 From: mateusmolina Date: Mon, 9 Dec 2024 11:15:43 +0100 Subject: [PATCH 6/6] fix: todo rel. to aas4j issue in ConnectedAasManager --- .../basyx/aasenvironment/client/ConnectedAasManager.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java index f28480ed7..73ae1cbe1 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java +++ b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java @@ -223,10 +223,7 @@ public void createSubmodelInAas(String aasIdentifier, Submodel submodel) { throw new RegistryHttpRequestException(aasIdentifier, e); } - Reference smRef = AasUtils.toReference(AasUtils.toReference(shell), submodel); - - // TODO See https://github.com/eclipse-aas4j/aas4j/issues/308 - smRef.setReferredSemanticId(submodel.getSemanticId()); + Reference smRef = AasUtils.toReference(AasUtils.toReference(shell), submodel, true); aasRepository.addSubmodelReference(aasIdentifier, smRef); }