Merge "Add code translation to Exception handling"
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/MetaprotocolHandler.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/MetaprotocolHandler.java
index aff1858..4edced5 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/MetaprotocolHandler.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/MetaprotocolHandler.java
@@ -7,10 +7,8 @@
 import org.eclipse.basyx.vab.coder.json.serialization.DefaultTypeFactory;
 import org.eclipse.basyx.vab.coder.json.serialization.GSONTools;
 import org.eclipse.basyx.vab.coder.json.serialization.GSONToolsFactory;
-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.protocol.http.server.ExceptionToHTTPCodeMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -87,9 +85,13 @@
 		} else if (isException instanceof Boolean && (boolean) isException) {
 			Map<String, Object> first = messages.iterator().next(); // assumes an Exception always comes with a message
 
-			String text = (String) first.get(Message.TEXT);
+			// Get the code of the exception message
+			String code = (String) first.get(Message.CODE);
 			
-			throw getExceptionFromString(text);
+			// Get the text from the exception
+			String text = (String) first.get(Message.TEXT);
+
+			throw getExceptionFromCode(code, text);
 			
 		} else {
 			throw new ProviderException("Format Error: no success but isException not true or not found.");
@@ -100,25 +102,17 @@
 	
 	/**
 	 * Creates a ProviderException from a String received form the Server</br>
-	 * The String has to be formated e.g. "ResourceNotFoundException: Requested Item was not found"
+	 * The String has to be formated e.g. "ResourceNotFoundException: Requested Item
+	 * was not found"
 	 * 
-	 * @param exceptionString the String received from the server
+	 * @param code - code of the exception message
 	 * @return the matching ProviderException
 	 */
-	public static ProviderException getExceptionFromString(String exceptionString) {
+	public static ProviderException getExceptionFromCode(String code, String text) {
+
+		int exceptionCode = Integer.parseInt(code);
 		
-		// Get the Message of the Exception (the String behind the ":")
-		String message = exceptionString.substring(exceptionString.indexOf(":") + 2);
-		
-		// Get the correct ProviderException matching the name before the ":")
-		if (exceptionString.contains(ResourceNotFoundException.class.getSimpleName())) {
-			return new ResourceNotFoundException(message);
-		} else if (exceptionString.contains(ResourceAlreadyExistsException.class.getSimpleName())) {
-			return new ResourceAlreadyExistsException(message);
-		} else if (exceptionString.contains(MalformedRequestException.class.getSimpleName())) {
-			return new MalformedRequestException(message);
-		} else {
-			return new ProviderException("Server threw exception: " + exceptionString);
-		}
+		// return exception based on code
+		return ExceptionToHTTPCodeMapper.mapToException(exceptionCode, text);
 	}
 }
diff --git a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/Result.java b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/Result.java
index 91c9269..40d0291 100644
--- a/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/Result.java
+++ b/sdks/java/basys.sdk/src/main/java/org/eclipse/basyx/vab/coder/json/metaprotocol/Result.java
@@ -6,6 +6,9 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.basyx.vab.exception.provider.ProviderException;
+import org.eclipse.basyx.vab.protocol.http.server.ExceptionToHTTPCodeMapper;
+
 /**
  * Wrapper class that handles meta-data
  * 
@@ -70,13 +73,24 @@
 	private static List<Message> getMessageListFromException(Exception e) {
 
 		List<Message> messageList = new LinkedList<Message>();
+		
+
+		// Translate the exception to code
+		if (e instanceof ProviderException) {
+			String code = new Integer(ExceptionToHTTPCodeMapper.mapFromException((ProviderException) e)).toString();
+			Message message = new Message(MessageType.Exception, code,
+					e.getClass().getSimpleName() + ": " + e.getMessage());
+
+			// replace with desired debugging output
+			messageList.add(message);
+		}
+
+
 
 		if (e.getCause() != null) {
 			messageList.addAll(getMessageListFromException((Exception) e.getCause()));
 		}
 
-		// replace with desired debugging output
-		messageList.add(new Message(MessageType.Exception, e.getClass().getSimpleName() + ": " + e.getMessage()));
 		
 		return messageList;
 	}
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
index e3eebba..4f58027 100644
--- 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
@@ -39,17 +39,17 @@
 	 * @param statusCode The received HTTP-code
 	 * @return the corresponding ProviderException
 	 */
-	public static ProviderException mapToException(int statusCode) {
+	public static ProviderException mapToException(int statusCode, String text) {
 		
 		switch(statusCode) {
 		case 400:
-			return new MalformedRequestException("Response-code: " + statusCode);
+			return new MalformedRequestException(text);
 		case 422:
-			return new ResourceAlreadyExistsException("Response-code: " + statusCode);
+			return new ResourceAlreadyExistsException(text);
 		case 404:
-			return new ResourceNotFoundException("Response-code: " + statusCode);
+			return new ResourceNotFoundException(text);
 		default:
-			return new ProviderException("Response-code: " + statusCode);
+			return new ProviderException(text);
 		}
 		
 	}
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/modelprovider/Exceptions.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/modelprovider/Exceptions.java
new file mode 100644
index 0000000..de5e108
--- /dev/null
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/modelprovider/Exceptions.java
@@ -0,0 +1,75 @@
+package org.eclipse.basyx.testsuite.regression.vab.modelprovider;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.eclipse.basyx.vab.coder.json.metaprotocol.Message;
+import org.eclipse.basyx.vab.coder.json.metaprotocol.Result;
+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.manager.VABConnectionManager;
+import org.eclipse.basyx.vab.modelprovider.VABElementProxy;
+
+/**
+ * Snippet to test the exception handling of an IModelProvider
+ * 
+ * @author zhangzai
+ *
+ */
+public class Exceptions {
+	/**
+	 * Tests for handling an exception and its code
+	 */
+	public static void testHandlingException(VABConnectionManager connManager) {
+		VABElementProxy connVABElement = connManager.connectToVABElement("urn:fhg:es.iese:vab:1:1:simplevabelement");
+
+		// Empty paths - at "" is a Map. Therefore create should throw an Exception
+		try {
+			connVABElement.createValue("", "");
+			fail();
+		} catch (ResourceAlreadyExistsException e) {
+			Result result = new Result(e);
+			Message msg = result.getMessages().get(0);
+			assertEquals("422", msg.getCode());
+		}
+
+		// Non-existing parent element
+		try {
+			connVABElement.getModelPropertyValue("unknown/x");
+			fail();
+		} catch (ResourceNotFoundException e) {
+			Result result = new Result(e);
+			Message msg = result.getMessages().get(0);
+			assertEquals("404", msg.getCode());
+
+		}
+
+		// Null path - should throw exception
+		try {
+			connVABElement.createValue(null, "");
+			fail();
+		} catch (MalformedRequestException e) {
+			Result result = new Result(e);
+			Message msg = result.getMessages().get(0);
+			assertEquals("400", msg.getCode());
+		}
+
+		// Invoke unsupported functional interface
+		try {
+			connVABElement.invokeOperation("operations/supplier");
+			fail();
+		} catch (MalformedRequestException e) {
+			// this is for FileSystemProvider that does not support invoke
+			Result result = new Result(e);
+			Message msg = result.getMessages().get(0);
+			assertEquals("400", msg.getCode());
+		} catch (ProviderException e) {
+			Result result = new Result(e);
+			Message msg = result.getMessages().get(0);
+			assertEquals("500", msg.getCode());
+		}
+
+	}
+}
diff --git a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/modelprovider/TestProvider.java b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/modelprovider/TestProvider.java
index 0384c6b..dc916cd 100644
--- a/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/modelprovider/TestProvider.java
+++ b/sdks/java/basys.sdk/src/test/java/org/eclipse/basyx/testsuite/regression/vab/modelprovider/TestProvider.java
@@ -52,4 +52,9 @@
 	public void testObjectTransfer() {
 		MapUpdate.testPushAll(getConnectionManager());
 	}
+
+	@Test
+	public void testHandlingException() {
+		Exceptions.testHandlingException(getConnectionManager());
+	}
 }