de.thingweb.desc.ThingDescriptionParserTest.java Source code

Java tutorial

Introduction

Here is the source code for de.thingweb.desc.ThingDescriptionParserTest.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Siemens AG and the thingweb community
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package de.thingweb.desc;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.siemens.ct.exi.EXIFactory;
import com.siemens.ct.exi.exceptions.EXIException;
import com.siemens.ct.exi.helpers.DefaultEXIFactory;
import com.siemens.ct.exi.json.EXIforJSONGenerator;

import de.thingweb.thing.Action;
import de.thingweb.thing.Event;
import de.thingweb.thing.Property;
import de.thingweb.thing.Thing;

public class ThingDescriptionParserTest {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testFromURLDoor() throws JsonParseException, IOException {
        URL jsonld = new URL("https://raw.githubusercontent.com/w3c/wot/master/TF-TD/TD%20Samples/door.jsonld");
        ThingDescriptionParser.fromURL(jsonld);
        // TODO any further checks?
    }

    @Test
    public void testFromURLLed() throws JsonParseException, IOException {
        URL jsonld = new URL("https://raw.githubusercontent.com/w3c/wot/master/TF-TD/TD%20Samples/led.jsonld");
        ThingDescriptionParser.fromURL(jsonld);
        // TODO any further checks?
    }

    @Test
    public void testFromURLLedEXI4JSON() throws JsonParseException, IOException, EXIException {
        URL jsonld = new URL("https://raw.githubusercontent.com/w3c/wot/master/TF-TD/TD%20Samples/led.jsonld");

        InputStream is = jsonld.openStream();

        File f = File.createTempFile("jsonld", "e4j");
        OutputStream os = new FileOutputStream(f);

        EXIFactory ef = DefaultEXIFactory.newInstance();
        ef.setSharedStrings(ThingDescriptionParser.SHARED_STRINGS_EXI_FOR_JSON);

        EXIforJSONGenerator e4j = new EXIforJSONGenerator(ef);
        e4j.generate(is, os);

        is.close();
        os.close();

        ThingDescriptionParser.fromFile(f.getAbsolutePath());
        // TODO any further checks?
    }

    @Test
    public void testFromURLLed_v02() throws JsonParseException, IOException {
        URL jsonld = new URL("https://raw.githubusercontent.com/w3c/wot/master/TF-TD/TD%20Samples/led_v02.jsonld");
        try {
            ThingDescriptionParser.fromURL(jsonld);
            // TODO are not recognized fields are ignored
            //           fail();
        } catch (IOException e) {
            // OK, expect failure
        }
    }

    @Test
    public void testFromURLOutlet() throws JsonParseException, IOException {
        URL jsonld = new URL("https://raw.githubusercontent.com/w3c/wot/master/TF-TD/TD%20Samples/outlet.jsonld");
        ThingDescriptionParser.fromURL(jsonld);
        // TODO any further checks?
    }

    @Test
    public void testFromURLWeather() throws JsonParseException, IOException {
        URL jsonld = new URL("https://raw.githubusercontent.com/w3c/wot/master/TF-TD/TD%20Samples/weather.jsonld");
        ThingDescriptionParser.fromURL(jsonld);
        // TODO any further checks?
    }

    @Test
    public void testLocalStrangeCharacters() throws JsonParseException, IOException {
        String foo = "{\"metadata\":{\"name\":\"Ugly strange n\u00E4ime\",\"protocols\":{\"CoAP\":{\"uri\":\"coap://MD1EWQUC/things/ugly+strange+n%c3%a4ime\",\"priority\":1},\"HTTP\":{\"uri\":\"http://MD1EWQUC:8080/things/ugly+strange+n%c3%a4ime\",\"priority\":2}},\"encodings\":[\"JSON\"]},\"interactions\":[{\"@type\":\"Property\",\"name\":\"not url komp\u00E4tibel\",\"writable\":false,\"outputData\":\"xsd:string\"},{\"@type\":\"Action\",\"name\":\"wierdly named \u00E4ktschn\",\"inputData\":null,\"outputData\":\"\"}],\"@context\":\"http://w3c.github.io/wot/w3c-wot-td-context.jsonld\"}";
        @SuppressWarnings("unused")
        Thing td = ThingDescriptionParser.fromBytes(foo.getBytes());
        // TODO any further checks?
    }

    @Test
    public void testFromFile() {
        String happyPath = "jsonld" + File.separator + "led.v2.jsonld";
        // should use parser for deprecated Thing Descriptions
        String happyPathOld = "jsonld" + File.separator + "led.jsonld";
        // should fail (required field not found)
        String invalid = "jsonld" + File.separator + "led.v2.invalid.jsonld";

        try {
            ThingDescriptionParser.fromFile(happyPath);
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }

        try {
            ThingDescriptionParser.fromFile(happyPathOld);
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }

        try {
            ThingDescriptionParser.fromFile(invalid);
            fail();
        } catch (IOException e) {
            if (e instanceof IOException) {
                // as expected
            } else {
                e.printStackTrace();
                fail();
            }
        }
    }

    @Test
    public void testRoundtrip1() throws Exception {
        // TODO shall we test round tripping of any node? e.g, "actuator:unit": "actuator:ms" as part of inputData

        // String filename = "jsonld" + File.separator + "led.v2.plain.jsonld";
        String tdSample = "{\r\n" + "  \"@context\": [\r\n"
                + "    \"http://w3c.github.io/wot/w3c-wot-td-context.jsonld\",\r\n"
                + "    { \"actuator\": \"http://example.org/actuator#\" }\r\n" + "  ],\r\n"
                + "  \"@type\": \"Thing\",\r\n" + "  \"name\": \"MyLEDThing\",\r\n" + "  \"uris\": [\r\n"
                + "    \"coap://myled.example.com:5683/\",\r\n"
                + "    \"http://mything.example.com:8080/myled/\"\r\n" + "  ],\r\n"
                + "  \"encodings\": [ \"JSON\",\"EXI\"],\r\n" + "  \"security\": {\r\n"
                + "    \"cat\": \"token:jwt\",\r\n" + "    \"alg\": \"HS256\",\r\n"
                + "    \"as\": \"https://authority-issuing.example.org\"\r\n" + "  },\r\n"
                + "  \"properties\": [\r\n" + "    {\r\n" + "      \"@type\": \"actuator:onOffStatus\",\r\n"
                + "      \"name\": \"status\",\r\n" + "      \"valueType\": { \"type\": \"boolean\" },\r\n"
                + "      \"writable\": true,\r\n" + "      \"hrefs\": [ \"pwr\", \"status\" ]\r\n" + "    }\r\n"
                + "  ],\r\n" + "  \"actions\": [\r\n" + "    {\r\n" + "      \"@type\": \"actuator:fadeIn\",\r\n"
                + "      \"name\": \"fadeIn\",\r\n" + "      \"inputData\": {\r\n"
                + "        \"valueType\": { \"type\": \"integer\" }"
                //            + ",\r\n" + 
                //            "        \"actuator:unit\": \"actuator:ms\"\r\n"
                + "      },\r\n" + "      \"hrefs\": [\"in\", \"led/in\"  ]\r\n" + "    },\r\n" + "    {\r\n"
                + "      \"@type\": \"actuator:fadeOut\",\r\n" + "      \"name\": \"fadeOut\",\r\n"
                + "      \"inputData\": {\r\n" + "        \"valueType\": { \"type\": \"integer\" }"
                //            + ",\r\n" + 
                //            "        \"actuator:unit\": \"actuator:ms\"\r\n"
                + "      },\r\n" + "      \"hrefs\": [\"out\", \"led/out\" ]\r\n" + "    }\r\n" + "  ],\r\n"
                + "  \"events\": [\r\n" + "    {\r\n" + "      \"@type\": \"actuator:alert\",\r\n"
                + "      \"name\": \"criticalCondition\",\r\n"
                + "      \"valueType\": { \"type\": \"string\" },\r\n"
                + "      \"hrefs\": [ \"ev\", \"alert\" ]\r\n" + "    }\r\n" + "  ]\r\n" + "}";

        ObjectMapper mapper = new ObjectMapper();

        JsonNode original = mapper.readValue(tdSample, JsonNode.class);
        JsonNode generated = mapper.readValue(
                ThingDescriptionParser.toBytes(ThingDescriptionParser.fromBytes(tdSample.getBytes())),
                JsonNode.class);

        assertTrue(original.equals(generated));
    }

    @Test
    public void testRoundtrip2() throws Exception {
        // e.g, JSON  Object, see http://w3c.github.io/wot/current-practices/wot-practices.html#td-context
        //       {
        //            "@context": {
        //              "name": "http://www.w3c.org/wot/td#name",
        //              "uris": "http://www.w3c.org/wot/td#associatedUri",
        //              "unit": "http://purl.oclc.org/NET/ssnx/qu/qu-rec20#unit",
        //              "Thing": "http://www.w3c.org/wot/td#Thing",
        //              ...
        //            }
        //          }

        String tdSample = "{\r\n" + "   \"@context\": {\r\n"
                + "      \"name\": \"http://www.w3c.org/wot/td#name\",\r\n"
                + "      \"uris\": \"http://www.w3c.org/wot/td#associatedUri\",\r\n"
                + "      \"unit\": \"http://purl.oclc.org/NET/ssnx/qu/qu-rec20#unit\",\r\n"
                + "      \"Thing\": \"http://www.w3c.org/wot/td#Thing\"\r\n" + "   },\r\n"
                + "   \"name\": \"Test\",\r\n" + "   \"properties\": [],\r\n" + "   \"actions\": [],\r\n"
                + "   \"events\": []\r\n" + "}";

        //       Thing t = new Thing("myName");
        //       ObjectNode on = factory.objectNode();
        //       on.put("name", factory.textNode("http://www.w3c.org/wot/td#name"));
        //       on.put("uris", factory.textNode("http://www.w3c.org/wot/td#associatedUri"));
        //       on.put("unit", factory.textNode("http://purl.oclc.org/NET/ssnx/qu/qu-rec20#unit"));
        //       on.put("Thing", factory.textNode("http://www.w3c.org/wot/td#Thing"));
        //       t.getMetadata().add("@context", on);

        ObjectMapper mapper = new ObjectMapper();

        JsonNode original = mapper.readValue(tdSample, JsonNode.class);
        JsonNode generated = mapper.readValue(
                ThingDescriptionParser.toBytes(ThingDescriptionParser.fromBytes(tdSample.getBytes())),
                JsonNode.class);

        assertTrue(original.equals(generated));

    }

    //    @Test
    //    public void testReshape() {
    //      try {
    //        File f = new File("jsonld/outlet_flattened.jsonld");
    //        FileReader r = new FileReader(f);
    //        char[] buf = new char [(int) f.length()];
    //        r.read(buf);
    //        r.close();
    //        String jsonld = ThingDescriptionParser.reshape(new String(buf).getBytes());
    //        // checks that reshaped jsonld is compliant to description parser's impl.
    //        ThingDescriptionParser.fromBytes(jsonld.getBytes());
    //        // TODO any further checks?
    //      } catch (Exception e) {
    //        fail(e.getMessage());
    //      }
    //    }

    //    {
    //         "@context": ["http://w3c.github.io/wot/w3c-wot-td-context.jsonld"],
    //         "@type": "Thing",
    //         "name": "MyTemperatureThing",
    //         "uris": "coap://www.mytemp.com:5683/",
    //         "encodings": ["JSON"],
    //         "properties": [
    //           {
    //             "name": "temperature",
    //             "valueType": {
    //               "type": "integer",
    //               "maximum": 13
    //             },
    //             "writable": false,
    //             "hrefs": ["temp"]
    //           }
    //         ]
    //       }
    @Test
    public void testJSONSchema1() throws Exception {
        String json = "{\n  \"@context\": [\"http://w3c.github.io/wot/w3c-wot-td-context.jsonld\"],\n  \"@type\": \"Thing\",\n  \"name\": \"MyTemperatureThing\",\n  \"uris\": \"coap://www.mytemp.com:5683/\",\n  \"encodings\": [\"JSON\"],\n  \"properties\": [\n    {\n      \"name\": \"temperature\",\n      \"valueType\": {\n        \"type\": \"integer\",\n        \"maximum\": 13\n      },\n      \"writable\": false,\n      \"hrefs\": [\"temp\"]\n    }\n  ]\n}";

        Thing td = ThingDescriptionParser.fromBytes(json.getBytes());
        // TODO any further checks?
        assertTrue("No Property temperature", td.getProperty("temperature") != null);
        Property p = td.getProperty("temperature");
        assertTrue("No valueType", p.getValueType() != null);
        JsonNode valueType = p.getValueType();
        assertTrue(valueType.findValue("type").asText().equals("integer"));
        assertTrue(valueType.findValue("maximum").asInt() == 13);
    }

    @Test
    // CP: Example 2: Semantic Annotations
    public void testJSONSchema2() throws Exception {
        String json = "{\n\t\"@context\": [\n\t\t\"http://w3c.github.io/wot/w3c-wot-td-context.jsonld\", {\n\t\t\t\"sensor\": \"http://example.org/sensors#\"\n\t\t}\n\t],\n\t\"@type\": \"Thing\",\n\t\"name\": \"MyTemperatureThing\",\n\t\"uris\": [\"coap://www.mytemp.com:5683/\"],\n\t\"encodings\": [\"JSON\"],\n\t\"properties\": [{\n\t\t\"@type\": \"sensor:Temperature\",\n\n\t\t\"name\": \"temperature\",\n\t\t\"sensor:unit\": \"sensor:Celsius\",\n\n\t\t\"valueType\": {\n\t\t\t\"type\": \"number\"\n\t\t},\n\t\t\"writable\": false,\n\t\t\"hrefs\": [\"temp\"]\n\t}]\n}";

        // @SuppressWarnings("unused")
        Thing td = ThingDescriptionParser.fromBytes(json.getBytes());
        assertTrue("No Property temperature", td.getProperty("temperature") != null);
        Property p = td.getProperty("temperature");
        assertTrue("No valueType", p.getValueType() != null);
        JsonNode valueType = p.getValueType();
        assertTrue(valueType.findValue("type").asText().equals("number"));
    }

    @Test
    // CP: Example 3: More Capabilities
    public void testJSONSchema3() throws Exception {
        String json = "{\n  \"@context\": [\n    \"http://w3c.github.io/wot/w3c-wot-td-context.jsonld\",\n    { \"actuator\": \"http://example.org/actuator#\" }\n  ],\n  \"@type\": \"Thing\",\n  \"name\": \"MyLEDThing\",\n  \"uris\": [\n    \"coap://myled.example.com:5683/\",\n    \"http://mything.example.com:8080/myled/\"\n  ],\n  \"encodings\": [ \"JSON\",\"EXI\"],\n  \"security\": {\n    \"cat\": \"token:jwt\",\n    \"alg\": \"HS256\",\n    \"as\": \"https://authority-issuing.example.org\"\n  },\n  \"properties\": [\n    {\n      \"@type\": \"actuator:onOffStatus\",\n      \"name\": \"status\",\n      \"valueType\": { \"type\": \"boolean\" },\n      \"writable\": true,\n      \"hrefs\": [ \"pwr\", \"status\" ]\n    }\n  ],\n  \"actions\": [\n    {\n      \"@type\": \"actuator:fadeIn\",\n      \"name\": \"fadeIn\",\n      \"inputData\": {\n        \"valueType\": { \"type\": \"integer\" },\n        \"actuator:unit\": \"actuator:ms\"\n      },\n      \"hrefs\": [\"in\", \"led/in\"  ]\n    },\n    {\n      \"@type\": \"actuator:fadeOut\",\n      \"name\": \"fadeOut\",\n      \"inputData\": {\n        \"valueType\": { \"type\": \"integer\" },\n        \"actuator:unit\": \"actuator:ms\"\n      },\n      \"hrefs\": [\"out\", \"led/out\" ]\n    }\n  ],\n  \"events\": [\n    {\n      \"@type\": \"actuator:alert\",\n      \"name\": \"criticalCondition\",\n      \"valueType\": { \"type\": \"string\" },\n      \"hrefs\": [ \"ev\", \"alert\" ]\n    }\n  ]\n}";

        Thing td = ThingDescriptionParser.fromBytes(json.getBytes());
        // TODO any further checks?

        {
            assertTrue("No Property status", td.getProperty("status") != null);
            Property p = td.getProperty("status");
            assertTrue("No valueType", p.getValueType() != null);
            JsonNode valueType = p.getValueType();
            assertTrue(valueType.findValue("type").asText().equals("boolean"));
        }

        {
            assertTrue("No Action fadeIn", td.getAction("fadeIn") != null);
            Action a1 = td.getAction("fadeIn");
            assertTrue("No inputType", a1.getInputType() != null);
            JsonNode valueType = a1.getInputType();
            assertTrue(valueType.findValue("type").asText().equals("integer"));
        }
        {
            assertTrue("No Action fadeOut", td.getAction("fadeOut") != null);
            Action a2 = td.getAction("fadeOut");
            assertTrue("No inputType", a2.getInputType() != null);
            JsonNode valueType = a2.getInputType();
            assertTrue(valueType.findValue("type").asText().equals("integer"));
        }

        {
            assertTrue("No Event criticalCondition", td.getEvent("criticalCondition") != null);
            Event e = td.getEvent("criticalCondition");
            assertTrue("No valueType", e.getValueType() != null);
            JsonNode valueType = e.getValueType();
            assertTrue(valueType.findValue("type").asText().equals("string"));
        }

    }

    @Test
    // CP: Example 17: JSON Object
    public void testJSONSchema4() throws Exception {
        String json = "{\n\t\"@context\": [\"http://w3c.github.io/wot/w3c-wot-td-context.jsonld\"],\n\t\"@type\": \"Thing\",\n\t\"name\": \"MyTestThing\",\n\t\"uris\": \"coap://www.mytest.com:5683/\",\n\t\"encodings\": [\"JSON\"],\n\t\"properties\": [{\n\t\t\"name\": \"obj\",\n\t\t\"valueType\": {\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": {\n\t\t\t\t\"id\": {\n\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t},\n\t\t\t\t\"name\": {\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"required\": [\"id\"]\n\t\t},\n\t\t\"writable\": false,\n\t\t\"hrefs\": [\"obj\"]\n\t}]\n}";

        // @SuppressWarnings("unused")
        Thing td = ThingDescriptionParser.fromBytes(json.getBytes());
        // TODO any further checks?
        assertTrue("No Property obj", td.getProperty("obj") != null);
        Property p = td.getProperty("obj");
        assertTrue("No valueType", p.getValueType() != null);
        JsonNode valueType = p.getValueType();
        assertTrue(valueType.findValue("type").asText().equals("object"));
        assertTrue(valueType.findValue("properties") != null);
        assertTrue(valueType.findValue("required") != null);
    }

    @Test
    // CP: Example 20: JSON Array
    public void testJSONSchema5() throws Exception {
        String json = "{\n\t\"@context\": [\"http://w3c.github.io/wot/w3c-wot-td-context.jsonld\"],\n\t\"@type\": \"Thing\",\n\t\"name\": \"MyTestThing\",\n\t\"uris\": \"coap://www.mytest.com:5683/\",\n\t\"encodings\": [\"JSON\"],\n\t\"properties\": [{\n\t\t\"name\": \"arr\",\n\t\t\"valueType\": {\n\t\t\t\"type\": \"array\",\n\t\t\t\"items\": {\n\t\t\t\t\"type\": \"number\",\n\t\t\t\t\"minimum\": 0,\n\t\t\t\t\"maximum\": 255\n\t\t\t},\n\t\t\t\"minItems\": 3,\n\t\t\t\"maxItems\": 3\n\t\t},\n\t\t\"writable\": false,\n\t\t\"hrefs\": [\"arr\"]\n\t}]\n}";

        // @SuppressWarnings("unused")
        Thing td = ThingDescriptionParser.fromBytes(json.getBytes());
        // TODO any further checks?
        assertTrue("No Property arr", td.getProperty("arr") != null);
        Property p = td.getProperty("arr");
        assertTrue("No valueType", p.getValueType() != null);
        JsonNode valueType = p.getValueType();
        assertTrue(valueType.findValue("type").asText().equals("array"));
        assertTrue(valueType.findValue("items") != null);
        assertTrue(valueType.findValue("minItems").asInt() == 3);
        assertTrue(valueType.findValue("maxItems").asInt() == 3);
    }

}