Fixes handling of "/" in IRIs in Registry

- Tomcat prevents usage of this in standard configuration

Change-Id: I62316d07e7a8ee499a8d03e1fb02ed4312469135
Signed-off-by: Frank Schnicke <frank.schnicke@iese.fraunhofer.de>
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 cf21aaf..54c5046 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
@@ -2,10 +2,6 @@
 
 import java.util.HashMap;
 
-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;
-
 /**
  * An implementation of the IAASRegistryService interface.
  * This registry can not store its entries permanently, because it is completely based on HashMaps.
@@ -21,17 +17,4 @@
 	public InMemoryRegistry() {
 		super(new HashMap<>());
 	}
-
-	@Override
-	public void register(IIdentifier aas, SubmodelDescriptor smDescriptor) {
-		AASDescriptor descriptor = descriptorMap.get(aas.getId());
-		descriptor.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/memory/MapRegistry.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/memory/MapRegistry.java
index 26bbe90..d5da072 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/memory/MapRegistry.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/registration/memory/MapRegistry.java
@@ -8,12 +8,16 @@
 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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Implements a preconfigured registry based on the Map interface
  */
 public class MapRegistry implements IAASRegistryService {
 	protected Map<String, AASDescriptor> descriptorMap;
+	
+	Logger logger = LoggerFactory.getLogger(MapRegistry.class);
 
 	/**
 	 * Constructor that takes a reference to a map as a base for the registry entries
@@ -30,26 +34,31 @@
 		}
 
 		descriptorMap.put(aasId, aasDescriptor);
+		logger.debug("Registered " + aasId);
 	}
 
 	@Override
 	public void registerOnly(AASDescriptor aasDescriptor) {
 		String aasId = aasDescriptor.getIdentifier().getId();
 		descriptorMap.put(aasId, aasDescriptor);
+		logger.debug("Registered " + aasId);
 	}
 
 	@Override
 	public void delete(IIdentifier aasIdentifier) {
 		descriptorMap.remove(aasIdentifier.getId());
+		logger.debug("Removed " + aasIdentifier.getId());
 	}
 
 	@Override
 	public AASDescriptor lookupAAS(IIdentifier aasIdentifier) {
+		logger.debug("Looking up " + aasIdentifier.getId());
 		return descriptorMap.get(aasIdentifier.getId());
 	}
 
 	@Override
 	public List<AASDescriptor> lookupAll() {
+		logger.debug("Looking up all AAS");
 		return new ArrayList<>(descriptorMap.values());
 	}
 
@@ -59,6 +68,8 @@
 		descriptor.addSubmodelDescriptor(smDescriptor);
 		// Do not assume that the returned descriptor is referenced in the base map
 		descriptorMap.put(aas.getId(), descriptor);
+		logger.debug("Registered submodel " + smDescriptor.getIdShort() + " for AAS " + aas.getId());
+
 		// TODO: Add data to remote AAS
 	}
 
@@ -68,6 +79,9 @@
 		desc.removeSubmodelDescriptor(smIdShort);
 		// Do not assume that the returned descriptor is referenced in the base map
 		descriptorMap.put(aasId.getId(), desc);
+
+		logger.debug("Deleted submodel " + smIdShort + " from AAS " + aasId.getId());
+
 	}
 
 }
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 b7bfc67..ca70ea1 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
@@ -135,14 +135,22 @@
 	@Override
 	public void delete(IIdentifier aasId, String smIdShort) {
 		try {
-			provider.deleteValue(VABPathTools.concatenatePaths(buildSubmodelPath(aasId), smIdShort));
+			provider.deleteValue(VABPathTools.concatenatePaths(buildSubmodelPath(aasId), URLEncoder.encode(smIdShort, "UTF-8")));
 		} catch (Exception e) {
 			logger.error("Exception in deleting a Submodel", e);
 		}
 	}
 
 	private String buildSubmodelPath(IIdentifier aas) {
-		return VABPathTools.concatenatePaths(aas.getId(), DirectoryModelProvider.SUBMODELS);
+		try {
+			// Encode id to handle usage of reserved symbols, e.g. /
+			String encodedAASId = URLEncoder.encode(aas.getId(), "UTF-8");
+			return VABPathTools.concatenatePaths(encodedAASId, DirectoryModelProvider.SUBMODELS);
+		} catch (UnsupportedEncodingException e) {
+			logger.error("Could not encode URL. This should not happen");
+			throw new RuntimeException(e);
+		}
+
 	}
 }
 
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 3607df8..6319e9d 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
@@ -87,16 +87,19 @@
 	}
 	
 	private String[] preparePath(String path) throws MalformedRequestException {
+		path = stripPrefix(path);
+
+		String[] splitted = splitPath(path);
+
 		try {
-			path = URLDecoder.decode(path, "UTF-8");
+			for (int i = 0; i < splitted.length; i++) {
+				splitted[i] = URLDecoder.decode(splitted[i], "UTF-8");
+			}
+			return splitted;
 		} catch (UnsupportedEncodingException e) {
 			//Malformed request because of unsupported encoding
 			throw new MalformedRequestException("Path has to be encoded as UTF-8 string.");
 		}
-		
-		path = stripPrefix(path);
-		
-		return splitPath(path);
 	}
 	
 	/**
@@ -240,8 +243,7 @@
 			
 		// Creating new submodel entry for existing aas
 		} else if (splitted.length == 2) { 
-			
-			ModelUrn aasId = new ModelUrn(splitted[0]);
+			ModelUrn aasId = retrieveModelURN(splitted[0]);
 			
 			SubmodelDescriptor smDescriptor = createSMDescriptorFromMap(newEntity);
 			
@@ -253,12 +255,15 @@
 			}
 			
 			registry.register(aasId, smDescriptor);
-			
 		} else {
 			throw new MalformedRequestException("Create was called with an unsupported path: " + path);
 		}
 	}
 
+	private ModelUrn retrieveModelURN(String str) {
+		return new ModelUrn(str);
+	}
+
 	@Override
 	public void deleteValue(String path) throws ProviderException {
 		String[] splitted = preparePath(path);
@@ -275,19 +280,15 @@
 			registry.delete(aasId);
 			
 		} else if(splitted.length == 3) { //delete a submodel
-	
-			ModelUrn aasId  = new ModelUrn(splitted[0]);
+			ModelUrn aasId = new ModelUrn(splitted[0]);
 			String smId = splitted[2];
-			
-			//a submodel with this Id does not exist in given aas
-			//getSmDescriptorFromAAS also checks if aas exists
-			if(getSmDescriptorFromAAS(aasId, smId) == null) {
-				throw new ResourceNotFoundException("A Submodel with id '" + smId +
-						"' does not exist in aas '" + splitted[0] + "'.");
+			// a submodel with this Id does not exist in given aas
+			// getSmDescriptorFromAAS also checks if aas exists
+			if (getSmDescriptorFromAAS(aasId, smId) == null) {
+				throw new ResourceNotFoundException("A Submodel with id '" + smId + "' does not exist in aas '" + splitted[0] + "'.");
 			}
-			
+
 			registry.delete(aasId, smId);
-			
 		} else {
 			throw new MalformedRequestException("Delete with empty path is not supported by registry");
 		}
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/connector/HTTPConnector.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/connector/HTTPConnector.java
index 0c1dd70..4d4ac34 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/connector/HTTPConnector.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/connector/HTTPConnector.java
@@ -12,9 +12,8 @@
 import org.eclipse.basyx.vab.modelprovider.VABPathTools;
 import org.eclipse.basyx.vab.protocol.api.IBaSyxConnector;
 import org.glassfish.jersey.client.HttpUrlConnectorProvider;
-
-import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * HTTP connector class
@@ -40,7 +39,7 @@
 	 */
 	@Override
 	public String getModelPropertyValue(String servicePath) {
-		return httpGet(encodeHash(servicePath));
+		return httpGet(servicePath);
 	}
 
 	public HTTPConnector(String address) {
@@ -68,7 +67,7 @@
 	@Override
 	public String setModelPropertyValue(String servicePath, String newValue) throws ServerException {
 
-		return httpPut(encodeHash(servicePath), newValue);
+		return httpPut(servicePath, newValue);
 	}
 
 	/**
@@ -86,7 +85,7 @@
 	@Override
 	public String deleteValue(String servicePath, String obj) throws ServerException {
 
-		return httpPatch(encodeHash(servicePath), obj);
+		return httpPatch(servicePath, obj);
 	}
 
 	/**
@@ -97,7 +96,7 @@
 	@Override
 	public String createValue(String servicePath, String newValue) throws ServerException {
 
-		return httpPost(encodeHash(servicePath), newValue);
+		return httpPost(servicePath, newValue);
 	}
 
 	/**
@@ -109,7 +108,7 @@
 	@Override
 	public String deleteValue(String servicePath) throws ServerException {
 
-		return httpDelete(encodeHash(servicePath));
+		return httpDelete(servicePath);
 	}
 
 	/**
@@ -235,15 +234,4 @@
 
 		return httpPost(path, parameter);
 	}
-
-	/**
-	 * Replaces # with %23
-	 * 
-	 * @param path
-	 * @return
-	 */
-	private String encodeHash(String path) {
-		return path.replace("#", "%23");
-	}
-
 }
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/AASHTTPServer.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/AASHTTPServer.java
index f21341f..712de52 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/AASHTTPServer.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/AASHTTPServer.java
@@ -12,7 +12,6 @@
 import org.apache.catalina.LifecycleListener;
 import org.apache.catalina.LifecycleState;
 import org.apache.catalina.startup.Tomcat;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,6 +26,11 @@
 	private static Logger logger = LoggerFactory.getLogger(AASHTTPServer.class);
 	
 	private Tomcat tomcat;
+
+	static {
+		// Enable coding of forward slash in tomcat
+		System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
+	}
 	   
 	/**
 	 * Constructor
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/VABHTTPInterface.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/VABHTTPInterface.java
index 5a052cf..5df8377 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/VABHTTPInterface.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/VABHTTPInterface.java
@@ -239,9 +239,6 @@
 		if (nUri.startsWith(contextPath) && nUri.length() > getEnvironmentPathSize(req)) {
 			String path = nUri.substring(getEnvironmentPathSize(req) + 1);
 
-			// Decode URL
-			path = java.net.URLDecoder.decode(path, "UTF-8");
-
 			return path;
 		}
 		throw new MalformedRequestException("The passed path " + uri + " is not a possbile path for this server.");
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 db6d8ac..a9395f0 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
@@ -27,10 +27,10 @@
 	protected final IAASRegistryService proxy = getRegistryService();
 
 	// 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 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 IIdentifier aasId1 = new ModelUrn("urn:de.FHG:devices.es.iese/test:aas:1.0:1:registryAAS#001");
+	protected IIdentifier aasId2 = new ModelUrn("urn:de.FHG:devices.es.iese/test:aas:1.0:1:registryAAS#002");
+	protected IIdentifier smId1 = new ModelUrn("urn:de.FHG:devices.es.iese/test:aas:1.0:1:statusSM#001");
+	protected IIdentifier smId2 = new ModelUrn("urn:de.FHG:devices.es.iese/test:aas:1.0:1:testSM#001");
 	protected String aasIdShort1 = "aasIdShort1";
 	protected String aasIdShort2 = "aasIdShort2";
 	protected String smIdShort1 = "smIdShort1";