net.jimj.automaton.commands.WeatherCommand.java Source code

Java tutorial

Introduction

Here is the source code for net.jimj.automaton.commands.WeatherCommand.java

Source

/*
 * Copyright (c) <2013> <Jim Johnson jimj@jimj.net>
 *
 * 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 net.jimj.automaton.commands;

import com.fasterxml.jackson.databind.JsonNode;
import net.jimj.automaton.events.BehaviorEvent;
import net.jimj.automaton.events.ReplyEvent;
import net.jimj.automaton.model.User;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;

public class WeatherCommand extends Command {
    private static final Logger LOGGER = LoggerFactory.getLogger(WeatherCommand.class);
    private static final double SECONDS_PER_HOUR = 3600d;
    private static final double METERS_PER_MILE = 1609.34d;

    private static final String[] RANDOM_LOCATIONS = { "hooker,ok", "crapstone", "timbuktu", "blowhard", "condom" };

    //Version 2.5
    //http://bugs.openweathermap.org/projects/api/wiki/Weather_Data
    private static final String WEATHER_API_URL = "http://api.openweathermap.org/data/2.5/weather";

    @Override
    public String getCommandName() {
        return "weather";
    }

    @Override
    public void execute(User user, String args) {
        String weatherLocation = args;
        if (StringUtils.isEmpty(weatherLocation)) {
            weatherLocation = user.getFirstPreference("city", "location");
            if (StringUtils.isEmpty(weatherLocation)) {
                addEvent(new ReplyEvent(user, "You don't have a preference set so I'll pick a location for you."));
                weatherLocation = RANDOM_LOCATIONS[RANDOM.nextInt(RANDOM_LOCATIONS.length)];
            }
        }

        HttpGet getWeatherMethod = null;
        try {
            URI getWeatherURI = new URIBuilder(WEATHER_API_URL).addParameter("q", weatherLocation).build();
            getWeatherMethod = new HttpGet(getWeatherURI);
            HttpResponse response = HTTP_CLIENT.execute(getWeatherMethod);
            if (response.getStatusLine().getStatusCode() != 200) {
                throw new IOException("Got status code " + response.getStatusLine().getStatusCode());
            }

            String body = EntityUtils.toString(response.getEntity());
            System.out.println(body);

            JsonNode parentNode = OBJECT_MAPPER.readTree(body);
            String locationName = parentNode.get("name").asText();

            //Toplevel node has temp, wind node, 'weather' node (conditions)
            JsonNode mainNode = parentNode.get("main");
            double tempK = mainNode.get("temp").asDouble();
            double tempC = tempK - 273.15d;
            double tempF = tempC * 1.8d + 32;

            StringBuilder weatherString = new StringBuilder(locationName).append(": ");
            weatherString.append(String.format("Temperature %.1f F (%.1f C)", tempF, tempC));

            JsonNode windNode = parentNode.get("wind");
            double windSpeedMPS = windNode.get("speed").asDouble();
            //mps * 60 seconds * 60 minutes / 1 mile in meters
            double windSpeedMPH = windSpeedMPS * SECONDS_PER_HOUR / METERS_PER_MILE;
            weatherString.append(" | ").append(String.format("Wind Speed %.2f mph", windSpeedMPH));

            JsonNode gustNode = windNode.get("gust");
            if (gustNode != null) {
                double windGustMPS = gustNode.asDouble();
                double windGustMPH = windGustMPS * SECONDS_PER_HOUR / METERS_PER_MILE;
                weatherString.append(" | ").append(String.format("Wind Gust %.2f mph", windGustMPH));
            }

            JsonNode weatherNode = parentNode.get("weather");
            if (weatherNode != null && weatherNode.size() > 0) {
                weatherString.append(" | Conditions ");
                for (int i = 0; i < weatherNode.size(); i++) {
                    if (i != 0) {
                        weatherString.append(", ");
                    }
                    weatherString.append(weatherNode.get(i).get("description").asText());
                }
            }

            addEvent(new ReplyEvent(user, weatherString.toString()));
        } catch (Exception e) {
            LOGGER.error("Error getting weather for " + weatherLocation, e);
            addEvent(new BehaviorEvent(user, BehaviorEvent.Behavior.SORRY));
        } finally {
            if (getWeatherMethod != null) {
                getWeatherMethod.releaseConnection();
            }
        }
    }

    @Override
    public void help(User user) {
        addEvent(new ReplyEvent(user,
                "weather [location] - gets the weather at the location specified,  based on your preference"));
        addEvent(new ReplyEvent(user,
                "If no location is provided, I will look for the first preference with a value "
                        + "in the set: {city, location} and use that value for the lookup.  It works best if you set the value to "
                        + "city name,state code. Zip codes work very poorly.  See the 'pref' command for more details on setting preferences."));
    }
}