no MessageMappingProcessor available in Ditto

252 views Asked by At

I got a stranger error although I follow guideline in ditto example.

Octopus can published messages to MQTT. I can see them use MQTT client. WebApp shows connection established and send send event works. I can change values through "my.test.octopus"panel. But when I query it using API, I can only my values from webapp, never got vales from octopus.

I checked connectivity logs, seems mapping problem...I used the following to create mapping when creating connection:

"incomingScript": "function mapToDittoProtocolMsg(
                              headers, 
                              textPayload, 
                              bytePayload, 
                              contentType) {

    const jsonString = String.fromCharCode.apply(null, new Uint8Array(bytePayload));
    const jsonData = JSON.parse(jsonString);
    const thingId = jsonData.thingId;
    const value = { 
      temp_sensor: { 
        properties: { 
          value: jsonData.temp 
        }
      },
      altitude: { 
        properties: { 
          value: jsonData.alt 
        }
      }
    };

    return Ditto.buildDittoProtocolMsg('my.test', thingId, 'things', 'twin', 'commands', 'modify', '/features', headers, value);
}"

Thanks for help

update

The error manifests in the following log line:

See the following log statement:

"The message mapper configuration failed due to: unterminated regular expression literal (incomingScript#1) - in line/column #1/472," -- ""incomingScript": "function mapToDittoProtocolMsg(headers, textPayload, bytePayload, contentType) {var jsonData = JSON.parse(textPayload);const thingId = jsonData.thingId;const value = {temp_sensor: { properties: { value: jsonData.temp } }, altitude: { properties: { value: jsonData.alt } } }; return Ditto.buildDittoProtocolMsg('my.test', thingId, 'things', 'twin', 'commands', 'modify', '/features', headers, value); }"
1

There are 1 answers

5
Yannic Bürgmann On

Your mapping script seems to work correctly. I created a unit test for it using the payload mapping testing from ditto-examples.

This test looks like the following:

 @Test
 public void incomingBytePayloadMapping() throws IOException {
     final Resource incomingMappingFunction = new Resource("incomingScript.js");
     final PayloadMappingFunction underTest = PayloadMappingFunction.fromJavaScript(incomingMappingFunction.getContent());

     final Map<String, String> headers = new HashMap<>();
     headers.put("content-type", ContentTypes.APPLICATION_OCTET_STREAM.toString());
     headers.put("device_id", "the-thing-id");

     final byte[] bytePayload = "{\"thingId\":\"my.test.thing\",\"temp\":25.6,\"alt\":11}".getBytes();
     final ExternalMessage message = ExternalMessageFactory.newExternalMessageBuilder(headers)
             .withBytes(bytePayload)
             .build();

     final Resource expectedAdaptableJsonResource = new Resource("expectedAdaptable.json");
     final JsonObject expectedAdaptableJson = JsonFactory.newObject(expectedAdaptableJsonResource.getContent());
     final Adaptable expectedAdaptable = ProtocolFactory
             .jsonifiableAdaptableFromJson(expectedAdaptableJson)
             .setDittoHeaders(DittoHeaders.of(headers));

     PayloadMappingTestCase.assertThat(message)
             .mappedByJavascriptPayloadMappingFunction(underTest)
             .isEqualTo(expectedAdaptable)
             .verify();
 }

incomingScript.js

function mapToDittoProtocolMsg(
    headers,
    textPayload,
    bytePayload,
    contentType) {

    const jsonString = String.fromCharCode.apply(null, new Uint8Array(bytePayload));
    const jsonData = JSON.parse(jsonString);
    const thingId = jsonData.thingId;
    const value = {
        temp_sensor: {
            properties: {
                value: jsonData.temp
            }
        },
        altitude: {
            properties: {
                value: jsonData.alt
            }
        }
    };

    return Ditto.buildDittoProtocolMsg('my.test', thingId, 'things', 'twin', 'commands', 'modify', '/features', headers,
                                       value);
}

expectedAdaptable.json

{
  "topic": "my.test/my.test.thing/things/twin/commands/modify",
  "headers": {},
  "path": "/features",
  "value": {
    "temp_sensor": {
      "properties": {
        "value": 25.6
      }
    },
    "altitude": {
      "properties": {
        "value": 11
      }
    }
  }
}

So far this seems to work, but in this test I assume the following incoming bytePayload:

final byte[] bytePayload = "{\"thingId\":\"my.test.thing\",\"temp\":25.6,\"alt\":11}".getBytes();

Could you somehow verify, that the byte payload your octopus is sending is looking correctly? Is the octopus really sending byte payload or is it text payload (application/json)?

update

According to the comment of Bob Su the octopus is sending text payload. In order to map this payload, you actually have to use the text payload instead of byte payload. In the following you'll see the updated incomingScript.

incomingScript.js

function mapToDittoProtocolMsg(
    headers,
    textPayload,
    bytePayload,
    contentType) {

    var jsonData = JSON.parse(textPayload);
    const thingId = jsonData.thingId;
    const value = {
        temp_sensor: {
            properties: {
                value: jsonData.temp
            }
        },
        altitude: {
            properties: {
                value: jsonData.alt
            }
        }
    };

    return Ditto.buildDittoProtocolMsg('my.test', thingId, 'things', 'twin', 'commands', 'modify', '/features', headers,
                                       value);
}

The test can be adapted to:

@Test
public void incomingTextPayloadMapping() throws IOException {
    final Resource incomingMappingFunction = new Resource("incomingScript.js");
    final PayloadMappingFunction underTest = PayloadMappingFunction.fromJavaScript(incomingMappingFunction.getContent());

    final Map<String, String> headers = new HashMap<>();
    headers.put("content-type", ContentTypes.APPLICATION_JSON.toString());
    headers.put("device_id", "the-thing-id");

    final ExternalMessage message = ExternalMessageFactory.newExternalMessageBuilder(headers)
            .withText("{\"thingId\":\"my.test.thing\",\"temp\":25.6,\"alt\":11}")
            .build();

    final Resource expectedAdaptableJsonResource = new Resource("expectedAdaptable.json");
    final JsonObject expectedAdaptableJson = JsonFactory.newObject(expectedAdaptableJsonResource.getContent());
    final Adaptable expectedAdaptable = ProtocolFactory
            .jsonifiableAdaptableFromJson(expectedAdaptableJson)
            .setDittoHeaders(DittoHeaders.of(headers));

    PayloadMappingTestCase.assertThat(message)
            .mappedByJavascriptPayloadMappingFunction(underTest)
            .isEqualTo(expectedAdaptable)
            .verify();
}