Skip to content

Commit a8f6332

Browse files
Implements component features (#14)
- Adds MQTT support of AAS Aggregator for component Co-Authored-By: FriedJannik <[email protected]> Signed-off-by: Jannis Jung <[email protected]>
1 parent 79fe543 commit a8f6332

File tree

13 files changed

+536
-88
lines changed

13 files changed

+536
-88
lines changed

basyx.components/basyx.components.docker/basyx.components.AASServer/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@
6262
<version>4.1.2</version>
6363
</dependency>
6464

65+
<!-- Moquette MQTT broker for testing MQTT events -->
66+
<dependency>
67+
<groupId>io.moquette</groupId>
68+
<artifactId>moquette-broker</artifactId>
69+
<version>0.15</version>
70+
<scope>test</scope>
71+
<exclusions>
72+
<exclusion>
73+
<groupId>org.slf4j</groupId>
74+
<artifactId>slf4j-log4j12</artifactId>
75+
</exclusion>
76+
</exclusions>
77+
</dependency>
78+
6579
</dependencies>
6680

6781
<profiles>

basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/AASServerComponent.java

Lines changed: 89 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.net.URISyntaxException;
1414
import java.nio.file.Files;
1515
import java.nio.file.Paths;
16+
import java.security.ProviderException;
1617
import java.util.Collection;
1718
import java.util.List;
1819
import java.util.Set;
@@ -34,29 +35,27 @@
3435
import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
3536
import org.eclipse.basyx.aas.registration.api.IAASRegistry;
3637
import org.eclipse.basyx.aas.registration.proxy.AASRegistryProxy;
37-
import org.eclipse.basyx.aas.restapi.api.IAASAPIFactory;
38-
import org.eclipse.basyx.aas.restapi.vab.VABAASAPIFactory;
3938
import org.eclipse.basyx.components.IComponent;
4039
import org.eclipse.basyx.components.aas.aasx.AASXPackageManager;
4140
import org.eclipse.basyx.components.aas.configuration.AASServerBackend;
4241
import org.eclipse.basyx.components.aas.configuration.BaSyxAASServerConfiguration;
4342
import org.eclipse.basyx.components.aas.mongodb.MongoDBAASAggregator;
44-
import org.eclipse.basyx.components.aas.mqtt.MqttSubmodelAPIFactory;
4543
import org.eclipse.basyx.components.aas.servlet.AASAggregatorAASXUploadServlet;
4644
import org.eclipse.basyx.components.aas.servlet.AASAggregatorServlet;
4745
import org.eclipse.basyx.components.configuration.BaSyxConfiguration;
4846
import org.eclipse.basyx.components.configuration.BaSyxContextConfiguration;
4947
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
5048
import org.eclipse.basyx.components.configuration.BaSyxMqttConfiguration;
5149
import org.eclipse.basyx.extensions.aas.aggregator.aasxupload.AASAggregatorAASXUpload;
50+
import org.eclipse.basyx.extensions.aas.aggregator.mqtt.MqttAASAggregator;
5251
import org.eclipse.basyx.submodel.metamodel.api.ISubmodel;
5352
import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
54-
import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPIFactory;
5553
import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
5654
import org.eclipse.basyx.vab.modelprovider.VABPathTools;
5755
import org.eclipse.basyx.vab.protocol.http.server.BaSyxContext;
5856
import org.eclipse.basyx.vab.protocol.http.server.BaSyxHTTPServer;
5957
import org.eclipse.basyx.vab.protocol.http.server.VABHTTPInterface;
58+
import org.eclipse.paho.client.mqttv3.MqttException;
6059
import org.slf4j.Logger;
6160
import org.slf4j.LoggerFactory;
6261
import org.xml.sax.SAXException;
@@ -84,7 +83,7 @@ public class AASServerComponent implements IComponent {
8483

8584
// Initial AASBundle
8685
protected Collection<AASBundle> aasBundles;
87-
86+
8887
// Watcher for AAS Aggregator functionality
8988
private boolean isAASXUploadEnabled = false;
9089

@@ -107,17 +106,17 @@ public AASServerComponent(BaSyxContextConfiguration contextConfig, BaSyxAASServe
107106
/**
108107
* Constructs an empty AAS server using the passed configuration
109108
*/
110-
public AASServerComponent(BaSyxContextConfiguration contextConfig, BaSyxAASServerConfiguration aasConfig,
111-
BaSyxMongoDBConfiguration mongoDBConfig) {
109+
public AASServerComponent(BaSyxContextConfiguration contextConfig, BaSyxAASServerConfiguration aasConfig, BaSyxMongoDBConfiguration mongoDBConfig) {
112110
this.contextConfig = contextConfig;
113111
this.aasConfig = aasConfig;
114112
this.aasConfig.setAASBackend(AASServerBackend.MONGODB);
115113
this.mongoDBConfig = mongoDBConfig;
116114
}
117115

118116
/**
119-
* Sets and enables mqtt connection configuration for this component. Has to be called before the component is
120-
* started. Currently only works for InMemory backend.
117+
* Sets and enables mqtt connection configuration for this component. Has to be
118+
* called before the component is started. Currently only works for InMemory
119+
* backend.
121120
*
122121
* @param configuration
123122
*/
@@ -126,12 +125,13 @@ public void enableMQTT(BaSyxMqttConfiguration configuration) {
126125
}
127126

128127
/**
129-
* Disables mqtt configuration. Has to be called before the component is started.
128+
* Disables mqtt configuration. Has to be called before the component is
129+
* started.
130130
*/
131131
public void disableMQTT() {
132132
this.mqttConfig = null;
133133
}
134-
134+
135135
/**
136136
* Enables AASX upload functionality
137137
*/
@@ -155,13 +155,11 @@ public void setRegistry(IAASRegistry registry) {
155155
public void startComponent() {
156156
logger.info("Create the server...");
157157
// Load the aggregator servlet
158-
createRegistryFromUrl();
159-
VABHTTPInterface<?> aggregatorServlet = loadAggregatorServlet();
158+
registry = createRegistryFromConfig(aasConfig);
160159

161160
// Init HTTP context and add an XMLAASServlet according to the configuration
162161
BaSyxContext context = contextConfig.createBaSyxContext();
163-
context.addServletMapping("/*", aggregatorServlet);
164-
162+
context.addServletMapping("/*", createAggregatorServlet());
165163

166164
// An initial AAS has been loaded from the drive?
167165
if (aasBundles != null) {
@@ -191,10 +189,10 @@ public String getURL() {
191189

192190
@Override
193191
public void stopComponent() {
194-
192+
195193
// Remove all AASs/SMs that were registered on startup
196194
AASBundleHelper.deregister(registry, aasBundles);
197-
195+
198196
server.shutdown();
199197
}
200198

@@ -221,8 +219,7 @@ private void loadBundleFromJSON(String jsonPath) throws IOException {
221219
this.aasBundles = new JSONAASBundleFactory(jsonContent).create();
222220
}
223221

224-
private void loadBundleFromAASX(String aasxPath)
225-
throws IOException, ParserConfigurationException, SAXException, URISyntaxException, InvalidFormatException {
222+
private void loadBundleFromAASX(String aasxPath) throws IOException, ParserConfigurationException, SAXException, URISyntaxException, InvalidFormatException {
226223
logger.info("Loading aas from aasx \"" + aasxPath + "\"");
227224

228225
// Instantiate the aasx package manager
@@ -235,25 +232,73 @@ private void loadBundleFromAASX(String aasxPath)
235232
this.aasBundles = packageManager.retrieveAASBundles();
236233
}
237234

238-
private VABHTTPInterface<?> loadAggregatorServlet() {
239-
// Load the initial AAS bundles from given source
235+
private VABHTTPInterface<?> createAggregatorServlet() {
240236
loadAASFromSource(aasConfig.getAASSource());
237+
IAASAggregator aggregator = createAggregator();
241238

242-
// Load the aggregator
243-
IAASAggregator aggregator = loadAASAggregator();
244-
245-
// Integrate the loaded bundles into the aggregator
246239
if (aasBundles != null) {
247240
AASBundleHelper.integrate(aggregator, aasBundles);
248241
}
249242

250-
// Return the servlet for the resulting aggregator
251243
if (isAASXUploadEnabled) {
252-
return new AASAggregatorAASXUploadServlet(new AASAggregatorAASXUpload(aggregator));
244+
return new AASAggregatorAASXUploadServlet(new AASAggregatorAASXUpload(aggregator));
253245
} else {
254246
return new AASAggregatorServlet(aggregator);
255247
}
256-
248+
}
249+
250+
private IAASAggregator createAggregator() {
251+
final IAASAggregator aggregatorBackend = createAggregatorBackend();
252+
final IAASAggregator decoratedRegistry = decorate(aggregatorBackend);
253+
return decoratedRegistry;
254+
}
255+
256+
private IAASAggregator decorate(IAASAggregator aasAggregator) {
257+
IAASAggregator decoratedAggregator = aasAggregator;
258+
if (this.mqttConfig != null) {
259+
try {
260+
decoratedAggregator = new MqttAASAggregator(decoratedAggregator, mqttConfig.getServer(), getMqttClientId());
261+
} catch (MqttException e) {
262+
throw new ProviderException("moquette.conf Error" + e.getMessage());
263+
}
264+
logger.info("Enable MQTT events for broker " + this.mqttConfig.getServer());
265+
}
266+
return decoratedAggregator;
267+
}
268+
269+
private IAASAggregator createAggregatorBackend() {
270+
final AASServerBackend backendType = aasConfig.getAASBackend();
271+
switch (backendType) {
272+
case MONGODB:
273+
return createMongoDBAggregatorBackend();
274+
case INMEMORY:
275+
return createInMemoryAggregatorBackend();
276+
default:
277+
throw new RuntimeException("Unknown backend type " + backendType);
278+
}
279+
}
280+
281+
private IAASAggregator createMongoDBAggregatorBackend() {
282+
logger.info("Using MongoDB backend");
283+
return createMongoDBAggregator();
284+
}
285+
286+
private IAASAggregator createInMemoryAggregatorBackend() {
287+
logger.info("Using InMemory backend");
288+
return new AASAggregator(registry);
289+
}
290+
291+
private IAASAggregator createMongoDBAggregator() {
292+
BaSyxMongoDBConfiguration config;
293+
if (this.mongoDBConfig == null) {
294+
config = new BaSyxMongoDBConfiguration();
295+
config.loadFromDefaultSource();
296+
} else {
297+
config = this.mongoDBConfig;
298+
}
299+
MongoDBAASAggregator aggregator = new MongoDBAASAggregator(config);
300+
aggregator.setRegistry(registry);
301+
return aggregator;
257302
}
258303

259304
private void loadAASFromSource(String aasSource) {
@@ -278,17 +323,19 @@ private void loadAASFromSource(String aasSource) {
278323
/**
279324
* Only creates the registry, if it hasn't been set explicitly before
280325
*/
281-
private void createRegistryFromUrl() {
326+
private IAASRegistry createRegistryFromConfig(BaSyxAASServerConfiguration aasConfig) {
282327
if (this.registry != null) {
283328
// Do not overwrite an explicitly set registry
284-
return;
329+
return this.registry;
285330
}
286-
// Load registry url from config
287-
String registryUrl = this.aasConfig.getRegistry();
288-
if (registryUrl != null && !registryUrl.isEmpty()) {
289-
registry = new AASRegistryProxy(registryUrl);
290-
logger.info("Registry loaded at \"" + registryUrl + "\"");
331+
String registryUrl = aasConfig.getRegistry();
332+
if (registryUrl == null || registryUrl.isEmpty()) {
333+
return null;
291334
}
335+
// Load registry url from config
336+
logger.info("Registry loaded at \"" + registryUrl + "\"");
337+
return new AASRegistryProxy(registryUrl);
338+
292339
}
293340

294341
private void registerEnvironment() {
@@ -387,7 +434,8 @@ private String getComponentBasePath() {
387434
}
388435

389436
/**
390-
* Fixes the File submodel element value paths according to the given endpoint configuration
437+
* Fixes the File submodel element value paths according to the given endpoint
438+
* configuration
391439
*/
392440
private void modifyFilePaths(String hostName, int port, String rootPath) {
393441
rootPath = rootPath + "/files";
@@ -399,41 +447,11 @@ private void modifyFilePaths(String hostName, int port, String rootPath) {
399447
}
400448
}
401449

402-
/**
403-
* Loads a aas aggregator servlet with a backend according to the configuration
404-
*
405-
* @return
406-
*/
407-
private IAASAggregator loadAASAggregator() {
408-
// Get aggregator according to backend config
409-
AASServerBackend backendType = aasConfig.getAASBackend();
410-
IAASAggregator aggregator = null;
411-
if (backendType == AASServerBackend.INMEMORY && mqttConfig == null) {
412-
logger.info("Using InMemory backend");
413-
aggregator = new AASAggregator(registry);
414-
} else if (backendType == AASServerBackend.INMEMORY && mqttConfig != null) {
415-
logger.info("Using InMemory backend with MQTT providers");
416-
IAASAPIFactory aasApiProvider = new VABAASAPIFactory();
417-
ISubmodelAPIFactory smApiProvider = new MqttSubmodelAPIFactory(mqttConfig);
418-
aggregator = new AASAggregator(aasApiProvider, smApiProvider, registry);
419-
} else if ( backendType == AASServerBackend.MONGODB ) {
420-
logger.info("Using MongoDB backend");
421-
aggregator = loadMongoDBAggregator();
450+
private String getMqttClientId() {
451+
if (aasBundles == null || aasBundles.isEmpty()) {
452+
return "defaultNoShellId";
422453
}
423-
424-
return aggregator;
454+
return aasBundles.stream().findFirst().get().getAAS().getIdShort();
425455
}
426456

427-
private IAASAggregator loadMongoDBAggregator() {
428-
BaSyxMongoDBConfiguration config;
429-
if (this.mongoDBConfig == null) {
430-
config = new BaSyxMongoDBConfiguration();
431-
config.loadFromDefaultSource();
432-
} else {
433-
config = this.mongoDBConfig;
434-
}
435-
MongoDBAASAggregator aggregator = new MongoDBAASAggregator(config);
436-
aggregator.setRegistry(registry);
437-
return aggregator;
438-
}
439-
}
457+
}

basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/configuration/BaSyxAASServerConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class BaSyxAASServerConfiguration extends BaSyxConfiguration {
3636
public static final String DEFAULT_SOURCE = "";
3737
public static final String DEFAULT_REGISTRY = "";
3838
public static final String DEFAULT_EVENTS = AASEventBackend.NONE.toString();
39-
public static final String DEFAULT_AASX_UPLOAD = AASXUploadBackend.DISABLED.toString();
39+
public static final String DEFAULT_AASX_UPLOAD = AASXUploadBackend.ENABLED.toString();
4040

4141
// Configuration keys
4242
public static final String REGISTRY = "registry.path";

basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/executable/AASServerExecutable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* They are made available at
2828
* <i>localhost:4000/aasServer/shells/${aasId}/aas</i>. Submodels are available
2929
* at
30-
* <i>localhost:4000/aasServer/shells/${aasId}/submodels/${submodelId}/submodel</i><br>
30+
* <i>localhost:4000/aasServer/shells/${aasId}/aas/submodels/${submodelId}/submodel</i><br>
3131
*
3232
* @author schnicke, espen
3333
*/

basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aas.properties

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ aas.events=NONE
4141
# #############################
4242
# Possible to enable AASX Upload
4343

44-
aas.aasxUpload=Disabled
45-
# aas.aasxUpload=Enabled
46-
44+
aas.aasxUpload=Enabled
45+
# aas.aasxUpload=Disabled
4746

4847
# #############################
4948
# Registry

basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/AASServerSuite.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public abstract class AASServerSuite {
3434
protected IAASRegistry aasRegistry;
3535
protected ConnectedAssetAdministrationShellManager manager;
3636

37-
protected String aasId = "testId";
37+
protected String shellId = "testId";
3838

3939
protected abstract String getURL();
4040

@@ -50,13 +50,19 @@ public void setUp() {
5050

5151
@Test
5252
public void testAddAAS() throws Exception {
53-
AssetAdministrationShell shell = new AssetAdministrationShell();
54-
IIdentifier identifier = new ModelUrn(aasId);
55-
shell.setIdentification(identifier);
56-
shell.setIdShort("aasIdShort");
53+
IIdentifier shellIdentifier = new ModelUrn(shellId);
54+
AssetAdministrationShell shell = createShell("aasIdShort", new ModelUrn(shellId));
55+
5756
manager.createAAS(shell, getURL());
5857

59-
IAssetAdministrationShell remote = manager.retrieveAAS(identifier);
58+
IAssetAdministrationShell remote = manager.retrieveAAS(shellIdentifier);
6059
assertEquals(shell.getIdShort(), remote.getIdShort());
6160
}
61+
62+
private AssetAdministrationShell createShell(String idShort, IIdentifier identifier) {
63+
AssetAdministrationShell shell = new AssetAdministrationShell();
64+
shell.setIdentification(identifier);
65+
shell.setIdShort(idShort);
66+
return shell;
67+
}
6268
}

0 commit comments

Comments
 (0)