net.solarnetwork.node.weather.nz.metservice.MetserviceWeatherDatumDataSource.java Source code

Java tutorial

Introduction

Here is the source code for net.solarnetwork.node.weather.nz.metservice.MetserviceWeatherDatumDataSource.java

Source

/* ==================================================================
 * MetserviceWeatherDatumDataSource.java - Oct 18, 2011 4:58:27 PM
 * 
 * Copyright 2007-2011 SolarNetwork.net Dev Team
 * 
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of 
 * the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
 * 02111-1307 USA
 * ==================================================================
 */

package net.solarnetwork.node.weather.nz.metservice;

import java.io.IOException;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import net.solarnetwork.node.DatumDataSource;
import net.solarnetwork.node.domain.GeneralAtmosphericDatum;
import net.solarnetwork.node.domain.GeneralLocationDatum;
import net.solarnetwork.node.settings.SettingSpecifier;
import net.solarnetwork.node.settings.SettingSpecifierProvider;
import net.solarnetwork.node.settings.support.BasicTextFieldSettingSpecifier;
import org.springframework.context.MessageSource;
import com.fasterxml.jackson.databind.JsonNode;

/**
 * MetService implementation of a {@link GeneralAtmosphericDatum}
 * {@link DatumDataSource}.
 * 
 * <p>
 * This implementation reads public data available on the MetService website to
 * collect weather information.
 * </p>
 * 
 * <p>
 * The configurable properties of this class are:
 * </p>
 * 
 * <dl class="class-properties">
 * <dt>oneMinObs</dt>
 * <dd>The name of the "oneMinObs" file to parse. This file is expected to
 * contain a single JSON object declaration with the temperature, timestamp,
 * etc. attributes. Defaults to {@link #DEFAULT_ONE_MIN_OBS_SET}.</dd>
 * 
 * <dt>localObs</dt>
 * <dd>The name of the "localObs" file to parse. This file is expected to
 * contain a single JSON object declaration with the humidity, pressure, etc.
 * attributes. Defaults to {@link #DEFAULT_LOCAL_OBS_SET}.</dd>
 * 
 * <dt>localForecast</dt>
 * <dd>The name of the "localForecast" file to parse. This file is expected to
 * contain a single JSON object declaration with an array of day JSON objects,
 * the first day from which the sky conditions are extracted. The real-time data
 * doesn't provide sky conditions, so we just use the presumably static value
 * for the day. Defaults to {@link #DEFAULT_LOCAL_FORECAST_SET}.</dd>
 * 
 * <dt>localForecastDayPattern</dt>
 * <dd>A regular expression used to extract a single day JSON object from the
 * {@code localForecast} file. This class doesn't perform actual JSON parsing,
 * and can only work with simple JSON objects. This regular expression must
 * include a single matching group that returns the appropriate day object from
 * the overall {@code localForecast} data. Defaults to
 * {@link #DEFAULT_LOCAL_FORECAST_DAY_PATTERN}.</dd>
 * 
 * <dt>timestampDateFormat</dt>
 * <dd>A {@link SimpleDateFormat} date and time pattern for parsing the
 * information date from the {@code oneMinObs} file. Defaults to
 * {@link #DEFAULT_TIMESTAMP_DATE_FORMAT}.</dd>
 * </dl>
 * 
 * @author matt
 * @version 1.2
 */
public class MetserviceWeatherDatumDataSource extends MetserviceSupport<GeneralAtmosphericDatum>
        implements DatumDataSource<GeneralLocationDatum>, SettingSpecifierProvider {

    /** The default value for the {@code oneMinObs} property. */
    public static final String DEFAULT_LOCAL_OBS_SET = "localObs_wellington-city";

    /** The default value for the {@code localForecast} property. */
    public static final String DEFAULT_LOCAL_FORECAST_SET = "localForecastwellington-city";

    /** The default value for the {@code timestampDateFormat} property. */
    public static final String DEFAULT_TIMESTAMP_DATE_FORMAT = "h:mma EEEE d MMM yyyy";

    private MessageSource messageSource;
    private String timestampDateFormat;
    private String localObs;
    private String localObsContainerKey = "threeHour";
    private String localForecast;

    public MetserviceWeatherDatumDataSource() {
        super();
        timestampDateFormat = DEFAULT_TIMESTAMP_DATE_FORMAT;
        localObs = DEFAULT_LOCAL_OBS_SET;
        localForecast = DEFAULT_LOCAL_FORECAST_SET;
    }

    @Override
    public Class<? extends GeneralLocationDatum> getDatumType() {
        return GeneralAtmosphericDatum.class;
    }

    @Override
    public GeneralLocationDatum readCurrentDatum() {
        GeneralAtmosphericDatum result = null;

        String url = getBaseUrl() + '/' + localObs;
        final SimpleDateFormat tsFormat = new SimpleDateFormat(getTimestampDateFormat());
        try {
            URLConnection conn = getURLConnection(url, HTTP_METHOD_GET);
            JsonNode root = getObjectMapper().readTree(getInputStreamFromURLConnection(conn));
            JsonNode data = root.get(localObsContainerKey);
            if (data == null) {
                log.warn("Local observation container key '{}' not found in {}", localObsContainerKey, url);
                return null;
            }
            Date infoDate = parseDateAttribute("dateTime", data, tsFormat);
            Float temp = parseFloatAttribute("temp", data);

            if (infoDate == null || temp == null) {
                log.debug("Date and/or temperature missing from {}", url);
                return null;
            }
            result = new GeneralAtmosphericDatum();
            result.setCreated(infoDate);
            result.setTemperature(temp);

            result.setHumidity(parseIntegerAttribute("humidity", data));

            Double millibar = parseDoubleAttribute("pressure", data);
            if (millibar != null) {
                int pascals = (int) (millibar.doubleValue() * 100);
                result.setAtmosphericPressure(pascals);
            }

            // get local forecast
            try {
                url = getBaseUrl() + '/' + localForecast;
                conn = getURLConnection(url, HTTP_METHOD_GET);
                root = getObjectMapper().readTree(getInputStreamFromURLConnection(conn));

                JsonNode forecastWord = root.findValue("forecastWord");
                if (forecastWord != null) {
                    result.setSkyConditions(forecastWord.asText());
                }
            } catch (IOException e) {
                log.warn("Error reading MetService URL [{}]: {}", url, e.getMessage());
            }

            log.debug("Obtained WeatherDatum: {}", result);

        } catch (IOException e) {
            log.warn("Error reading MetService URL [{}]: {}", url, e.getMessage());
        }
        return result;
    }

    @Override
    public String getSettingUID() {
        return "net.solarnetwork.node.weather.nz.metservice.weather";
    }

    @Override
    public String getDisplayName() {
        return "New Zealand Metservice weather information";
    }

    @Override
    public MessageSource getMessageSource() {
        return messageSource;
    }

    @Override
    public List<SettingSpecifier> getSettingSpecifiers() {
        MetserviceWeatherDatumDataSource defaults = new MetserviceWeatherDatumDataSource();
        return Arrays.asList((SettingSpecifier) new BasicTextFieldSettingSpecifier("uid", null),
                (SettingSpecifier) new BasicTextFieldSettingSpecifier("groupUID", null),
                (SettingSpecifier) new BasicTextFieldSettingSpecifier("baseUrl", defaults.getBaseUrl()),
                (SettingSpecifier) new BasicTextFieldSettingSpecifier("localForecast", defaults.getLocalForecast()),
                (SettingSpecifier) new BasicTextFieldSettingSpecifier("localObs", defaults.getLocalObs()),
                (SettingSpecifier) new BasicTextFieldSettingSpecifier("localObsContainerKey",
                        defaults.getLocalObsContainerKey()),
                (SettingSpecifier) new BasicTextFieldSettingSpecifier("timestampDateFormat",
                        defaults.getTimestampDateFormat()));
    }

    public String getTimestampDateFormat() {
        return timestampDateFormat;
    }

    public void setTimestampDateFormat(String timestampDateFormat) {
        this.timestampDateFormat = timestampDateFormat;
    }

    public String getLocalObs() {
        return localObs;
    }

    public void setLocalObs(String localObs) {
        this.localObs = localObs;
    }

    public String getLocalForecast() {
        return localForecast;
    }

    public void setLocalForecast(String localForecast) {
        this.localForecast = localForecast;
    }

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public String getLocalObsContainerKey() {
        return localObsContainerKey;
    }

    public void setLocalObsContainerKey(String localObsContainerKey) {
        this.localObsContainerKey = localObsContainerKey;
    }

}