com.brewtab.ircbot.applets.WundergroundApplet.java Source code

Java tutorial

Introduction

Here is the source code for com.brewtab.ircbot.applets.WundergroundApplet.java

Source

/*
 * Copyright (c) 2013 Christopher Thunes
 *
 * 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.brewtab.ircbot.applets;

import java.io.IOException;
import java.net.MalformedURLException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.brewtab.irc.User;
import com.brewtab.irc.client.Channel;
import com.brewtab.ircbot.util.SQLProperties;
import com.brewtab.ircbot.util.URLBuilder;

public class WundergroundApplet implements BotApplet {
    private static final Logger log = LoggerFactory.getLogger(WundergroundApplet.class);

    private static final String AUTOCOMPLETE_URL = "http://autocomplete.wunderground.com/aq";
    private static final String API_URL_TEMPLATE = "http://api.wunderground.com/api/%s/%s%s.xml";

    private SQLProperties properties;
    private DocumentBuilder documentBuilder;
    private XPath xpath;
    private String apikey;

    private Options options;
    private PosixParser parser;

    public WundergroundApplet(SQLProperties properties, String apikey) {
        this.properties = properties;
        this.apikey = apikey;

        try {
            documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }

        xpath = XPathFactory.newInstance().newXPath();

        options = new Options();
        options.addOption("c", "metric", false, "use metric units");
        options.addOption("f", "imperial", false, "use imperial units (default)");
        options.addOption("n", "no-save", false, "do not save the query as default");
        parser = new PosixParser();
    }

    private URLBuilder makeUrl(String base) {
        try {
            return new URLBuilder(base);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    private String buildKey(Channel channel, User from) {
        return "wunderground:" + channel.getName() + ":" + from.getNick() + ":";
    }

    public String findLocation(Channel channel, User from, String query, boolean saveSettings) throws Exception {
        if (StringUtils.isBlank(query)) {
            String location = properties.<String>get(buildKey(channel, from) + "location");
            return location;
        }

        URLBuilder url = makeUrl(AUTOCOMPLETE_URL);
        url.setParameter("format", "xml");
        url.setParameter("query", query);

        Document doc = documentBuilder.parse(url.toString());
        String location = xpath.evaluate("/RESULTS/l[1]", doc);

        if (StringUtils.isNotBlank(location) && saveSettings) {
            properties.set(buildKey(channel, from) + "location", location);
        }

        return location;
    }

    private Document request(String feature, String location) throws SAXException, IOException {
        String url = String.format(API_URL_TEMPLATE, apikey, feature, location);
        return documentBuilder.parse(url);
    }

    private String formatTemp(String s) {
        int value = (int) Float.parseFloat(s);
        return Integer.toString(value);
    }

    @Override
    public void run(Channel channel, User from, String command, String[] args, String unparsed) {
        try {
            CommandLine commandLine = parser.parse(options, args, true);
            boolean saveSettings = !commandLine.hasOption("no-save");
            boolean useMetric = commandLine.hasOption("metric");
            boolean useImperial = commandLine.hasOption("imperial");
            String query = StringUtils.join(commandLine.getArgs(), " ");

            String locationQuery = findLocation(channel, from, query, saveSettings);

            if (StringUtils.isBlank(locationQuery)) {
                channel.write("No location found");
                return;
            }

            // Get current conditions
            Document result = request("conditions", locationQuery);
            String location = xpath.evaluate("/response/current_observation/display_location/full", result);
            String temp_f = formatTemp(xpath.evaluate("/response/current_observation/temp_f", result));
            String temp_c = formatTemp(xpath.evaluate("/response/current_observation/temp_c", result));
            String condition = xpath.evaluate("/response/current_observation/weather", result);

            // Get todays forecast
            result = request("forecast", locationQuery);
            String forecastBase = "/response/forecast/simpleforecast/forecastdays/forecastday[1]/";
            String high_f = formatTemp(xpath.evaluate(forecastBase + "high/fahrenheit", result));
            String high_c = formatTemp(xpath.evaluate(forecastBase + "high/celsius", result));
            String low_f = formatTemp(xpath.evaluate(forecastBase + "low/fahrenheit", result));
            String low_c = formatTemp(xpath.evaluate(forecastBase + "low/celsius", result));

            if (!useMetric && !useImperial) {
                useMetric = properties.<Boolean>get(buildKey(channel, from) + "metric", false);
            } else if (saveSettings) {
                properties.set(buildKey(channel, from) + "metric", useMetric);
            }

            if (useMetric) {
                channel.write(String.format("%s: %s, %sC, high of %sC, low of %sC", location, condition, temp_c,
                        high_c, low_c));
            } else {
                channel.write(String.format("%s: %s, %sF, high of %sF, low of %sF", location, condition, temp_f,
                        high_f, low_f));
            }
        } catch (Exception e) {
            log.error("Caught exception running Wunderground applet", e);
        }
    }
}