Java tutorial
/******************************************************************************* * /*** * * * * Copyright 2013 Netflix, Inc. * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * ******************************************************************************/ package com.netflix.paas.config.base; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; import org.apache.commons.lang.StringUtils; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.Maps; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.PropertyWrapper; import com.netflix.governator.annotations.Configuration; import com.netflix.paas.config.annotations.DefaultValue; import com.netflix.paas.config.annotations.Dynamic; import java.lang.reflect.Field; import org.apache.commons.configuration.AbstractConfiguration; /** * Utility class used by ConfigurationProxyFactory implementations to proxy methods of a * configuration interface using information from the Configuration annotation * * @author elandau */ public class ConfigurationProxyUtils { public static class PropertyWrapperSupplier<T> implements Supplier<T> { private final PropertyWrapper<T> wrapper; public PropertyWrapperSupplier(PropertyWrapper<T> wrapper) { this.wrapper = wrapper; } @Override public T get() { return this.wrapper.getValue(); } } static Supplier<?> getDynamicSupplier(Class<?> type, String key, String defaultValue, DynamicPropertyFactory propertyFactory) { if (type.isAssignableFrom(String.class)) { return new PropertyWrapperSupplier<String>(propertyFactory.getStringProperty(key, defaultValue)); } else if (type.isAssignableFrom(Integer.class)) { return new PropertyWrapperSupplier<Integer>( propertyFactory.getIntProperty(key, defaultValue == null ? 0 : Integer.parseInt(defaultValue))); } else if (type.isAssignableFrom(Double.class)) { return new PropertyWrapperSupplier<Double>(propertyFactory.getDoubleProperty(key, defaultValue == null ? 0.0 : Double.parseDouble(defaultValue))); } else if (type.isAssignableFrom(Long.class)) { return new PropertyWrapperSupplier<Long>( propertyFactory.getLongProperty(key, defaultValue == null ? 0L : Long.parseLong(defaultValue))); } else if (type.isAssignableFrom(Boolean.class)) { return new PropertyWrapperSupplier<Boolean>(propertyFactory.getBooleanProperty(key, defaultValue == null ? false : Boolean.parseBoolean(defaultValue))); } throw new RuntimeException("Unsupported value type " + type.getCanonicalName()); } static Supplier<?> getStaticSupplier(Class<?> type, String key, String defaultValue, AbstractConfiguration configuration) { if (type.isAssignableFrom(String.class)) { return Suppliers.ofInstance(configuration.getString(key, defaultValue)); } else if (type.isAssignableFrom(Integer.class)) { return Suppliers.ofInstance( configuration.getInteger(key, defaultValue == null ? 0 : Integer.parseInt(defaultValue))); } else if (type.isAssignableFrom(Double.class)) { return Suppliers.ofInstance( configuration.getDouble(key, defaultValue == null ? 0.0 : Double.parseDouble(defaultValue))); } else if (type.isAssignableFrom(Long.class)) { return Suppliers.ofInstance( configuration.getLong(key, defaultValue == null ? 0L : Long.parseLong(defaultValue))); } else if (type.isAssignableFrom(Boolean.class)) { return Suppliers.ofInstance(configuration.getBoolean(key, defaultValue == null ? false : Boolean.parseBoolean(defaultValue))); } throw new RuntimeException("Unsupported value type " + type.getCanonicalName()); } static String getPropertyName(Method method, Configuration c) { String name = c.value(); if (name.isEmpty()) { name = method.getName(); name = StringUtils.removeStart(name, "is"); name = StringUtils.removeStart(name, "get"); name = name.toLowerCase(); } return name; } static String getPropertyName(Field field, Configuration c) { String name = c.value(); if (name.isEmpty()) { return field.getName(); } return name; } static <T> Map<String, Supplier<?>> getMethodSuppliers(Class<T> configClass, DynamicPropertyFactory propertyFactory, AbstractConfiguration configuration) { final Map<String, Supplier<?>> properties = Maps.newHashMap(); for (Method method : configClass.getMethods()) { Configuration c = method.getAnnotation(Configuration.class); if (c == null) continue; String defaultValue = null; DefaultValue dv = method.getAnnotation(DefaultValue.class); if (dv != null) defaultValue = dv.value(); String name = getPropertyName(method, c); if (method.getReturnType().isAssignableFrom(Supplier.class)) { Type returnType = method.getGenericReturnType(); if (returnType instanceof ParameterizedType) { ParameterizedType type = (ParameterizedType) returnType; Class<?> actualType = (Class<?>) type.getActualTypeArguments()[0]; properties.put(method.getName(), method.getAnnotation(Dynamic.class) != null ? Suppliers.ofInstance( getDynamicSupplier(actualType, name, defaultValue, propertyFactory)) : Suppliers.ofInstance( getStaticSupplier(actualType, name, defaultValue, configuration))); } else { throw new RuntimeException("We'll get to this later"); } } else { properties.put(method.getName(), method.getAnnotation(Dynamic.class) != null ? getDynamicSupplier(method.getReturnType(), name, defaultValue, propertyFactory) : getStaticSupplier(method.getReturnType(), name, defaultValue, configuration)); } } return properties; } static void assignFieldValues(final Object obj, Class<?> type, DynamicPropertyFactory propertyFactory, AbstractConfiguration configuration) throws Exception { // Iterate through all fields and set initial value as well as set up dynamic properties // where necessary for (final Field field : type.getFields()) { Configuration c = field.getAnnotation(Configuration.class); if (c == null) continue; String defaultValue = field.get(obj).toString(); String name = ConfigurationProxyUtils.getPropertyName(field, c); Supplier<?> supplier = ConfigurationProxyUtils.getStaticSupplier(field.getType(), name, defaultValue, configuration); field.set(obj, supplier.get()); if (field.getAnnotation(Dynamic.class) != null) { final PropertyWrapper<?> property; if (field.getType().isAssignableFrom(String.class)) { property = propertyFactory.getStringProperty(name, defaultValue); } else if (field.getType().isAssignableFrom(Integer.class)) { property = propertyFactory.getIntProperty(name, defaultValue == null ? 0 : Integer.parseInt(defaultValue)); } else if (field.getType().isAssignableFrom(Double.class)) { property = propertyFactory.getDoubleProperty(name, defaultValue == null ? 0.0 : Double.parseDouble(defaultValue)); } else if (field.getType().isAssignableFrom(Long.class)) { property = propertyFactory.getLongProperty(name, defaultValue == null ? 0L : Long.parseLong(defaultValue)); } else if (field.getType().isAssignableFrom(Boolean.class)) { property = propertyFactory.getBooleanProperty(name, defaultValue == null ? false : Boolean.parseBoolean(defaultValue)); } else { throw new RuntimeException("Unsupported type " + field.getType()); } property.addCallback(new Runnable() { @Override public void run() { try { field.set(obj, property.getValue()); } catch (Exception e) { e.printStackTrace(); } } }); } } } }