Adds mqtt event extension for IAASRegistryService

Signed-off-by: Ashfaqul Haque <ashfaqul.haque@iese.fraunhofer.de>
Change-Id: I9bb162b31cee87ec0b5305e6e5e6114d8c39d7a7
diff --git a/components/basys.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mqtt/MqttSubmodelAPIFactory.java b/components/basys.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mqtt/MqttSubmodelAPIFactory.java
index dfac89d..bc944aa 100644
--- a/components/basys.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mqtt/MqttSubmodelAPIFactory.java
+++ b/components/basys.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mqtt/MqttSubmodelAPIFactory.java
@@ -3,7 +3,7 @@
 import java.util.Set;
 
 import org.eclipse.basyx.components.configuration.BaSyxMqttConfiguration;
-import org.eclipse.basyx.extensions.events.submodel.mqtt.MqttSubmodelAPI;
+import org.eclipse.basyx.extensions.submodel.mqtt.MqttSubmodelAPI;
 import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
 import org.eclipse.basyx.submodel.metamodel.map.qualifier.Identifiable;
 import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPI;
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/aas/registration/mqtt/MqttAASRegistryService.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/aas/registration/mqtt/MqttAASRegistryService.java
new file mode 100644
index 0000000..d1cd947
--- /dev/null
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/aas/registration/mqtt/MqttAASRegistryService.java
@@ -0,0 +1,128 @@
+package org.eclipse.basyx.extensions.aas.registration.mqtt;
+
+import java.util.List;
+
+import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
+import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
+import org.eclipse.basyx.aas.registration.api.IAASRegistryService;
+import org.eclipse.basyx.extensions.shared.mqtt.MqttEventService;
+import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation variant for the AASRegistryService that triggers MQTT events for
+ * different operations on the registry. Has to be based on a backend
+ * implementation of the IAASRegistryService to forward its method calls.
+ * 
+ * @author haque
+ *
+ */
+public class MqttAASRegistryService extends MqttEventService implements IAASRegistryService {
+	private static Logger logger = LoggerFactory.getLogger(MqttAASRegistryService.class);
+
+	// List of topics
+	public static final String TOPIC_REGISTERAAS = "Registry_registeredAAS";
+	public static final String TOPIC_REGISTERSUBMODEL = "Registry_registeredSubmodel";
+	public static final String TOPIC_DELETEAAS = "Registry_deletedAAS";
+	public static final String TOPIC_DELETESUBMODEL = "Registry_deletedSubmodel";
+
+	// The underlying AASRegistryService
+	protected IAASRegistryService observedRegistryService;
+	
+	/**
+	 * Constructor for adding this MQTT extension on top of an AASRegistryService
+	 * 
+	 * @param observedRegistryService the underlying registry service 
+	 * @param serverEndpoint endpoint of mqtt broker
+	 * @param clientId unique client identifier
+	 * @throws MqttException
+	 */
+	public MqttAASRegistryService(IAASRegistryService observedRegistryService, String serverEndpoint, String clientId) throws MqttException {
+		super(serverEndpoint, clientId);
+		logger.info("Create new MQTT AAS Registry Service for endpoint " + serverEndpoint);
+		this.observedRegistryService = observedRegistryService;
+	}
+
+	/**
+	 * Constructor for adding this MQTT extension on top of an AASRegistryService
+	 * 
+	 * @param observedRegistryService the underlying registry service 
+	 * @param serverEndpoint endpoint of mqtt broker
+	 * @param clientId unique client identifier
+	 * @param user username for authentication with broker
+	 * @param pw password for authentication with broker
+	 * @throws MqttException
+	 */
+	public MqttAASRegistryService(IAASRegistryService observedRegistryService, String serverEndpoint, String clientId, String user, char[] pw)
+			throws MqttException {
+		super(serverEndpoint, clientId, user, pw);
+		logger.info("Create new MQTT AAS Registry Service for endpoint " + serverEndpoint);
+		this.observedRegistryService = observedRegistryService;
+	}
+	
+	/**
+	 * Constructor for adding this MQTT extension on top of an AASRegistryService
+	 * 
+	 * @param observedRegistryService the underlying registry service 
+	 * @param client already configured client
+	 * @throws MqttException
+	 */
+	public MqttAASRegistryService(IAASRegistryService observedRegistryService, MqttClient client) throws MqttException {
+		super(client);
+		logger.info("Create new MQTT AAS Registry Service for endpoint " + client.getServerURI());
+		this.observedRegistryService = observedRegistryService;
+	}
+
+	
+	@Override
+	public void register(AASDescriptor deviceAASDescriptor) throws ProviderException {
+		this.observedRegistryService.register(deviceAASDescriptor);
+		sendMqttMessage(TOPIC_REGISTERAAS, deviceAASDescriptor.getIdentifier().getId());	
+	}
+
+	@Override
+	public void register(IIdentifier aas, SubmodelDescriptor smDescriptor) throws ProviderException {
+		this.observedRegistryService.register(aas, smDescriptor);
+		sendMqttMessage(TOPIC_REGISTERSUBMODEL, concatAasSmId(aas, smDescriptor.getIdentifier()));
+	}
+
+	@Override
+	public void delete(IIdentifier aasId) throws ProviderException {
+		this.observedRegistryService.delete(aasId);
+		sendMqttMessage(TOPIC_DELETEAAS, aasId.getId());
+	}
+
+	@Override
+	public void delete(IIdentifier aasId, IIdentifier smId) throws ProviderException {
+		this.observedRegistryService.delete(aasId, smId);
+		sendMqttMessage(TOPIC_DELETESUBMODEL, concatAasSmId(aasId, smId));
+	}
+
+	@Override
+	public AASDescriptor lookupAAS(IIdentifier aasId) throws ProviderException {
+		return this.observedRegistryService.lookupAAS(aasId);
+	}
+
+	@Override
+	public List<AASDescriptor> lookupAll() throws ProviderException {
+		return this.observedRegistryService.lookupAll();
+	}
+
+	@Override
+	public List<SubmodelDescriptor> lookupSubmodels(IIdentifier aasId) throws ProviderException {
+		return this.observedRegistryService.lookupSubmodels(aasId);
+	}
+
+	@Override
+	public SubmodelDescriptor lookupSubmodel(IIdentifier aasId, IIdentifier smId) throws ProviderException {
+		return this.observedRegistryService.lookupSubmodel(aasId, smId);
+	}
+	
+	public static String concatAasSmId(IIdentifier aasId, IIdentifier smId) {
+		return "(" + aasId.getId() + "," + smId.getId() + ")";
+	}
+}
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/shared/mqtt/MqttEventService.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/shared/mqtt/MqttEventService.java
new file mode 100644
index 0000000..d31019b
--- /dev/null
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/shared/mqtt/MqttEventService.java
@@ -0,0 +1,107 @@
+package org.eclipse.basyx.extensions.shared.mqtt;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
+import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of common parts of MQTT event propagation services.
+ * Extend this class to make a service MQTT extendable
+ *  
+ * @author haque
+ *
+ */
+public class MqttEventService {
+	private static Logger logger = LoggerFactory.getLogger(MqttEventService.class);
+
+	// The MQTTClient
+	protected MqttClient mqttClient;
+
+	// QoS for MQTT messages (1, 2 or 3).
+	protected int qos = 1;
+	
+	/**
+	 * Constructor for creating an MqttClient (no authentication)
+	 * @param serverEndpoint
+	 * @param clientId
+	 * @throws MqttException
+	 */
+	public MqttEventService(String serverEndpoint, String clientId) throws MqttException {
+		this.mqttClient = new MqttClient(serverEndpoint, clientId, new MqttDefaultFilePersistence());
+		mqttClient.connect();
+	}
+	
+	/**
+	 * Constructor for creating an MqttClient with authentication
+	 * @param serverEndpoint
+	 * @param clientId
+	 * @param user
+	 * @param pw
+	 * @throws MqttException
+	 */
+	public MqttEventService(String serverEndpoint, String clientId, String user, char[] pw)
+			throws MqttException {
+		this.mqttClient = new MqttClient(serverEndpoint, clientId, new MqttDefaultFilePersistence());
+		MqttConnectOptions options = new MqttConnectOptions();
+		options.setUserName(user);
+		options.setPassword(pw);
+		mqttClient.connect(options);
+	}
+	
+	/**
+	 * Constructor for creating an MqttClient with existing client
+	 * @param client
+	 * @throws MqttException
+	 */
+	public MqttEventService(MqttClient client) throws MqttException {
+		this.mqttClient = client;
+		mqttClient.connect();
+	}
+
+	/**
+	 * Sets the QoS for MQTT messages
+	 * 
+	 * @param qos
+	 */
+	public void setQoS(int qos) {
+		if (qos >= 0 && qos <= 3) {
+			this.qos = qos;
+		} else {
+			throw new IllegalArgumentException("Invalid QoS: " + qos);
+		}
+	}
+
+	/**
+	 * Gets the QoS for MQTT messages
+	 * 
+	 * @param qos
+	 */
+	public int getQoS() {
+		return this.qos;
+	}
+	
+	/**
+	 * Sends MQTT message to connected broker
+	 * @param topic in which the message will be published
+	 * @param payload the actual message
+	 */
+	protected void sendMqttMessage(String topic, String payload) {
+		MqttMessage msg = new MqttMessage(payload.getBytes());
+		if (this.qos != 1) {
+			msg.setQos(this.qos);
+		}
+		try {
+			logger.debug("Send MQTT message to " + topic + ": " + payload);
+			mqttClient.publish(topic, msg);
+		} catch (MqttPersistenceException e) {
+			logger.error("Could not persist mqtt message", e);
+		} catch (MqttException e) {
+			logger.error("Could not send mqtt message", e);
+		}
+	}
+}
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/events/submodel/mqtt/MqttSubmodelAPI.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/submodel/mqtt/MqttSubmodelAPI.java
similarity index 76%
rename from sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/events/submodel/mqtt/MqttSubmodelAPI.java
rename to sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/submodel/mqtt/MqttSubmodelAPI.java
index 04cc3b6..0bb1352 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/events/submodel/mqtt/MqttSubmodelAPI.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/extensions/submodel/mqtt/MqttSubmodelAPI.java
@@ -1,20 +1,17 @@
-package org.eclipse.basyx.extensions.events.submodel.mqtt;
+package org.eclipse.basyx.extensions.submodel.mqtt;
 
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
+import org.eclipse.basyx.extensions.shared.mqtt.MqttEventService;
 import org.eclipse.basyx.submodel.metamodel.api.ISubModel;
 import org.eclipse.basyx.submodel.metamodel.api.submodelelement.ISubmodelElement;
 import org.eclipse.basyx.submodel.metamodel.api.submodelelement.operation.IOperation;
 import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPI;
 import org.eclipse.basyx.vab.modelprovider.VABPathTools;
 import org.eclipse.paho.client.mqttv3.MqttClient;
-import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
 import org.eclipse.paho.client.mqttv3.MqttException;
-import org.eclipse.paho.client.mqttv3.MqttMessage;
-import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
-import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -26,7 +23,7 @@
  * @author espen
  *
  */
-public class MqttSubmodelAPI implements ISubmodelAPI {
+public class MqttSubmodelAPI extends MqttEventService implements ISubmodelAPI {
 	private static Logger logger = LoggerFactory.getLogger(MqttSubmodelAPI.class);
 
 	// List of topics
@@ -38,16 +35,10 @@
 	// The underlying SubmodelAPI
 	protected ISubmodelAPI observedAPI;
 
-	// The MQTTClient
-	protected MqttClient mqttClient;
-
 	// Submodel Element whitelist for filtering
 	protected boolean useWhitelist = false;
 	protected Set<String> whitelist = new HashSet<>();
 
-	// QoS for MQTT messages (1, 2 or 3).
-	protected int qos = 1;
-
 	/**
 	 * Constructor for adding this MQTT extension on top of another SubmodelAPI
 	 * 
@@ -55,10 +46,9 @@
 	 * @throws MqttException
 	 */
 	public MqttSubmodelAPI(ISubmodelAPI observedAPI, String serverEndpoint, String clientId) throws MqttException {
+		super(serverEndpoint, clientId);
 		logger.info("Create new MQTT submodel for endpoint " + serverEndpoint);
 		this.observedAPI = observedAPI;
-		this.mqttClient = new MqttClient(serverEndpoint, clientId, new MqttDefaultFilePersistence());
-		mqttClient.connect();
 		sendMqttMessage(TOPIC_ADDSUBMODEL, observedAPI.getSubmodel().getIdentification().getId());
 	}
 
@@ -70,60 +60,26 @@
 	 */
 	public MqttSubmodelAPI(ISubmodelAPI observedAPI, String serverEndpoint, String clientId, String user, char[] pw)
 			throws MqttException {
+		super(serverEndpoint, clientId, user, pw);
 		logger.info("Create new MQTT submodel for endpoint " + serverEndpoint);
 		this.observedAPI = observedAPI;
-		this.mqttClient = new MqttClient(serverEndpoint, clientId, new MqttDefaultFilePersistence());
-		MqttConnectOptions options = new MqttConnectOptions();
-		options.setUserName(user);
-		options.setPassword(pw);
-		mqttClient.connect(options);
 		sendMqttMessage(TOPIC_ADDSUBMODEL, observedAPI.getSubmodel().getIdentification().getId());
 	}
 
 	/**
-	 * Returns the connected mqttClient
-	 * 
-	 * @return
-	 */
-	public MqttClient getClient() {
-		return mqttClient;
-	}
-
-	/**
 	 * Constructor for adding this MQTT extension on top of another SubmodelAPI.
 	 * 
 	 * @param observedAPI The underlying submodelAPI
 	 * @param client      An already connected mqtt client
+	 * @throws MqttException 
 	 */
-	public MqttSubmodelAPI(ISubmodelAPI observedAPI, MqttClient client) {
+	public MqttSubmodelAPI(ISubmodelAPI observedAPI, MqttClient client) throws MqttException {
+		super(client);
 		this.observedAPI = observedAPI;
-		this.mqttClient = client;
 		sendMqttMessage(TOPIC_ADDSUBMODEL, observedAPI.getSubmodel().getIdentification().getId());
 	}
 
 	/**
-	 * Sets the QoS for MQTT messages
-	 * 
-	 * @param qos
-	 */
-	public void setQoS(int qos) {
-		if (qos >= 0 && qos <= 3) {
-			this.qos = qos;
-		} else {
-			throw new IllegalArgumentException("Invalid QoS: " + qos);
-		}
-	}
-
-	/**
-	 * Gets the QoS for MQTT messages
-	 * 
-	 * @param qos
-	 */
-	public int getQoS() {
-		return this.qos;
-	}
-
-	/**
 	 * Adds a submodel element to the filter whitelist. Can also be a path for nested submodel elements.
 	 * 
 	 * @param element
@@ -237,21 +193,6 @@
 		return observedAPI.getOperationResult(idShort, requestId);
 	}
 
-	private void sendMqttMessage(String topic, String payload) {
-		MqttMessage msg = new MqttMessage(payload.getBytes());
-		if (this.qos != 1) {
-			msg.setQos(this.qos);
-		}
-		try {
-			logger.debug("Send MQTT message to " + topic + ": " + payload);
-			mqttClient.publish(topic, msg);
-		} catch (MqttPersistenceException e) {
-			logger.error("Could not persist mqtt message", e);
-		} catch (MqttException e) {
-			logger.error("Could not send mqtt message", e);
-		}
-	}
-
 	private boolean filter(String idShort) {
 		return !useWhitelist || whitelist.contains(idShort);
 	}
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/aas/registration/mqtt/TestMqttAASRegistryService.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/aas/registration/mqtt/TestMqttAASRegistryService.java
new file mode 100644
index 0000000..cd6df8d
--- /dev/null
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/aas/registration/mqtt/TestMqttAASRegistryService.java
@@ -0,0 +1,135 @@
+package org.eclipse.basyx.testsuite.regression.extensions.aas.registration.mqtt;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.eclipse.basyx.aas.metamodel.api.parts.asset.AssetKind;
+import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;
+import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
+import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
+import org.eclipse.basyx.aas.metamodel.map.parts.Asset;
+import org.eclipse.basyx.aas.registration.api.IAASRegistryService;
+import org.eclipse.basyx.aas.registration.memory.InMemoryRegistry;
+import org.eclipse.basyx.extensions.aas.registration.mqtt.MqttAASRegistryService;
+import org.eclipse.basyx.submodel.metamodel.api.identifier.IdentifierType;
+import org.eclipse.basyx.submodel.metamodel.map.SubModel;
+import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
+import org.eclipse.basyx.testsuite.regression.extensions.shared.mqtt.MqttTestListener;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import io.moquette.broker.Server;
+import io.moquette.broker.config.ClasspathResourceLoader;
+import io.moquette.broker.config.IConfig;
+import io.moquette.broker.config.IResourceLoader;
+import io.moquette.broker.config.ResourceLoaderConfig;
+
+/**
+ * Tests events emitting with the MqttAASRegistryService
+ * 
+ * @author haque
+ *
+ */
+public class TestMqttAASRegistryService {
+	
+	private static final String AASID = "aasid1";
+	private static final String SUBMODELID = "submodelid1";
+	private static final String AASENDPOINT = "http://localhost:8080/aasList/" + AASID + "/aas";
+	private static final Identifier AASIDENTIFIER = new Identifier(IdentifierType.IRI, AASID);
+	private static final Identifier SUBMODELIDENTIFIER = new Identifier(IdentifierType.IRI, SUBMODELID);
+	
+	private static Server mqttBroker;
+	private static MqttAASRegistryService eventAPI;
+	private MqttTestListener listener;
+
+	/**
+	 * Sets up the MQTT broker and AASRegistryService for tests
+	 */
+	@BeforeClass
+	public static void setUpClass() throws MqttException, IOException {
+		// Start MQTT broker
+		mqttBroker = new Server();
+		IResourceLoader classpathLoader = new ClasspathResourceLoader();
+		final IConfig classPathConfig = new ResourceLoaderConfig(classpathLoader);
+		mqttBroker.startServer(classPathConfig);
+
+		// Create underlying registry service
+		IAASRegistryService registryService = new InMemoryRegistry();
+		
+		eventAPI = new MqttAASRegistryService(registryService, "tcp://localhost:1884", "testClient");
+	}
+
+	@AfterClass
+	public static void tearDownClass() {
+		mqttBroker.stopServer();
+	}
+	
+	@Before
+	public void setUp() {
+		AssetAdministrationShell shell = new AssetAdministrationShell(AASID, AASIDENTIFIER, new Asset("assetid1", new Identifier(IdentifierType.IRI, "assetid1"), AssetKind.INSTANCE));
+		AASDescriptor aasDescriptor = new AASDescriptor(shell, AASENDPOINT);
+		eventAPI.register(aasDescriptor);
+		
+		SubModel submodel = new SubModel(SUBMODELID, SUBMODELIDENTIFIER);
+		String submodelEndpoint = AASENDPOINT + "/submodels/" + SUBMODELID + "/submodel";
+		SubmodelDescriptor submodelDescriptor = new SubmodelDescriptor(submodel, submodelEndpoint);
+		eventAPI.register(AASIDENTIFIER, submodelDescriptor);
+		
+		listener = new MqttTestListener();
+		mqttBroker.addInterceptHandler(listener);
+	}
+	
+	@After
+	public void tearDown() {
+		mqttBroker.removeInterceptHandler(listener);
+	}
+	
+	@Test
+	public void testRegisterAAS() {
+		String newAASId = "aasid2";
+		Identifier newIdentifier = new Identifier(IdentifierType.IRI, newAASId);
+		AssetAdministrationShell shell = new AssetAdministrationShell(newAASId, newIdentifier, new Asset("assetid1", new Identifier(IdentifierType.IRI, "assetid2"), AssetKind.INSTANCE));
+		String aasEndpoint = "http://localhost:8080/aasList/" + newAASId + "/aas";
+		
+		AASDescriptor aasDescriptor = new AASDescriptor(shell, aasEndpoint);
+		eventAPI.register(aasDescriptor);
+		
+		assertEquals(newAASId, listener.lastPayload);
+		assertEquals(MqttAASRegistryService.TOPIC_REGISTERAAS, listener.lastTopic);
+	}
+	
+	@Test
+	public void testRegisterSubmodel() {
+		String submodelid = "submodelid2";
+		Identifier newSubmodelIdentifier = new Identifier(IdentifierType.IRI, submodelid);
+		SubModel submodel = new SubModel(submodelid, newSubmodelIdentifier);
+		String submodelEndpoint = AASENDPOINT + "/submodels/" + submodelid + "/submodel";
+		SubmodelDescriptor submodelDescriptor = new SubmodelDescriptor(submodel, submodelEndpoint);
+		
+		eventAPI.register(AASIDENTIFIER, submodelDescriptor);
+		
+		assertEquals(MqttAASRegistryService.concatAasSmId(AASIDENTIFIER, newSubmodelIdentifier), listener.lastPayload);
+		assertEquals(MqttAASRegistryService.TOPIC_REGISTERSUBMODEL, listener.lastTopic);
+	}
+	
+	@Test
+	public void testDeleteAAS() {
+		eventAPI.delete(AASIDENTIFIER);
+		
+		assertEquals(AASID, listener.lastPayload);
+		assertEquals(MqttAASRegistryService.TOPIC_DELETEAAS, listener.lastTopic);
+	}
+	
+	@Test
+	public void testDeleteSubmodel() {
+		eventAPI.delete(AASIDENTIFIER, SUBMODELIDENTIFIER);
+
+		assertEquals(MqttAASRegistryService.concatAasSmId(AASIDENTIFIER, SUBMODELIDENTIFIER), listener.lastPayload);
+		assertEquals(MqttAASRegistryService.TOPIC_DELETESUBMODEL, listener.lastTopic);
+	}
+}
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/events/submodel/mqtt/MqttTestListener.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/shared/mqtt/MqttTestListener.java
similarity index 95%
rename from sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/events/submodel/mqtt/MqttTestListener.java
rename to sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/shared/mqtt/MqttTestListener.java
index 92ad66c..e0e297d 100644
--- a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/events/submodel/mqtt/MqttTestListener.java
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/shared/mqtt/MqttTestListener.java
@@ -1,4 +1,4 @@
-package org.eclipse.basyx.testsuite.regression.extensions.events.submodel.mqtt;
+package org.eclipse.basyx.testsuite.regression.extensions.shared.mqtt;
 
 import java.nio.charset.StandardCharsets;
 
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/events/submodel/mqtt/TestMqttSubmodelAPIEvents.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/submodel/mqtt/TestMqttSubmodelAPIEvents.java
similarity index 94%
rename from sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/events/submodel/mqtt/TestMqttSubmodelAPIEvents.java
rename to sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/submodel/mqtt/TestMqttSubmodelAPIEvents.java
index 6fafffb..2eb9ca0 100644
--- a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/events/submodel/mqtt/TestMqttSubmodelAPIEvents.java
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/extensions/submodel/mqtt/TestMqttSubmodelAPIEvents.java
@@ -1,17 +1,18 @@
-package org.eclipse.basyx.testsuite.regression.extensions.events.submodel.mqtt;
+package org.eclipse.basyx.testsuite.regression.extensions.submodel.mqtt;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
 import java.io.IOException;
 
-import org.eclipse.basyx.extensions.events.submodel.mqtt.MqttSubmodelAPI;
+import org.eclipse.basyx.extensions.submodel.mqtt.MqttSubmodelAPI;
 import org.eclipse.basyx.submodel.metamodel.api.identifier.IdentifierType;
 import org.eclipse.basyx.submodel.metamodel.map.SubModel;
 import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
 import org.eclipse.basyx.submodel.metamodel.map.submodelelement.SubmodelElementCollection;
 import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.Property;
 import org.eclipse.basyx.submodel.restapi.vab.VABSubmodelAPI;
+import org.eclipse.basyx.testsuite.regression.extensions.shared.mqtt.MqttTestListener;
 import org.eclipse.basyx.vab.modelprovider.map.VABMapProvider;
 import org.eclipse.paho.client.mqttv3.MqttException;
 import org.junit.After;