eu.vital.orchestrator.rest.EvaluationRESTService.java Source code

Java tutorial

Introduction

Here is the source code for eu.vital.orchestrator.rest.EvaluationRESTService.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
 * contributors by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package eu.vital.orchestrator.rest;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import org.apache.commons.math3.stat.regression.SimpleRegression;

import java.util.Calendar;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/evaluation")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class EvaluationRESTService extends RESTService {

    @Inject
    ObjectMapper objectMapper;

    @POST
    @Path("/latest")
    public Response executeLatestScenario(JsonNode input) throws Exception {
        String dmsUrl = "https://local.vital-iot.eu:8443/vital-core-dms";

        // 1. Get List of sensors from DMS observing AvailableBikes
        Client dmsClient = ClientBuilder.newClient();
        WebTarget dmsTarget = dmsClient.target(dmsUrl).path("querySensor").queryParam("encodeKeys", "false");
        ObjectNode sensorQuery = objectMapper.createObjectNode();
        sensorQuery.put("http://purl\\u002eoclc\\u002eorg/NET/ssnx/ssn#observes.@type",
                "http://vital-iot.eu/ontology/ns/Speed");
        ArrayNode sensorList = dmsTarget.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(sensorQuery),
                ArrayNode.class);

        // 2. Find the nearest sensor
        double minDistance = Double.MAX_VALUE;
        JsonNode nearestSensor = null;
        for (int i = 0; i < sensorList.size(); i++) {
            JsonNode sensor = sensorList.get(i);

            // Calculate Distance:
            double tmp = distance(input.get("lat").asDouble(), input.get("lng").asDouble(),
                    sensor.get("hasLastKnownLocation").get("geo:lat").asDouble(),
                    sensor.get("hasLastKnownLocation").has("geo:long")
                            ? sensor.get("hasLastKnownLocation").get("geo:long").asDouble()
                            : sensor.get("hasLastKnownLocation").get("geo:lon").asDouble());
            if (tmp < minDistance) {
                minDistance = tmp;
                nearestSensor = sensor;
            }
        }

        // 3. Find the System of the Sensor
        dmsTarget = dmsClient.target(dmsUrl).path("querySystem").queryParam("encodeKeys", "false");
        ObjectNode systemQuery = objectMapper.createObjectNode();
        systemQuery.put("http://vital-iot\\u002eeu/ontology/ns/managesSensor.@id",
                nearestSensor.get("id").asText());
        ArrayNode systemList = dmsTarget.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(systemQuery),
                ArrayNode.class);
        JsonNode system = systemList.get(0);

        // 4. Find the Observation Service of the System
        dmsTarget = dmsClient.target(dmsUrl).path("queryService").queryParam("encodeKeys", "false");

        ObjectNode serviceAndQuery = objectMapper.createObjectNode();
        ArrayNode serviceAndParameters = objectMapper.createArrayNode();
        serviceAndQuery.put("$and", serviceAndParameters);

        ObjectNode serviceIdQuery = objectMapper.createObjectNode();
        ObjectNode serviceInQuery = objectMapper.createObjectNode();
        serviceInQuery.put("$in", system.get("services"));
        serviceIdQuery.put("@id", serviceInQuery);
        serviceAndParameters.add(serviceIdQuery);

        ObjectNode serviceTypeQuery = objectMapper.createObjectNode();
        serviceTypeQuery.put("@type", "http://vital-iot.eu/ontology/ns/ObservationService");
        serviceAndParameters.add(serviceTypeQuery);

        ArrayNode serviceList = dmsTarget.request(MediaType.APPLICATION_JSON_TYPE)
                .post(Entity.json(serviceAndQuery), ArrayNode.class);
        JsonNode observationService = serviceList.get(0);

        // 5. Call GetObservation operation of the service
        String operationUrl = observationService.get("operations").get("hrest:hasAddress").asText();
        Client systemClient = ClientBuilder.newClient();
        WebTarget systemTarget = systemClient.target(operationUrl);
        ObjectNode operationInput = objectMapper.createObjectNode();
        ArrayNode sensorsArray = objectMapper.createArrayNode();
        sensorsArray.add(nearestSensor.get("id").asText());
        operationInput.put("sensor", sensorsArray);
        operationInput.put("property", "http://vital-iot.eu/ontology/ns/Speed");

        ArrayNode observationList = systemTarget.request(MediaType.APPLICATION_JSON_TYPE)
                .post(Entity.json(operationInput), ArrayNode.class);
        JsonNode latestObservation = observationList.get(0);

        // 6. Parse Result and return response
        ObjectNode result = objectMapper.createObjectNode();
        result.put("measurementValue",
                latestObservation.get("ssn:observationResult").get("ssn:hasValue").get("value"));
        result.put("measurementDate", latestObservation.get("ssn:observationResultTime").get("time:inXSDDateTime"));

        return Response.ok(result).build();
    }

    @POST
    @Path("/prediction")
    public Response executePredictionScenario(JsonNode input) throws Exception {
        String dmsUrl = "https://local.vital-iot.eu:8443/vital-core-dms";

        // 1. Get List of sensors from DMS observing AvailableBikes
        Client dmsClient = ClientBuilder.newClient();
        WebTarget dmsTarget = dmsClient.target(dmsUrl).path("querySensor").queryParam("encodeKeys", "false");
        ObjectNode sensorQuery = objectMapper.createObjectNode();
        sensorQuery.put("http://purl\\u002eoclc\\u002eorg/NET/ssnx/ssn#observes.@type",
                "http://vital-iot.eu/ontology/ns/Speed");
        ArrayNode sensorList = dmsTarget.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(sensorQuery),
                ArrayNode.class);

        // 2. Find the nearest sensor
        double minDistance = Double.MAX_VALUE;
        JsonNode nearestSensor = null;
        for (int i = 0; i < sensorList.size(); i++) {
            JsonNode sensor = sensorList.get(i);

            // Calculate Distance:
            double tmp = distance(input.get("lat").asDouble(), input.get("lng").asDouble(),
                    sensor.get("hasLastKnownLocation").get("geo:lat").asDouble(),
                    sensor.get("hasLastKnownLocation").has("geo:long")
                            ? sensor.get("hasLastKnownLocation").get("geo:long").asDouble()
                            : sensor.get("hasLastKnownLocation").get("geo:lon").asDouble());
            if (tmp < minDistance) {
                minDistance = tmp;
                nearestSensor = sensor;
            }
        }

        // 3. Get all observations of this sensor from DMS archive
        dmsTarget = dmsClient.target(dmsUrl).path("queryObservation").queryParam("encodeKeys", "false");
        ObjectNode observationQuery = objectMapper.createObjectNode();
        observationQuery.put("http://purl\\u002eoclc\\u002eorg/NET/ssnx/ssn#observedBy.@value",
                nearestSensor.get("id").asText());
        observationQuery.put("http://purl\\u002eoclc\\u002eorg/NET/ssnx/ssn#observationProperty.@type",
                "http://vital-iot.eu/ontology/ns/Speed");

        ArrayNode observationList = dmsTarget.request(MediaType.APPLICATION_JSON_TYPE)
                .post(Entity.json(observationQuery), ArrayNode.class);

        // 4. Run the prediction algorithm
        SimpleRegression regression = new SimpleRegression();
        for (int i = 0; i < observationList.size(); i++) {
            JsonNode observation = observationList.get(i);
            double value = observation.get("ssn:observationResult").get("ssn:hasValue").get("value").asDouble();
            String dateStr = observation.get("ssn:observationResultTime").get("time:inXSDDateTime").asText();
            Calendar date = javax.xml.bind.DatatypeConverter.parseDateTime(dateStr);
            regression.addData(date.getTimeInMillis(), value);
        }
        double futureMillis = javax.xml.bind.DatatypeConverter.parseDateTime(input.get("atDate").asText())
                .getTimeInMillis();
        double prediction = regression.predict(futureMillis);

        // 5. Return the result:
        ObjectNode result = objectMapper.createObjectNode();
        result.put("predictionValue", prediction);
        result.put("predictionDate", input.get("atDate").asText());

        return Response.ok(result).build();
    }

    private double distance(double lat1, double lon1, double lat2, double lon2) {
        int R = 6371; // Radius of the earth in km
        double dLat = deg2rad(lat2 - lat1); // deg2rad below
        double dLon = deg2rad(lon2 - lon1);
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
                + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        double d = R * c; // Distance in km
        return d;
    }

    private double deg2rad(double deg) {
        return deg * (Math.PI / 180);
    }
}