diff --git a/documentation/src/main/resources/pages/ditto/connectivity-mapping.md b/documentation/src/main/resources/pages/ditto/connectivity-mapping.md index 2c87964edb..ff565c5944 100644 --- a/documentation/src/main/resources/pages/ditto/connectivity-mapping.md +++ b/documentation/src/main/resources/pages/ditto/connectivity-mapping.md @@ -267,19 +267,21 @@ Ditto comes with a few helper functions, which makes writing the mapping scripts * @param {string} path - The path which is affected by the message, e.g.: "/attributes" * @param {Object.} dittoHeaders - The headers Object containing all Ditto Protocol header values * @param {*} [value] - The value to apply / which was applied (e.g. in a "modify" action) + * @param {number} status - The status code that indicates the result of the command. * @returns {DittoProtocolMessage} dittoProtocolMessage - * the mapped Ditto Protocol message or * null if the message could/should not be mapped */ -let buildDittoProtocolMsg = function(namespace, id, group, channel, criterion, action, path, dittoHeaders, value) { +function buildDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value, status) { let dittoProtocolMsg = {}; dittoProtocolMsg.topic = namespace + "/" + id + "/" + group + "/" + channel + "/" + criterion + "/" + action; dittoProtocolMsg.path = path; dittoProtocolMsg.headers = dittoHeaders; dittoProtocolMsg.value = value; + dittoProtocolMsg.status = status; return dittoProtocolMsg; -}; +} /** * Builds an external message from the passed parameters. @@ -291,7 +293,7 @@ let buildDittoProtocolMsg = function(namespace, id, group, channel, criterion, a * the mapped external message * or null if the message could/should not be mapped */ -let buildExternalMsg = function(headers, textPayload, bytePayload, contentType) { +function buildExternalMsg(headers, textPayload, bytePayload, contentType) { let externalMsg = {}; externalMsg.headers = headers; @@ -299,7 +301,7 @@ let buildExternalMsg = function(headers, textPayload, bytePayload, contentType) externalMsg.bytePayload = bytePayload; externalMsg.contentType = contentType; return externalMsg; -}; +} /** * Transforms the passed ArrayBuffer to a String interpreting the content of the passed arrayBuffer as unsigned 8 @@ -308,10 +310,10 @@ let buildExternalMsg = function(headers, textPayload, bytePayload, contentType) * @param {ArrayBuffer} arrayBuffer the ArrayBuffer to transform to a String * @returns {String} the transformed String */ -let arrayBufferToString = function(arrayBuffer) { +function arrayBufferToString(arrayBuffer) { return String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); -}; +} /** * Transforms the passed String to an ArrayBuffer using unsigned 8 bit integers. @@ -319,7 +321,7 @@ let arrayBufferToString = function(arrayBuffer) { * @param {String} string the String to transform to an ArrayBuffer * @returns {ArrayBuffer} the transformed ArrayBuffer */ -let stringToArrayBuffer = function(string) { +function stringToArrayBuffer(string) { let buf = new ArrayBuffer(string.length); let bufView = new Uint8Array(buf); @@ -327,7 +329,7 @@ let stringToArrayBuffer = function(string) { bufView[i] = string.charCodeAt(i); } return buf; -}; +} /** * Transforms the passed ArrayBuffer to a {ByteBuffer} (from bytebuffer.js library which needs to be loaded). @@ -335,12 +337,12 @@ let stringToArrayBuffer = function(string) { * @param {ArrayBuffer} arrayBuffer the ArrayBuffer to transform * @returns {ByteBuffer} the transformed ByteBuffer */ -let asByteBuffer = function(arrayBuffer) { +function asByteBuffer(arrayBuffer) { let byteBuffer = new ArrayBuffer(arrayBuffer.byteLength); new Uint8Array(byteBuffer).set(new Uint8Array(arrayBuffer)); return dcodeIO.ByteBuffer.wrap(byteBuffer); -}; +} ``` ### Mapping incoming messages @@ -379,12 +381,13 @@ function mapToDittoProtocolMsg( action, path, dittoHeaders, - value + value, + status ); } ``` -The result of the function has to be an JavaScript object in [Ditto Protocol](protocol-overview.html) or an array of +The result of the function has to be a JavaScript object in [Ditto Protocol](protocol-overview.html) or an array of such JavaScript objects. That's where the helper method `Ditto.buildDittoProtocolMsg` is useful: it explicitly defines which parameters are required for the Ditto Protocol message. @@ -405,6 +408,7 @@ can be mapped to external messages by implementing the following JavaScript func * @param {string} path - The path which is affected by the message, e.g.: "/attributes" * @param {Object.} dittoHeaders - The headers Object containing all Ditto Protocol header values * @param {*} [value] - The value to apply / which was applied (e.g. in a "modify" action) + * @param {number} status - The status code that indicates the result of the command. * @returns {(ExternalMessage|Array)} externalMessage - * The mapped external message, * an array of external messages or @@ -419,7 +423,8 @@ function mapFromDittoProtocolMsg( action, path, dittoHeaders, - value + value, + status ) { // ### diff --git a/services/connectivity/mapping/src/main/resources/javascript/ditto-scope.js b/services/connectivity/mapping/src/main/resources/javascript/ditto-scope.js index 2dcbb404fd..aa5dde1f6e 100644 --- a/services/connectivity/mapping/src/main/resources/javascript/ditto-scope.js +++ b/services/connectivity/mapping/src/main/resources/javascript/ditto-scope.js @@ -5,6 +5,7 @@ * @property {string} path - The path containing the info what to change / what changed * @property {Object.} headers - The Ditto headers * @property {*} value - The value to change to / changed value + * @property {number} status - The status code that indicates the result of the command. */ /** @@ -20,97 +21,99 @@ * Defines the Ditto scope containing helper methods. */ let Ditto = (function () { - /** - * Builds a Ditto Protocol message from the passed parameters. - * @param {string} namespace - The namespace of the entity in java package notation, e.g.: "org.eclipse.ditto" - * @param {string} id - The ID of the entity - * @param {string} group - The affected group/entity, one of: "things" - * @param {string} channel - The channel for the signal, one of: "twin"|"live" - * @param {string} criterion - The criterion to apply, one of: "commands"|"events"|"search"|"messages"|"errors" - * @param {string} action - The action to perform, one of: "create"|"retrieve"|"modify"|"delete" - * @param {string} path - The path which is affected by the message, e.g.: "/attributes" - * @param {Object.} dittoHeaders - The headers Object containing all Ditto Protocol header values - * @param {*} [value] - The value to apply / which was applied (e.g. in a "modify" action) - * @returns {DittoProtocolMessage} dittoProtocolMessage(s) - - * The mapped Ditto Protocol message or - * null if the message could/should not be mapped - */ - let buildDittoProtocolMsg = function(namespace, id, group, channel, criterion, action, path, dittoHeaders, value) { + /** + * Builds a Ditto Protocol message from the passed parameters. + * @param {string} namespace - The namespace of the entity in java package notation, e.g.: "org.eclipse.ditto" + * @param {string} id - The ID of the entity + * @param {string} group - The affected group/entity, one of: "things" + * @param {string} channel - The channel for the signal, one of: "twin"|"live" + * @param {string} criterion - The criterion to apply, one of: "commands"|"events"|"search"|"messages"|"errors" + * @param {string} action - The action to perform, one of: "create"|"retrieve"|"modify"|"delete" + * @param {string} path - The path which is affected by the message, e.g.: "/attributes" + * @param {Object.} dittoHeaders - The headers Object containing all Ditto Protocol header values + * @param {*} [value] - The value to apply / which was applied (e.g. in a "modify" action) + * @param {number} status - The status code that indicates the result of the command. + * @returns {DittoProtocolMessage} dittoProtocolMessage(s) - + * The mapped Ditto Protocol message or + * null if the message could/should not be mapped + */ + function buildDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value, status) { - let dittoProtocolMsg = {}; - dittoProtocolMsg.topic = namespace + "/" + id + "/" + group + "/" + channel + "/" + criterion + "/" + action; - dittoProtocolMsg.path = path; - dittoProtocolMsg.headers = dittoHeaders; - dittoProtocolMsg.value = value; - return dittoProtocolMsg; - }; + let dittoProtocolMsg = {}; + dittoProtocolMsg.topic = namespace + "/" + id + "/" + group + "/" + channel + "/" + criterion + "/" + action; + dittoProtocolMsg.path = path; + dittoProtocolMsg.headers = dittoHeaders; + dittoProtocolMsg.value = value; + dittoProtocolMsg.status = status; + return dittoProtocolMsg; + } - /** - * Builds an external message from the passed parameters. - * @param {Object.} headers - The external headers Object containing header values - * @param {string} [textPayload] - The external mapped String - * @param {ArrayBuffer} [bytePayload] - The external mapped bytes as ArrayBuffer - * @param {string} [contentType] - The returned Content-Type - * @returns {ExternalMessage} externalMessage - - * The mapped external message or - * null if the message could/should not be mapped - */ - let buildExternalMsg = function(headers, textPayload, bytePayload, contentType) { + /** + * Builds an external message from the passed parameters. + * @param {Object.} headers - The external headers Object containing header values + * @param {string} [textPayload] - The external mapped String + * @param {ArrayBuffer} [bytePayload] - The external mapped bytes as ArrayBuffer + * @param {string} [contentType] - The returned Content-Type + * @returns {ExternalMessage} externalMessage - + * The mapped external message or + * null if the message could/should not be mapped + */ + function buildExternalMsg(headers, textPayload, bytePayload, contentType) { - let externalMsg = {}; - externalMsg.headers = headers; - externalMsg.textPayload = textPayload; - externalMsg.bytePayload = bytePayload; - externalMsg.contentType = contentType; - return externalMsg; - }; + let externalMsg = {}; + externalMsg.headers = headers; + externalMsg.textPayload = textPayload; + externalMsg.bytePayload = bytePayload; + externalMsg.contentType = contentType; + return externalMsg; + } - /** - * Transforms the passed ArrayBuffer to a String interpreting the content of the passed arrayBuffer as unsigned 8 - * bit integers. - * - * @param {ArrayBuffer} arrayBuffer the ArrayBuffer to transform to a String - * @returns {String} the transformed String - */ - let arrayBufferToString = function(arrayBuffer) { + /** + * Transforms the passed ArrayBuffer to a String interpreting the content of the passed arrayBuffer as unsigned 8 + * bit integers. + * + * @param {ArrayBuffer} arrayBuffer the ArrayBuffer to transform to a String + * @returns {String} the transformed String + */ + function arrayBufferToString(arrayBuffer) { - return String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); - }; + return String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); + } - /** - * Transforms the passed String to an ArrayBuffer using unsigned 8 bit integers. - * - * @param {String} string the String to transform to an ArrayBuffer - * @returns {ArrayBuffer} the transformed ArrayBuffer - */ - let stringToArrayBuffer = function(string) { + /** + * Transforms the passed String to an ArrayBuffer using unsigned 8 bit integers. + * + * @param {String} string the String to transform to an ArrayBuffer + * @returns {ArrayBuffer} the transformed ArrayBuffer + */ + function stringToArrayBuffer(string) { - let buf = new ArrayBuffer(string.length); - let bufView = new Uint8Array(buf); - for (let i=0, strLen=string.length; inull if the message could/should not be mapped */ function mapToDittoProtocolMsg( - headers, - textPayload, - bytePayload, - contentType + headers, + textPayload, + bytePayload, + contentType ) { - // ### - // Insert your mapping logic here: - if (contentType === 'application/vnd.eclipse.ditto+json') { - let dittoProtocolMsg = JSON.parse(textPayload); - Object.assign(dittoProtocolMsg.headers, headers); - return dittoProtocolMsg; - } - if (headers) { - return null; // returning 'null' means that the message will be dropped - // TODO replace with something useful - } - // ### + // ### + // Insert your mapping logic here: + if (contentType === 'application/vnd.eclipse.ditto+json') { + let dittoProtocolMsg = JSON.parse(textPayload); + Object.assign(dittoProtocolMsg.headers, headers); + return dittoProtocolMsg; + } + if (headers) { + return null; // returning 'null' means that the message will be dropped + // TODO replace with something useful + } + // ### - return Ditto.buildDittoProtocolMsg( - namespace, - id, - group, - channel, - criterion, - action, - path, - dittoHeaders, - value - ); + return Ditto.buildDittoProtocolMsg( + namespace, + id, + group, + channel, + criterion, + action, + path, + dittoHeaders, + value, + status + ); } /** @@ -52,10 +53,10 @@ function mapToDittoProtocolMsg( */ function mapToDittoProtocolMsgWrapper(externalMsg) { - let headers = externalMsg.headers; - let textPayload = externalMsg.textPayload; - let bytePayload = externalMsg.bytePayload; - let contentType = externalMsg.contentType; + let headers = externalMsg.headers; + let textPayload = externalMsg.textPayload; + let bytePayload = externalMsg.bytePayload; + let contentType = externalMsg.contentType; - return mapToDittoProtocolMsg(headers, textPayload, bytePayload, contentType); + return mapToDittoProtocolMsg(headers, textPayload, bytePayload, contentType); } diff --git a/services/connectivity/mapping/src/main/resources/javascript/outgoing-mapping.js b/services/connectivity/mapping/src/main/resources/javascript/outgoing-mapping.js index 828c0998f4..885134ae2e 100644 --- a/services/connectivity/mapping/src/main/resources/javascript/outgoing-mapping.js +++ b/services/connectivity/mapping/src/main/resources/javascript/outgoing-mapping.js @@ -9,38 +9,41 @@ * @param {string} path - The path which is affected by the message, e.g.: "/attributes" * @param {Object.} dittoHeaders - The headers Object containing all Ditto Protocol header values * @param {*} [value] - The value to apply / which was applied (e.g. in a "modify" action) + * @param {number} status - The status code that indicates the result of the command. * @returns {(ExternalMessage|Array)} externalMessage - * The mapped external message, * an array of external messages or * null if the message could/should not be mapped */ function mapFromDittoProtocolMsg( - namespace, - id, - group, - channel, - criterion, - action, - path, - dittoHeaders, - value + namespace, + id, + group, + channel, + criterion, + action, + path, + dittoHeaders, + value, + status ) { - // ### - // Insert your mapping logic here: - let headers = dittoHeaders; - let textPayload = JSON.stringify(Ditto.buildDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value)); - // TODO replace with something useful, this will publish the message in Ditto Protocol JSON - let bytePayload = null; - let contentType = 'application/vnd.eclipse.ditto+json'; - // ### + // ### + // Insert your mapping logic here: + let headers = dittoHeaders; + let textPayload = JSON.stringify( + Ditto.buildDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value)); + // TODO replace with something useful, this will publish the message in Ditto Protocol JSON + let bytePayload = null; + let contentType = 'application/vnd.eclipse.ditto+json'; + // ### - return Ditto.buildExternalMsg( - headers, - textPayload, - bytePayload, - contentType - ); + return Ditto.buildExternalMsg( + headers, + textPayload, + bytePayload, + contentType + ); } /** @@ -53,19 +56,20 @@ function mapFromDittoProtocolMsg( */ function mapFromDittoProtocolMsgWrapper(dittoProtocolMsg) { - let topic = dittoProtocolMsg.topic; - let splitTopic = topic.split("/"); + let topic = dittoProtocolMsg.topic; + let splitTopic = topic.split("/"); - let namespace = splitTopic[0]; - let id = splitTopic[1]; - let group = splitTopic[2]; - let channel = splitTopic[3]; - let criterion = splitTopic[4]; - let action = splitTopic[5]; + let namespace = splitTopic[0]; + let id = splitTopic[1]; + let group = splitTopic[2]; + let channel = splitTopic[3]; + let criterion = splitTopic[4]; + let action = splitTopic[5]; - let path = dittoProtocolMsg.path; - let dittoHeaders = dittoProtocolMsg.headers; - let value = dittoProtocolMsg.value; + let path = dittoProtocolMsg.path; + let dittoHeaders = dittoProtocolMsg.headers; + let value = dittoProtocolMsg.value; + let status = dittoProtocolMsg.status; - return mapFromDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value); + return mapFromDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value, status); } diff --git a/services/connectivity/mapping/src/test/java/org/eclipse/ditto/services/connectivity/mapping/javascript/JavaScriptMessageMapperRhinoTest.java b/services/connectivity/mapping/src/test/java/org/eclipse/ditto/services/connectivity/mapping/javascript/JavaScriptMessageMapperRhinoTest.java index b9fd722c44..eaf25a9554 100644 --- a/services/connectivity/mapping/src/test/java/org/eclipse/ditto/services/connectivity/mapping/javascript/JavaScriptMessageMapperRhinoTest.java +++ b/services/connectivity/mapping/src/test/java/org/eclipse/ditto/services/connectivity/mapping/javascript/JavaScriptMessageMapperRhinoTest.java @@ -25,6 +25,7 @@ import javax.annotation.Nullable; import org.eclipse.ditto.json.JsonFactory; +import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; import org.eclipse.ditto.json.assertions.DittoJsonAssertions; @@ -45,7 +46,9 @@ import org.eclipse.ditto.services.models.connectivity.ExternalMessage; import org.eclipse.ditto.services.models.connectivity.ExternalMessageFactory; import org.eclipse.ditto.signals.commands.things.modify.CreateThing; +import org.eclipse.ditto.signals.commands.things.modify.CreateThingResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyAttribute; +import org.eclipse.ditto.signals.commands.things.modify.ModifyThingResponse; import org.junit.BeforeClass; import org.junit.Test; @@ -133,7 +136,8 @@ public final class JavaScriptMessageMapperRhinoTest { " action,\n" + " path,\n" + " dittoHeaders,\n" + - " value\n" + + " value,\n" + + " status\n" + ") {\n" + "\n" + " // ###\n" + @@ -173,7 +177,8 @@ public final class JavaScriptMessageMapperRhinoTest { " action,\n" + " path,\n" + " dittoHeaders,\n" + - " value\n" + + " value,\n" + + " status\n" + ") {\n" + "\n" + " return null;" + @@ -223,7 +228,8 @@ public final class JavaScriptMessageMapperRhinoTest { " action,\n" + " path,\n" + " dittoHeaders,\n" + - " value\n" + + " value,\n" + + " status\n" + ") {\n" + "\n" + " // ###\n" + @@ -244,6 +250,43 @@ public final class JavaScriptMessageMapperRhinoTest { " );" + "}"; + private static final String MAPPING_INCOMING_WITH_STATUS = + "function mapToDittoProtocolMsg(\n" + + " headers,\n" + + " textPayload,\n" + + " bytePayload,\n" + + " contentType\n" + + ") {\n" + + "\n" + + " // ###\n" + + " // Insert your mapping logic here\n" + + " let namespace = \"" + MAPPING_INCOMING_NAMESPACE + "\";\n" + + " let id = \"" + MAPPING_INCOMING_ID + "\";\n" + + " let group = \"things\";\n" + + " let channel = \"twin\";\n" + + " let criterion = \"commands\";\n" + + " let action = \"modify\";\n" + + " let path = \"" + MAPPING_INCOMING_PATH + "\";\n" + + " let dittoHeaders = {};\n" + + " dittoHeaders[\"correlation-id\"] = headers[\"correlation-id\"];\n" + + " let value = textPayload;\n" + + " let status = 204;\n" + + " // ###\n" + + "\n" + + " return Ditto.buildDittoProtocolMsg(\n" + + " namespace,\n" + + " id,\n" + + " group,\n" + + " channel,\n" + + " criterion,\n" + + " action,\n" + + " path,\n" + + " dittoHeaders,\n" + + " value,\n" + + " status\n" + + " );\n" + + "}"; + private static final String MAPPING_INCOMING_DEFAULT = "function mapToDittoProtocolMsg(\n" + " headers,\n" + " textPayload,\n" + @@ -273,7 +316,8 @@ public final class JavaScriptMessageMapperRhinoTest { " action, // The action to perform, one of: \"create\"|\"retrieve\"|\"modify\"|\"delete\"\n" + " path, // The path which is affected by the message, e.g.: \"/attributes\"\n" + " dittoHeaders, // The headers Object containing all Ditto Protocol header values\n" + - " value // The value to apply / which was applied (e.g. in a \"modify\" action)\n" + + " value, // The value to apply / which was applied (e.g. in a \"modify\" action)\n" + + " status // The status code that indicates the result of the command\n" + " );\n" + "}\n"; @@ -286,13 +330,14 @@ public final class JavaScriptMessageMapperRhinoTest { " action,\n" + " path,\n" + " dittoHeaders,\n" + - " value\n" + + " value,\n" + + " status\n" + ") {\n" + "\n" + " // ###\n" + " // Insert your mapping logic here:\n" + " let headers = dittoHeaders;\n" + - " let textPayload = JSON.stringify(Ditto.buildDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value));\n" + + " let textPayload = JSON.stringify(Ditto.buildDittoProtocolMsg(namespace, id, group, channel, criterion, action, path, dittoHeaders, value, status));\n" + " // TODO replace with something useful, this will publish the message in Ditto Protocol JSON\n" + " let bytePayload = null;\n" + " let contentType = 'application/vnd.eclipse.ditto+json';\n" + @@ -308,6 +353,7 @@ public final class JavaScriptMessageMapperRhinoTest { private static MessageMapper javaScriptRhinoMapperNoop; private static MessageMapper javaScriptRhinoMapperPlain; + private static MessageMapper javaScriptRhinoMapperPlainWithStatus; private static MessageMapper javaScriptRhinoMapperEmpty; private static MessageMapper javaScriptRhinoMapperBinary; private static MessageMapper javaScriptRhinoMapperDefault; @@ -332,6 +378,15 @@ public static void setup() { .build() ); + javaScriptRhinoMapperPlainWithStatus = JavaScriptMessageMapperFactory.createJavaScriptMessageMapperRhino(); + javaScriptRhinoMapperPlainWithStatus.configure(MAPPING_CONFIG, + JavaScriptMessageMapperFactory + .createJavaScriptMessageMapperConfigurationBuilder("plainStatus", Collections.emptyMap()) + .incomingScript(MAPPING_INCOMING_WITH_STATUS) + .outgoingScript(MAPPING_OUTGOING_PLAIN) + .build() + ); + javaScriptRhinoMapperEmpty = JavaScriptMessageMapperFactory.createJavaScriptMessageMapperRhino(); javaScriptRhinoMapperEmpty.configure(MAPPING_CONFIG, JavaScriptMessageMapperFactory @@ -368,7 +423,7 @@ public void testNoopJavascriptIncomingMapping() { headers.put(ExternalMessage.CONTENT_TYPE_HEADER, DittoConstants.DITTO_PROTOCOL_CONTENT_TYPE); final ModifyAttribute modifyAttribute = - ModifyAttribute.of(ThingId.of(MAPPING_INCOMING_NAMESPACE , MAPPING_INCOMING_ID), + ModifyAttribute.of(ThingId.of(MAPPING_INCOMING_NAMESPACE, MAPPING_INCOMING_ID), JsonPointer.of("foo"), JsonValue.of(MAPPING_INCOMING_PAYLOAD_STRING), DittoHeaders.newBuilder() @@ -376,7 +431,8 @@ public void testNoopJavascriptIncomingMapping() { .schemaVersion(JsonSchemaVersion.V_2) .build()); final Adaptable inputAdaptable = DittoProtocolAdapter.newInstance().toAdaptable(modifyAttribute); - final JsonifiableAdaptable jsonifiableInputAdaptable = ProtocolFactory.wrapAsJsonifiableAdaptable(inputAdaptable); + final JsonifiableAdaptable jsonifiableInputAdaptable = + ProtocolFactory.wrapAsJsonifiableAdaptable(inputAdaptable); final ExternalMessage message = ExternalMessageFactory.newExternalMessageBuilder(headers) .withText(jsonifiableInputAdaptable.toJsonString()) .build(); @@ -404,7 +460,8 @@ public void testNoopJavascriptOutgoingMapping() { DittoHeaders.newBuilder().correlationId(correlationId).putHeader("subject", "{{topic:action-subject}}").build()); final Adaptable inputAdaptable = DittoProtocolAdapter.newInstance().toAdaptable(createThing); - final JsonifiableAdaptable jsonifiableInputAdaptable = ProtocolFactory.wrapAsJsonifiableAdaptable(inputAdaptable); + final JsonifiableAdaptable jsonifiableInputAdaptable = + ProtocolFactory.wrapAsJsonifiableAdaptable(inputAdaptable); final long startTs = System.nanoTime(); @@ -444,7 +501,8 @@ public void testDefaultJavascriptOutgoingMapping() { System.out.println("CREATE THING :" + createThing); final Adaptable inputAdaptable = DittoProtocolAdapter.newInstance().toAdaptable(createThing); - final JsonifiableAdaptable jsonifiableInputAdaptable = ProtocolFactory.wrapAsJsonifiableAdaptable(inputAdaptable); + final JsonifiableAdaptable jsonifiableInputAdaptable = + ProtocolFactory.wrapAsJsonifiableAdaptable(inputAdaptable); final long startTs = System.nanoTime(); @@ -468,6 +526,50 @@ public void testDefaultJavascriptOutgoingMapping() { .isEqualToIgnoringFieldDefinitions(jsonifiableInputAdaptable.toJson()); } + @Test + public void testDefaultJavascriptOutgoingMappingWithStatus() { + final ThingId thingId = ThingId.of("org.eclipse.ditto:foo-bar-plain"); + final String correlationId = UUID.randomUUID().toString(); + final Thing newThing = Thing.newBuilder() + .setId(thingId) + .setAttributes(Attributes.newBuilder().set("foo", "bar").build()) + .build(); + final CreateThingResponse createThingResponse = CreateThingResponse.of(newThing, DittoHeaders.newBuilder() + .correlationId(correlationId) + .putHeader("subject", "{{topic:action-subject}}") + .build()); + + + System.out.println( + "HEADERS: " + ProtocolFactory.newHeadersWithDittoContentType(createThingResponse.getDittoHeaders())); + + System.out.println("CREATE THING RESPONSE :" + createThingResponse); + + final Adaptable adaptable = DittoProtocolAdapter.newInstance().toAdaptable(createThingResponse); + final JsonifiableAdaptable jsonifiableAdaptable = ProtocolFactory.wrapAsJsonifiableAdaptable(adaptable); + + final long startTs = System.nanoTime(); + + System.out.println("ADAPTABLE: " + jsonifiableAdaptable); + System.out.println("ADAPTABLE TO JSON: " + jsonifiableAdaptable.toJsonString()); + + final List rawMessageOpt = javaScriptRhinoMapperDefault.map(adaptable); + final ExternalMessage rawMessage = rawMessageOpt.get(0); + + System.out.println(rawMessage.getHeaders()); + + System.out.println(rawMessage); + System.out.println("testDefaultJavascriptOutgoingMappingWithStatus Duration: " + + (System.nanoTime() - startTs) / 1000000.0 + "ms"); + + assertThat(rawMessage.findContentType()).contains(DittoConstants.DITTO_PROTOCOL_CONTENT_TYPE); + assertThat(rawMessage.findHeader(HEADER_CORRELATION_ID)).contains(correlationId); + assertThat(rawMessage.isTextMessage()).isTrue(); + final String textPayload = rawMessage.getTextPayload().get(); + final JsonObject jsonPayload = JsonFactory.readFrom(textPayload).asObject(); + DittoJsonAssertions.assertThat(jsonPayload).isEqualToIgnoringFieldDefinitions(jsonifiableAdaptable.toJson()); + } + @Test public void testPlainJavascriptIncomingMapping() { final String correlationId = UUID.randomUUID().toString(); @@ -495,6 +597,38 @@ public void testPlainJavascriptIncomingMapping() { assertThat(adaptable.getPayload().getValue()).contains(JsonValue.of(MAPPING_INCOMING_PAYLOAD_STRING)); } + @Test + public void testPlainJavascriptIncomingMappingWithStatus() { + final String correlationId = UUID.randomUUID().toString(); + final Map headers = new HashMap<>(); + headers.put(HEADER_CORRELATION_ID, correlationId); + headers.put(ExternalMessage.CONTENT_TYPE_HEADER, CONTENT_TYPE_PLAIN); + final ThingId thingId = ThingId.of("org.eclipse.ditto:foo-bar-plain"); + final ModifyThingResponse modifyThingResponse = ModifyThingResponse.modified(thingId, DittoHeaders.newBuilder() + .correlationId(correlationId) + .putHeader("subject", "{{topic:action-subject}}") + .build()); + final ExternalMessage message = ExternalMessageFactory.newExternalMessageBuilder(headers) + .withText(modifyThingResponse.toJsonString()) + .build(); + + + final long startTs = System.nanoTime(); + final List adaptables = javaScriptRhinoMapperPlainWithStatus.map(message); + final Adaptable adaptable = adaptables.get(0); + System.out.println(adaptable); + System.out.println( + "testPlainJavascriptIncomingMapping Duration: " + (System.nanoTime() - startTs) / 1000000.0 + "ms"); + + assertThat(adaptable.getTopicPath().getChannel()).isEqualTo(TopicPath.Channel.TWIN); + assertThat(adaptable.getTopicPath().getCriterion()).isEqualTo(TopicPath.Criterion.COMMANDS); + assertThat(adaptable.getTopicPath().getAction()).contains(TopicPath.Action.MODIFY); + assertThat(adaptable.getTopicPath().getNamespace()).isEqualTo(MAPPING_INCOMING_NAMESPACE); + assertThat(adaptable.getTopicPath().getId()).isEqualTo(MAPPING_INCOMING_ID); + assertThat(adaptable.getPayload().getPath().toString()).isEqualTo(MAPPING_INCOMING_PATH); + assertThat(adaptable.getPayload().getValue()).map(JsonValue::asString).contains(modifyThingResponse.toJsonString()); + } + @Test public void testPlainJavascriptOutgoingMapping() { final ThingId thingId = ThingId.of("org.eclipse.ditto:foo-bar-plain");