TestMigrationTask1.
29 | */
30 | public TestMigrationTask1()
31 | {
32 | super("TestTask1", 4);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/tasks/normal/TestMigrationTask4.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.tasks.normal;
17 |
18 | import com.tacitknowledge.util.migration.tasks.BaseTestMigrationTask;
19 |
20 | /**
21 | * Basic test migration task.
22 | *
23 | * @author Scott Askew (scott@tacitknowledge.com)
24 | */
25 | public class TestMigrationTask4 extends BaseTestMigrationTask
26 | {
27 | /**
28 | * Creates a new TestMigrationTask3.
29 | */
30 | public TestMigrationTask4()
31 | {
32 | super("TestTask4", 7);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/test/listeners/TestListener2.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.test.listeners;
17 |
18 | import java.util.Properties;
19 |
20 | import com.tacitknowledge.util.migration.AbstractMigrationListener;
21 | import com.tacitknowledge.util.migration.MigrationException;
22 |
23 | /**
24 | * @author Alex Soto (apsoto@gmail.com)
25 | */
26 | public class TestListener2 extends AbstractMigrationListener
27 | {
28 |
29 | public void initialize(String systemName, Properties properties) throws MigrationException
30 | {
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/tasks/post/TestPostMigrationTask1.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.tasks.post;
17 |
18 | import com.tacitknowledge.util.migration.tasks.BaseTestMigrationTask;
19 |
20 | /**
21 | * Basic test post migration task.
22 | *
23 | * @author Mike Hardy (mike@tacitknowledge.com)
24 | */
25 | public class TestPostMigrationTask1 extends BaseTestMigrationTask
26 | {
27 | /**
28 | * Creates a new TestMigrationTask1.
29 | */
30 | public TestPostMigrationTask1()
31 | {
32 | super("TestPostTask1", 1);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/tasks/post/TestPostMigrationTask2.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.tasks.post;
17 |
18 | import com.tacitknowledge.util.migration.tasks.BaseTestMigrationTask;
19 |
20 | /**
21 | * Basic test post migration task.
22 | *
23 | * @author Mike Hardy (mike@tacitknowledge.com)
24 | */
25 | public class TestPostMigrationTask2 extends BaseTestMigrationTask
26 | {
27 | /**
28 | * Creates a new TestMigrationTask2.
29 | */
30 | public TestPostMigrationTask2()
31 | {
32 | super("TestPostTask2", 2);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/integration-test/resources/missingpatchstrategybatch4-inttest-migration.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Which context do we use for the orchestration patch store? Orders.
3 | #
4 | migration.strategy=com.tacitknowledge.util.migration.MissingPatchMigrationRunnerStrategy
5 |
6 | #
7 | # Configure a context named nodes, and make it a multi-node context
8 | #
9 | nodes.context=nodes
10 | nodes.controlled.systems=nodes
11 | nodes.jdbc.database.type=hsqldb
12 | nodes.jdbc.driver=org.hsqldb.jdbcDriver
13 | nodes.jdbc.url=jdbc:hsqldb:mem:nodes
14 | nodes.jdbc.username=sa
15 | nodes.jdbc.password=
16 | nodes.patch.path=com.tacitknowledge.util.migration.inttest-tasks.missingpatchstrategy.batch2
17 |
18 | nodes.jdbc.systems=jdbcnode1,jdbcnode2,jdbcnode3
19 | nodes.jdbcnode1.database.type=hsqldb
20 | nodes.jdbcnode1.driver=org.hsqldb.jdbcDriver
21 | nodes.jdbcnode1.url=jdbc:hsqldb:mem:node1
22 | nodes.jdbcnode1.username=sa
23 | nodes.jdbcnode1.password=
24 | nodes.jdbcnode2.database.type=hsqldb
25 | nodes.jdbcnode2.driver=org.hsqldb.jdbcDriver
26 | nodes.jdbcnode2.url=jdbc:hsqldb:mem:node2
27 | nodes.jdbcnode2.username=sa
28 | nodes.jdbcnode2.password=
29 | nodes.jdbcnode3.database.type=hsqldb
30 | nodes.jdbcnode3.driver=org.hsqldb.jdbcDriver
31 | nodes.jdbcnode3.url=jdbc:hsqldb:mem:node3
32 | nodes.jdbcnode3.username=sa
33 | nodes.jdbcnode3.password=
--------------------------------------------------------------------------------
/examples/distributed-sample/conf/migration.properties:
--------------------------------------------------------------------------------
1 | distributed-sample.context=orchestrator
2 | distributed-sample.controlled.systems=app1,app2,app3
3 |
4 | orchestrator.jdbc.database.type=hsqldb
5 | orchestrator.jdbc.driver=org.hsqldb.jdbcDriver
6 | orchestrator.jdbc.url=jdbc:hsqldb:file:./var/orchestrator
7 | orchestrator.jdbc.username=sa
8 | orchestrator.jdbc.password=
9 | orchestrator.patch.path=orchestrator:example.orchestrator.db.patch
10 |
11 |
12 | app1.jdbc.database.type=hsqldb
13 | app1.jdbc.driver=org.hsqldb.jdbcDriver
14 | app1.jdbc.url=jdbc:hsqldb:file:./var/app1
15 | app1.jdbc.username=sa
16 | app1.jdbc.password=
17 | app1.patch.path=app1:example.app1.db.patch
18 |
19 | app2.jdbc.database.type=hsqldb
20 | app2.jdbc.driver=org.hsqldb.jdbcDriver
21 | app2.jdbc.url=jdbc:hsqldb:file:./var/app2
22 | app2.jdbc.username=sa
23 | app2.jdbc.password=
24 | app2.patch.path=app2:example.app2.db.patch
25 |
26 | app3.jdbc.systems=jdbc-system1,jdbc-system2
27 | app3.jdbc-system1.database.type=hsqldb
28 | app3.jdbc-system1.driver=org.hsqldb.jdbcDriver
29 | app3.jdbc-system1.url=jdbc:hsqldb:file:./var/app3/system1
30 | app3.jdbc-system1.username=sa
31 | app3.jdbc-system1.password=
32 | app3.jdbc-system2.database.type=hsqldb
33 | app3.jdbc-system2.driver=org.hsqldb.jdbcDriver
34 | app3.jdbc-system2.url=jdbc:hsqldb:file:./var/app3/system2
35 | app3.jdbc-system2.username=sa
36 | app3.jdbc-system2.password=
37 | app3.patch.path=app3:example.app3.db.patch
--------------------------------------------------------------------------------
/migration.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Which context do we use for the orchestration patch store?
3 | #
4 | orchestration.context=core
5 | orchestration.controlled.systems=core,orders,catalog
6 | orchestration.lockPollRetries=10
7 | #
8 | # Configure a context named "core"
9 | #
10 | core.jdbc.database.type=postgres
11 | core.jdbc.driver=org.postgresql.Driver
12 | core.jdbc.url=jdbc:postgresql://localhost/core
13 | core.jdbc.username=core
14 | core.jdbc.password=password
15 | core.patch.path=patches.core
16 | #
17 | # Configure a context named "orders"
18 | #
19 | orders.jdbc.database.type=postgres
20 | orders.jdbc.driver=org.postgresql.Driver
21 | orders.jdbc.url=jdbc:postgresql://localhost/orders
22 | orders.jdbc.username=orders
23 | orders.jdbc.password=password
24 | orders.patch.path=patches.orders
25 | #
26 | # Configure a context named catalog
27 | #
28 | catalog.jdbc.database.type=postgres
29 | catalog.jdbc.driver=org.postgresql.Driver
30 | catalog.jdbc.url=jdbc:postgresql://localhost/catalog
31 | catalog.jdbc.username=catalog
32 | catalog.jdbc.password=password
33 | catalog.patch.path=patches.catalog
34 | #
35 | # Configure a spikebook context
36 | #
37 | spikebook.jdbc.database.type=postgres
38 | spikebook.jdbc.driver=org.postgresql.Driver
39 | spikebook.jdbc.url=jdbc:postgresql://localhost/spikebook
40 | spikebook.jdbc.username=spikebook
41 | spikebook.jdbc.password=dbspikeb00k
42 | spikebook.patch.path=patches:com.tacitknowledge.spikebook.patches
43 |
--------------------------------------------------------------------------------
/src/integration-test/resources/missingpatchstrategybatch2-inttest-migration.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Which context do we use for the orchestration patch store? Orders.
3 | #
4 | migration.strategy=com.tacitknowledge.util.migration.MissingPatchMigrationRunnerStrategy
5 |
6 | #
7 | # Configure a context named "orders"
8 | #
9 | orders.jdbc.database.type=hsqldb
10 | orders.jdbc.driver=org.hsqldb.jdbcDriver
11 | orders.jdbc.url=jdbc:hsqldb:mem:orders
12 | orders.jdbc.username=sa
13 | orders.jdbc.password=
14 | orders.patch.path=com.tacitknowledge.util.migration.inttest-tasks.missingpatchstrategy.batch2
15 |
16 | #
17 | # Configure a context named nodes, and make it a multi-node context
18 | #
19 | nodes.context=nodes
20 | nodes.controlled.systems=nodes
21 | nodes.jdbc.database.type=hsqldb
22 | nodes.jdbc.driver=org.hsqldb.jdbcDriver
23 | nodes.jdbc.url=jdbc:hsqldb:mem:nodes
24 | nodes.jdbc.username=sa
25 | nodes.jdbc.password=
26 | nodes.patch.path=com.tacitknowledge.util.migration.inttest-tasks.missingpatchstrategy.batch2
27 |
28 | nodes.jdbc.systems=jdbcnode1,jdbcnode2
29 | nodes.jdbcnode1.database.type=hsqldb
30 | nodes.jdbcnode1.driver=org.hsqldb.jdbcDriver
31 | nodes.jdbcnode1.url=jdbc:hsqldb:mem:node1
32 | nodes.jdbcnode1.username=sa
33 | nodes.jdbcnode1.password=
34 | nodes.jdbcnode2.database.type=hsqldb
35 | nodes.jdbcnode2.driver=org.hsqldb.jdbcDriver
36 | nodes.jdbcnode2.url=jdbc:hsqldb:mem:node2
37 | nodes.jdbcnode2.username=sa
38 | nodes.jdbcnode2.password=
--------------------------------------------------------------------------------
/src/integration-test/resources/missingpatchstrategybatch1-inttest-migration.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Which context do we use for the orchestration patch store? Orders.
3 | #
4 | migration.strategy=com.tacitknowledge.util.migration.MissingPatchMigrationRunnerStrategy
5 |
6 | #
7 | # Configure a context named "orders"
8 | #
9 | orders.jdbc.database.type=hsqldb
10 | orders.jdbc.driver=org.hsqldb.jdbcDriver
11 | orders.jdbc.url=jdbc:hsqldb:mem:orders
12 | orders.jdbc.username=sa
13 | orders.jdbc.password=
14 | orders.patch.path=com.tacitknowledge.util.migration.inttest-tasks.missingpatchstrategy.batch1
15 |
16 | #
17 | # Configure a context named nodes, and make it a multi-node context
18 | #
19 | nodes.context=nodes
20 | nodes.controlled.systems=nodes
21 | nodes.jdbc.database.type=hsqldb
22 | nodes.jdbc.driver=org.hsqldb.jdbcDriver
23 | nodes.jdbc.url=jdbc:hsqldb:mem:nodes
24 | nodes.jdbc.username=sa
25 | nodes.jdbc.password=
26 | nodes.patch.path=com.tacitknowledge.util.migration.inttest-tasks.missingpatchstrategy.batch1
27 |
28 | nodes.jdbc.systems=jdbcnode1,jdbcnode2
29 | nodes.jdbcnode1.database.type=hsqldb
30 | nodes.jdbcnode1.driver=org.hsqldb.jdbcDriver
31 | nodes.jdbcnode1.url=jdbc:hsqldb:mem:node1
32 | nodes.jdbcnode1.username=sa
33 | nodes.jdbcnode1.password=
34 | nodes.jdbcnode2.database.type=hsqldb
35 | nodes.jdbcnode2.driver=org.hsqldb.jdbcDriver
36 | nodes.jdbcnode2.url=jdbc:hsqldb:mem:node2
37 | nodes.jdbcnode2.username=sa
38 | nodes.jdbcnode2.password=
39 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/jdbc/TestDataSourceMigrationContext.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc;
17 |
18 | import java.sql.Connection;
19 | import java.sql.SQLException;
20 |
21 | import com.tacitknowledge.util.migration.TestMigrationContext;
22 |
23 | /**
24 | * A DataSourceMigrationContext that doesn't actually talk to a database.
25 | *
26 | * @author Mike Hardy (mike@tacitknowledge.com)
27 | */
28 | public class TestDataSourceMigrationContext extends TestMigrationContext
29 | {
30 | /**
31 | * Always returns null, doesn't talk to a database
32 | *
33 | * @return null every time
34 | * @exception SQLException never throws
35 | */
36 | public Connection getConnection() throws SQLException
37 | {
38 | return null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/MigrationTaskSource.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * A source of MigrationTasks.
22 | *
23 | * @author Scott Askew (scott@tacitknowledge.com)
24 | */
25 | public interface MigrationTaskSource
26 | {
27 | /**
28 | * Returns a list of MigrationTasks that are in the given
29 | * package.
30 | *
31 | * @param packageName to package to search for migration tasks
32 | * @return a list of migration tasks; if not tasks were found, then an empty
33 | * list must be returned.
34 | * @throws MigrationException if an unrecoverable error occurs
35 | */
36 | public ListMigrationContext for this run
29 | * @throws MigrationException if an unexpected error occurred
30 | */
31 | public void migrate(MigrationContext context) throws MigrationException;
32 |
33 | /**
34 | * Returns the name of this migration task.
35 | *
36 | * @return the name of this migration task
37 | */
38 | public String getName();
39 |
40 | /**
41 | * Returns the relative order in which this migration should occur.
42 | *
43 | * @return the relative order in which this migration should occur; may never
44 | * return null
45 | */
46 | public Integer getLevel();
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/resources/com/tacitknowledge/util/migration/jdbc/mysql.properties:
--------------------------------------------------------------------------------
1 | supportsMultipleStatements=true
2 |
3 | patches.create=CREATE TABLE IF NOT EXISTS patches ( \
4 | system_name VARCHAR(30) NOT NULL \
5 | , patch_level INT4 NOT NULL \
6 | , patch_date TIMESTAMP NOT NULL default CURRENT_TIMESTAMP \
7 | , patch_in_progress CHAR(1) NOT NULL default 'F' \
8 | , PRIMARY KEY(system_name, patch_level))
9 |
10 | # Validates that a record exists for a given system
11 | level.create=INSERT INTO patches (system_name, patch_level) VALUES ( ?, 0 )
12 | level.table.exists=SELECT patch_level FROM patches WHERE system_name = ?
13 | level.read=SELECT MAX(patch_level) FROM patches WHERE system_name = ?
14 | level.rollback=DELETE FROM patches WHERE patch_level = ? and system_name = ?
15 | level.update=INSERT INTO patches (patch_level, system_name, patch_date) VALUES ( ?, ?, CURRENT_TIMESTAMP)
16 | level.exists=SELECT patch_level FROM patches WHERE system_name=? and patch_level=?
17 |
18 | patches.all=SELECT patch_level FROM patches WHERE system_name = ?
19 |
20 | # Since most DBs do not have a boolean type, return 0 or 1 row to determine if
21 | # the system is currently locked.
22 | lock.read=SELECT patch_in_progress FROM patches WHERE system_name = ? AND ( patch_in_progress <> 'F' OR patch_level in ( SELECT MAX(patch_level) FROM patches WHERE system_name = ? ))
23 | lock.obtain=UPDATE patches SET patch_in_progress = 'T' WHERE system_name = ? AND patch_in_progress = 'F' AND patch_level in ( SELECT max_patch_level FROM (SELECT MAX(patch_level) AS max_patch_level FROM patches WHERE system_name = ? ) AS tmptable )
24 | lock.release=UPDATE patches SET patch_in_progress = 'F' WHERE system_name = ? AND patch_in_progress <> 'F'
--------------------------------------------------------------------------------
/src/main/resources/com/tacitknowledge/util/migration/jdbc/sybase.properties:
--------------------------------------------------------------------------------
1 | supportsMultipleStatements=false
2 |
3 | patches.create=CREATE TABLE patches (\
4 | system_name VARCHAR(30) NOT NULL PRIMARY KEY,\
5 | patch_level INT NOT NULL,\
6 | patch_date DATETIME DEFAULT getdate() NOT NULL,\
7 | patch_in_progress CHAR(1) DEFAULT 'F' NOT NULL,\
8 | primary key clustered (system_name, patch_level))
9 |
10 | # Validates that a record exists for a given system
11 | level.create=INSERT INTO patches (system_name, patch_level) VALUES ( ?, 0 )
12 | level.table.exists=SELECT patch_level FROM patches WHERE system_name = ?
13 | level.read=SELECT MAX(patch_level) FROM patches WHERE system_name = ?
14 | level.rollback=DELETE FROM patches WHERE patch_level = ? and system_name = ?
15 | level.update=INSERT INTO patches (patch_level, system_name, patch_date) VALUES ( ?, ?, getdate())
16 | level.exists=SELECT patch_level FROM patches WHERE system_name=? and patch_level=?
17 |
18 | patches.all=SELECT patch_level FROM patches WHERE system_name = ?
19 |
20 | # Since most DBs do not have a boolean type, return 0 or 1 row to determine if
21 | # the system is currently locked.
22 | lock.read=SELECT patch_in_progress FROM patches WHERE system_name = ? AND ( patch_in_progress <> 'F' OR patch_level in ( SELECT MAX(patch_level) FROM patches WHERE system_name = ? ))
23 | lock.obtain=UPDATE patches SET patch_in_progress = 'T' WHERE system_name = ? AND patch_in_progress = 'F' AND patch_level in ( SELECT MAX(patch_level) FROM patches WHERE system_name = ? )
24 | lock.release=UPDATE patches SET patch_in_progress = 'F' WHERE system_name = ? AND patch_in_progress <> 'F'
25 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/tasks/rollback/migrationtasks/TestMigrationTaskRollback1.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.tasks.rollback.migrationtasks;
17 |
18 | import com.tacitknowledge.util.migration.MigrationContext;
19 | import com.tacitknowledge.util.migration.MigrationException;
20 | import com.tacitknowledge.util.migration.MigrationTaskSupport;
21 | import com.tacitknowledge.util.migration.RollbackableMigrationTask;
22 | import com.tacitknowledge.util.migration.TestMigrationContext;
23 |
24 | public class TestMigrationTaskRollback1 extends MigrationTaskSupport implements RollbackableMigrationTask
25 | {
26 |
27 | public TestMigrationTaskRollback1()
28 | {
29 | setName("TestMigrationTaskRollback1");
30 | setLevel(new Integer(13));
31 | }
32 |
33 | public void migrate(MigrationContext context) throws MigrationException
34 | {
35 | if (context instanceof TestMigrationContext)
36 | {
37 | TestMigrationContext ctx = (TestMigrationContext) context;
38 | ctx.recordExecution(getName());
39 | }
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/integration-test/resources/inttest-migration.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Which context do we use for the orchestration patch store? Core.
3 | #
4 | integration_test.context=core
5 | integration_test.controlled.systems=core,orders,catalog
6 | integration_test.listeners=com.tacitknowledge.util.migration.listeners.WhinyMigrationListener
7 |
8 | # Configure a context named "core"
9 | #
10 | core.jdbc.database.type=hsqldb
11 | core.jdbc.driver=org.hsqldb.jdbcDriver
12 | core.jdbc.url=jdbc:hsqldb:mem:core
13 | core.jdbc.username=sa
14 | core.jdbc.password=
15 | core.patch.path=com.tacitknowledge.util.migration.inttest-tasks.core
16 | #
17 | # Configure a context named "orders"
18 | #
19 | orders.jdbc.database.type=hsqldb
20 | orders.jdbc.driver=org.hsqldb.jdbcDriver
21 | orders.jdbc.url=jdbc:hsqldb:mem:orders
22 | orders.jdbc.username=sa
23 | orders.jdbc.password=
24 | orders.patch.path=com.tacitknowledge.util.migration.inttest-tasks.order
25 |
26 | #
27 | # Configure a context named catalog, and make it a multi-node context
28 | #
29 | catalog.jdbc.systems=jdbccatalog1,jdbccatalog2,jdbccatalog3
30 | catalog.jdbccatalog1.database.type=hsqldb
31 | catalog.jdbccatalog1.driver=org.hsqldb.jdbcDriver
32 | catalog.jdbccatalog1.url=jdbc:hsqldb:mem:catalog1
33 | catalog.jdbccatalog1.username=sa
34 | catalog.jdbccatalog1.password=
35 | catalog.jdbccatalog2.database.type=hsqldb
36 | catalog.jdbccatalog2.driver=org.hsqldb.jdbcDriver
37 | catalog.jdbccatalog2.url=jdbc:hsqldb:mem:catalog2
38 | catalog.jdbccatalog2.username=sa
39 | catalog.jdbccatalog2.password=
40 | catalog.jdbccatalog3.database.type=hsqldb
41 | catalog.jdbccatalog3.driver=org.hsqldb.jdbcDriver
42 | catalog.jdbccatalog3.url=jdbc:hsqldb:mem:catalog3
43 | catalog.jdbccatalog3.username=sa
44 | catalog.jdbccatalog3.password=
45 | catalog.patch.path=com.tacitknowledge.util.migration.inttest-tasks.catalog
--------------------------------------------------------------------------------
/examples/distributed-sample/build.xml:
--------------------------------------------------------------------------------
1 | TestMigrationTask3.
36 | */
37 | public TestMigrationTask3()
38 | {
39 | super("TestTask3", 6);
40 | }
41 |
42 | /**
43 | * @see BaseTestMigrationTask#migrate(MigrationContext)
44 | */
45 | public void migrate(MigrationContext context) throws MigrationException
46 | {
47 | if (fail)
48 | {
49 | throw new MigrationException("Test exception");
50 | }
51 | super.migrate(context);
52 | }
53 |
54 | /**
55 | * Determins if the task should simulate a MigrationException
56 | *
57 | * @param f trueif the task should simulate a MigrationException
58 | */
59 | public static void setFail(boolean f)
60 | {
61 | TestMigrationTask3.fail = f;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/tasks/normal/TestMigrationTask2.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.tasks.normal;
17 |
18 | import com.tacitknowledge.util.migration.tasks.BaseTestMigrationTask;
19 |
20 | /**
21 | * Basic test migration task.
22 | *
23 | * @author Scott Askew (scott@tacitknowledge.com)
24 | */
25 | public class TestMigrationTask2 extends BaseTestMigrationTask
26 | {
27 | /**
28 | * The patch level to use instead of '2'
29 | */
30 | private static Integer patchLevelOverride = new Integer(5);
31 |
32 | /**
33 | * Creates a new TestMigrationTask3.
34 | */
35 | public TestMigrationTask2()
36 | {
37 | super("TestTask2", 5);
38 | }
39 |
40 | /**
41 | * @see com.tacitknowledge.util.migration.MigrationTaskSupport#getLevel()
42 | */
43 | public Integer getLevel()
44 | {
45 | return patchLevelOverride;
46 | }
47 |
48 | /**
49 | * Sets the patch level to use for all instances of this class.
50 | *
51 | * @param level the patch level to use for all instances of this class; if
52 | * null, then the default patch level (2) will be used
53 | */
54 | public static void setPatchLevelOverride(Integer level)
55 | {
56 | patchLevelOverride = level;
57 | }
58 |
59 | /**
60 | * Resets the task the its default state.
61 | */
62 | public static void reset()
63 | {
64 | patchLevelOverride = new Integer(5);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/integration-test/resources/node-added-inttest-migration.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Which context do we use for the orchestration patch store? Core.
3 | #
4 | integration_test.context=core
5 | integration_test.controlled.systems=core,orders,catalog
6 | #
7 | # Configure a context named "core"
8 | #
9 | core.jdbc.database.type=hsqldb
10 | core.jdbc.driver=org.hsqldb.jdbcDriver
11 | core.jdbc.url=jdbc:hsqldb:mem:core
12 | core.jdbc.username=sa
13 | core.jdbc.password=
14 | core.patch.path=com.tacitknowledge.util.migration.inttest-tasks.core
15 | #
16 | # Configure a context named "orders"
17 | #
18 | orders.jdbc.database.type=hsqldb
19 | orders.jdbc.driver=org.hsqldb.jdbcDriver
20 | orders.jdbc.url=jdbc:hsqldb:mem:orders
21 | orders.jdbc.username=sa
22 | orders.jdbc.password=
23 | orders.patch.path=com.tacitknowledge.util.migration.inttest-tasks.order
24 | #
25 | # Configure a context named catalog, and make it a multi-node context
26 | #
27 | catalog.jdbc.systems=jdbccatalog1,jdbccatalog2,jdbccatalog3,jdbccatalog4,jdbccatalog5
28 | catalog.jdbccatalog1.database.type=hsqldb
29 | catalog.jdbccatalog1.driver=org.hsqldb.jdbcDriver
30 | catalog.jdbccatalog1.url=jdbc:hsqldb:mem:catalog1
31 | catalog.jdbccatalog1.username=sa
32 | catalog.jdbccatalog1.password=
33 | catalog.jdbccatalog2.database.type=hsqldb
34 | catalog.jdbccatalog2.driver=org.hsqldb.jdbcDriver
35 | catalog.jdbccatalog2.url=jdbc:hsqldb:mem:catalog2
36 | catalog.jdbccatalog2.username=sa
37 | catalog.jdbccatalog2.password=
38 | catalog.jdbccatalog3.database.type=hsqldb
39 | catalog.jdbccatalog3.driver=org.hsqldb.jdbcDriver
40 | catalog.jdbccatalog3.url=jdbc:hsqldb:mem:catalog3
41 | catalog.jdbccatalog3.username=sa
42 | catalog.jdbccatalog3.password=
43 | catalog.jdbccatalog4.database.type=hsqldb
44 | catalog.jdbccatalog4.driver=org.hsqldb.jdbcDriver
45 | catalog.jdbccatalog4.url=jdbc:hsqldb:mem:catalog4
46 | catalog.jdbccatalog4.username=sa
47 | catalog.jdbccatalog4.password=
48 | catalog.jdbccatalog5.database.type=hsqldb
49 | catalog.jdbccatalog5.driver=org.hsqldb.jdbcDriver
50 | catalog.jdbccatalog5.url=jdbc:hsqldb:mem:catalog5
51 | catalog.jdbccatalog5.username=sa
52 | catalog.jdbccatalog5.password=
53 | catalog.patch.path=com.tacitknowledge.util.migration.inttest-tasks.catalog
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/AbstractMigrationListener.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | /**
19 | * Abstract base class for MigrationListener authors that aren't interested in
20 | * implementing all the MigrationListener events.
21 | *
22 | * @author Alex Soto (apsoto@gmail.com)
23 | */
24 | public abstract class AbstractMigrationListener implements MigrationListener
25 | {
26 |
27 | /**
28 | * @see com.tacitknowledge.util.migration.MigrationListener#migrationFailed(com.tacitknowledge.util.migration.MigrationTask, com.tacitknowledge.util.migration.MigrationContext, com.tacitknowledge.util.migration.MigrationException)
29 | */
30 | public void migrationFailed(MigrationTask task, MigrationContext context,
31 | MigrationException e) throws MigrationException
32 | {
33 | }
34 |
35 | /**
36 | * @see com.tacitknowledge.util.migration.MigrationListener#migrationStarted(com.tacitknowledge.util.migration.MigrationTask, com.tacitknowledge.util.migration.MigrationContext)
37 | */
38 | public void migrationStarted(MigrationTask task, MigrationContext context)
39 | throws MigrationException
40 | {
41 | }
42 |
43 | /**
44 | * @see com.tacitknowledge.util.migration.MigrationListener#migrationSuccessful(com.tacitknowledge.util.migration.MigrationTask, com.tacitknowledge.util.migration.MigrationContext)
45 | */
46 | public void migrationSuccessful(MigrationTask task, MigrationContext context)
47 | throws MigrationException
48 | {
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/RollbackableMigrationTask.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | /**
19 | * A single, idempotent and migration task, which also supports rollbacks.
20 | *
21 | * @author Artie Pesh-Imam (apeshimam@tacitknowledge.com)
22 | */
23 | public interface RollbackableMigrationTask extends MigrationTask
24 | {
25 |
26 | /**
27 | * Performs a migration
28 | *
29 | * @param context the MigrationContext for this run.
30 | * @throws MigrationException if an unexpected error occurs
31 | */
32 | public void up(MigrationContext context) throws MigrationException;
33 |
34 | /**
35 | * Performs a rollback
36 | *
37 | * @param context the MigrationContext for this run.
38 | * @throws MigrationException if an unexpected error occurrs
39 | */
40 | public void down(MigrationContext context) throws MigrationException;
41 |
42 | /**
43 | * Returns a boolean indicating if this task can be rolled back.
44 | *
45 | * @return a boolean indicating if the task can be rolled back.
46 | */
47 | public boolean isRollbackSupported();
48 |
49 | /**
50 | * Returns the name of this migration task.
51 | *
52 | * @return the name of this migration task
53 | */
54 | public String getName();
55 |
56 | /**
57 | * Returns the relative order in which this migration should occur.
58 | *
59 | * @return the relative order in which this migration should occur; may never
60 | * return null
61 | */
62 | public Integer getLevel();
63 | }
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | AutoPatch
2 | =========
3 |
4 | AutoPatch automates the application of changes to persistent storage.
5 |
6 | AutoPatch was born from the needs of using an agile development process
7 | while working on systems that have persistent storage. Without
8 | AutoPatch, developers usually can't afford the maintenance headache of
9 | their own database, and DBAs are required just to apply changes to all
10 | of the various environments a serious development effort requires.
11 |
12 | The very application of database changes becomes an inefficient,
13 | error-prone, expensive process, all conspiring to discourage any
14 | refactoring that touches the model, or being a bottleneck when model
15 | changes are made.
16 |
17 | AutoPatch solves this problem, completely.
18 |
19 | With AutoPatch, an agile development process that requires a database
20 | change looks like this:
21 |
22 | * Developer alters the model, which requires a change to the database
23 | * Developer possibly consults a DBA, and develops a SQL patch against
24 | their personal database that implements the alteration
25 | * Developer commits the patch to source control at the same time as they
26 | commit their dependent code
27 | * Other developers' and environments' databases are automatically updated
28 | by AutoPatch the next time the new source is run
29 |
30 | This represents streamlined environment maintenance, allowing developers
31 | to cheaply have their own databases and all databases to stay in synch
32 | with massively lower costs and no environment skew.
33 |
34 | Requirements
35 | ------------
36 |
37 | * Java 6. That's it.
38 |
39 |
40 | Where do I get AutoPatch?
41 | -------------------------
42 | AutoPatch is open source and is hosted at [Github](http://github.com/tacitknowledge/autopatch).
43 |
44 | The documentation for AutoPatch is on the [AutoPatch Wiki](https://github.com/tacitknowledge/autopatch/wiki)
45 |
46 | You can include AutoPatch in your Maven project via:
47 |
48 | MigrationContext by adding a log of test executions.
25 | *
26 | * @author Scott Askew (scott@tacitknowledge.com)
27 | */
28 | public class TestMigrationContext extends DataSourceMigrationContext
29 | {
30 | /**
31 | * A record of task executions
32 | */
33 | private Map executionLog = new HashMap();
34 |
35 | /**
36 | * Records a successful task execution
37 | *
38 | * @param taskName the name of the task
39 | */
40 | public void recordExecution(String taskName)
41 | {
42 | executionLog.put(taskName, Boolean.TRUE);
43 | }
44 |
45 | /**
46 | * Determines if the given task has been executed
47 | *
48 | * @param taskName the name of the task to validate
49 | * @return true if the task has successfully executed
50 | */
51 | public boolean hasExecuted(String taskName)
52 | {
53 | return executionLog.containsKey(taskName);
54 | }
55 |
56 | /**
57 | * @see com.tacitknowledge.util.migration.MigrationContext#commit()
58 | */
59 | public void commit() throws MigrationException
60 | {
61 | // does nothing
62 | }
63 |
64 | /**
65 | * @see com.tacitknowledge.util.migration.MigrationContext#rollback()
66 | */
67 | public void rollback() throws MigrationException
68 | {
69 | // does nothing
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/tasks/rollback/TestRollbackableTask2.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.tasks.rollback;
17 |
18 | import com.tacitknowledge.util.migration.MigrationContext;
19 | import com.tacitknowledge.util.migration.MigrationException;
20 | import com.tacitknowledge.util.migration.RollbackableMigrationTask;
21 | import com.tacitknowledge.util.migration.TestMigrationContext;
22 |
23 | public class TestRollbackableTask2 extends BaseTestRollbackableMigrationTask
24 | implements RollbackableMigrationTask
25 | {
26 | private static Integer patchLevelOverride = new Integer(9);
27 |
28 | public static void setPatchLevelOverride(Integer i)
29 | {
30 | patchLevelOverride = (i);
31 | }
32 |
33 | public Integer getLevel()
34 | {
35 | return patchLevelOverride;
36 | }
37 |
38 | public static void reset()
39 | {
40 | patchLevelOverride = new Integer(9);
41 | }
42 |
43 | public TestRollbackableTask2()
44 | {
45 | super("TestRollbackableTask2", 9);
46 | }
47 |
48 | public void down(MigrationContext context) throws MigrationException
49 | {
50 | if (context instanceof TestMigrationContext)
51 | {
52 | TestMigrationContext ctx = (TestMigrationContext) context;
53 | ctx.recordExecution(getName());
54 | }
55 | }
56 |
57 | public void up(MigrationContext context) throws MigrationException
58 | {
59 | if (context instanceof TestMigrationContext)
60 | {
61 | TestMigrationContext ctx = (TestMigrationContext) context;
62 | ctx.recordExecution(getName());
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/integration-test/java/com/tacitknowledge/util/migration/listeners/WhinyMigrationListener.java:
--------------------------------------------------------------------------------
1 | package com.tacitknowledge.util.migration.listeners;
2 |
3 |
4 | import com.tacitknowledge.util.migration.MigrationContext;
5 | import com.tacitknowledge.util.migration.MigrationException;
6 | import com.tacitknowledge.util.migration.MigrationListener;
7 | import com.tacitknowledge.util.migration.MigrationTask;
8 | import com.tacitknowledge.util.migration.jdbc.JdbcMigrationContext;
9 | import org.apache.commons.logging.Log;
10 | import org.apache.commons.logging.LogFactory;
11 |
12 | import java.util.Properties;
13 |
14 |
15 | /**
16 | * @author Alex Soto (apsoto@gmail.com)
17 | */
18 | public class WhinyMigrationListener implements MigrationListener
19 | {
20 | /**
21 | * Class logger
22 | */
23 | private static Log log = LogFactory.getLog(WhinyMigrationListener.class);
24 |
25 | protected String getTaskInfo(MigrationTask task, MigrationContext context)
26 | {
27 | String ctxInfo = "";
28 | if (context instanceof JdbcMigrationContext)
29 | {
30 | JdbcMigrationContext ctx = (JdbcMigrationContext) context;
31 | ctxInfo += ctx.getSystemName() + " : " + ctx.getDatabaseName();
32 | }
33 |
34 | return "Task => (" + task.toString() + "), Context => (" + ctxInfo + ")";
35 | }
36 |
37 | public void migrationFailed(MigrationTask task, MigrationContext context, MigrationException e) throws MigrationException
38 | {
39 | log.debug("MIGRATION FAILED, " + getTaskInfo(task, context) + " WAHHH!!!");
40 | }
41 |
42 | public void migrationStarted(MigrationTask task, MigrationContext context) throws MigrationException
43 | {
44 | log.debug("MIGRATION STARTED, " + getTaskInfo(task, context) + " WAHHH!!!");
45 | }
46 |
47 | public void migrationSuccessful(MigrationTask task, MigrationContext context) throws MigrationException
48 | {
49 | log.debug("MIGRATION SUCCEEDED, " + getTaskInfo(task, context) + " WAHHH!!!");
50 | }
51 |
52 | /**
53 | * @see com.tacitknowledge.util.migration.MigrationListener#initialize(Properties)
54 | */
55 | public void initialize(String systemName, Properties properties) throws MigrationException
56 | {
57 | log.debug("MIGRATION LISTENER INTIALIZED FOR " + systemName + " SYSTEM, WAHHH!!!");
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/tasks/rollback/BaseTestRollbackableMigrationTask.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.tasks.rollback;
17 |
18 | import com.tacitknowledge.util.migration.MigrationContext;
19 | import com.tacitknowledge.util.migration.MigrationException;
20 | import com.tacitknowledge.util.migration.MigrationTaskSupport;
21 | import com.tacitknowledge.util.migration.TestMigrationContext;
22 |
23 | /**
24 | * Base class for rollback task tests.
25 | *
26 | * @author Artie Pesh-Imam (apeshimam@tacitknowledge.com)
27 | */
28 | public abstract class BaseTestRollbackableMigrationTask extends MigrationTaskSupport
29 | {
30 | /**
31 | * Create a new BaseTestRollbackableMigrationTask.
32 | *
33 | * @param name
34 | * the name of the task
35 | * @param level
36 | * the patch level of the task
37 | */
38 | protected BaseTestRollbackableMigrationTask(String name, int level)
39 | {
40 | setName(name);
41 | setLevel(new Integer(level));
42 | }
43 |
44 | /**
45 | * Perform a rollback
46 | * @param context migration context
47 | * @throws MigrationException if an error happens
48 | */
49 | public void down(MigrationContext context) throws MigrationException
50 | {
51 | if (context instanceof TestMigrationContext)
52 | {
53 | TestMigrationContext ctx = (TestMigrationContext) context;
54 | ctx.recordExecution(getName());
55 | }
56 | }
57 |
58 | /**
59 | * Return true indicating that rollback is supported
60 | * @return true if rollback is supported.
61 | */
62 | public boolean isRollbackSupported()
63 | {
64 | return true;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/MigrationRunnerStrategy.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * Dictates the methods that different algorithms should run when we
22 | * try to apply patches or get information about the patches that need to be run.
23 | *
24 | * @author Oscar Gonzalez (oscar@tacitknowledge.com)
25 | * @author Hemri Herrera (hemri@tacitknowledge.com)
26 | * @author Ulises Pulido (upulido@tacitknowledge.com)
27 | */
28 |
29 | public interface MigrationRunnerStrategy
30 | {
31 | /**
32 | * Determines if a MigrationTask is able to run.
33 | *
34 | * @param migrationLevel of the MigrationTask to be check as in int
35 | * @param patchInfoStore object representing patch level information
36 | * @return boolean value telling us if we should run the migration or not.
37 | */
38 | public boolean shouldMigrationRun(int migrationLevel, PatchInfoStore patchInfoStore) throws MigrationException;
39 |
40 | /**
41 | * Determines if two stores are synchronized to each other.
42 | *
43 | * @param currentPatchInfoStore
44 | * @param patchInfoStore
45 | * @return
46 | * @throws MigrationException
47 | */
48 | public boolean isSynchronized(PatchInfoStore currentPatchInfoStore, PatchInfoStore patchInfoStore) throws MigrationException;
49 |
50 | /**
51 | * Retrieves all tasks that are candidates for rollback.
52 | *
53 | * @param allMigrationTasks
54 | * @param rollbackLevels
55 | * @param currentPatchInfoStore
56 | * @return
57 | * @throws MigrationException
58 | */
59 | public ListBaseTestMigrationTask.
32 | *
33 | * @param name the name of the task
34 | * @param level the patch level of the task
35 | */
36 | protected BaseTestMigrationTask(String name, int level)
37 | {
38 | setName(name);
39 | setLevel(new Integer(level));
40 | }
41 |
42 | /**
43 | * @see MigrationTaskSupport#migrate(MigrationContext)
44 | */
45 | public void migrate(MigrationContext context) throws MigrationException
46 | {
47 | if (context instanceof TestMigrationContext)
48 | {
49 | TestMigrationContext ctx = (TestMigrationContext) context;
50 | ctx.recordExecution(getName());
51 | }
52 | }
53 |
54 | public void up(MigrationContext context) throws MigrationException
55 | {
56 | if (context instanceof TestMigrationContext)
57 | {
58 | TestMigrationContext ctx = (TestMigrationContext) context;
59 | ctx.recordExecution(getName());
60 | }
61 | }
62 |
63 | public void down(MigrationContext context) throws MigrationException
64 | {
65 | if (context instanceof TestMigrationContext)
66 | {
67 | TestMigrationContext ctx = (TestMigrationContext) context;
68 | ctx.recordExecution(getName());
69 | }
70 | }
71 |
72 | public boolean isRollbackSupported() {
73 | return true;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/MigrationListener.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | import java.util.Properties;
19 |
20 | /**
21 | * Receives notifications regarding migration task migrations.
22 | *
23 | * @author Scott Askew (scott@tacitknowledge.com)
24 | */
25 | public interface MigrationListener
26 | {
27 | /**
28 | * Initialize the migration listener. This provides an opportunity
29 | * for the MigrationListener to initialize itself before patching
30 | * begins.
31 | *
32 | * @param properties The properties loaded from migration.properties
33 | */
34 | public void initialize(String systemName, Properties properties) throws MigrationException;
35 |
36 | /**
37 | * Notifies the listener that the given task is about to start execution.
38 | *
39 | * @param task the recently finished task
40 | * @param context the migration context
41 | * @throws MigrationException if an unrecoverable error occurs
42 | */
43 | public void migrationStarted(MigrationTask task, MigrationContext context)
44 | throws MigrationException;
45 |
46 | /**
47 | * Notifies the listener that the given task has completed execution.
48 | *
49 | * @param task the recently finished task
50 | * @param context the migration context
51 | * @throws MigrationException if an unrecoverable error occurs
52 | */
53 | public void migrationSuccessful(MigrationTask task, MigrationContext context)
54 | throws MigrationException;
55 |
56 | /**
57 | * Notifies the listener that the given task has completed execution.
58 | *
59 | * @param task the recently finished task
60 | * @param context the migration context
61 | * @param e the MigrationException thrown by the task
62 | * @throws MigrationException if an unrecoverable error occurs
63 | */
64 | public void migrationFailed(MigrationTask task,
65 | MigrationContext context, MigrationException e) throws MigrationException;
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/jdbc/JdbcMigrationLauncherFactoryLoader.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc;
17 |
18 | import org.apache.commons.logging.Log;
19 | import org.apache.commons.logging.LogFactory;
20 |
21 | /**
22 | * Load a MigrationLauncherFactory. This will default to loading the
23 | * JdbcMigrationLauncherFactory, but will examine the system properties
24 | * for a property called "migration.factory" and load that one if specified
25 | *
26 | * @author Jacques Morel
27 | */
28 | public class JdbcMigrationLauncherFactoryLoader
29 | {
30 | /**
31 | * Class logger
32 | */
33 | private static Log log = LogFactory.getLog(JdbcMigrationLauncherFactoryLoader.class);
34 |
35 |
36 | /**
37 | * Create the JdbcMigrationLauncherFactory
38 | *
39 | * @return JdbcMigrationLauncherFactory (or subclass)
40 | */
41 | public JdbcMigrationLauncherFactory createFactory()
42 | {
43 | // Get the factory name from the system properties if possible
44 | String factoryName = System.getProperties().getProperty("migration.factory");
45 | if (factoryName == null)
46 | {
47 | factoryName = JdbcMigrationLauncherFactory.class.getName();
48 | }
49 | log.debug("Creating JdbcMigrationLauncher using " + factoryName);
50 |
51 | // Load the factory
52 | Class factoryClass = null;
53 | try
54 | {
55 | factoryClass = Class.forName(factoryName);
56 | }
57 | catch (ClassNotFoundException e)
58 | {
59 | throw new IllegalArgumentException("Migration factory class '"
60 | + factoryName + "' not found. Aborting.");
61 | }
62 | try
63 | {
64 | return (JdbcMigrationLauncherFactory) factoryClass.newInstance();
65 | }
66 | catch (Exception e)
67 | {
68 | throw new RuntimeException("Problem while instantiating factory class '"
69 | + factoryName + "'. Aborting.", e);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/ClassMigrationTaskSourceTest.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | import java.util.List;
19 |
20 | import junit.framework.TestCase;
21 |
22 | /**
23 | * Exercise the ClassMigrationTaskSource object
24 | *
25 | * @author Mike Hardy (mike@tacitknowledge.com)
26 | */
27 | public class ClassMigrationTaskSourceTest extends TestCase
28 | {
29 | /**
30 | * Make sure class instantiation fails on null package name
31 | */
32 | public void testInstantiateTasksNullPackage()
33 | {
34 | ClassMigrationTaskSource source = new ClassMigrationTaskSource();
35 | try
36 | {
37 | source.getMigrationTasks(null);
38 | fail("We should have gotten an exception for the null package");
39 | }
40 | catch (MigrationException me)
41 | {
42 | // we expect this
43 | }
44 | }
45 |
46 | /**
47 | * Make sure class instantiation fails on package with no types
48 | */
49 | public void testInstantiateTasksNoTasks()
50 | {
51 | ClassMigrationTaskSource source = new ClassMigrationTaskSource();
52 | try
53 | {
54 | List tasks = source.getMigrationTasks("com.tacitknowledge.foo.bar");
55 | assertEquals(0, tasks.size());
56 | }
57 | catch (MigrationException me)
58 | {
59 | fail("We should not have gotten an exception");
60 | }
61 | }
62 |
63 | /**
64 | * Make sure class instantiation fails on package with bad tasks
65 | */
66 | public void testInstantiateTasksInstantiationException()
67 | {
68 | ClassMigrationTaskSource source = new ClassMigrationTaskSource();
69 | try
70 | {
71 | source.getMigrationTasks(getClass().getPackage().getName() + ".tasks.instantiation");
72 | fail("We should have gotten an exception");
73 | }
74 | catch (MigrationException me)
75 | {
76 | assertTrue(me.getCause() instanceof RuntimeException);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/PatchRollbackPredicate.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | import org.apache.commons.collections.Predicate;
19 |
20 | /**
21 | * This class defines a predicate for CollectionUtils which evaluates if a
22 | * given RollbackableMigrationTask should remain in the collection
23 | *
24 | * @author Artie Pesh-Imam (apeshimam@tacitknowledge.com)
25 | * @see Predicate
26 | */
27 | public class PatchRollbackPredicate implements Predicate
28 | {
29 | /* initialize both to max value */
30 | private int rollbackPatchLevel = Integer.MAX_VALUE;
31 | private int currentPatchLevel = Integer.MAX_VALUE;
32 |
33 | /**
34 | * Constructor for this predicate. The current patch level and the rollback
35 | * patch level are set in this constructor.
36 | *
37 | * @param currentPatchLevel
38 | * @param rollbackPatchLevel
39 | */
40 | public PatchRollbackPredicate(int currentPatchLevel, int rollbackPatchLevel)
41 | {
42 | this.rollbackPatchLevel = rollbackPatchLevel;
43 | this.currentPatchLevel = currentPatchLevel;
44 | }
45 |
46 | /**
47 | * The evaluate method returns false if the passed object is:
48 | * RollbackableMigrationTaskMigrationException thrown by the task
63 | * @throws MigrationException if an unrecoverable error occurs
64 | */
65 | public void rollbackFailed(RollbackableMigrationTask task,
66 | MigrationContext context, MigrationException e) throws MigrationException;
67 |
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/jdbc/loader/FileLoadingUtility.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc.loader;
17 |
18 | import org.apache.commons.logging.Log;
19 | import org.apache.commons.logging.LogFactory;
20 |
21 | import java.io.File;
22 | import java.io.FileInputStream;
23 | import java.io.FileNotFoundException;
24 | import java.io.InputStream;
25 |
26 | /**
27 | * This is a very simple utility that looks for a file
28 | * based upon its existence in the classpath or the
29 | * absolute path if provided.
30 | *
31 | * @author Chris A. (chris@tacitknowledge.com)
32 | */
33 | public class FileLoadingUtility
34 | {
35 | /**
36 | * Class logger
37 | */
38 | private static Log log = LogFactory.getLog(FileLoadingUtility.class);
39 |
40 | /**
41 | * The name of the file to load
42 | */
43 | private String fileName = null;
44 |
45 | /**
46 | * Creates a new FileLoadingUtility.
47 | *
48 | * @param fileName the name of the file to load
49 | */
50 | public FileLoadingUtility(String fileName)
51 | {
52 | this.fileName = fileName;
53 | }
54 |
55 | /**
56 | * Gets an input stream by first checking the current classloader,
57 | * then trying to use the system classloader, and finally, trying
58 | * to access the file on the file system. If the file is not found,
59 | * an IllegalArgumentException will be thrown.
60 | *
61 | * @return the file as an input stream
62 | */
63 | public InputStream getResourceAsStream()
64 | {
65 | InputStream stream =
66 | Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
67 | if (stream == null)
68 | {
69 | stream = ClassLoader.getSystemResourceAsStream(fileName);
70 |
71 | }
72 | if (stream == null)
73 | {
74 | File f = new File(fileName);
75 | try
76 | {
77 | stream = new FileInputStream(f);
78 | }
79 | catch (FileNotFoundException e)
80 | {
81 | log.error("The file: " + fileName + " was not found.", e);
82 | throw new IllegalArgumentException("Must have a valid file name.");
83 | }
84 | }
85 | return stream;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/test/java/com/tacitknowledge/util/migration/jdbc/StandaloneMigrationLauncherTest.java:
--------------------------------------------------------------------------------
1 | package com.tacitknowledge.util.migration.jdbc;
2 |
3 | import com.tacitknowledge.util.migration.MigrationException;
4 | import com.tacitknowledge.util.migration.jdbc.util.MigrationUtil;
5 | import junit.framework.TestCase;
6 | import org.easymock.EasyMock;
7 | import org.easymock.classextension.IMocksControl;
8 |
9 | import static org.easymock.EasyMock.eq;
10 | import static org.easymock.classextension.EasyMock.createStrictControl;
11 |
12 | /**
13 | * @author Hemri Herrera hemri@tacitknowledge.com
14 | * @author Ulises Pulido ulises@tacitknowledge.com
15 | */
16 |
17 | public class StandaloneMigrationLauncherTest extends TestCase
18 | {
19 |
20 | public void testShouldRunMigrationsForcingRollback() throws Exception
21 | {
22 | IMocksControl mockControl = createStrictControl();
23 | MigrationUtil migrationUtil = mockControl.createMock(MigrationUtil.class);
24 | StandaloneMigrationLauncher migrationLauncher = new StandaloneMigrationLauncher(migrationUtil);
25 | String[] arguments = new String[]{"orders","migration.properties","-force", "-rollback", "1"};
26 |
27 |
28 | migrationUtil.doRollbacks(eq("orders"), eq("migration.properties"), EasyMock.MigrationTask in a specific package.
28 | *
29 | * @author Scott Askew (scott@tacitknowledge.com)
30 | */
31 | public class ClassMigrationTaskSource implements MigrationTaskSource
32 | {
33 | /**
34 | * Class logger
35 | */
36 | private static Log log = LogFactory.getLog(ClassMigrationTaskSource.class);
37 |
38 | /**
39 | * {@inheritDoc}
40 | */
41 | public ListMigrationTasks
58 | * @throws MigrationException if a class could not be instantiated; this
59 | * is most likely due to the abscense of a default constructor
60 | */
61 | private Listtrue if the patch store is already locked
57 | * @throws MigrationException if checking for the lock fails
58 | */
59 | public boolean isPatchStoreLocked() throws MigrationException;
60 |
61 | /**
62 | * Places a lock for this system on the patch store
63 | *
64 | * @throws MigrationException if locking the store fails
65 | * @throws IllegalStateException if a lock already exists
66 | */
67 | public void lockPatchStore() throws MigrationException, IllegalStateException;
68 |
69 | /**
70 | * Removes any locks for this system on the patch store
71 | *
72 | * @throws MigrationException if unlocking the store fails
73 | */
74 | public void unlockPatchStore() throws MigrationException;
75 |
76 | /**
77 | * Determines if a given patch has been applied in the system
78 | *
79 | * @throws MigrationException if unlocking the store fails
80 | */
81 | public boolean isPatchApplied(int patchLevel) throws MigrationException;
82 |
83 | /**
84 | * Updates the system patch level to the specified value after rollback
85 | *
86 | * @param rollbackLevel the new system patch level
87 | * @throws MigrationException if updating the patch level failed
88 | */
89 | public void updatePatchLevelAfterRollBack(int rollbackLevel) throws MigrationException;
90 |
91 | /**
92 | * Obtains all patches applied in the system.
93 | *
94 | * @return a set containing all patches number applied in the system.
95 | * @throws MigrationException if retrieving patches fails.
96 | */
97 | public SetgetName(). Calls the
49 | * abstract method processWorkbook()
50 | *
51 | * @param ctx the JdbcMigrationContext
52 | * @throws MigrationException if an unexpected error occurs
53 | */
54 | public void migrate(MigrationContext ctx) throws MigrationException
55 | {
56 | DataSourceMigrationContext context = (DataSourceMigrationContext) ctx;
57 | FileLoadingUtility utility = new FileLoadingUtility(getName());
58 | Connection conn = null;
59 |
60 | try
61 | {
62 | conn = context.getConnection();
63 | POIFSFileSystem fs = new POIFSFileSystem(utility.getResourceAsStream());
64 | HSSFWorkbook wb = new HSSFWorkbook(fs);
65 | processWorkbook(wb, conn);
66 | context.commit();
67 | }
68 | catch (IOException e)
69 | {
70 | log.error("An IO Exception occurred while trying to parse the Excel file.", e);
71 | context.rollback();
72 | throw new MigrationException("Error reading file.", e);
73 | }
74 | catch (SQLException e)
75 | {
76 | log.error("Caught a SQLException when trying to obtain a database connection");
77 | context.rollback();
78 | throw new MigrationException("Error obtaining database connection", e);
79 | }
80 | finally
81 | {
82 | SqlUtil.close(conn, null, null);
83 | }
84 | }
85 |
86 | /**
87 | * Process workbook by overwriting this method
88 | *
89 | * @param wb the excel workbook to process
90 | * @param conn the database connection to use for data loading
91 | * @throws MigrationException if something goes wrong
92 | */
93 | public abstract void processWorkbook(HSSFWorkbook wb, Connection conn)
94 | throws MigrationException;
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/MigrationTaskSupport.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration;
17 |
18 | /**
19 | * Convenience base class for migration tasks.
20 | *
21 | * @author Scott Askew (scott@tacitknowledge.com)
22 | * @author Artie Pesh-Imam (apeshimam@tacitknowledge.com)
23 | */
24 | public abstract class MigrationTaskSupport implements RollbackableMigrationTask
25 | {
26 | protected boolean isRollbackSupported = false;
27 |
28 | /**
29 | * The name of this migration task
30 | */
31 | private String name = this.getClass().getName();
32 |
33 | /**
34 | * The relative order in which this test should run
35 | */
36 | private Integer level;
37 |
38 | /**
39 | * {@inheritDoc}
40 | */
41 | public String getName()
42 | {
43 | return name;
44 | }
45 |
46 | /**
47 | * Sets the name of this migration task.
48 | *
49 | * @param name the name of this migration task
50 | */
51 | public void setName(String name)
52 | {
53 | this.name = name;
54 | }
55 |
56 | /**
57 | * {@inheritDoc}
58 | */
59 | public Integer getLevel()
60 | {
61 | return level;
62 | }
63 |
64 | /**
65 | * Sets the relative order in which this test should run
66 | *
67 | * @param lvl the relative order in which this test should run
68 | */
69 | public void setLevel(Integer lvl)
70 | {
71 | this.level = lvl;
72 | }
73 |
74 | /**
75 | * {@inheritDoc}
76 | */
77 | public int compareTo(Object o)
78 | {
79 | MigrationTask task = (MigrationTask) o;
80 | if (task.getLevel() == null)
81 | {
82 | return 1;
83 | }
84 | return getLevel().compareTo(task.getLevel());
85 | }
86 |
87 | /**
88 | * By default, this method is not supported.
89 | */
90 | public void down(MigrationContext context) throws MigrationException
91 | {
92 | throw new UnsupportedOperationException("This method is not supported by this task.");
93 | }
94 |
95 | /**
96 | * @return a boolean indicating if rollback is supported
97 | */
98 | public boolean isRollbackSupported()
99 | {
100 | return isRollbackSupported;
101 | }
102 |
103 | /**
104 | * Sets the isRollbackSupported attribute
105 | *
106 | * @param isRollbackSupported
107 | */
108 | public void setRollbackSupported(boolean isRollbackSupported)
109 | {
110 | this.isRollbackSupported = isRollbackSupported;
111 | }
112 |
113 | /**
114 | * By default, this method delegates to the up method.
115 | */
116 | public void migrate(MigrationContext context) throws MigrationException
117 | {
118 | up(context);
119 | }
120 |
121 | /**
122 | * By default, this method is a no-op. If a legacy task extends
123 | * MigrationTaskSupport but does not implement up, it would cause a
124 | * compilation error. This no-op method resolves that issue.
125 | */
126 | public void up(MigrationContext context) throws MigrationException
127 | {
128 | // no op
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/jdbc/DistributedJdbcMigrationLauncher.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc;
17 |
18 | import com.tacitknowledge.util.migration.DistributedMigrationProcess;
19 | import com.tacitknowledge.util.migration.MigrationException;
20 | import com.tacitknowledge.util.migration.MigrationProcess;
21 | import com.tacitknowledge.util.migration.MigrationRunnerFactory;
22 |
23 | /**
24 | * Core starting point for a distributed database migration run.
25 | * This class obtains a connection to the orchestration database,
26 | * checks its patch level, delegates the actual execution of the
27 | * migration tasks to a MigrationProcess instance,
28 | * and then commits and cleans everything up at the end.
29 | *
30 | * This class is NOT threadsafe.
31 | *
32 | * @author Mike Hardy (mike@tacitknowledge.com)
33 | */
34 | public class DistributedJdbcMigrationLauncher extends JdbcMigrationLauncher
35 | {
36 | /**
37 | * Create a new MigrationProcess and add a SqlScriptMigrationTaskSource
38 | */
39 | public DistributedJdbcMigrationLauncher()
40 | {
41 | super();
42 | }
43 |
44 | /**
45 | * Create a new MigrationLancher.
46 | *
47 | * @param context the JdbcMigrationContext to use.
48 | */
49 | public DistributedJdbcMigrationLauncher(JdbcMigrationContext context)
50 | {
51 | super(context);
52 | }
53 |
54 | /**
55 | * Override the sub-class so we get a DistributedMigrationProcess instead of the
56 | * normal one
57 | *
58 | * @return DistributedMigrationProcess
59 | */
60 | public MigrationProcess getNewMigrationProcess()
61 | {
62 | DistributedMigrationProcess migrationProcess = new DistributedMigrationProcess();
63 | migrationProcess.setMigrationRunnerStrategy
64 | (MigrationRunnerFactory.getMigrationRunnerStrategy(getMigrationStrategy()));
65 | return migrationProcess;
66 | }
67 |
68 | /**
69 | * Starts the application migration process across all configured contexts
70 | *
71 | * @return the number of patches applied
72 | * @throws MigrationException if an unrecoverable error occurs during
73 | * the migration
74 | */
75 | public int doMigrations() throws MigrationException
76 | {
77 | if (getContexts().size() == 0)
78 | {
79 | throw new MigrationException("You must configure a migration context");
80 | }
81 |
82 | return super.doMigrations();
83 | }
84 |
85 | /**
86 | * Starts the application migration process across all configured contexts
87 | *
88 | * @return the number of patches applied
89 | * @throws MigrationException if an unrecoverable error occurs during
90 | * the migration
91 | */
92 | public int doRollbacks(int rollbackLevel) throws MigrationException
93 | {
94 | if (getContexts().size() == 0)
95 | {
96 | throw new MigrationException("You must configure a migration context");
97 | }
98 |
99 | return super.doRollbacks(new int[]{rollbackLevel});
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/OrderedMigrationRunnerStrategy.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.tacitknowledge.util.migration;
16 |
17 | import org.apache.commons.collections.CollectionUtils;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collections;
21 | import java.util.List;
22 |
23 | /**
24 | * Helps to get information about how the migrations should run based in an ordered stategy, i.e.
25 | * If the level of the MigrationTask is greater than the current level and
26 | * the MigrationTaskhas not yet been applied. Then the information of that migration
27 | * is considered missing.
28 | *
29 | * @author Oscar Gonzalez (oscar@tacitknowledge.com)
30 | * @author Hemri Herrera (hemri@tacitknowledge.com)
31 | * @author Ulises Pulido (upulido@tacitknowledge.com)
32 | */
33 | public class OrderedMigrationRunnerStrategy implements MigrationRunnerStrategy
34 | {
35 | public boolean shouldMigrationRun(int migrationLevel, PatchInfoStore patchInfoStore) throws MigrationException
36 | {
37 | return migrationLevel > patchInfoStore.getPatchLevel();
38 | }
39 |
40 | public boolean isSynchronized(PatchInfoStore currentPatchInfoStore, PatchInfoStore patchInfoStore) throws MigrationException
41 | {
42 |
43 | if (currentPatchInfoStore == null || patchInfoStore == null)
44 | {
45 | throw new IllegalArgumentException("currentPatchInfoStore and patchInfoStore should not be null");
46 | }
47 |
48 | return currentPatchInfoStore.getPatchLevel() == patchInfoStore.getPatchLevel();
49 | }
50 |
51 | public ListServletContextEvent being handled
39 | * @throws MigrationException
40 | */
41 | public static void doMigrations(final ServletContextEvent sce) throws MigrationException
42 | {
43 | JdbcMigrationLauncherFactory launcherFactory =
44 | new JdbcMigrationLauncherFactoryLoader().createFactory();
45 | JdbcMigrationLauncher launcher = launcherFactory.createMigrationLauncher(sce);
46 | launcher.doMigrations();
47 | }
48 |
49 | /**
50 | * Helper method to initiate the migration process.
51 | *
52 | * @param migrationSystemName the name of the system to migrate
53 | * @param migrationSettings additional properties for migration
54 | * @throws MigrationException
55 | */
56 | public static void doMigrations(final String migrationSystemName,
57 | final String migrationSettings) throws MigrationException
58 | {
59 | JdbcMigrationLauncherFactory launcherFactory = new JdbcMigrationLauncherFactoryLoader()
60 | .createFactory();
61 | JdbcMigrationLauncher launcher = null;
62 |
63 | if (migrationSettings == null)
64 | {
65 | log.info("Using migration.properties (default)");
66 | launcher = launcherFactory.createMigrationLauncher(migrationSystemName);
67 | }
68 | else
69 | {
70 | log.info("Using " + migrationSettings);
71 | launcher = launcherFactory.createMigrationLauncher(migrationSystemName,
72 | migrationSettings);
73 | }
74 |
75 | launcher.doMigrations();
76 | }
77 |
78 | /**
79 | * Helper method to initiate the migration process.
80 | *
81 | * @param migrationSystemName the name of the system to migrate
82 | * @param migrationSettings additional properties for migration
83 | * @throws MigrationException
84 | */
85 | public void doRollbacks(final String migrationSystemName,
86 | final String migrationSettings, final int[] rollbackLevel, final boolean forceRollback)
87 | throws MigrationException
88 | {
89 |
90 | JdbcMigrationLauncher launcher = null;
91 |
92 | if (migrationSettings == null)
93 | {
94 | log.info("Using migration.properties (default)");
95 | launcher = getLauncherFactory().createMigrationLauncher(migrationSystemName);
96 | }
97 | else
98 | {
99 | log.info("Using " + migrationSettings);
100 | launcher = getLauncherFactory().createMigrationLauncher(migrationSystemName,
101 | migrationSettings);
102 | }
103 |
104 | launcher.doRollbacks(rollbackLevel, forceRollback);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/jdbc/util/ConnectionWrapperDataSource.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc.util;
17 |
18 | import javax.sql.DataSource;
19 | import java.io.PrintWriter;
20 | import java.sql.Connection;
21 | import java.sql.SQLException;
22 | import java.sql.SQLFeatureNotSupportedException;
23 | import java.util.logging.Logger;
24 |
25 | /**
26 | * A partial DataSource implementation that simply wraps a single,
27 | * already opened Connection.
28 | *
29 | * Only the two getConnection methods are supported.
30 | *
31 | * @author Scott Askew (scott@tacitknowledge.com)
32 | */
33 | public class ConnectionWrapperDataSource implements DataSource
34 | {
35 | /**
36 | * The message used in UnsupportedOperationExceptions.
37 | */
38 | public static final String UNSUPPORTED_OPERATION_EXCEPTION_MSG
39 | = ConnectionWrapperDataSource.class
40 | + " is not a fully functioning DataSource and only"
41 | + " supports the getConnection methods.";
42 |
43 | /**
44 | * The underlying connection
45 | */
46 | private Connection connection = null;
47 |
48 | /**
49 | * Creates a new ConnectionWrapperDataSource.
50 | *
51 | * @param connection the connection to use for this data source
52 | */
53 | public ConnectionWrapperDataSource(Connection connection)
54 | {
55 | this.connection = connection;
56 | }
57 |
58 | /**
59 | * {@inheritDoc}
60 | */
61 | public Connection getConnection() throws SQLException
62 | {
63 | return connection;
64 | }
65 |
66 | /**
67 | * {@inheritDoc}
68 | */
69 | public Connection getConnection(String user, String pass) throws SQLException
70 | {
71 | return connection;
72 | }
73 |
74 | /**
75 | * {@inheritDoc}
76 | */
77 | public PrintWriter getLogWriter() throws UnsupportedOperationException
78 | {
79 | throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MSG);
80 | }
81 |
82 | /**
83 | * {@inheritDoc}
84 | */
85 | public void setLogWriter(PrintWriter arg0) throws UnsupportedOperationException
86 | {
87 | throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MSG);
88 | }
89 |
90 | /**
91 | * {@inheritDoc}
92 | */
93 | public int getLoginTimeout() throws UnsupportedOperationException
94 | {
95 | throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MSG);
96 | }
97 |
98 | /**
99 | * {@inheritDoc}
100 | */
101 | public Logger getParentLogger() throws SQLFeatureNotSupportedException {
102 | throw new SQLFeatureNotSupportedException();
103 | }
104 |
105 | /**
106 | * {@inheritDoc}
107 | */
108 | public void setLoginTimeout(int arg0) throws UnsupportedOperationException
109 | {
110 | throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MSG);
111 | }
112 |
113 | /**
114 | * {@inheritDoc}
115 | */
116 | public boolean isWrapperFor(Class iface)
117 | {
118 | return connection != null && iface.isAssignableFrom(connection.getClass());
119 | }
120 |
121 | /**
122 | * {@inheritDoc}
123 | */
124 | public Object unwrap(Class iface)
125 | {
126 | return connection;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/jdbc/DistributedStandaloneMigrationLauncher.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc;
17 |
18 | import com.tacitknowledge.util.migration.jdbc.util.ConfigurationUtil;
19 | import org.apache.commons.logging.Log;
20 | import org.apache.commons.logging.LogFactory;
21 |
22 |
23 | /**
24 | * Launches the migration process as a standalone application.
25 | *
26 | * This class expects the following Java environment parameters:
27 | *
33 | * ...
34 | * <target name="patch.database" description="Runs the migration system">
35 | * <java
36 | * fork="true"
37 | * classpathref="patch.classpath"
38 | * failonerror="true"
39 | * classname=
40 | * "com.tacitknowledge.util.migration.jdbc.DistributedStandaloneMigrationLauncher">
41 | * <sysproperty key="migration.systemname" value="${application.name}"/>
42 | * </java>
43 | * </target>
44 | * ...
45 | *
46 | *
47 | * @author Mike Hardy (mike@tacitknowledge.com)
48 | * @see com.tacitknowledge.util.migration.DistributedMigrationProcess
49 | */
50 | public class DistributedStandaloneMigrationLauncher
51 | {
52 | /**
53 | * Class logger
54 | */
55 | private static Log log = LogFactory.getLog(DistributedStandaloneMigrationLauncher.class);
56 |
57 | /**
58 | * Private constructor - this object shouldn't be instantiated
59 | */
60 | private DistributedStandaloneMigrationLauncher()
61 | {
62 | // does nothing
63 | }
64 |
65 | /**
66 | * Run the migrations for the given system name
67 | *
68 | * @param arguments the command line arguments, if any (none are used)
69 | * @throws Exception if anything goes wrong
70 | */
71 | public static void main(String[] arguments) throws Exception
72 | {
73 | String systemName = ConfigurationUtil.getRequiredParam("migration.systemname",
74 | System.getProperties(), arguments);
75 |
76 | String migrationSettings = ConfigurationUtil.getOptionalParam("migration.settings",
77 | System.getProperties(), arguments, 1);
78 |
79 | // The MigrationLauncher is responsible for handling the interaction
80 | // between the PatchTable and the underlying MigrationTasks; as each
81 | // task is executed, the patch level is incremented, etc.
82 | try
83 | {
84 | DistributedJdbcMigrationLauncherFactory factory =
85 | new DistributedJdbcMigrationLauncherFactory();
86 | JdbcMigrationLauncher launcher = null;
87 |
88 | if (migrationSettings == null)
89 | {
90 | log.info("Using migration.properties (default)");
91 | launcher = factory.createMigrationLauncher(systemName);
92 | }
93 | else
94 | {
95 | log.info("Using " + migrationSettings);
96 | launcher = factory.createMigrationLauncher(systemName, migrationSettings);
97 | }
98 | launcher.doMigrations();
99 |
100 | }
101 | catch (Exception e)
102 | {
103 | log.error(e);
104 | throw e;
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/jdbc/DistributedMigrationTableUnlock.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc;
17 |
18 | import com.tacitknowledge.util.migration.MigrationContext;
19 | import org.apache.commons.logging.Log;
20 | import org.apache.commons.logging.LogFactory;
21 |
22 | import java.util.Map;
23 |
24 | /**
25 | * Allows you to force-unlock a migration table with an orphaned lock. Should
26 | * be used in the same way that DistributedMigrationInformation is used
27 | *
28 | * @author Mike Hardy (mike@tacitknowledge.com)
29 | * @see com.tacitknowledge.util.migration.jdbc.DistributedMigrationInformation
30 | */
31 | public class DistributedMigrationTableUnlock
32 | {
33 | /**
34 | * Class logger
35 | */
36 | private static Log log = LogFactory.getLog(DistributedMigrationTableUnlock.class);
37 |
38 | /**
39 | * Get the migration level information for the given system name
40 | *
41 | * @param arguments the command line arguments, if any (none are used)
42 | * @throws Exception if anything goes wrong
43 | */
44 | public static void main(String[] arguments) throws Exception
45 | {
46 | DistributedMigrationTableUnlock unlock = new DistributedMigrationTableUnlock();
47 | String migrationName = System.getProperty("migration.systemname");
48 | if (migrationName == null)
49 | {
50 | if ((arguments != null) && (arguments.length > 0))
51 | {
52 | migrationName = arguments[0].trim();
53 | }
54 | else
55 | {
56 | throw new IllegalArgumentException("The migration.systemname "
57 | + "system property is required");
58 | }
59 | }
60 | unlock.tableUnlock(migrationName);
61 | }
62 |
63 | /**
64 | * unlock the patch table for the given system name
65 | *
66 | * @param systemName the name of the system
67 | * @throws Exception if anything goes wrong
68 | */
69 | public void tableUnlock(String systemName) throws Exception
70 | {
71 | tableUnlock(systemName, MigrationContext.MIGRATION_CONFIG_FILE);
72 | }
73 |
74 | /**
75 | * unlock the patch table for the given system name
76 | *
77 | * @param systemName the name of the system
78 | * @param migrationSettings migration settings file
79 | * @throws Exception if anything goes wrong
80 | */
81 | public void tableUnlock(String systemName, String migrationSettings) throws Exception
82 | {
83 | // The MigrationLauncher is responsible for handling the interaction
84 | // between the PatchTable and the underlying MigrationTasks; as each
85 | // task is executed, the patch level is incremented, etc.
86 | try
87 | {
88 | DistributedJdbcMigrationLauncherFactory factory =
89 | new DistributedJdbcMigrationLauncherFactory();
90 | DistributedJdbcMigrationLauncher launcher
91 | = (DistributedJdbcMigrationLauncher) factory.createMigrationLauncher(systemName, migrationSettings);
92 |
93 | Map contextMap = launcher.getContexts();
94 | JdbcMigrationContext context =
95 | (JdbcMigrationContext) contextMap.keySet().iterator().next();
96 | launcher.createPatchStore(context).unlockPatchStore();
97 | }
98 | catch (Exception e)
99 | {
100 | log.error(e);
101 | throw e;
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/com/tacitknowledge/util/migration/jdbc/loader/FlatXmlDataSetTaskSource.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2004 Tacit Knowledge
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.tacitknowledge.util.migration.jdbc.loader;
17 |
18 | import com.tacitknowledge.util.discovery.ClassDiscoveryUtil;
19 | import com.tacitknowledge.util.migration.MigrationException;
20 | import com.tacitknowledge.util.migration.MigrationTask;
21 | import com.tacitknowledge.util.migration.MigrationTaskSource;
22 | import org.apache.commons.logging.Log;
23 | import org.apache.commons.logging.LogFactory;
24 |
25 | import java.io.File;
26 | import java.util.ArrayList;
27 | import java.util.List;
28 | import java.util.regex.Matcher;
29 | import java.util.regex.Pattern;
30 |
31 | /**
32 | * Search a package (directory) for xml files that match a specific pattern
33 | * and returns corresponding {@link FlatXmlDataSetMigrationTask}s. The name
34 | * of each script must follow the pattern of "patch(\d+)(_.+)?\.xml".
35 | *
36 | * @author Alex Soto (apsoto@gmail.com)
37 | */
38 | public class FlatXmlDataSetTaskSource implements MigrationTaskSource
39 | {
40 |
41 | /**
42 | * Class logger
43 | */
44 | private static Log log = LogFactory.getLog(FlatXmlDataSetTaskSource.class);
45 |
46 | /**
47 | * The regular expression used to match XML patch files.
48 | */
49 | private static final String XML_PATCH_REGEX = "^patch(\\d+)(_.+)?\\.xml";
50 |
51 |
52 | /**
53 | * {@inheritDoc}
54 | */
55 | public List