Refactors VABInterfaces and Providers to use ProviderExceptions

Refactors VABBaSyxTCPInterface and VABHTTPInterface to handle ProviderExceptions
Refactors JSONProvider, AASAggregationProvider and DirectoryModelProvider to use ProviderExceptions
Refactors tests to test new Exception behavior

Change-Id: I7f24a2abb20f4c7e7e3613b7c7f5018759128f3a
Signed-off-by: Maximilian Conradi <maximilian.conradi@iese.fraunhofer.de>
diff --git a/components/basys.components/basyx.components.docker/basyx.components.sqlregistry/src/test/java/org/eclipse/basyx/regression/registry/ITSQLRegistryRaw.java b/components/basys.components/basyx.components.docker/basyx.components.sqlregistry/src/test/java/org/eclipse/basyx/regression/registry/ITSQLRegistryRaw.java
index 53b9609..9f96f53 100644
--- a/components/basys.components/basyx.components.docker/basyx.components.sqlregistry/src/test/java/org/eclipse/basyx/regression/registry/ITSQLRegistryRaw.java
+++ b/components/basys.components/basyx.components.docker/basyx.components.sqlregistry/src/test/java/org/eclipse/basyx/regression/registry/ITSQLRegistryRaw.java
@@ -8,6 +8,8 @@
 import java.util.Collection;
 import java.util.Map;
 
+import javax.ws.rs.NotFoundException;
+
 import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
 import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;
 import org.eclipse.basyx.components.configuration.BaSyxContextConfiguration;
@@ -96,8 +98,12 @@
 	@After
 	public void tearDown() throws UnsupportedEncodingException {
 		// Delete AAS registration
-		client.delete(aasUrl1);
-		client.delete(aasUrl2);
+		try {
+			client.delete(aasUrl1);			
+		} catch(NotFoundException e) {}
+		try {
+			client.delete(aasUrl2);			
+		} catch(NotFoundException e) {}
 	}
 
 	/**
@@ -173,7 +179,7 @@
 		try {
 			getResult(client.get(aasUrl2));
 			fail();
-		} catch(Exception e) {}
+		} catch(NotFoundException e) {}
 
 		// Create new AAS registration
 		client.post(registryUrl, serializedDescriptor2);
@@ -190,7 +196,7 @@
 		try {
 			getResult(client.get(aasUrl2));
 			fail();
-		} catch(Exception e) {}
+		} catch(NotFoundException e) {}
 	}
 
 	/**
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/aggregator/restapi/AASAggregationProvider.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/aggregator/restapi/AASAggregationProvider.java
index b000110..142a2f8 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/aggregator/restapi/AASAggregationProvider.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/aas/aggregator/restapi/AASAggregationProvider.java
@@ -9,6 +9,9 @@
 import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;
 import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
 import org.eclipse.basyx.submodel.metamodel.map.modeltype.ModelType;
+import org.eclipse.basyx.vab.exception.provider.MalformedRequestException;
+import org.eclipse.basyx.vab.exception.provider.ResourceAlreadyExistsException;
+import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
 import org.eclipse.basyx.vab.modelprovider.VABPathTools;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 
@@ -34,11 +37,12 @@
 	 * prefix)
 	 * @param path
 	 * @return
+	 * @throws MalformedRequestException 
 	 */
-	private String stripPrefix(String path) {
+	private String stripPrefix(String path) throws MalformedRequestException {
 		path = VABPathTools.stripSlashes(path);
 		if (!path.startsWith(PREFIX)) {
-			throw new RuntimeException("Path " + path + " not recognized as aggregator path. Has to start with " + PREFIX);
+			throw new MalformedRequestException("Path " + path + " not recognized as aggregator path. Has to start with " + PREFIX);
 		}
 		path = path.replace(PREFIX, "");
 		path = VABPathTools.stripSlashes(path);
@@ -51,13 +55,14 @@
 	 * 
 	 * @param value the AAS Map object
 	 * @return an AAS
+	 * @throws MalformedRequestException 
 	 */
 	@SuppressWarnings("unchecked")
-	private AssetAdministrationShell createAASFromMap(Object value) {
+	private AssetAdministrationShell createAASFromMap(Object value) throws MalformedRequestException {
 		
 		//check if the given value is a Map
 		if(!(value instanceof Map)) {
-			throw new RuntimeException("Given newValue is not a Map");
+			throw new MalformedRequestException("Given newValue is not a Map");
 		}
 
 		Map<String, Object> map = (Map<String, Object>) value;
@@ -68,7 +73,7 @@
 		//have to accept Objects without modeltype information,
 		//as modeltype is not part of the public metamodel
 		if(!AssetAdministrationShell.MODELTYPE.equals(type) && type != null) {
-			throw new RuntimeException("Given newValue map has not the correct ModelType");
+			throw new MalformedRequestException("Given newValue map has not the correct ModelType");
 		}
 		
 		AssetAdministrationShell aas = AssetAdministrationShell.createAsFacade(map);
@@ -90,7 +95,7 @@
 			
 			//Throw an Exception if the requested aas does not exist
 			if(aas == null) {
-				throw new RuntimeException("Requested aasID '" + path + "' does not exist.");
+				throw new ResourceNotFoundException("Requested aasID '" + path + "' does not exist.");
 			}
 			return aas;
 		}
@@ -109,16 +114,16 @@
 			ModelUrn identifier = new ModelUrn(path);
 			
 			if(!aas.getIdentification().getId().equals(path)) {
-				throw new RuntimeException("Given aasID and given AAS do not match");
+				throw new MalformedRequestException("Given aasID and given AAS do not match");
 			}
 			
 			if(aggregator.getAAS(identifier) == null) {
-				throw new RuntimeException("Can not update non existing value '" + path + "'. Try create instead.");
+				throw new ResourceAlreadyExistsException("Can not update non existing value '" + path + "'. Try create instead.");
 			}
 
 			aggregator.updateAAS(aas);
 		} else {
-			throw new RuntimeException("Set with empty path is not supported by aggregator");
+			throw new MalformedRequestException("Set with empty path is not supported by aggregator");
 		}
 	}
 
@@ -132,12 +137,12 @@
 		if (path.isEmpty()) { // Creating new entry
 			
 			if(aggregator.getAAS(aas.getIdentification()) != null) {
-				throw new RuntimeException("Value '" + path + "' to be created already exists. Try update instead.");
+				throw new ResourceAlreadyExistsException("Value '" + path + "' to be created already exists. Try update instead.");
 			}
 			
 			aggregator.createAAS(aas);
 		} else {
-			throw new RuntimeException("Create was called with an unsupported path: " + path);
+			throw new MalformedRequestException("Create was called with an unsupported path: " + path);
 		}
 		
 	}
@@ -153,23 +158,23 @@
 			IIdentifier identifier = new ModelUrn(path);
 			
 			if(aggregator.getAAS(identifier) == null) {
-				throw new RuntimeException("Value '" + path + "' to be deleted does not exists.");
+				throw new ResourceNotFoundException("Value '" + path + "' to be deleted does not exists.");
 			}
 			
 			aggregator.deleteAAS(identifier);
 		} else {
-			throw new RuntimeException("Delete with empty path is not supported by registry");
+			throw new MalformedRequestException("Delete with empty path is not supported by registry");
 		}
 	}
 
 	@Override
 	public void deleteValue(String path, Object obj) throws Exception {
-		throw new RuntimeException("DeleteValue with parameter not supported by aggregator");
+		throw new MalformedRequestException("DeleteValue with parameter not supported by aggregator");
 	}
 
 	@Override
 	public Object invokeOperation(String path, Object... parameter) throws Exception {
-		throw new RuntimeException("Invoke not supported by aggregator");
+		throw new MalformedRequestException("Invoke not supported by aggregator");
 	}
 	
 }
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 6dc3165..b48cc90 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
@@ -1,5 +1,6 @@
 package org.eclipse.basyx.aas.registration.restapi;
 
+import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.util.Map;
 import java.util.Set;
@@ -11,6 +12,10 @@
 import org.eclipse.basyx.aas.registration.memory.InMemoryRegistry;
 import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
 import org.eclipse.basyx.submodel.metamodel.map.modeltype.ModelType;
+import org.eclipse.basyx.vab.exception.provider.MalformedRequestException;
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
+import org.eclipse.basyx.vab.exception.provider.ResourceAlreadyExistsException;
+import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
 import org.eclipse.basyx.vab.modelprovider.VABPathTools;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 
@@ -41,11 +46,12 @@
 	 * 
 	 * @param path
 	 * @return
+	 * @throws MalformedRequestException if path does not start with PERFIX "api/v1/registry"
 	 */
-	private String stripPrefix(String path) {
+	private String stripPrefix(String path) throws MalformedRequestException {
 		path = VABPathTools.stripSlashes(path);
 		if (!path.startsWith(PREFIX)) {
-			throw new RuntimeException("Path " + path + " not recognized as registry path. Has to start with " + PREFIX);
+			throw new MalformedRequestException("Path " + path + " not recognized as registry path. Has to start with " + PREFIX);
 		}
 		path = path.replace(PREFIX, "");
 		path = VABPathTools.stripSlashes(path);
@@ -57,8 +63,9 @@
 	 * 
 	 * @param path the path to be splitted
 	 * @return Array of path elements
+	 * @throws MalformedRequestException if path is not valid
 	 */
-	private String[] splitPath(String path) {
+	private String[] splitPath(String path) throws MalformedRequestException {
 		
 		if(path.isEmpty()) {
 			return new String[0];
@@ -68,29 +75,43 @@
 		
 		//Assumes "submodels" is not a valid AASId
 		if(splitted[0].equals(SUBMODELS)) {
-			throw new RuntimeException("Path must not start with " + SUBMODELS);
+			throw new MalformedRequestException("Path must not start with " + SUBMODELS);
 		}
 		
 		//If path contains more than one element, the second one has to be "submodels"
 		if(splitted.length > 1 && !splitted[1].equals(SUBMODELS)) {
-			throw new RuntimeException("Second path element must be (if present): " + SUBMODELS);
+			throw new MalformedRequestException("Second path element must be (if present): " + SUBMODELS);
 		}
 		
 		return splitted;
 	}
 	
+	private String[] preparePath(String path) throws MalformedRequestException {
+		try {
+			path = URLDecoder.decode(path, "UTF-8");
+		} 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);
+	}
+	
 	/**
 	 * Checks if a given Object is a Map and checks if it has the correct modelType
 	 * 
 	 * @param expectedModelType the modelType the Object is expected to have
 	 * @param value the Object to be checked and casted
 	 * @return the object casted to a Map
+	 * @throws MalformedRequestException 
 	 */
 	@SuppressWarnings("unchecked")
-	private Map<String, Object> checkModelType(String expectedModelType, Object value) {
+	private Map<String, Object> checkModelType(String expectedModelType, Object value) throws MalformedRequestException {
 		//check if the given value is a Map
 		if(!(value instanceof Map)) {
-			throw new RuntimeException("Given newValue is not a Map");
+			throw new MalformedRequestException("Given newValue is not a Map");
 		}
 
 		Map<String, Object> map = (Map<String, Object>) value;
@@ -101,7 +122,7 @@
 		//have to accept Objects without modeltype information,
 		//as modeltype is not part of the public metamodel
 		if(!expectedModelType.equals(type) && type != null) {
-			throw new RuntimeException("Given newValue map has not the correct ModelType");
+			throw new MalformedRequestException("Given newValue map has not the correct ModelType");
 		}
 		
 		return map;
@@ -113,8 +134,9 @@
 	 * 
 	 * @param value the AAS Map object
 	 * @return an AAS
+	 * @throws MalformedRequestException 
 	 */
-	private AASDescriptor createAASDescriptorFromMap(Object value) {
+	private AASDescriptor createAASDescriptorFromMap(Object value) throws MalformedRequestException {
 		Map<String, Object> map = checkModelType(AASDescriptor.MODELTYPE, value);
 		AASDescriptor aasDescriptor = new AASDescriptor(map);
 		return aasDescriptor;
@@ -126,32 +148,30 @@
 	 * 
 	 * @param value the AAS Map object
 	 * @return an AAS
+	 * @throws MalformedRequestException 
 	 */
-	private SubmodelDescriptor createSMDescriptorFromMap(Object value) {
+	private SubmodelDescriptor createSMDescriptorFromMap(Object value) throws MalformedRequestException {
 		Map<String, Object> map = checkModelType(SubmodelDescriptor.MODELTYPE, value);
 		SubmodelDescriptor smDescriptor = new SubmodelDescriptor(map);
 		return smDescriptor;
 	}
 
 	@Override
-	public Object getModelPropertyValue(String path) throws Exception {
-		path = stripPrefix(path);
-		path = URLDecoder.decode(path, "UTF-8");
+	public Object getModelPropertyValue(String path) throws ProviderException {
+		String[] splitted = preparePath(path);
 
 		//Path is empty, request for all AASDescriptors
-		if (path.isEmpty()) {
+		if (splitted.length == 0) {
 			return registry.lookupAll();
 		} else {
 			
-			String[] splitted = splitPath(path);
-			
 			//Given path consists only of an AAS Id
 			if(splitted.length == 1) {
-				AASDescriptor descriptor = registry.lookupAAS(new ModelUrn(path));
+				AASDescriptor descriptor = registry.lookupAAS(new ModelUrn(splitted[0]));
 				
 				//Throw an Exception if the requested AAS does not exist 
 				if(descriptor == null) {
-					throw new RuntimeException("Specified AASid '" + path + "' does not exist.");
+					throw new ResourceNotFoundException("Specified AASid '" + splitted[0] + "' does not exist.");
 				}
 				return descriptor;
 			
@@ -165,28 +185,24 @@
 			} else if(splitted.length == 3) {
 				SubmodelDescriptor smDescriptor = getSmDescriptorFromAAS(new ModelUrn(splitted[0]), splitted[2]);
 				if(smDescriptor == null) {
-					throw new RuntimeException("Specified SubmodelId '" + splitted[2] + "' does not exist in AAS '" + splitted[0] + "'.");
+					throw new ResourceNotFoundException("Specified SubmodelId '" + splitted[2] + "' does not exist in AAS '" + splitted[0] + "'.");
 				}
 				return smDescriptor;
 			}
 			
 			//path has more than three elements and is therefore invalid
-			throw new RuntimeException("Given path '" + path + "' contains more than three path elements and is therefore invalid.");
+			throw new MalformedRequestException("Given path '" + path + "' contains more than three path elements and is therefore invalid.");
 		}
 	}
 
 	@Override
-	public void setModelPropertyValue(String path, Object newValue) throws Exception {
-		path = stripPrefix(path);
-		path = URLDecoder.decode(path, "UTF-8");
+	public void setModelPropertyValue(String path, Object newValue) throws ProviderException {
+		String[] splitted = preparePath(path);
 
-		if (!path.isEmpty()) { // Overwriting existing entry
-			
-			String[] splitted = splitPath(path);
-			
+		if (splitted.length > 0) { // Overwriting existing entry
 			//if path contains more or less than an aasID after the prefix
 			if(splitted.length != 1) {
-				throw new RuntimeException("Path '" + path + "' is invalid for updating an aas.");
+				throw new MalformedRequestException("Path '" + path + "' is invalid for updating an aas.");
 			}
 			
 			// Decode encoded path
@@ -194,23 +210,20 @@
 			
 			//aas to be updated does not exist
 			if(registry.lookupAAS(identifier) == null) {
-				throw new RuntimeException("AAS '" + path + "' to be updated does not exist. Try create instead.");
+				throw new ResourceNotFoundException("AAS '" + path + "' to be updated does not exist. Try create instead.");
 			}
 			
 			//delete old value and create the new one
 			registry.delete(identifier);
 			registry.register(createAASDescriptorFromMap(newValue));
 		} else {
-			throw new RuntimeException("Set with empty path is not supported by registry");
+			throw new MalformedRequestException("Set with empty path is not supported by registry");
 		}
 	}
 
 	@Override
-	public void createValue(String path, Object newEntity) throws Exception {
-		path = stripPrefix(path);
-		path = URLDecoder.decode(path, "UTF-8");
-		
-		String[] splitted = splitPath(path);
+	public void createValue(String path, Object newEntity) throws ProviderException {
+		String[] splitted = preparePath(path);
 
 		// Creating new entry
 		if (splitted.length == 0) {
@@ -219,7 +232,7 @@
 			
 			//aas to be created already exists
 			if(registry.lookupAAS(aas.getIdentifier()) != null) {
-				throw new RuntimeException("AAS with Id '" +
+				throw new ResourceAlreadyExistsException("AAS with Id '" +
 						aas.getIdentifier().getId() + "' already exists. Try update instead.");
 			}
 			
@@ -235,23 +248,20 @@
 			//a submodel with this Id already exists in given aas
 			//getSmDescriptorFromAAS also checks if aas exists
 			if(getSmDescriptorFromAAS(aasId, smDescriptor.getIdShort()) != null) {
-				throw new RuntimeException("A Submodel with id '" + smDescriptor.getIdShort() +
+				throw new ResourceAlreadyExistsException("A Submodel with id '" + smDescriptor.getIdShort() +
 						"' already exists in aas '" + splitted[0] + "'. Try update instead.");
 			}
 			
 			registry.register(aasId, smDescriptor);
 			
 		} else {
-			throw new RuntimeException("Create was called with an unsupported path: " + path);
+			throw new MalformedRequestException("Create was called with an unsupported path: " + path);
 		}
 	}
 
 	@Override
-	public void deleteValue(String path) throws Exception {
-		path = stripPrefix(path);
-		path = URLDecoder.decode(path, "UTF-8");
-		
-		String[] splitted = splitPath(path);
+	public void deleteValue(String path) throws ProviderException {
+		String[] splitted = preparePath(path);
 			
 		if (splitted.length == 1) { //delete an aas
 			
@@ -259,7 +269,7 @@
 			
 			//aas to be deleted does not exist
 			if(registry.lookupAAS(aasId) == null) {
-				throw new RuntimeException("AAS '" + splitted[0] + "' to be deleted does not exist.");
+				throw new ResourceNotFoundException("AAS '" + splitted[0] + "' to be deleted does not exist.");
 			}
 			
 			registry.delete(aasId);
@@ -272,25 +282,25 @@
 			//a submodel with this Id does not exist in given aas
 			//getSmDescriptorFromAAS also checks if aas exists
 			if(getSmDescriptorFromAAS(aasId, smId) == null) {
-				throw new RuntimeException("A Submodel with id '" + smId +
+				throw new ResourceNotFoundException("A Submodel with id '" + smId +
 						"' does not exist in aas '" + splitted[0] + "'.");
 			}
 			
 			registry.delete(aasId, smId);
 			
 		} else {
-			throw new RuntimeException("Delete with empty path is not supported by registry");
+			throw new MalformedRequestException("Delete with empty path is not supported by registry");
 		}
 	}
 
 	@Override
 	public void deleteValue(String path, Object obj) throws Exception {
-		throw new RuntimeException("DeleteValue with parameter not supported by registry");
+		throw new MalformedRequestException("DeleteValue with parameter not supported by registry");
 	}
 
 	@Override
 	public Object invokeOperation(String path, Object... parameter) throws Exception {
-		throw new RuntimeException("Invoke not supported by registry");
+		throw new MalformedRequestException("Invoke not supported by registry");
 	}
 	
 	/**
@@ -299,11 +309,12 @@
 	 * 
 	 * @param id id of the aas
 	 * @return Set of contained SubmodelDescriptor objects
+	 * @throws ResourceNotFoundException if the AAS does not exist
 	 */
-	private Set<SubmodelDescriptor> getSmDescriptorsFromAAS(IIdentifier id) {
+	private Set<SubmodelDescriptor> getSmDescriptorsFromAAS(IIdentifier id) throws ResourceNotFoundException {
 		AASDescriptor aasDescriptor = registry.lookupAAS(id);
 		if(aasDescriptor == null) {
-			throw new RuntimeException("Specified AASid '" + id.getId() + "' does not exist.");
+			throw new ResourceNotFoundException("Specified AASid '" + id.getId() + "' does not exist.");
 		}
 		return aasDescriptor.getSubModelDescriptors();
 	}
@@ -315,11 +326,13 @@
 	 * @param aasId id of the aas
 	 * @param smId id of the submodel
 	 * @return the SubmodelDescriptor with the given id
+	 * @throws ResourceNotFoundException if aasId does not exist
 	 */
-	private SubmodelDescriptor getSmDescriptorFromAAS(IIdentifier aasId, String smId) {
+	private SubmodelDescriptor getSmDescriptorFromAAS(IIdentifier aasId, String smId)
+			throws ResourceNotFoundException {
 		AASDescriptor aasDescriptor = registry.lookupAAS(aasId);
 		if(aasDescriptor == null) {
-			throw new RuntimeException("Specified AASid '" + aasId.getId() + "' does not exist.");
+			throw new ResourceNotFoundException("Specified AASid '" + aasId.getId() + "' does not exist.");
 		}
 		
 		return aasDescriptor.getSubmodelDescriptorFromIdShort(smId);
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/provider/JSONProvider.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/provider/JSONProvider.java
index 09cc270..5056bd1 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/provider/JSONProvider.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/provider/JSONProvider.java
@@ -11,6 +11,8 @@
 import org.eclipse.basyx.vab.coder.json.serialization.GSONToolsFactory;
 import org.eclipse.basyx.vab.exception.LostHTTPRequestParameterException;
 import org.eclipse.basyx.vab.exception.ServerException;
+import org.eclipse.basyx.vab.exception.provider.MalformedRequestException;
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -137,29 +139,26 @@
 	
 
 	/**
-	 * Send JSON encoded response
-	 */
-	private void sendJSONResponse(PrintWriter outputStream, String jsonValue) {
-		// Write result to output stream
-		outputStream.write(jsonValue); 
-		outputStream.flush();
-	}
-	
-
-	/**
 	 * Send Error
 	 * @param e
 	 * @param path
 	 * @param resp
 	 */
-	private void sendException(PrintWriter resp, Exception e) {
-		logger.error("Exception in sendException", e);
+	private void sendException(PrintWriter resp, Exception e) throws ProviderException {
 		
 		// Serialize Exception
 		String jsonString = serialize(e);
 
-		// Send error response
-		sendJSONResponse(resp, jsonString);
+		resp.write(jsonString);
+		
+		//If the Exception is a ProviderException, just rethrow it
+		if(e instanceof ProviderException) {
+			throw (ProviderException) e;
+		}
+		
+		//If the Exception is not a ProviderException encapsulate it in one and log it
+		logger.error("Unknown Exception in JSONProvider", e);
+		throw new ProviderException(e);
 	}
 
 	
@@ -170,24 +169,31 @@
 	 * @param serializedJSONValue
 	 * @param outputStream
 	 * @return
+	 * @throws MalformedRequestException 
 	 * @throws LostHTTPRequestParameterException 
 	 * @throws ServerException
 	 */
-	private Object extractParameter(String path, String serializedJSONValue, PrintWriter outputStream) {
+	private Object extractParameter(String path, String serializedJSONValue, PrintWriter outputStream) throws MalformedRequestException {
 		// Return value
 		Object result = null;
 
-		// Deserialize json body
-		result = serializer.deserialize(serializedJSONValue);
-			
+		try {
+			// Deserialize json body
+			result = serializer.deserialize(serializedJSONValue);
+		} catch (Exception e) {
+			//JSON could not be deserialized
+			throw new MalformedRequestException(e);
+		}
+		
 		return result;
 	}
 	
 
 	/**
 	 * Process a BaSys get operation, return JSON serialized result
+	 * @throws ProviderException 
 	 */
-	public void processBaSysGet(String path, PrintWriter outputStream) {
+	public void processBaSysGet(String path, PrintWriter outputStream) throws ProviderException {
 
 		try {
 			// Get requested value from provider backend
@@ -197,7 +203,7 @@
 			String jsonString = serialize(true, value, null);
 
 			// Send response
-			sendJSONResponse(outputStream, jsonString);
+			outputStream.write(jsonString);
 		} catch (Exception e) {
 			sendException(outputStream, e);
 		}
@@ -210,8 +216,9 @@
 	 * @param path
 	 * @param serializedJSONValue
 	 * @param outputStream
+	 * @throws ProviderException 
 	 */
-	public void processBaSysSet(String path, String serializedJSONValue, PrintWriter outputStream) {
+	public void processBaSysSet(String path, String serializedJSONValue, PrintWriter outputStream) throws ProviderException {
 		
 		// Try to set value of BaSys VAB element
 		try {
@@ -226,7 +233,7 @@
 			String jsonString = serialize(true);
 			
 			// Send response
-			sendJSONResponse(outputStream, jsonString);
+			outputStream.write(jsonString);
 
 		} catch (Exception e) {
 			sendException(outputStream, e);
@@ -236,9 +243,10 @@
 	
 	/**
 	 * Process a BaSys invoke operation
+	 * @throws ProviderException 
 	 */
 	@SuppressWarnings("unchecked")
-	public void processBaSysInvoke(String path, String serializedJSONValue, PrintWriter outputStream) {
+	public void processBaSysInvoke(String path, String serializedJSONValue, PrintWriter outputStream) throws ProviderException {
 
 		try {
 			
@@ -271,7 +279,7 @@
 			String jsonString = serialize(true, result, null);
 			
 			// Send response
-			sendJSONResponse(outputStream, jsonString);
+			outputStream.write(jsonString);
 
 		} catch (Exception e) {
 			sendException(outputStream, e);
@@ -285,8 +293,9 @@
 	 * @param path
 	 * @param serializedJSONValue If this parameter is not null (basystype),we remove an element from a collection by index / remove from map by key. We assume that the parameter only contains 1 element
 	 * @param outputStream
+	 * @throws ProviderException 
 	 */
-	public void processBaSysDelete(String path, String serializedJSONValue, PrintWriter outputStream) {
+	public void processBaSysDelete(String path, String serializedJSONValue, PrintWriter outputStream) throws ProviderException {
 		
 		try {
 
@@ -304,7 +313,7 @@
 			String jsonString = serialize(true);
 			
 			// Send response
-			sendJSONResponse(outputStream, jsonString);
+			outputStream.write(jsonString);
 
 		} catch (Exception e) {
 			sendException(outputStream, e);
@@ -318,8 +327,9 @@
 	 * @param path
 	 * @param parameter
 	 * @param outputStream
+	 * @throws ProviderException 
 	 */
-	public void processBaSysCreate(String path, String serializedJSONValue, PrintWriter outputStream) {
+	public void processBaSysCreate(String path, String serializedJSONValue, PrintWriter outputStream) throws ProviderException {
 
 		try {
 			// Deserialize json body. 
@@ -332,7 +342,7 @@
 			String jsonString = serialize(true);
 			
 			// Send response
-			sendJSONResponse(outputStream, jsonString);
+			outputStream.write(jsonString);
 
 		} catch (Exception e) {
 			sendException(outputStream, e);
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/basyx/server/VABBaSyxTCPInterface.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/basyx/server/VABBaSyxTCPInterface.java
index b13416b..4d1fd95 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/basyx/server/VABBaSyxTCPInterface.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/basyx/server/VABBaSyxTCPInterface.java
@@ -8,6 +8,7 @@
 import java.nio.channels.SocketChannel;
 
 import org.eclipse.basyx.vab.coder.json.provider.JSONProvider;
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 import org.eclipse.basyx.vab.protocol.basyx.CoderTools;
 import org.slf4j.Logger;
@@ -92,11 +93,20 @@
 			String path = new String(rxFrame, 1 + 4, pathLen);
 
 			// Forward request to provider
-			providerBackend.processBaSysGet(path, output);
+			try {
+				providerBackend.processBaSysGet(path, output);
+			} catch (ProviderException e) {
+				logger.error("Exception in BASYX_GET", e);
+				// Catch Exceptions from JSONProvider
+				// No further action here, as the current version
+				// of the TCP-Mapping states, that always Statuscode 0x00 
+				// should be returned with Exceptions encoded in returned String
+			}
 
 			// System.out.println("Processed GET:"+path);
 
 			// Send response frame
+			output.flush();
 			sendResponseFrame(byteArrayOutput);
 
 			break;
@@ -111,9 +121,18 @@
 			String jsonValue = new String(rxFrame, 1 + 4 + pathLen + 4, jsonValueLen);
 
 			// Invoke get operation
-			providerBackend.processBaSysSet(path, jsonValue, output);
+			try {
+				providerBackend.processBaSysSet(path, jsonValue, output);
+			} catch (ProviderException e) {
+				logger.error("Exception in BASYX_SET", e);
+				// Catch Exceptions from JSONProvider
+				// No further action here, as the current version
+				// of the TCP-Mapping states, that always Statuscode 0x00 
+				// should be returned with Exceptions encoded in returned String
+			}
 
 			// Send response frame
+			output.flush();
 			sendResponseFrame(byteArrayOutput);
 
 			break;
@@ -128,9 +147,18 @@
 			String jsonValue = new String(rxFrame, 1 + 4 + pathLen + 4, jsonValueLen);
 
 			// Invoke get operation
-			providerBackend.processBaSysCreate(path, jsonValue, output);
+			try {
+				providerBackend.processBaSysCreate(path, jsonValue, output);
+			} catch (ProviderException e) {
+				logger.error("Exception in BASYX_CREATE", e);
+				// Catch Exceptions from JSONProvider
+				// No further action here, as the current version
+				// of the TCP-Mapping states, that always Statuscode 0x00 
+				// should be returned with Exceptions encoded in returned String
+			}
 
 			// Send response frame
+			output.flush();
 			sendResponseFrame(byteArrayOutput);
 
 			break;
@@ -154,9 +182,18 @@
 			}
 
 			// Invoke delete operation
-			providerBackend.processBaSysDelete(path, jsonValue, output);
+			try {
+				providerBackend.processBaSysDelete(path, jsonValue, output);
+			} catch (ProviderException e) {
+				logger.error("Exception in BASYX_DELETE", e);
+				// Catch Exceptions from JSONProvider
+				// No further action here, as the current version
+				// of the TCP-Mapping states, that always Statuscode 0x00 
+				// should be returned with Exceptions encoded in returned String
+			}
 
 			// Send response frame
+			output.flush();
 			sendResponseFrame(byteArrayOutput);
 
 			break;
@@ -170,9 +207,18 @@
 			int jsonValueLen = CoderTools.getInt32(rxFrame, 1 + 4 + pathLen);
 			String jsonValue = new String(rxFrame, 1 + 4 + pathLen + 4, jsonValueLen);
 			// Invoke get operation
-			providerBackend.processBaSysInvoke(path, jsonValue, output);
+			try {
+				providerBackend.processBaSysInvoke(path, jsonValue, output);
+			} catch (ProviderException e) {
+				logger.error("Exception in BASYX_INVOKE", e);
+				// Catch Exceptions from JSONProvider
+				// No further action here, as the current version
+				// of the TCP-Mapping states, that always Statuscode 0x00 
+				// should be returned with Exceptions encoded in returned String
+			}
 
 			// Send response frame
+			output.flush();
 			sendResponseFrame(byteArrayOutput);
 
 			break;
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/ExceptionToHTTPCodeMapper.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/ExceptionToHTTPCodeMapper.java
new file mode 100644
index 0000000..454b9dd
--- /dev/null
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/protocol/http/server/ExceptionToHTTPCodeMapper.java
@@ -0,0 +1,36 @@
+package org.eclipse.basyx.vab.protocol.http.server;
+
+import org.eclipse.basyx.vab.exception.provider.MalformedRequestException;
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
+import org.eclipse.basyx.vab.exception.provider.ResourceAlreadyExistsException;
+import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
+
+/**
+ * Maps Exceptions from providers to HTTP-Codes
+ * 
+ * @author conradi
+ *
+ */
+public class ExceptionToHTTPCodeMapper {
+
+	
+	/**
+	 * Maps ProviderExceptions to HTTP-Codes
+	 * 
+	 * @param e The thrown ProviderException
+	 * @return HTTP-Code
+	 */
+	public static int mapException(ProviderException e) {
+
+		if(e instanceof MalformedRequestException) {
+			return 400;
+		} else if(e instanceof ResourceAlreadyExistsException) {
+			return 422;
+		} else if(e instanceof ResourceNotFoundException) {
+			return 404;
+		}
+		return 500;
+		
+	}
+	
+}
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 cdb470e..8d7ba63 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
@@ -3,13 +3,13 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.UnsupportedEncodingException;
-
 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.basyx.vab.coder.json.provider.JSONProvider;
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
 import org.eclipse.basyx.vab.modelprovider.VABPathTools;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 
@@ -91,9 +91,22 @@
 		// Setup HTML response header
 		resp.setContentType("application/json");
 		resp.setCharacterEncoding("UTF-8");
-
-		// Process get request
-		providerBackend.processBaSysGet(path, resp.getWriter());
+		
+		resp.setStatus(200);
+		
+		PrintWriter responseWriter = resp.getWriter();
+		
+		try {
+			// Process get request
+			providerBackend.processBaSysGet(path, responseWriter);
+			responseWriter.flush();
+		} catch(ProviderException e) {
+			int httpCode = ExceptionToHTTPCodeMapper.mapException(e);
+			resp.setStatus(httpCode);
+			responseWriter.flush();
+			logger.error("Exception in HTTP-GET. Response-code: " + httpCode, e);
+		}
+		
 	}
 
 	
@@ -106,7 +119,19 @@
 		String serValue = extractSerializedValue(req);
 		logger.trace("DoPut: {}", serValue);
 		
-		providerBackend.processBaSysSet(path, serValue.toString(), resp.getWriter());
+		resp.setStatus(200);
+		
+		PrintWriter responseWriter = resp.getWriter();
+		
+		try {
+			providerBackend.processBaSysSet(path, serValue.toString(), responseWriter);
+			responseWriter.flush();
+		} catch(ProviderException e) {
+			int httpCode = ExceptionToHTTPCodeMapper.mapException(e);
+			resp.setStatus(httpCode);
+			responseWriter.flush();
+			logger.error("Exception in HTTP-PUT. Response-code: " + httpCode, e);
+		}
 	}
 
 	
@@ -123,16 +148,35 @@
 		logger.trace("DoPost: {}", serValue);
 		
 		// Setup HTML response header
+		resp.setStatus(201);
 		resp.setContentType("application/json");
 		resp.setCharacterEncoding("UTF-8");
+		
+		PrintWriter responseWriter = resp.getWriter();
 
 		// Check if request is for property creation or operation invoke
 		if (VABPathTools.isOperationPath(path)) {
 			// Invoke BaSys VAB 'invoke' primitive
-			providerBackend.processBaSysInvoke(path, serValue, resp.getWriter());
+			try {
+				providerBackend.processBaSysInvoke(path, serValue, responseWriter);
+				responseWriter.flush();
+			} catch(ProviderException e) {
+				int httpCode = ExceptionToHTTPCodeMapper.mapException(e);
+				resp.setStatus(httpCode);
+				responseWriter.flush();
+				logger.error("Exception in HTTP-POST. Response-code: " + httpCode, e);
+			}
 		} else {
 			// Invoke the BaSys 'create' primitive
-			providerBackend.processBaSysCreate(path, serValue, resp.getWriter());
+			try {
+				providerBackend.processBaSysCreate(path, serValue, responseWriter);
+				responseWriter.flush();
+			} catch(ProviderException e) {
+				int httpCode = ExceptionToHTTPCodeMapper.mapException(e);
+				resp.setStatus(httpCode);
+				responseWriter.flush();
+				logger.error("Exception in HTTP-POST. Response-code: " + httpCode, e);
+			}
 		}
 	}
 
@@ -147,7 +191,19 @@
 		String serValue = extractSerializedValue(req);
 		logger.trace("DoPatch: {}", serValue);
 		
-		providerBackend.processBaSysDelete(path, serValue, resp.getWriter());
+		resp.setStatus(200);
+		
+		PrintWriter responseWriter = resp.getWriter();
+		
+		try {
+			providerBackend.processBaSysDelete(path, serValue, responseWriter);
+			responseWriter.flush();
+		} catch(ProviderException e) {
+			int httpCode = ExceptionToHTTPCodeMapper.mapException(e);
+			resp.setStatus(httpCode);
+			responseWriter.flush();
+			logger.error("Exception in HTTP-PATCH. Response-code: " + httpCode, e);
+		}
 	}
 
 	
@@ -161,7 +217,19 @@
 		// No parameter to read! Provide serialized null
 		String nullParam = "";
 
-		providerBackend.processBaSysDelete(path, nullParam, resp.getWriter());
+		resp.setStatus(200);
+		
+		PrintWriter responseWriter = resp.getWriter();
+		
+		try {
+			providerBackend.processBaSysDelete(path, nullParam, responseWriter);
+			responseWriter.flush();
+		} catch(ProviderException e) {
+			int httpCode = ExceptionToHTTPCodeMapper.mapException(e);
+			resp.setStatus(httpCode);
+			responseWriter.flush();
+			logger.error("Exception in HTTP-DELETE. Response-code: " + httpCode, e);
+		}
 	}
 
 	
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/coder/json/IBasyxConnectorFacade.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/coder/json/IBasyxConnectorFacade.java
index 4183b75..50ffb75 100644
--- a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/coder/json/IBasyxConnectorFacade.java
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/coder/json/IBasyxConnectorFacade.java
@@ -3,6 +3,7 @@
 import java.io.FileNotFoundException;
 
 import org.eclipse.basyx.vab.coder.json.provider.JSONProvider;
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
 import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 import org.eclipse.basyx.vab.protocol.api.IBaSyxConnector;
 import org.slf4j.Logger;
@@ -39,7 +40,7 @@
 			provider.processBaSysGet(path, outputstream);
 			
 			return outputstream.getResult();
-		} catch (FileNotFoundException e) {
+		} catch (FileNotFoundException | ProviderException e) {
 			logger.error("[TEST] Exception in getModelPropertyValue", e);
 		}
 		return null;