/** * 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.gfx; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.openhab.binding.weather.internal.common.LocationConfig; import org.openhab.binding.weather.internal.common.Unit; import org.openhab.binding.weather.internal.common.WeatherContext; import org.openhab.binding.weather.internal.model.Weather; import org.openhab.binding.weather.internal.utils.PropertyUtils; import org.openhab.binding.weather.internal.utils.UnitUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Replaces tokens in weather layout files. * * @author Gerhard Riegler * @since 1.6.0 */ public class WeatherTokenResolver implements TokenResolver { private static final Logger logger = LoggerFactory.getLogger(WeatherTokenResolver.class); private static final String PREFIX_TOKEN_WEATHER = "weather"; private static final String PREFIX_TOKEN_FORECAST = "forecast"; private static final String PREFIX_TOKEN_CONFIG = "config"; private static final String PREFIX_TOKEN_PARAM = "param"; private Weather weather; private String locationId; private Map<String, String> params = new HashMap<String, String>(); public WeatherTokenResolver(Weather weather, String locationId) { this.weather = weather; this.locationId = locationId; } /** * Adds a HTTP request parameter. */ public void addParameter(String name, String value) { params.put(name, value); } /** * {@inheritDoc} */ @Override public String resolveToken(String tokenName) { try { Token token = parseTokenName(tokenName); if (PREFIX_TOKEN_WEATHER.equals(token.prefix)) { return replaceWeather(token, weather); } else if (PREFIX_TOKEN_FORECAST.equals(token.prefix)) { return replaceForecast(token); } else if (PREFIX_TOKEN_CONFIG.equals(token.prefix)) { return replaceConfig(token); } else if (PREFIX_TOKEN_PARAM.equals(token.prefix)) { return replaceParameter(token); } else { throw new RuntimeException("Invalid weather token: " + tokenName); } } catch (Exception ex) { logger.warn(ex.getMessage()); return null; } } /** * Replaces the token with a property of the weather object. */ private String replaceWeather(Token token, Weather instance) throws Exception { if (!PropertyUtils.hasProperty(instance, token.name)) { throw new RuntimeException("Invalid weather token: " + token.full); } Object propertyValue = PropertyUtils.getPropertyValue(instance, token.name); if (token.unit != null && propertyValue instanceof Double) { propertyValue = UnitUtils.convertUnit((Double) propertyValue, token.unit, token.name); } if (token.formatter != null) { return String.format(token.formatter, propertyValue); } return ObjectUtils.toString(propertyValue); } /** * Replaces the token with a property of a forecast object. */ private String replaceForecast(Token token) throws Exception { int day = NumberUtils.toInt(token.qualifier); if (day < weather.getForecast().size()) { Weather forecast = weather.getForecast().get(day); return replaceWeather(token, forecast); } else { throw new RuntimeException("Weather forecast day " + day + " not available, only " + Math.max(weather.getForecast().size() - 1, 0) + " available"); } } /** * Replaces the token with properties of the weather LocationConfig object. */ private String replaceConfig(Token token) { LocationConfig locationConfig = WeatherContext.getInstance().getConfig().getLocationConfig(locationId); if (locationConfig == null) { throw new RuntimeException("Weather locationId '" + locationId + "' does not exist"); } if ("latitude".equals(token.name)) { return locationConfig.getLatitude().toString(); } else if ("longitude".equals(token.name)) { return locationConfig.getLongitude().toString(); } else if ("name".equals(token.name)) { return locationConfig.getName(); } else if ("language".equals(token.name)) { return locationConfig.getLanguage(); } else if ("updateInterval".equals(token.name)) { return ObjectUtils.toString(locationConfig.getUpdateInterval()); } else if ("locationId".equals(token.name)) { return locationConfig.getLocationId(); } else if ("providerName".equals(token.name)) { return ObjectUtils.toString(locationConfig.getProviderName()); } else { throw new RuntimeException("Invalid weather token: " + token.full); } } /** * Replaces the token with a HTTP request parameter. */ private String replaceParameter(Token token) { return params.get(token.name); } /** * Parses the token which should be replaced. */ private Token parseTokenName(String tokenName) { Token token = new Token(); token.full = tokenName; token.prefix = StringUtils.substringBefore(token.full, ":"); if (StringUtils.contains(token.prefix, "(")) { token.qualifier = StringUtils.substringBetween(token.prefix, "(", ")"); token.prefix = StringUtils.substringBefore(token.prefix, "("); } token.name = StringUtils.substringAfter(token.full, ":"); if (StringUtils.contains(token.name, "(")) { token.formatter = StringUtils.substringBetween(token.name, "(", ")"); token.name = StringUtils.substringBefore(token.name, "("); } if (StringUtils.contains(token.full, "[")) { token.unit = Unit.parse(StringUtils.substringBetween(token.full, "[", "]")); token.name = StringUtils.substringBefore(token.name, "["); } if (!token.isValid()) { throw new RuntimeException("Invalid weather token: " + token.full); } return token; } /** * Helper class with the parts of a token. * * @author Gerhard Riegler * @since 1.6.0 */ private class Token { public String full; public String prefix; public String qualifier; public String name; public String formatter; public Unit unit; /** * Returns true, if a token contains a prefix and a name. */ public boolean isValid() { return StringUtils.isNotBlank(prefix) && StringUtils.isNotBlank(name); } } }