From ee9469ad7ae98a3be4e6387d1e6e9ce1e1a64a70 Mon Sep 17 00:00:00 2001 From: Mohammad Ghazanfar Ali Danish <62088117+mdanish98@users.noreply.github.com> Date: Tue, 21 Mar 2023 07:00:13 +0100 Subject: [PATCH] Updates ConAasManager's implementation to try all endpoints (#248) Signed-off-by: Mohammad Ghazanfar Ali Danish --- ...nectedAssetAdministrationShellManager.java | 87 +++++++++++++----- .../regression/aas/manager/TestAASHTTP.java | 78 ++++++++++++---- ...nectedAssetAdministrationShellManager.java | 89 +++++++++++++++---- 3 files changed, 194 insertions(+), 60 deletions(-) diff --git a/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java b/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java index 40b48918..cdecc479 100644 --- a/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java +++ b/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java @@ -28,6 +28,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.eclipse.basyx.aas.aggregator.AASAggregatorAPIHelper; @@ -41,9 +42,12 @@ import org.eclipse.basyx.aas.registration.api.IAASRegistry; import org.eclipse.basyx.submodel.metamodel.api.ISubmodel; import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier; +import org.eclipse.basyx.submodel.metamodel.connected.ConnectedElement; import org.eclipse.basyx.submodel.metamodel.connected.ConnectedSubmodel; import org.eclipse.basyx.submodel.metamodel.map.Submodel; import org.eclipse.basyx.submodel.restapi.SubmodelProvider; +import org.eclipse.basyx.vab.exception.provider.ProviderException; +import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException; import org.eclipse.basyx.vab.factory.java.ModelProxyFactory; import org.eclipse.basyx.vab.modelprovider.VABElementProxy; import org.eclipse.basyx.vab.modelprovider.VABPathTools; @@ -55,7 +59,7 @@ * Implement a AAS manager backend that communicates via HTTP/REST
*
* - * @author kuhn, schnicke + * @author kuhn, schnicke, danish * */ public class ConnectedAssetAdministrationShellManager implements IAssetAdministrationShellManager { @@ -85,14 +89,8 @@ public ConnectedAssetAdministrationShellManager(IAASRegistry directory, IConnect @Override public ISubmodel retrieveSubmodel(IIdentifier aasId, IIdentifier smId) { - // look up SM descriptor in the registry - SubmodelDescriptor smDescriptor = aasDirectory.lookupSubmodel(aasId, smId); - - // get address of the submodel descriptor - String addr = smDescriptor.getFirstEndpoint(); - - // Return a new VABElementProxy - return new ConnectedSubmodel(proxyFactory.createProxy(addr)); + VABElementProxy proxy = getSubmodelProxyFromId(aasId, smId); + return new ConnectedSubmodel(proxy); } @Override @@ -107,26 +105,14 @@ public Map retrieveSubmodels(IIdentifier aasId) { Collection smDescriptors = aasDesc.getSubmodelDescriptors(); Map submodels = new LinkedHashMap<>(); for (SubmodelDescriptor smDesc : smDescriptors) { - String smEndpoint = smDesc.getFirstEndpoint(); String smIdShort = smDesc.getIdShort(); - VABElementProxy smProxy = proxyFactory.createProxy(smEndpoint); - ConnectedSubmodel connectedSM = new ConnectedSubmodel(smProxy); + ISubmodel connectedSM = retrieveSubmodel(aasDesc.getIdentifier(), smDesc.getIdentifier()); submodels.put(smIdShort, connectedSM); } + return submodels; } - private VABElementProxy getAASProxyFromId(IIdentifier aasId) { - // Lookup AAS descriptor - AASDescriptor aasDescriptor = aasDirectory.lookupAAS(aasId); - - // Get AAS address from AAS descriptor - String addr = aasDescriptor.getFirstEndpoint(); - - // Return a new VABElementProxy - return proxyFactory.createProxy(addr); - } - /** * Retrieves all AASs registered. This can take a long time if many AASs are * present! Use with caution! @@ -196,4 +182,59 @@ public void createAAS(AssetAdministrationShell aas, String endpoint) { String combinedEndpoint = VABPathTools.concatenatePaths(harmonizedEndpoint, AASAggregatorAPIHelper.getAASAccessPath(aas.getIdentification())); aasDirectory.register(new AASDescriptor(aas, combinedEndpoint)); } + + private VABElementProxy getAASProxyFromId(IIdentifier aasId) { + AASDescriptor aasDescriptor = aasDirectory.lookupAAS(aasId); + + Optional> optionalAasDescriptor = getWorkingAasEndpoint(aasDescriptor.getEndpoints()); + + if (!optionalAasDescriptor.isPresent()) + throw new ResourceNotFoundException("The resource with id : " + aasId + " could not be found!"); + + return proxyFactory.createProxy((String) optionalAasDescriptor.get().get(AssetAdministrationShell.ADDRESS)); + } + + private VABElementProxy getSubmodelProxyFromId(IIdentifier aasId, IIdentifier smId) { + SubmodelDescriptor smDescriptor = aasDirectory.lookupSubmodel(aasId, smId); + + Optional> optionalSubmodelDescriptor = getWorkingSubmodelEndpoint(smDescriptor.getEndpoints()); + + if (!optionalSubmodelDescriptor.isPresent()) + throw new ResourceNotFoundException("The resource with id : " + aasId + " could not be found!"); + + return proxyFactory.createProxy((String) optionalSubmodelDescriptor.get().get(AssetAdministrationShell.ADDRESS)); + } + + private Optional> getWorkingAasEndpoint(Collection> endpoints) { + return endpoints.stream().filter(endpoint -> isWorking(new ConnectedAssetAdministrationShell(createProxy(endpoint)))).findFirst(); + } + + private Optional> getWorkingSubmodelEndpoint(Collection> endpoints) { + return endpoints.stream().filter(endpoint -> isWorking(new ConnectedSubmodel(createProxy(endpoint)))).findFirst(); + } + + private VABElementProxy createProxy(Map endpoint) { + return proxyFactory.createProxy((String) endpoint.get(AssetAdministrationShell.ADDRESS)); + } + + private boolean isWorking(ConnectedElement connectedElement) { + + try { + attemptIdentificationRetrieval(connectedElement); + + return true; + } catch (ProviderException e) { + return false; + } + + } + + private void attemptIdentificationRetrieval(ConnectedElement connectedElement) { + if (connectedElement instanceof ConnectedAssetAdministrationShell) { + ((ConnectedAssetAdministrationShell) connectedElement).getIdentification(); + } else { + ((ConnectedSubmodel) connectedElement).getIdentification(); + } + } + } diff --git a/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestAASHTTP.java b/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestAASHTTP.java index 06328f77..dfc0f6de 100644 --- a/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestAASHTTP.java +++ b/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestAASHTTP.java @@ -47,7 +47,6 @@ import org.eclipse.basyx.vab.exception.provider.ProviderException; import org.eclipse.basyx.vab.protocol.http.connector.HTTPConnectorFactory; import org.eclipse.basyx.vab.protocol.http.server.BaSyxContext; -import org.eclipse.basyx.vab.registry.memory.VABInMemoryRegistry; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; @@ -55,15 +54,23 @@ /** * Tests access to an AAS provided by a servlet. This is an integration test * - * @author schnicke + * @author schnicke, danish * */ public class TestAASHTTP { + private static final String WORKING_SM_ENDPOINT = "http://localhost:8080/basys.sdk/Testsuite/StubAAS/aas/submodels/" + StubAASServlet.SMIDSHORT + "/submodel"; + private static final String WORKING_AAS_ENDPOINT = "http://localhost:8080/basys.sdk/Testsuite/StubAAS/aas"; + private static final String NOT_WORKING_404_ENDPOINT_1 = "http://localhost:8080/basys.sdk/Testsuite/StubAAS1/aas"; + private static final String NOT_WORKING_404_ENDPOINT_2 = "http://localhost:8080/basys.sdk/Testsuite/StubAAS2/aas"; + // Manager used to connect to the AAS ConnectedAssetAdministrationShellManager manager; private static BaSyxContext context = new BaSyxContext("/basys.sdk", System.getProperty("java.io.tmpdir")).addServletMapping("/Testsuite/StubAAS/*", new StubAASServlet()); + + private AASDescriptor aasDescriptor; + private SubmodelDescriptor submodelDescriptor; /** * Makes sure Tomcat Server is started @@ -76,26 +83,12 @@ public class TestAASHTTP { */ @Before public void build() { - // Fill directory stub - VABInMemoryRegistry directory = new VABInMemoryRegistry(); - directory.addMapping(StubAASServlet.AASURN.getId(), "http://localhost:8080/basys.sdk/Testsuite/StubAAS/aas"); - directory.addMapping(StubAASServlet.SMURN.getId(), "http://localhost:8080/basys.sdk/Testsuite/StubAAS/aas/submodels/" + StubAASServlet.SMIDSHORT + "/submodel"); - InMemoryRegistry registry = new InMemoryRegistry(); + + aasDescriptor = createAasDescriptor(WORKING_AAS_ENDPOINT); - // Create aas descriptor for the aas registry - AASDescriptor aasDescriptor = new AASDescriptor(StubAASServlet.AASURN, "http://localhost:8080/basys.sdk/Testsuite/StubAAS/aas"); - - // Create the submodel descriptor - SubmodelDescriptor submodelDescriptor = new SubmodelDescriptor(StubAASServlet.SMIDSHORT, StubAASServlet.SMURN, "http://localhost:8080/basys.sdk/Testsuite/StubAAS/aas/submodels/" + StubAASServlet.SMIDSHORT + "/submodel"); - - // add submodel descriptor to the aas descriptor - aasDescriptor.addSubmodelDescriptor(submodelDescriptor); - - // register the aas in the registry - registry.register(aasDescriptor); + registerAasDescriptorWithSubmodelDescriptor(registry, aasDescriptor); - // Create manager using the directory stub an the HTTPConnectorProvider manager = new ConnectedAssetAdministrationShellManager(registry, new HTTPConnectorFactory()); } @@ -119,6 +112,15 @@ public void testAAS() throws Exception { assertEquals(1, submodels.size()); assertTrue(submodels.containsKey(StubAASServlet.SMIDSHORT)); } + + @Test + public void retrieveSingleAas() throws Exception { + prepareAasDescriptorForMultipleEndpoints(); + + IAssetAdministrationShell assetAdministrationShell = manager.retrieveAAS(StubAASServlet.AASURN); + + assertEquals(StubAASServlet.AASIDSHORT, assetAdministrationShell.getIdShort()); + } /** * Tests accessing a submodel @@ -172,6 +174,44 @@ public void testSubmodel() throws Exception { Map elements = sm.getSubmodelElements(); // 2 properties, 4 operations, 1 collection assertEquals(9, elements.size()); + } + + @Test + public void retrieveSingleSubmodel() { + prepareSubmodelDescriptorForMultipleEndpoints(); + + ISubmodel submodel = manager.retrieveSubmodel(StubAASServlet.AASURN, StubAASServlet.SMURN); + + assertEquals(StubAASServlet.SMIDSHORT, submodel.getIdShort()); + } + + private void prepareAasDescriptorForMultipleEndpoints() { + aasDescriptor.removeEndpoint(WORKING_AAS_ENDPOINT); + aasDescriptor.addEndpoint(NOT_WORKING_404_ENDPOINT_1); + aasDescriptor.addEndpoint(WORKING_AAS_ENDPOINT); + aasDescriptor.addEndpoint(NOT_WORKING_404_ENDPOINT_2); + } + + private void prepareSubmodelDescriptorForMultipleEndpoints() { + submodelDescriptor.removeEndpoint(WORKING_SM_ENDPOINT); + submodelDescriptor.addEndpoint(NOT_WORKING_404_ENDPOINT_1); + submodelDescriptor.addEndpoint(WORKING_SM_ENDPOINT); + submodelDescriptor.addEndpoint(NOT_WORKING_404_ENDPOINT_2); + } + + private void registerAasDescriptorWithSubmodelDescriptor(InMemoryRegistry registry, AASDescriptor aasDescriptor) { + submodelDescriptor = createSubmodelDescriptor(); + + aasDescriptor.addSubmodelDescriptor(submodelDescriptor); + + registry.register(aasDescriptor); + } + + private SubmodelDescriptor createSubmodelDescriptor() { + return new SubmodelDescriptor(StubAASServlet.SMIDSHORT, StubAASServlet.SMURN, WORKING_SM_ENDPOINT); + } + private AASDescriptor createAasDescriptor(String url) { + return new AASDescriptor(StubAASServlet.AASURN, url); } } diff --git a/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestConnectedAssetAdministrationShellManager.java b/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestConnectedAssetAdministrationShellManager.java index 3a1edf4a..5fb0c5fa 100644 --- a/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestConnectedAssetAdministrationShellManager.java +++ b/src/test/java/org/eclipse/basyx/testsuite/regression/aas/manager/TestConnectedAssetAdministrationShellManager.java @@ -30,7 +30,6 @@ import static org.junit.Assert.fail; import java.util.Collection; - import org.eclipse.basyx.aas.aggregator.AASAggregator; import org.eclipse.basyx.aas.aggregator.restapi.AASAggregatorProvider; import org.eclipse.basyx.aas.manager.ConnectedAssetAdministrationShellManager; @@ -68,10 +67,11 @@ /** * Tests ConnectedAssetAdministrationShellManager class * - * @author schnicke + * @author schnicke, danish * */ public class TestConnectedAssetAdministrationShellManager { + ConnectedAssetAdministrationShellManager manager; ConnectorProviderStub connectorProvider; IAASRegistry registry; @@ -96,7 +96,7 @@ public void build() { @Test public void createAAS() throws Exception { // Register AAS at directory - IIdentifier aasId = new Identifier(IdentifierType.CUSTOM, "aasId"); + IIdentifier aasId = createIdentifier("aasId"); String aasIdShort = "aasName"; IModelProvider provider = new AASAggregatorProvider(new AASAggregator()); prepareConnectorProvider(provider); @@ -118,8 +118,8 @@ public void createAAS() throws Exception { @Test public void createSubmodel() throws Exception { - IIdentifier aasId = new Identifier(IdentifierType.CUSTOM, "aasId"); - IIdentifier smId = new Identifier(IdentifierType.CUSTOM, "smId"); + IIdentifier aasId = createIdentifier("aasId"); + IIdentifier smId = createIdentifier("smId"); String smIdShort = "smName"; // Register AAS at directory @@ -163,9 +163,9 @@ public void createSubmodel() throws Exception { public void registerSubmodel() { String aasEndpoint = ""; - IIdentifier aasId = new Identifier(IdentifierType.CUSTOM, "aasId"); + IIdentifier aasId = createIdentifier("aasId"); String aasIdShort = "aasName"; - IIdentifier smId = new Identifier(IdentifierType.CUSTOM, "smId"); + IIdentifier smId = createIdentifier("smId"); String smIdShort = "smName"; String expectedSubmodelEndpoint = aasEndpoint + "shells/aasId/aas/submodels/" + smIdShort + "/submodel"; @@ -187,10 +187,10 @@ public void registerSubmodel() { @Test public void deleteSubmodel() { - IIdentifier aasId = new Identifier(IdentifierType.CUSTOM, "aasId"); + IIdentifier aasId = createIdentifier("aasId"); String aasIdShort = "aasName"; - IIdentifier smId = new Identifier(IdentifierType.CUSTOM, "smId"); + IIdentifier smId = createIdentifier("smId"); String smIdShort = "smName"; IModelProvider provider = new AASAggregatorProvider(new AASAggregator()); @@ -214,7 +214,7 @@ public void deleteSubmodel() { @Test public void deleteAAS() { - IIdentifier aasId = new Identifier(IdentifierType.CUSTOM, "aasId"); + IIdentifier aasId = createIdentifier("aasId"); String aasIdShort = "aasName"; IModelProvider provider = new AASAggregatorProvider(new AASAggregator()); @@ -233,25 +233,64 @@ public void deleteAAS() { @Test public void retrieveAll() { - IIdentifier aasId1 = new Identifier(IdentifierType.CUSTOM, "aasId1"); + IIdentifier aasId1 = createIdentifier("aasId1"); String aasIdShort1 = "aasName1"; - IIdentifier aasId2 = new Identifier(IdentifierType.CUSTOM, "aasId2"); + IIdentifier aasId2 = createIdentifier("aasId2"); String aasIdShort2 = "aasName2"; - + IModelProvider provider = new AASAggregatorProvider(new AASAggregator()); prepareConnectorProvider(provider); - // Create the AASs - AssetAdministrationShell aas1 = createTestAAS(aasId1, aasIdShort1); - AssetAdministrationShell aas2 = createTestAAS(aasId2, aasIdShort2); - manager.createAAS(aas1, ""); - manager.createAAS(aas2, ""); + createAasInManager(aasId1, aasIdShort1); + + createAasInManager(aasId2, aasIdShort2); // Retrieve them Collection connectedAASs = manager.retrieveAASAll(); assertEquals(2, connectedAASs.size()); connectedAASs.stream().forEach(aas -> assertTrue(aas.getIdShort().equals(aasIdShort1) || aas.getIdShort().equals(aasIdShort2))); } + + @Test + public void retrieveSingleAAS() { + IIdentifier aasId1 = createIdentifier("aasId1"); + String aasIdShort1 = "aasName1"; + IIdentifier aasId2 = createIdentifier("aasId2"); + String aasIdShort2 = "aasName2"; + + IModelProvider provider = new AASAggregatorProvider(new AASAggregator()); + prepareConnectorProvider(provider); + + createAasInManager(aasId1, aasIdShort1); + + createAasInManager(aasId2, aasIdShort2); + + IAssetAdministrationShell assetAdministrationShell = manager.retrieveAAS(aasId2); + + assertEquals(aasIdShort2, assetAdministrationShell.getIdShort()); + assertEquals(aasId2, assetAdministrationShell.getIdentification()); + } + + @Test + public void retrieveSingleSubmodel() { + IIdentifier aasId = createIdentifier("aasId"); + String aasIdShort = "aasName"; + + IIdentifier smId = createIdentifier("smId"); + String smIdShort = "smName"; + + IModelProvider provider = new AASAggregatorProvider(new AASAggregator()); + prepareConnectorProvider(provider); + + createAasInManager(aasId, aasIdShort); + + createSubmodelInManager(aasId, smId, smIdShort); + + ISubmodel submodel = manager.retrieveSubmodel(aasId, smId); + + assertEquals(smIdShort, submodel.getIdShort()); + assertEquals(smId, submodel.getIdentification()); + } /** * Tries to retrieve a nonexistent AAS @@ -325,6 +364,20 @@ public void aasCreationUrlHarmonizationRemovesShellsSuffix() { Mockito.verifyNoMoreInteractions(mockedProvider); } + + private void createAasInManager(IIdentifier aasId, String aasIdShort) { + AssetAdministrationShell aas = createTestAAS(aasId, aasIdShort); + manager.createAAS(aas, ""); + } + + private void createSubmodelInManager(IIdentifier aasId, IIdentifier smId, String smIdShort) { + Submodel sm = new Submodel(smIdShort, smId); + manager.createSubmodel(aasId, sm); + } + + private Identifier createIdentifier(String id) { + return new CustomId(id); + } private ConnectorFactory createAndConfigureConnectorFactoryMock() { ConnectorFactory mockedProvider = Mockito.mock(ConnectorFactory.class);