package com.revolsys.spring;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.MapFactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ResourceLoader;
import com.revolsys.beans.propertyeditor.ResourceEditorRegistrar;
import com.revolsys.collection.map.AttributeMap;
import com.revolsys.spring.config.AttributesBeanConfigurer;
import com.revolsys.spring.resource.Resource;
public class ModuleImport implements BeanFactoryPostProcessor, BeanNameAware, DisposableBean {
public static GenericBeanDefinition newTargetBeanDefinition(
final BeanDefinitionRegistry beanFactory, final String beanName) {
if (beanFactory.containsBeanDefinition(beanName)) {
final BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
final boolean singleton = beanDefinition.isSingleton();
final GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition();
proxyBeanDefinition.setBeanClass(TargetBeanFactoryBean.class);
final MutablePropertyValues values = new MutablePropertyValues();
final String beanClassName = beanDefinition.getBeanClassName();
final PropertyValue beanDefinitionProperty = new PropertyValue("targetBeanDefinition",
beanDefinition);
beanDefinitionProperty.setConvertedValue(beanDefinition);
values.addPropertyValue(beanDefinitionProperty);
values.addPropertyValue("targetBeanName", beanName);
values.addPropertyValue("targetBeanClass", beanClassName);
values.addPropertyValue("targetBeanFactory", beanFactory);
values.addPropertyValue("singleton", singleton);
proxyBeanDefinition.setPropertyValues(values);
return proxyBeanDefinition;
} else {
return null;
}
}
public static void registerTargetBeanDefinition(final BeanDefinitionRegistry registry,
final BeanFactory beanFactory, final String beanName, final String alias) {
final BeanDefinition beanDefinition = newTargetBeanDefinition(
(BeanDefinitionRegistry)beanFactory, beanName);
if (beanDefinition != null) {
registry.registerBeanDefinition(alias, beanDefinition);
}
}
private GenericApplicationContext applicationContext;
private String beanName;
private Set<String> beanNamesNotToExport = new HashSet<>();
private boolean enabled = true;
private boolean exportAllBeans = false;
private Map<String, String> exportBeanAliases = Collections.emptyMap();
private List<String> exportBeanNames = Collections.emptyList();
private Map<String, String> importBeanAliases = Collections.emptyMap();
private List<String> importBeanNames = Collections.emptyList();
private Map<String, Object> parameters = new HashMap<>();
private ResourceEditorRegistrar resourceEditorRegistrar = new ResourceEditorRegistrar();
private Collection<Resource> resources = new LinkedHashSet<>();
public ModuleImport() {
this.beanNamesNotToExport.add("com.revolsys.spring.config.AttributesBeanConfigurer");
}
protected void afterPostProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry) {
}
protected void beforePostProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry)
throws BeansException {
}
@Override
public void destroy() {
if (this.applicationContext != null) {
this.applicationContext.close();
this.applicationContext = null;
this.beanName = null;
this.beanNamesNotToExport = null;
this.exportBeanAliases = null;
this.exportBeanNames = null;
this.importBeanAliases = null;
this.importBeanNames = null;
this.parameters = null;
this.resourceEditorRegistrar = null;
this.resources = null;
}
}
protected GenericApplicationContext getApplicationContext(
final BeanDefinitionRegistry parentRegistry) {
if (this.applicationContext == null) {
this.applicationContext = new GenericApplicationContext();
if (parentRegistry instanceof ResourceLoader) {
final ResourceLoader resourceLoader = (ResourceLoader)parentRegistry;
final ClassLoader classLoader = resourceLoader.getClassLoader();
this.applicationContext.setClassLoader(classLoader);
}
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.applicationContext, null);
final DefaultListableBeanFactory beanFactory = this.applicationContext
.getDefaultListableBeanFactory();
final BeanFactory parentBeanFactory = (BeanFactory)parentRegistry;
for (final String beanName : parentRegistry.getBeanDefinitionNames()) {
final BeanDefinition beanDefinition = parentRegistry.getBeanDefinition(beanName);
final String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null) {
if (beanClassName.equals(AttributeMap.class.getName())) {
registerTargetBeanDefinition(this.applicationContext, parentBeanFactory, beanName,
beanName);
this.beanNamesNotToExport.add(beanName);
} else if (beanClassName.equals(MapFactoryBean.class.getName())) {
final PropertyValue targetMapClass = beanDefinition.getPropertyValues()
.getPropertyValue("targetMapClass");
if (targetMapClass != null) {
final Object mapClass = targetMapClass.getValue();
if (AttributeMap.class.getName().equals(mapClass)) {
registerTargetBeanDefinition(this.applicationContext, parentBeanFactory, beanName,
beanName);
this.beanNamesNotToExport.add(beanName);
}
}
}
}
}
beanFactory.addPropertyEditorRegistrar(this.resourceEditorRegistrar);
final AttributesBeanConfigurer attributesConfig = new AttributesBeanConfigurer(
this.applicationContext, this.parameters);
this.applicationContext.addBeanFactoryPostProcessor(attributesConfig);
for (final String beanName : this.importBeanNames) {
registerTargetBeanDefinition(this.applicationContext, parentBeanFactory, beanName,
beanName);
this.beanNamesNotToExport.add(beanName);
}
for (final Entry<String, String> entry : this.importBeanAliases.entrySet()) {
final String beanName = entry.getKey();
final String aliasName = entry.getValue();
registerTargetBeanDefinition(this.applicationContext, parentBeanFactory, beanName,
aliasName);
this.beanNamesNotToExport.add(aliasName);
}
final XmlBeanDefinitionReader beanReader = new XmlBeanDefinitionReader(
this.applicationContext);
for (final Resource resource : this.resources) {
beanReader.loadBeanDefinitions(resource);
}
this.applicationContext.refresh();
}
return this.applicationContext;
}
public Map<String, String> getExportBeanAliases() {
return this.exportBeanAliases;
}
public List<String> getExportBeanNames() {
return this.exportBeanNames;
}
public Map<String, String> getImportBeanAliases() {
return this.importBeanAliases;
}
public List<String> getImportBeanNames() {
return this.importBeanNames;
}
public Map<String, Object> getParameters() {
return this.parameters;
}
public ResourceEditorRegistrar getResourceEditorRegistrar() {
return this.resourceEditorRegistrar;
}
public Collection<Resource> getResources() {
return this.resources;
}
public boolean isEnabled() {
return this.enabled;
}
public boolean isExportAllBeans() {
return this.exportAllBeans;
}
private void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry)
throws BeansException {
beforePostProcessBeanDefinitionRegistry(registry);
if (this.enabled) {
final GenericApplicationContext beanFactory = getApplicationContext(registry);
if (this.exportAllBeans) {
for (final String beanName : beanFactory.getBeanDefinitionNames()) {
if (!this.beanNamesNotToExport.contains(beanName)) {
registerTargetBeanDefinition(registry, beanFactory, beanName, beanName);
for (final String alias : beanFactory.getAliases(beanName)) {
if (!this.beanNamesNotToExport.contains(alias)) {
registerTargetBeanDefinition(registry, beanFactory, beanName, alias);
}
}
}
}
} else {
for (final String beanName : this.exportBeanNames) {
if (!this.beanNamesNotToExport.contains(beanName)) {
registerTargetBeanDefinition(registry, beanFactory, beanName, beanName);
}
}
}
for (final Entry<String, String> exportBeanAlias : this.exportBeanAliases.entrySet()) {
final String beanName = exportBeanAlias.getKey();
final String alias = exportBeanAlias.getValue();
if (!this.beanNamesNotToExport.contains(alias)) {
registerTargetBeanDefinition(registry, beanFactory, beanName, alias);
}
}
afterPostProcessBeanDefinitionRegistry(registry);
}
}
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory)
throws BeansException {
if (beanFactory instanceof BeanDefinitionRegistry) {
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
postProcessBeanDefinitionRegistry(registry);
}
}
@Override
public void setBeanName(final String beanName) {
this.beanName = beanName;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public void setExportAllBeans(final boolean exportAllBeans) {
this.exportAllBeans = exportAllBeans;
}
public void setExportBeanAliases(final Map<String, String> exportBeanAliases) {
this.exportBeanAliases = exportBeanAliases;
}
public void setExportBeanNames(final List<String> exportBeanNames) {
this.exportBeanNames = exportBeanNames;
}
public void setImportBeanAliases(final Map<String, String> importBeanAliases) {
this.importBeanAliases = importBeanAliases;
}
public void setImportBeanNames(final List<String> importBeanNames) {
this.importBeanNames = importBeanNames;
}
public void setParameters(final Map<String, Object> parameters) {
this.parameters = parameters;
}
public void setResource(final String resourceUrl) {
final Resource resource = Resource.getResource(resourceUrl);
this.resources.add(resource);
}
public void setResourceEditorRegistrar(final ResourceEditorRegistrar resourceEditorRegistrar) {
this.resourceEditorRegistrar = resourceEditorRegistrar;
}
public void setResources(final Collection<Resource> resources) {
this.resources = resources;
}
@Override
public String toString() {
return this.beanName;
}
}