/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.weather.internal.common; import java.util.Collection; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.openhab.binding.weather.internal.model.ProviderName; import org.openhab.binding.weather.internal.utils.PropertyResolver; import org.osgi.service.cm.ConfigurationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Parses the config in openhab.cfg. * * <pre> * ############################## Weather Binding ############################## * # * # The apikey for the different weather providers, at least one must be specified * # Note: Hamweather requires two apikeys: client_id=apikey, client_secret=apikey2 * #weather:apikey.ForecastIo= * #weather:apikey.OpenWeatherMap= * #weather:apikey.WorldWeatherOnline= * #weather:apikey.Wunderground= * #weather:apikey.Hamweather= * #weather:apikey2.Hamweather= * * # location configuration, you can specify multiple locations * #weather:location.<locationId1>.latitude= (not required for Yahoo provider) * #weather:location.<locationId1>.longitude= (not required for Yahoo provider) * #weather:location.<locationId1>.provider= * #weather:location.<locationId1>.woeid= (required for Yahoo provider) * #weather:location.<locationId1>.language= * #weather:location.<locationId1>.updateInterval= (optional, defaults to 240) * #weather:location.<locationId1>.units= (optional; defaults to "si") * * #weather:location.<locationId2>.latitude= (not required for Yahoo provider) * #weather:location.<locationId2>.longitude= (not required for Yahoo provider) * #weather:location.<locationId2>.provider= * #weather:location.<locationId2>.woeid= (required for Yahoo provider) * #weather:location.<locationId2>.language= * #weather:location.<locationId2>.updateInterval= (optional, defaults to 240) * #weather:location.<locationId2>.units= (optional; defaults to "si") * </pre> * * @author Gerhard Riegler * @since 1.6.0 */ public class WeatherConfig { private static final Logger logger = LoggerFactory.getLogger(WeatherConfig.class); private Map<ProviderName, ProviderConfig> providerConfigs = new HashMap<ProviderName, ProviderConfig>(); private Map<String, LocationConfig> locationConfigs = new HashMap<String, LocationConfig>(); private boolean valid; private boolean parseCompleted; /** * Parses and validates the properties in openhab.cfg. */ public void parse(Dictionary<String, ?> properties) throws ConfigurationException { parseCompleted = false; valid = false; if (properties == null) { parseCompleted = true; logger.warn("No configuration found for the weather binding. Check openhab.cfg."); throw new ConfigurationException("weather", "No configuration found for the weather binding. Check openhab.cfg."); } Enumeration<String> keys = properties.keys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); String value = StringUtils.trimToNull((String) properties.get(key)); if (StringUtils.startsWithIgnoreCase(key, "apikey")) { parseApiKey(key, value); } else if (StringUtils.startsWithIgnoreCase(key, "location")) { parseLocation(key, value); } } // check all LocationConfigs for (LocationConfig lc : locationConfigs.values()) { if (!lc.isValid()) { parseCompleted = true; logger.warn("Incomplete location config for locationId '{}'. Check openhab.cfg.", lc.getLocationId()); throw new ConfigurationException("weather", "Incomplete location config for locationId '" + lc.getLocationId() + "'. Check openhab.cfg."); } if (lc.getProviderName() != ProviderName.YAHOO && !providerConfigs.containsKey(lc.getProviderName())) { parseCompleted = true; logger.warn("No apikey found for provider '{}'. Check openhab.cfg.", lc.getProviderName()); throw new ConfigurationException("weather", "No apikey found for provider '" + lc.getProviderName() + "'. Check openhab.cfg."); } } // check all ProviderConfigs for (ProviderConfig pc : providerConfigs.values()) { if (!pc.isValid()) { parseCompleted = true; logger.warn("Invalid apikey config for provider '{}'. Check openhab.cfg.", pc.getProviderName()); throw new ConfigurationException("weather", "Invalid apikey config for provider '" + pc.getProviderName() + "'. Check openhab.cfg."); } } valid = locationConfigs.size() > 0; parseCompleted = true; logger.debug("Parsing of weather configuration settings completed."); } /** * Parses the properties for a location config. */ private void parseLocation(String key, String value) throws ConfigurationException { if (value == null) { logger.warn("Weather location setting '{}' has no value. Check openhab.cfg.", key); return; } String locationId = StringUtils.substringBetween(key, "."); if (StringUtils.isBlank(locationId)) { logger.warn("Weather location setting '{}' is missing its location. Check openhab.cfg.", key); } LocationConfig lc = locationConfigs.get(locationId); if (lc == null) { lc = new LocationConfig(); lc.setLocationId(locationId); locationConfigs.put(locationId, lc); } String keyId = PropertyResolver.last(key); if (StringUtils.equalsIgnoreCase(keyId, "provider")) { lc.setProviderName(getProviderName(value)); } else if (StringUtils.equalsIgnoreCase(keyId, "updateInterval")) { lc.setUpdateInterval(parseNumber(key, value).intValue()); } else if (StringUtils.equalsIgnoreCase(keyId, "latitude")) { lc.setLatitude(parseNumber(key, value)); } else if (StringUtils.equalsIgnoreCase(keyId, "longitude")) { lc.setLongitude(parseNumber(key, value)); } else if (StringUtils.equalsIgnoreCase(keyId, "woeid")) { lc.setWoeid(value); } else if (StringUtils.equalsIgnoreCase(keyId, "language")) { lc.setLanguage(value); } else if (StringUtils.equalsIgnoreCase(keyId, "name")) { lc.setName(value); } else if (StringUtils.equalsIgnoreCase(keyId, "units")) { lc.setMeasurementUnits(value.toLowerCase()); } else { logger.debug("Unknown weather configuration setting '{}'. Check openhab.cfg.", key); } } /** * Parses the properties for a provider config. */ private void parseApiKey(String key, String value) throws ConfigurationException { if (value == null) { logger.warn("Weather apikey setting '{}' has no value. Check openhab.cfg.", key); return; } String provider = PropertyResolver.last(key); ProviderName providerName = getProviderName(provider); ProviderConfig pConfig = providerConfigs.get(providerName); if (pConfig == null) { pConfig = new ProviderConfig(); pConfig.setProviderName(providerName); providerConfigs.put(providerName, pConfig); } String keyId = PropertyResolver.first(key); if (StringUtils.equalsIgnoreCase(keyId, "apikey")) { pConfig.setApiKey(value); } else if (StringUtils.equalsIgnoreCase(keyId, "apikey2")) { pConfig.setApiKey2(value); } else { logger.warn("Unknown configuration key '{}'. Check openhab.cfg.", key); } } /** * Parse a double value from a string. */ private Double parseNumber(String key, String value) throws ConfigurationException { try { return Double.parseDouble(value); } catch (Exception ex) { logger.warn("Parameter '{}' empty or in wrong format ('{}'). Check openhab.cfg.", key, value); throw new ConfigurationException("weather", "Parameter '" + key + "' empty or in wrong format ('" + value + "'). Check openhab.cfg."); } } /** * Parse a ProviderName from a string. */ private ProviderName getProviderName(String name) throws ConfigurationException { ProviderName providerName = ProviderName.parse(name); if (providerName == null) { logger.warn("Provider with name '{}' not found. Check openhab.cfg.", name); throw new ConfigurationException("weather", "Provider with name '" + name + "' not found. Check openhab.cfg."); } return providerName; } /** * Returns the LocationConfig for the specified locationId. */ public LocationConfig getLocationConfig(String locationId) { return locationConfigs.get(locationId); } /** * Returns all LocationConfigurations. */ public Collection<LocationConfig> getAllLocationConfigs() { return locationConfigs.values(); } /** * Returns the ProviderConfig for the specified providerName. */ public ProviderConfig getProviderConfig(ProviderName providerName) { return providerConfigs.get(providerName); } /** * Returns true, if all configurations are valid. */ public boolean isValid() { return valid; } /** * Returns true if the parse routine is not currently in progress. */ public boolean finishedParsing() { return parseCompleted; } /** * Dumps the config to the log. */ public void dump() { for (ProviderName providerName : providerConfigs.keySet()) { logger.info("{}", providerConfigs.get(providerName)); } for (String locationId : locationConfigs.keySet()) { logger.info("{}", locationConfigs.get(locationId)); } } }