
org.dellroad.stuff.spring.AbstractSpringSchemaUpdate Maven / Gradle / Ivy
Show all versions of dellroad-stuff-spring Show documentation
/*
* Copyright (C) 2022 Archie L. Cobbs. All rights reserved.
*/
package org.dellroad.stuff.spring;
import java.util.HashSet;
import org.dellroad.stuff.schema.AbstractSchemaUpdate;
import org.dellroad.stuff.schema.SchemaUpdate;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
/**
* Support superclass for {@link SchemaUpdate}s declared in Spring {@link BeanFactory}s that infer their
* names and required predecessors from their Spring bean attributes.
*
*
* Instances infer their {@linkplain #getName name} and {@linkplain #getRequiredPredecessors required predecessors} from
* their Spring bean name (specified by the id
XML attribute) and Spring dependencies (specified by
* the depends-on
XML attribute), respectively.
*
*
* Note: the use of depends-on
is an abuse of Spring's dependency notation for convenience. Normally
* depends-on
refers to bean intialization ordering, whereas this class uses it to refer to schema update ordering.
* Schema updates are not normally expected to have any initialization ordering requirements, so this abuse shouldn't matter.
* If they do, this class should not be used.
*
*
* The containing {@link BeanFactory} must be a {@link ConfigurableBeanFactory} (normally this is always the case).
*
* @param database transaction type
*/
public abstract class AbstractSpringSchemaUpdate extends AbstractSchemaUpdate
implements BeanNameAware, BeanFactoryAware, InitializingBean {
protected String beanName;
protected BeanFactory beanFactory;
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
/**
* Configures the update name and required predecessors based on the Spring bean's name and
* {@link BeanFactory} dependencies.
*/
@Override
public void afterPropertiesSet() throws Exception {
if (this.beanFactory == null)
throw new IllegalArgumentException("no BeanFactory configured");
if (this.beanName == null)
throw new IllegalArgumentException("no beanName configured");
this.setName(this.beanName);
this.setRequiredPredecessorsFromDependencies();
}
/**
* Infer required predecessors from Spring dependencies.
*
* @throws IllegalArgumentException if this instance's {@code beanFactory} is not yet configured,
* or not a {@link ConfigurableBeanFactory}
*/
@SuppressWarnings("unchecked")
protected void setRequiredPredecessorsFromDependencies() {
// Check factory type
if (!(this.beanFactory instanceof ConfigurableBeanFactory))
throw new IllegalArgumentException("BeanFactory is not a ConfigurableBeanFactory: " + this.beanFactory);
ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory)this.beanFactory;
// Find required predecessors defined as Spring dependencies
String[] predecessorNames = configurableBeanFactory.getDependenciesForBean(this.beanName);
HashSet> predecessors = new HashSet<>(predecessorNames.length);
for (String predecessorName : predecessorNames) {
try {
predecessors.add((SchemaUpdate)configurableBeanFactory.getBean(predecessorName, SchemaUpdate.class));
} catch (NoSuchBeanDefinitionException e) {
continue;
} catch (BeanNotOfRequiredTypeException e) {
continue;
}
}
this.setRequiredPredecessors(predecessors);
}
}