001
002 /*
003 * Copyright (C) 2011 Archie L. Cobbs. All rights reserved.
004 *
005 * $Id: AbstractSpringSchemaUpdate.java 240 2012-01-19 19:42:54Z archie.cobbs $
006 */
007
008 package org.dellroad.stuff.schema;
009
010 import java.util.HashSet;
011
012 import org.springframework.beans.factory.BeanFactory;
013 import org.springframework.beans.factory.BeanFactoryAware;
014 import org.springframework.beans.factory.BeanNameAware;
015 import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
016 import org.springframework.beans.factory.InitializingBean;
017 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
018 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
019
020 /**
021 * Support superclass for {@link SchemaUpdate}s declared in Spring {@link BeanFactory}s that infer their
022 * names and required predecessors from their Spring bean attributes.
023 *
024 * <p>
025 * Instances infer their {@linkplain #getName name} and {@linkplain #getRequiredPredecessors required predecessors} from
026 * their Spring bean name (specified by the <code>id</code> XML attribute) and Spring dependencies (specified by
027 * the <code>depends-on</code> XML attribute), respectively.
028 *
029 * <p>
030 * Note: the use of <code>depends-on</code> is an abuse of Spring's dependency notation for convenience. Normally
031 * <code>depends-on</code> refers to bean intialization ordering, whereas this class uses it to refer to schema update ordering.
032 * Schema updates are not normally expected to have any initialization ordering requirements, so this abuse shouldn't matter.
033 * If they do, this class should not be used.
034 *
035 * <p>
036 * The containing {@link BeanFactory} must be a {@link ConfigurableBeanFactory} (normally this is always the case).
037 *
038 * @param <T> database transaction type
039 */
040 public abstract class AbstractSpringSchemaUpdate<T> extends AbstractSchemaUpdate<T>
041 implements BeanNameAware, BeanFactoryAware, InitializingBean {
042
043 protected String beanName;
044 protected BeanFactory beanFactory;
045
046 @Override
047 public void setBeanName(String beanName) {
048 this.beanName = beanName;
049 }
050
051 @Override
052 public void setBeanFactory(BeanFactory beanFactory) {
053 this.beanFactory = beanFactory;
054 }
055
056 /**
057 * Configures the update name and required predecessors based on the Spring bean's name and
058 * {@link BeanFactory} dependencies.
059 */
060 @Override
061 public void afterPropertiesSet() throws Exception {
062 if (this.beanFactory == null)
063 throw new IllegalArgumentException("no BeanFactory configured");
064 if (this.beanName == null)
065 throw new IllegalArgumentException("no beanName configured");
066 this.setName(this.beanName);
067 this.setRequiredPredecessorsFromDependencies();
068 }
069
070 /**
071 * Infer required predecessors from Spring dependencies.
072 *
073 * @throws IllegalArgumentException if this instance's {@code beanFactory} is not yet configured,
074 * or not a {@link ConfigurableBeanFactory}
075 */
076 @SuppressWarnings("unchecked")
077 protected void setRequiredPredecessorsFromDependencies() {
078
079 // Check factory type
080 if (!(this.beanFactory instanceof ConfigurableBeanFactory))
081 throw new IllegalArgumentException("BeanFactory is not a ConfigurableBeanFactory: " + this.beanFactory);
082 ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory)this.beanFactory;
083
084 // Find required predecessors defined as Spring dependencies
085 String[] predecessorNames = configurableBeanFactory.getDependenciesForBean(this.beanName);
086 HashSet<SchemaUpdate<T>> predecessors = new HashSet<SchemaUpdate<T>>(predecessorNames.length);
087 for (String predecessorName : predecessorNames) {
088 try {
089 predecessors.add((SchemaUpdate<T>)configurableBeanFactory.getBean(predecessorName, SchemaUpdate.class));
090 } catch (NoSuchBeanDefinitionException e) {
091 continue;
092 } catch (BeanNotOfRequiredTypeException e) {
093 continue;
094 }
095 }
096 this.setRequiredPredecessors(predecessors);
097 }
098 }
099