001    
002    /*
003     * Copyright (C) 2011 Archie L. Cobbs. All rights reserved.
004     *
005     * $Id: SpringSQLSchemaUpdate.java 205 2012-01-06 22:43:05Z archie.cobbs $
006     */
007    
008    package org.dellroad.stuff.schema;
009    
010    import java.sql.Connection;
011    import java.util.ArrayList;
012    import java.util.List;
013    
014    /**
015     * Spring-enabled SQL {@link SchemaUpdate}.
016     *
017     * <p>
018     * The {@link #setSQLCommandList sqlCommandList} property is required.
019     *
020     * <p>
021     * Instances can be created succintly in Spring using the <code>&lt;dellroad-stuff:sql-update&gt;</code> custom XML element,
022     * which works just like <code>&lt;dellroad-stuff:sql&gt;</code> except that it wraps the resulting {@link SQLCommandList}
023     * as a delegate inside an instance of this class.
024     *
025     * <p>
026     * For example:
027     * <blockquote><pre>
028     *  &lt;beans xmlns="http://www.springframework.org/schema/beans"
029     *    <b>xmlns:dellroad-stuff="http://dellroad-stuff.googlecode.com/schema/dellroad-stuff"</b>
030     *    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
031     *    xsi:schemaLocation="
032     *      http://www.springframework.org/schema/beans
033     *        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
034     *      <b>http://dellroad-stuff.googlecode.com/schema/dellroad-stuff
035     *        http://dellroad-stuff.googlecode.com/svn/wiki/schemas/dellroad-stuff-1.0.xsd</b>"&gt;
036     *
037     *      &lt;!-- Schema update to add the 'phone' column to the 'User' table --&gt;
038     *      <b>&lt;dellroad-stuff:sql-update id="addPhone"&gt;ALTER TABLE User ADD phone VARCHAR(64)&lt;/dellroad-stuff:sql-update&gt;</b>
039     *
040     *      &lt;!-- Schema update to run some complicated external SQL script --&gt;
041     *      <b>&lt;dellroad-stuff:sql-update id="majorChanges" depends-on="addPhone" resource="classpath:majorChanges.sql"/&gt;</b>
042     *
043     *      &lt;!-- more beans... --&gt;
044     *
045     *  &lt;/beans&gt;
046     * </pre></blockquote>
047     * </p>
048     *
049     * <p>
050     * A multi-statement SQL script is normally treated as a set of individual updates. For example:
051     * <blockquote><pre>
052     *      <b>&lt;dellroad-stuff:sql-update id="renameColumn"&gt;
053     *          ALTER TABLE User ADD newName VARCHAR(64);
054     *          ALTER TABLE User SET newName = oldName;
055     *          ALTER TABLE User DROP oldName;
056     *      &lt;/dellroad-stuff:sql-update&gt;</b>
057     * </pre></blockquote>
058     * This will create three separate update beans named <code>renameColumn-00001</code>, <code>renameColumn-00002</code>, and
059     * <code>renameColumn-00003</code>. You can disable this behavior by adding the attribute <code>single-action="true"</code>,
060     * in which case all three of the statements will be executed together in the same transaction and recorded under the name
061     * <code>renameColumn</code>; this means that they must all complete successfully or you could end up with a partially
062     * completed update.
063     * </p>
064     *
065     * <p>
066     * Note that if the nested SQL script only contains one SQL statement, any <code>single-action</code> attribute is
067     * ignored and the bean's given name (e.g., <code>renameColumn</code>) is always used as the name of the single update.
068     * </p>
069     *
070     * @see SQLCommandList
071     */
072    public class SpringSQLSchemaUpdate extends AbstractSpringSchemaUpdate<Connection> {
073    
074        private SQLCommandList sqlCommandList;
075    
076        @Override
077        public void afterPropertiesSet() throws Exception {
078            super.afterPropertiesSet();
079            if (this.sqlCommandList == null)
080                throw new Exception("no SQLCommandList configured");
081        }
082    
083        /**
084         * Configure the {@link SQLCommandList}. This is a required property.
085         *
086         * @see DatabaseAction
087         */
088        public void setSQLCommandList(SQLCommandList sqlCommandList) {
089            this.sqlCommandList = sqlCommandList;
090        }
091    
092        public SQLCommandList getSQLCommandList() {
093            return this.sqlCommandList;
094        }
095    
096        @Override
097        public List<DatabaseAction<Connection>> getDatabaseActions() {
098            return new ArrayList<DatabaseAction<Connection>>(this.getSQLCommandList().split());
099        }
100    }
101