Merge "Adds possibility to register submodels to an aas"
diff --git a/components/basys.components/src/test/java/org/eclipse/basyx/regression/directory/sql/TestSQLRegistryProvider.java b/components/basys.components/src/test/java/org/eclipse/basyx/regression/directory/sql/TestSQLRegistryProvider.java
index 851d291..035f879 100644
--- a/components/basys.components/src/test/java/org/eclipse/basyx/regression/directory/sql/TestSQLRegistryProvider.java
+++ b/components/basys.components/src/test/java/org/eclipse/basyx/regression/directory/sql/TestSQLRegistryProvider.java
@@ -58,4 +58,10 @@
 		IModelProvider apiProxy = new VABElementProxy("/api/v1/registry", provider);
 		return apiProxy;
 	}
+
+	@Override
+	public void testSubmodelCalls() {
+		// FIXME: This test case is currently overwritten since the SQLProvider does not
+		// support the submodel api.
+	}
 }
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java
index 7750b07..2adffa1 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/manager/ConnectedAssetAdministrationShellManager.java
@@ -51,7 +51,7 @@
 		AASDescriptor aasDescriptor = aasDirectory.lookupAAS(aasId);
 
 		// Get submodel descriptor from the aas descriptor
-		SubmodelDescriptor smDescriptor = aasDescriptor.getSubModelDescriptor(smId.getId());
+		SubmodelDescriptor smDescriptor = aasDescriptor.getSubModelDescriptorFromIdentifierId(smId.getId());
 
 		// get address of the submodel descriptor
 		String addr = smDescriptor.getFirstEndpoint();
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/AASDescriptor.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/AASDescriptor.java
index cf31e92..22d135c 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/AASDescriptor.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/AASDescriptor.java
@@ -3,6 +3,7 @@
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -91,11 +92,26 @@
 		return this;
 	}
 
+	@SuppressWarnings("unchecked")
+	public void removeSubmodelDescriptor(String idShort) {
+		Optional<SubmodelDescriptor> toRemove = getSubModelDescriptors().stream().filter(x -> x.getIdShort().equals(idShort)).findAny();
+
+		// TODO: Exception in else case
+		if (toRemove.isPresent()) {
+			// Don't use getSubmodelDescriptors here since it returns a copy
+			((Set<Object>) get(AssetAdministrationShell.SUBMODELS)).remove(toRemove.get());
+		}
+	}
+
 	/**
-	 * Get a specific sub model descriptor
+	 * Retrieves a submodel descriptor based on the globally unique id of the
+	 * submodel
+	 * 
+	 * @param subModelId
+	 * @return
 	 */
 	@SuppressWarnings("unchecked")
-	public SubmodelDescriptor getSubModelDescriptor(String subModelId) {
+	public SubmodelDescriptor getSubModelDescriptorFromIdentifierId(String subModelId) {
 		// Sub model descriptors are stored in a list
 		Collection<Map<String, Object>> smDescriptorMaps = (Collection<Map<String, Object>>) get(
 				AssetAdministrationShell.SUBMODELS);
@@ -114,10 +130,20 @@
 	}
 
 	/**
+	 * Retrieves a submodel descriptor based on the idShort of the submodel
+	 * 
+	 * @param idShort
+	 * @return
+	 */
+	public SubmodelDescriptor getSubmodelDescriptorFromIdShort(String idShort) {
+		return getSubModelDescriptors().stream().filter(x -> x.getIdShort().equals(idShort)).findAny().orElse(null); // TODO: Exception
+	}
+
+	/**
 	 * Get a specific sub model descriptor from a ModelUrn
 	 */
 	public SubmodelDescriptor getSubModelDescriptor(ModelUrn submodelUrn) {
-		return getSubModelDescriptor(submodelUrn.getURN());
+		return getSubModelDescriptorFromIdentifierId(submodelUrn.getURN());
 	}
 
 	/**
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/ModelDescriptor.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/ModelDescriptor.java
index 2a18a4d..61fe599 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/ModelDescriptor.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/metamodel/map/descriptor/ModelDescriptor.java
@@ -5,9 +5,11 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+
 import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;
 import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
 import org.eclipse.basyx.submodel.metamodel.facade.identifier.IdentifierFacade;
+import org.eclipse.basyx.submodel.metamodel.facade.qualifier.ReferableFacade;
 import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
 import org.eclipse.basyx.submodel.metamodel.map.qualifier.Identifiable;
 import org.eclipse.basyx.submodel.metamodel.map.qualifier.Referable;
@@ -62,6 +64,10 @@
 		return new IdentifierFacade(identifierModel);
 	}
 	
+	public String getIdShort() {
+		return new ReferableFacade(this).getIdShort();
+	}
+
 	/**
 	 * Return first AAS endpoint
 	 */
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/api/IAASRegistryService.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/api/IAASRegistryService.java
index 17462e9..4b0b0e2 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/api/IAASRegistryService.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/api/IAASRegistryService.java
@@ -3,6 +3,7 @@
 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.submodel.metamodel.api.identifier.IIdentifier;
 
 
@@ -28,15 +29,24 @@
 
 	
 	/**
+	 * Register SM descriptor in registry, delete old registration
+	 */
+	public void register(IIdentifier aas, SubmodelDescriptor smDescriptor);
+
+	/**
 	 * Delete AAS descriptor from registry
 	 */
-	public void delete(IIdentifier aasID);
+	public void delete(IIdentifier aasId);
 	
+	/**
+	 * Delete SM descriptor from registry
+	 */
+	public void delete(IIdentifier aasId, String smIdShort);
 	
 	/**
 	 * Lookup AAS
 	 */
-	public AASDescriptor lookupAAS(IIdentifier aasID);
+	public AASDescriptor lookupAAS(IIdentifier aasId);
 
 	/**
 	 * Retrieve all registered AAS
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/memory/InMemoryRegistry.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/memory/InMemoryRegistry.java
index e770bcb..70d0281 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/memory/InMemoryRegistry.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/memory/InMemoryRegistry.java
@@ -6,6 +6,7 @@
 import java.util.Map;
 
 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.submodel.metamodel.api.identifier.IIdentifier;
 
@@ -47,4 +48,16 @@
 		return new ArrayList<>(descriptorMap.values());
 	}
 
+	@Override
+	public void register(IIdentifier aas, SubmodelDescriptor smDescriptor) {
+		descriptorMap.get(aas.getId()).addSubmodelDescriptor(smDescriptor);
+		// TODO: Add data to remote AAS
+	}
+
+	@Override
+	public void delete(IIdentifier aasId, String smIdShort) {
+		AASDescriptor desc = descriptorMap.get(aasId.getId());
+		desc.removeSubmodelDescriptor(smIdShort);
+	}
+
 }
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/proxy/AASRegistryProxy.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/proxy/AASRegistryProxy.java
index 7174ecb..b7bfc67 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/proxy/AASRegistryProxy.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/proxy/AASRegistryProxy.java
@@ -8,11 +8,14 @@
 import java.util.stream.Collectors;
 
 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.aas.registration.restapi.DirectoryModelProvider;
 import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
 import org.eclipse.basyx.vab.coder.json.connector.JSONConnector;
 import org.eclipse.basyx.vab.directory.proxy.VABDirectoryProxy;
 import org.eclipse.basyx.vab.modelprovider.VABElementProxy;
+import org.eclipse.basyx.vab.modelprovider.VABPathTools;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 import org.eclipse.basyx.vab.protocol.http.connector.HTTPConnector;
 import org.slf4j.Logger;
@@ -118,5 +121,28 @@
 			return null;
 		}
 	}
+
+	@Override
+	public void register(IIdentifier aas, SubmodelDescriptor smDescriptor) {
+		delete(aas, smDescriptor.getIdShort());
+		try {
+			provider.createValue(buildSubmodelPath(aas), smDescriptor);
+		} catch (Exception e) {
+			logger.error("Exception in registering a Submodel", e);
+		}
+	}
+
+	@Override
+	public void delete(IIdentifier aasId, String smIdShort) {
+		try {
+			provider.deleteValue(VABPathTools.concatenatePaths(buildSubmodelPath(aasId), smIdShort));
+		} catch (Exception e) {
+			logger.error("Exception in deleting a Submodel", e);
+		}
+	}
+
+	private String buildSubmodelPath(IIdentifier aas) {
+		return VABPathTools.concatenatePaths(aas.getId(), DirectoryModelProvider.SUBMODELS);
+	}
 }
 
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/restapi/DirectoryModelProvider.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/restapi/DirectoryModelProvider.java
index 92fba3f..a40c408 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/restapi/DirectoryModelProvider.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/restapi/DirectoryModelProvider.java
@@ -4,6 +4,7 @@
 
 import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
 import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;
+import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
 import org.eclipse.basyx.aas.registration.api.IAASRegistryService;
 import org.eclipse.basyx.aas.registration.memory.InMemoryRegistry;
 import org.eclipse.basyx.vab.modelprovider.VABPathTools;
@@ -18,8 +19,9 @@
 public class DirectoryModelProvider implements IModelProvider {
 
 	IAASRegistryService registry;
-	
+
 	private static final String PREFIX = "api/v1/registry";
+	public static final String SUBMODELS = "submodels";
 
 	public DirectoryModelProvider(IAASRegistryService registry) {
 		this.registry = registry;
@@ -83,8 +85,10 @@
 
 		if (path.isEmpty()) { // Creating new entry
 			registry.register((AASDescriptor) newEntity);
+		} else if (path.endsWith(SUBMODELS)) {
+			registry.register(new ModelUrn(path.replace("/" + SUBMODELS, "")), (SubmodelDescriptor) newEntity);
 		} else {
-			throw new RuntimeException("Create with non-empty path is not supported by registry");
+			throw new RuntimeException("Create was called with an unsupported path: " + path);
 		}
 	}
 
@@ -93,9 +97,17 @@
 		path = stripPrefix(path);
 
 		if (!path.isEmpty()) { // Deleting an entry
-			// Decode encoded path
-			path = URLDecoder.decode(path, "UTF-8");
-			registry.delete(new ModelUrn(path));
+			if (path.contains(SUBMODELS)) {
+				// Delete submodel from AAS
+				String[] splitted = path.split("/" + SUBMODELS + "/");
+				String aasId = URLDecoder.decode(splitted[0], "UTF-8");
+				String smIdShort = splitted[1];
+				registry.delete(new ModelUrn(aasId), smIdShort);
+			} else {
+				// Decode encoded path
+				path = URLDecoder.decode(path, "UTF-8");
+				registry.delete(new ModelUrn(path));
+			}
 		} else {
 			throw new RuntimeException("Delete with empty path is not supported by registry");
 		}
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/proxy/TestRegistryProvider.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/proxy/TestRegistryProvider.java
index 718bbe7..53cdec5 100644
--- a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/proxy/TestRegistryProvider.java
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/proxy/TestRegistryProvider.java
@@ -9,6 +9,7 @@
 import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
 import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;
 import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
+import org.eclipse.basyx.aas.registration.api.IAASRegistryService;
 import org.eclipse.basyx.aas.registration.proxy.AASRegistryProxy;
 import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
 import org.eclipse.basyx.submodel.metamodel.map.qualifier.Referable;
@@ -25,19 +26,22 @@
  */
 public abstract class TestRegistryProvider {
 	// The registry proxy that is used to access the sql servlet
-	protected final AASRegistryProxy proxy = new AASRegistryProxy(getProxyProvider());
+	protected final IAASRegistryService proxy = new AASRegistryProxy(getProxyProvider());
 
 	// Ids, shortIds and endpoints for registered AAS and submodel
 	protected IIdentifier aasId1 = new ModelUrn("urn:de.FHG:devices.es.iese:aas:1.0:1:registryAAS#001");
 	protected IIdentifier aasId2 = new ModelUrn("urn:de.FHG:devices.es.iese:aas:1.0:1:registryAAS#002");
-	protected IIdentifier smId = new ModelUrn("urn:de.FHG:devices.es.iese:aas:1.0:1:statusSM#001");
+	protected IIdentifier smId1 = new ModelUrn("urn:de.FHG:devices.es.iese:aas:1.0:1:statusSM#001");
+	protected IIdentifier smId2 = new ModelUrn("urn:de.FHG:devices.es.iese:aas:1.0:1:testSM#001");
 	protected String aasIdShort1 = "aasIdShort1";
 	protected String aasIdShort2 = "aasIdShort2";
-	protected String smIdShort = "smIdShort";
+	protected String smIdShort1 = "smIdShort1";
+	protected String smIdShort2 = "smIdShort2";
 	protected String aasEndpoint1 = "http://www.registrytest.de/aas01/aas";
 	protected String aasEndpoint2 = "http://www.registrytest.de/aas02/aas";
-	protected String smEndpoint = "http://www.registrytest.de/aas01/aas/submodels/" + smIdShort;
-
+	protected String smEndpoint1 = "http://www.registrytest.de/aas01/aas/submodels/" + smIdShort1;
+	protected String smEndpoint2 = "http://www.registrytest.de/aas01/aas/submodels/" + smIdShort2;
+	
 	/**
 	 * Getter for the tested registry provider. Tests for actual registry provider
 	 * have to realize this method.
@@ -51,7 +55,7 @@
 	public void setUp() {
 		// Create descriptors for AAS and submodels
 		AASDescriptor aasDesc1 = new AASDescriptor(aasIdShort1, aasId1, aasEndpoint1);
-		aasDesc1.addSubmodelDescriptor(new SubmodelDescriptor(smIdShort, smId, smEndpoint));
+		aasDesc1.addSubmodelDescriptor(new SubmodelDescriptor(smIdShort1, smId1, smEndpoint1));
 		AASDescriptor aasDesc2 = new AASDescriptor(aasIdShort2, aasId2, aasEndpoint2);
 		
 		// Register Asset Administration Shells
@@ -83,11 +87,11 @@
 		assertEquals(aasEndpoint1, descriptor.getFirstEndpoint());
 		
 		// Check, if the SM descriptor in the AASDescriptor is correct 
-		SubmodelDescriptor smDescriptor = descriptor.getSubModelDescriptor(smId.getId());
-		assertEquals(smId.getId(), smDescriptor.getIdentifier().getId());
-		assertEquals(smId.getIdType(), smDescriptor.getIdentifier().getIdType());
-		assertEquals(smIdShort, smDescriptor.get(Referable.IDSHORT));
-		assertEquals(smEndpoint, smDescriptor.getFirstEndpoint());
+		SubmodelDescriptor smDescriptor = descriptor.getSubModelDescriptorFromIdentifierId(smId1.getId());
+		assertEquals(smId1.getId(), smDescriptor.getIdentifier().getId());
+		assertEquals(smId1.getIdType(), smDescriptor.getIdentifier().getIdType());
+		assertEquals(smIdShort1, smDescriptor.get(Referable.IDSHORT));
+		assertEquals(smEndpoint1, smDescriptor.getFirstEndpoint());
 		
 		// Retrieve and check the second AAS
 		result = proxy.lookupAAS(aasId2);
@@ -119,4 +123,27 @@
 		assertNull(proxy.lookupAAS(aasId1));
 		assertNull(proxy.lookupAAS(aasId2));
 	}
+
+	/**
+	 * Tests additiona, retrieval and removal of submodels
+	 */
+	@Test
+	public void testSubmodelCalls() {
+		// Add descriptor
+		SubmodelDescriptor smDesc = new SubmodelDescriptor(smIdShort2, smId2, smEndpoint2);
+		proxy.register(aasId1, smDesc);
+
+		// Ensure that the submodel is correctly stored in the aas descriptor
+		AASDescriptor aasDesc = proxy.lookupAAS(aasId1);
+		assertEquals(smDesc.getEndpoints(), aasDesc.getSubmodelDescriptorFromIdShort(smIdShort2).getEndpoints());
+		assertNotNull(aasDesc.getSubmodelDescriptorFromIdShort(smIdShort1));
+
+		// Remove Submodel
+		proxy.delete(aasId1, smIdShort2);
+
+		// Ensure that the submodel was correctly removed
+		aasDesc = proxy.lookupAAS(aasId1);
+		assertNotNull(aasDesc.getSubmodelDescriptorFromIdShort(smIdShort1));
+		assertNull(aasDesc.getSubmodelDescriptorFromIdShort(smIdShort2));
+	}
 }
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/restapi/TestDirectoryModelProvider.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/restapi/TestDirectoryModelProvider.java
index 8d8f553..4acc2ac 100644
--- a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/restapi/TestDirectoryModelProvider.java
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/aas/registration/restapi/TestDirectoryModelProvider.java
@@ -5,6 +5,13 @@
 import org.eclipse.basyx.vab.modelprovider.VABElementProxy;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 
+/**
+ * Tests correct behaviour of the DirectoryModelProvider using an InMemory
+ * database
+ * 
+ * @author schnicke
+ *
+ */
 public class TestDirectoryModelProvider extends TestRegistryProvider {
 
 	@Override