All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.antelopeframework.dynamicproperty.spring.DynamicValuePostProcessor Maven / Gradle / Ivy

The newest version!
package com.github.antelopeframework.dynamicproperty.spring;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.ReflectionUtils.FieldFilter;

import com.github.antelopeframework.dynamicproperty.DynamicPropertiesException;
import com.github.antelopeframework.dynamicproperty.DynamicPropertyChangeListener;
import com.github.antelopeframework.dynamicproperty.ValueConverter;
import com.github.antelopeframework.dynamicproperty.util.Assert;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Setter
public class DynamicValuePostProcessor implements BeanPostProcessor, InitializingBean {
	
	private GlobalVars globalVars;
	
    private ValueConverter valueConverter;
    
	@Override
	public void afterPropertiesSet() throws Exception {
		org.springframework.util.Assert.notNull(globalVars);
		org.springframework.util.Assert.notNull(valueConverter);
	}
	
	@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

	@Override
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    	ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                DynamicValue dValue = field.getAnnotation(DynamicValue.class);
                field.setAccessible(true);
                
                String propName = dValue.value();
                String description = dValue.description();
                
                if (log.isTraceEnabled()) {
                    log.trace("DynamicValue: propName={}, description={}", propName, description);
                }
                
                Object defaultValue = field.get(bean);
                String v = globalVars.getValue(propName);
                if (StringUtils.isNotBlank(v)) {
                	Object value = valueConverter.convert(v, field.getType());
                	if (value == null) {
                		value = defaultValue;
                	}
                	
                	field.set(bean, value);
                }
                
                DynamicPropertyChangeListener listener = new PropertyChangeListenerImpl(bean, field, defaultValue, valueConverter);
                GlobalVars.registDynamicPropertyListener(globalVars, propName, listener);
            }
        }, new FieldFilter() {
			
			@Override
			public boolean matches(Field field) {
				return field.isAnnotationPresent(DynamicValue.class);
			}
		});
        
        return bean;
    }
    
	@Slf4j
    private static class PropertyChangeListenerImpl implements DynamicPropertyChangeListener {
    	private final WeakReference beanRef;
        private final Field field;
        private final Object defaultValue;
        private final ValueConverter valueConverter;
        
        
        PropertyChangeListenerImpl(Object bean, Field field, Object defaultValue, ValueConverter valueConverter) {
        	this.beanRef = new WeakReference<>(Assert.argumentNotNull(bean, "bean"));
            this.field = Assert.argumentNotNull(field, "field");
            this.defaultValue = defaultValue;
            this.valueConverter = valueConverter;
        }
        
        @Override
        public void onUpdate(String value) {
        	updateValue(value);
        }
        
        @Override
        public void onDelete(String value) {
        	updateValue(null);
        }
        
        private void updateValue(String value) {
        	try {
                Object bean = beanRef.get();
                if (bean != null) {
                	Object oldValue = field.get(bean);
                	Object converted;
                	if (StringUtils.isNotBlank(value)) {
                		converted = valueConverter.convert(value, field.getType());
                	} else {
                		converted = defaultValue;
                	}
                	
                	if (log.isDebugEnabled()) {
                		log.debug("update field value: field={}, from={}, to={}", field.getDeclaringClass().getName() + "." + field.getName(), oldValue, converted);
                	}
                	
                    field.setAccessible(true);
                    field.set(bean, converted);
                }
            } catch (Exception e) {
                throw new DynamicPropertiesException(String.format("Error set field %s on %s", field.getName(), field.getDeclaringClass()), e);
            }
        }
    }
}