com.github.ithildir.airbot.service.impl.WaqiMeasurementServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.github.ithildir.airbot.service.impl.WaqiMeasurementServiceImpl.java

Source

/**
 * Copyright (c) 2017 Andrea Di Giorgi
 *
 * 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 com.github.ithildir.airbot.service.impl;

import com.github.ithildir.airbot.model.Measurement;
import com.github.ithildir.airbot.service.MeasurementService;

import io.netty.handler.codec.http.HttpResponseStatus;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.serviceproxy.ServiceException;

import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author Andrea Di Giorgi
 */
public class WaqiMeasurementServiceImpl implements MeasurementService {

    public WaqiMeasurementServiceImpl(Vertx vertx, String key) {
        _key = Objects.requireNonNull(key);

        WebClientOptions webClientOptions = new WebClientOptions();

        webClientOptions.setDefaultHost("api.waqi.info");
        webClientOptions.setDefaultPort(443);
        webClientOptions.setSsl(true);

        _webClient = WebClient.create(vertx, webClientOptions);
    }

    @Override
    public void getMeasurement(double latitude, double longitude, Handler<AsyncResult<Measurement>> handler) {

        HttpRequest<Buffer> httpRequest = _webClient.get("/feed/geo:" + latitude + ";" + longitude + "/");

        httpRequest.setQueryParam("token", _key);

        httpRequest.send(asyncResult -> {
            HttpResponse<Buffer> httpResponse = _handleHttpResponse(asyncResult, handler);

            if (httpResponse == null) {
                return;
            }

            Measurement measurement = _getMeasurement(httpResponse.bodyAsJsonObject());

            handler.handle(Future.succeededFuture(measurement));
        });
    }

    @Override
    public void getName(Handler<AsyncResult<String>> handler) {
        handler.handle(Future.succeededFuture("aqicn"));
    }

    @Override
    public void init(Handler<AsyncResult<Void>> handler) {
        handler.handle(Future.succeededFuture());
    }

    private Measurement _getMeasurement(JsonObject jsonObject) {
        String status = jsonObject.getString("status");

        if (!"ok".equals(status)) {
            _logger.warn("Unable to use response {0}", jsonObject);

            return null;
        }

        JsonObject dataJsonObject = jsonObject.getJsonObject("data");

        JsonObject cityJsonObject = dataJsonObject.getJsonObject("city");

        String city = cityJsonObject.getString("name");

        JsonObject timeJsonObject = dataJsonObject.getJsonObject("time");

        String dateTime = timeJsonObject.getString("s");
        String dateTimeOffset = timeJsonObject.getString("tz");

        String date = dateTime.substring(0, 10);
        String time = dateTime.substring(11);

        TemporalAccessor temporalAccessor = DateTimeFormatter.ISO_OFFSET_DATE_TIME
                .parse(date + "T" + time + dateTimeOffset);

        Instant instant = Instant.from(temporalAccessor);

        int aqi = dataJsonObject.getInteger("aqi");
        String mainPollutant = dataJsonObject.getString("dominentpol");

        Map<String, Double> values = new HashMap<>();

        JsonObject valuesJsonObject = dataJsonObject.getJsonObject("iaqi");

        for (String pollutant : valuesJsonObject.fieldNames()) {
            JsonObject pollutantJsonObject = valuesJsonObject.getJsonObject(pollutant);

            double value = pollutantJsonObject.getDouble("v");

            values.put(pollutant, value);
        }

        return new Measurement(city, instant.toEpochMilli(), aqi, mainPollutant, values, null);
    }

    private <R, T> HttpResponse<T> _handleHttpResponse(AsyncResult<HttpResponse<T>> asyncResult,
            Handler<AsyncResult<R>> handler) {

        if (asyncResult.failed()) {
            handler.handle(Future.failedFuture(asyncResult.cause()));

            return null;
        }

        HttpResponse<T> httpResponse = asyncResult.result();

        int statusCode = httpResponse.statusCode();

        if (statusCode != HttpResponseStatus.OK.code()) {
            JsonObject jsonObject = httpResponse.bodyAsJsonObject();

            handler.handle(ServiceException.fail(statusCode, jsonObject.getString("message"), jsonObject));

            return null;
        }

        return httpResponse;
    }

    private static final Logger _logger = LoggerFactory.getLogger(WaqiMeasurementServiceImpl.class);

    private final String _key;
    private final WebClient _webClient;

}