/**
* 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.metadata;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.weather.internal.annotation.Forecast;
import org.openhab.binding.weather.internal.annotation.ForecastMappings;
import org.openhab.binding.weather.internal.annotation.Provider;
import org.openhab.binding.weather.internal.annotation.ProviderMappings;
import org.openhab.binding.weather.internal.converter.Converter;
import org.openhab.binding.weather.internal.converter.ConverterFactory;
import org.openhab.binding.weather.internal.converter.ConverterType;
import org.openhab.binding.weather.internal.model.ProviderName;
import org.openhab.binding.weather.internal.model.Weather;
import org.openhab.binding.weather.internal.utils.PropertyResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Scans the model package and extracts mapping infos from the annotations.
*
* @author Gerhard Riegler
* @since 1.6.0
*/
public class MetadataHandler {
private static final Logger logger = LoggerFactory.getLogger(MetadataHandler.class);
private static final String PACKAGE_TO_SCAN = StringUtils.substringBeforeLast(Weather.class.getName(), ".");
private Map<ProviderName, Map<String, ProviderMappingInfo>> providerMappings = new HashMap<ProviderName, Map<String, ProviderMappingInfo>>();
private Map<ProviderName, List<String>> forecastMappings = new HashMap<ProviderName, List<String>>();
private static MetadataHandler instance;
private MetadataHandler() {
}
/**
* Returns the singleton instance of the MetadataHandler.
*/
public static MetadataHandler getInstance() {
if (instance == null) {
instance = new MetadataHandler();
}
return instance;
}
/**
* Scans the class and generates metadata.
*/
public void generate(Class<?> clazz) throws IllegalAccessException {
if (clazz == null) {
return;
}
for (Field field : clazz.getDeclaredFields()) {
if (field.getType().getName().startsWith(PACKAGE_TO_SCAN) && !field.isEnumConstant()) {
generate(field.getType());
} else {
for (Annotation annotation : field.getAnnotations()) {
if (annotation.annotationType().equals(ProviderMappings.class)) {
ProviderMappings providerAnnotations = (ProviderMappings) annotation;
for (Provider provider : providerAnnotations.value()) {
Map<String, ProviderMappingInfo> mappings = providerMappings.get(provider.name());
if (mappings == null) {
mappings = new HashMap<String, ProviderMappingInfo>();
providerMappings.put(provider.name(), mappings);
}
Converter<?> converter = getConverter(field, provider.converter());
String target = clazz.getSimpleName().toLowerCase() + "." + field.getName();
ProviderMappingInfo pm = new ProviderMappingInfo(provider.property(), target, converter);
mappings.put(pm.getSource(), pm);
logger.trace("Added provider mapping {}: {}", provider.name(), pm);
}
} else if (annotation.annotationType().equals(ForecastMappings.class)) {
ForecastMappings forecastsAnnotations = (ForecastMappings) annotation;
for (Forecast forecast : forecastsAnnotations.value()) {
List<String> forecastProperties = forecastMappings.get(forecast.provider());
if (forecastProperties == null) {
forecastProperties = new ArrayList<String>();
forecastMappings.put(forecast.provider(), forecastProperties);
}
forecastProperties.add(forecast.property());
logger.trace("Added forecast mapping {}: {}", forecast.provider(), forecast.property());
}
}
}
}
}
}
/**
* Autodetects a converter or returns a specified instance.
*/
private Converter<?> getConverter(Field field, ConverterType type) {
if (type == ConverterType.AUTO) {
String fieldType = field.getType().getSimpleName().toUpperCase();
return ConverterFactory.getConverter(ConverterType.valueOf(fieldType));
} else if (type == ConverterType.NONE) {
return null;
} else {
return ConverterFactory.getConverter(type);
}
}
/**
* Returns the MappingInfo for the specified provider and property.
*/
public ProviderMappingInfo getProviderMappingInfo(ProviderName provider, String property) {
Map<String, ProviderMappingInfo> mapping = providerMappings.get(provider);
if (mapping == null) {
return null;
}
ProviderMappingInfo provMapping = mapping.get(property);
String nestedProperty = property;
while (provMapping == null && PropertyResolver.hasNested(nestedProperty)) {
nestedProperty = PropertyResolver.removeFirst(nestedProperty);
provMapping = mapping.get(nestedProperty);
}
return provMapping;
}
/**
* Returns true, if the property is a forecast property.
*/
public boolean isForecast(ProviderName provider, String property) {
if (property == null || !forecastMappings.containsKey(provider)) {
return false;
}
return forecastMappings.get(provider).contains(property);
}
}