com.netflix.paas.config.base.ConfigurationProxyUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.paas.config.base.ConfigurationProxyUtils.java

Source

/*******************************************************************************
 * /***
 *  *
 *  *  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();
                        }
                    }
                });
            }
        }
    }

}