Skip to content

Commit 2b2fbcb

Browse files
committed
Fix registry descriptor synchronization
Signed-off-by: Aaron Zielstorff <aaron.zielstorff@iese.fraunhofer.de>
1 parent 3f4c911 commit 2b2fbcb

4 files changed

Lines changed: 355 additions & 4 deletions

File tree

basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepository.java

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public AssetAdministrationShell getAas(String shellId) throws ElementDoesNotExis
7979

8080
@Override
8181
public void createAas(AssetAdministrationShell shell) throws CollidingIdentifierException {
82-
AssetAdministrationShellDescriptor descriptor = new AasDescriptorFactory(aasRepositoryRegistryLink.getAasRepositoryBaseURLs(), attributeMapper).create(shell);
82+
AssetAdministrationShellDescriptor descriptor = createDescriptor(shell);
8383

8484
decorated.createAas(shell);
8585

@@ -96,7 +96,16 @@ public void createAas(AssetAdministrationShell shell) throws CollidingIdentifier
9696

9797
@Override
9898
public void updateAas(String shellId, AssetAdministrationShell shell) {
99+
AssetAdministrationShell previousShell = decorated.getAas(shellId);
100+
99101
decorated.updateAas(shellId, shell);
102+
103+
try {
104+
updateDescriptor(shellId, shell);
105+
} catch (RuntimeException e) {
106+
rollbackAasUpdate(shellId, previousShell, e);
107+
throw e;
108+
}
100109
}
101110

102111
@Override
@@ -128,7 +137,16 @@ public void removeSubmodelReference(String shellId, String submodelId) {
128137

129138
@Override
130139
public void setAssetInformation(String shellId, AssetInformation shellInfo) throws ElementDoesNotExistException {
140+
AssetInformation previousAssetInformation = decorated.getAssetInformation(shellId);
141+
131142
decorated.setAssetInformation(shellId, shellInfo);
143+
144+
try {
145+
updateDescriptor(shellId, decorated.getAas(shellId));
146+
} catch (RuntimeException e) {
147+
rollbackAssetInformationUpdate(shellId, previousAssetInformation, e);
148+
throw e;
149+
}
132150
}
133151

134152
@Override
@@ -144,7 +162,61 @@ private void registerAas(AssetAdministrationShellDescriptor descriptor) {
144162

145163
logger.info("Shell '{}' has been automatically linked with the Registry", descriptor.getId());
146164
} catch (ApiException e) {
147-
throw new RepositoryRegistryLinkException(descriptor.getId(), e);
165+
throw createRegistryLinkException(descriptor.getId(), "creation", e);
166+
}
167+
}
168+
169+
private void updateDescriptor(String shellId, AssetAdministrationShell shell) {
170+
RegistryAndDiscoveryInterfaceApi registryApi = aasRepositoryRegistryLink.getRegistryApi();
171+
172+
try {
173+
AssetAdministrationShellDescriptor existingDescriptor = registryApi.getAssetAdministrationShellDescriptorById(shellId);
174+
AssetAdministrationShellDescriptor updatedDescriptor = createDescriptor(shell);
175+
updatedDescriptor.setSubmodelDescriptors(existingDescriptor.getSubmodelDescriptors());
176+
177+
registryApi.putAssetAdministrationShellDescriptorById(shellId, updatedDescriptor);
178+
179+
logger.info("Shell descriptor '{}' has been automatically updated in the Registry", shellId);
180+
} catch (ApiException e) {
181+
throw createRegistryLinkException(shellId, "update", e);
182+
}
183+
}
184+
185+
private AssetAdministrationShellDescriptor createDescriptor(AssetAdministrationShell shell) {
186+
return new AasDescriptorFactory(aasRepositoryRegistryLink.getAasRepositoryBaseURLs(), attributeMapper).create(shell);
187+
}
188+
189+
private RepositoryRegistryLinkException createRegistryLinkException(String shellId, String operation, ApiException cause) {
190+
StringBuilder details = new StringBuilder("Registry descriptor ").append(operation).append(" failed");
191+
192+
if (cause.getCode() > 0)
193+
details.append(" with HTTP status ").append(cause.getCode());
194+
195+
String responseDetails = cause.getResponseBody();
196+
if (responseDetails == null || responseDetails.isBlank())
197+
responseDetails = cause.getMessage();
198+
199+
if (responseDetails != null && !responseDetails.isBlank())
200+
details.append(": ").append(responseDetails);
201+
202+
return new RepositoryRegistryLinkException(shellId, details.toString(), cause);
203+
}
204+
205+
private void rollbackAasUpdate(String shellId, AssetAdministrationShell previousShell, RuntimeException updateException) {
206+
try {
207+
decorated.updateAas(shellId, previousShell);
208+
} catch (RuntimeException rollbackException) {
209+
updateException.addSuppressed(rollbackException);
210+
logger.error("Unable to restore AAS '{}' after Registry synchronization failed.", shellId, rollbackException);
211+
}
212+
}
213+
214+
private void rollbackAssetInformationUpdate(String shellId, AssetInformation previousAssetInformation, RuntimeException updateException) {
215+
try {
216+
decorated.setAssetInformation(shellId, previousAssetInformation);
217+
} catch (RuntimeException rollbackException) {
218+
updateException.addSuppressed(rollbackException);
219+
logger.error("Unable to restore Asset Information for AAS '{}' after Registry synchronization failed.", shellId, rollbackException);
148220
}
149221
}
150222

basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@
3232
import java.util.List;
3333

3434
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
35+
import org.apache.hc.core5.http.ParseException;
3536
import org.eclipse.digitaltwin.basyx.aasregistry.client.ApiException;
3637
import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
3738
import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetAdministrationShellDescriptor;
39+
import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetKind;
3840
import org.eclipse.digitaltwin.basyx.aasregistry.client.model.GetAssetAdministrationShellDescriptorsResult;
3941
import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.DummyAasDescriptorFactory;
4042
import org.eclipse.digitaltwin.basyx.core.RepositoryUrlHelper;
@@ -93,6 +95,64 @@ public void deleteAas() throws FileNotFoundException, IOException, ApiException
9395
assertDescriptionDeletionAtRegistry();
9496
}
9597

98+
@Test
99+
public void updateAasUpdatesDescriptor() throws FileNotFoundException, IOException, ApiException {
100+
String updatedAas = getAas1JSONString()
101+
.replace("\"ExampleMotor\"", "\"UpdatedMotor\"")
102+
.replace("\"Instance\"", "\"Type\"");
103+
104+
try (CloseableHttpResponse creationResponse = createAasOnRepo(getAas1JSONString())) {
105+
assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode());
106+
}
107+
108+
try {
109+
try (CloseableHttpResponse updateResponse = updateAasOnRepo(updatedAas)) {
110+
assertEquals(HttpStatus.NO_CONTENT.value(), updateResponse.getCode());
111+
}
112+
113+
AssetAdministrationShellDescriptor descriptor = retrieveDescriptorFromRegistry();
114+
assertEquals("UpdatedMotor", descriptor.getIdShort());
115+
assertEquals(AssetKind.TYPE, descriptor.getAssetKind());
116+
} finally {
117+
resetRepository();
118+
}
119+
}
120+
121+
@Test
122+
public void updateAssetInformationUpdatesDescriptor() throws FileNotFoundException, IOException, ApiException {
123+
try (CloseableHttpResponse creationResponse = createAasOnRepo(getAas1JSONString())) {
124+
assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode());
125+
}
126+
127+
try {
128+
try (CloseableHttpResponse updateResponse = updateAssetInformationOnRepo("{\"assetKind\":\"Type\",\"globalAssetId\":\"globalAssetId\"}")) {
129+
assertEquals(HttpStatus.NO_CONTENT.value(), updateResponse.getCode());
130+
}
131+
132+
assertEquals(AssetKind.TYPE, retrieveDescriptorFromRegistry().getAssetKind());
133+
} finally {
134+
resetRepository();
135+
}
136+
}
137+
138+
@Test
139+
public void preExistingDescriptorReturnsRegistryFailureDetailsAndRollsBackAas() throws IOException, ApiException, ParseException {
140+
getAasRegistryApi().postAssetAdministrationShellDescriptor(DUMMY_DESCRIPTOR);
141+
142+
try {
143+
try (CloseableHttpResponse creationResponse = createAasOnRepo(getAas1JSONString())) {
144+
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), creationResponse.getCode());
145+
assertTrue(BaSyxHttpTestUtils.getResponseAsString(creationResponse).contains(Integer.toString(HttpStatus.CONFLICT.value())));
146+
}
147+
148+
try (CloseableHttpResponse retrievalResponse = BaSyxHttpTestUtils.executeGetOnURL(getSpecificAasAccessURL(DUMMY_AAS_ID))) {
149+
assertEquals(HttpStatus.NOT_FOUND.value(), retrievalResponse.getCode());
150+
}
151+
} finally {
152+
getAasRegistryApi().deleteAssetAdministrationShellDescriptorById(DUMMY_AAS_ID);
153+
}
154+
}
155+
96156
private AssetAdministrationShellDescriptor retrieveDescriptorFromRegistry() throws ApiException {
97157
RegistryAndDiscoveryInterfaceApi api = getAasRegistryApi();
98158

@@ -125,10 +185,17 @@ private String getAas1JSONString() throws FileNotFoundException, IOException {
125185
}
126186

127187
private CloseableHttpResponse createAasOnRepo(String aasJsonContent) throws IOException {
128-
String url = RepositoryUrlHelper.createRepositoryUrl(getFirstAasRepoBaseUrl(), AAS_REPOSITORY_PATH);
129188
return BaSyxHttpTestUtils.executePostOnURL(RepositoryUrlHelper.createRepositoryUrl(getFirstAasRepoBaseUrl(), AAS_REPOSITORY_PATH), aasJsonContent);
130189
}
131190

191+
private CloseableHttpResponse updateAasOnRepo(String aasJsonContent) throws IOException {
192+
return BaSyxHttpTestUtils.executePutOnURL(getSpecificAasAccessURL(DUMMY_AAS_ID), aasJsonContent);
193+
}
194+
195+
private CloseableHttpResponse updateAssetInformationOnRepo(String assetInformationJson) throws IOException {
196+
return BaSyxHttpTestUtils.executePutOnURL(getSpecificAasAccessURL(DUMMY_AAS_ID) + "/asset-information", assetInformationJson);
197+
}
198+
132199
private String getSpecificAasAccessURL(String aasId) {
133200
return RepositoryUrlHelper.createRepositoryUrl(getFirstAasRepoBaseUrl(), AAS_REPOSITORY_PATH) + "/"
134201
+ Base64UrlEncodedIdentifier.encodeIdentifier(aasId);
@@ -138,4 +205,4 @@ private String getFirstAasRepoBaseUrl() {
138205
return getAasRepoBaseUrls()[0];
139206
}
140207

141-
}
208+
}

0 commit comments

Comments
 (0)