1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.rsmart.kuali.tools.ant.tasks;
18
19 import org.apache.tools.ant.taskdefs.Jar;
20 import org.apache.tools.ant.types.FileSet;
21
22 import liquibase.resource.CompositeResourceAccessor;
23 import liquibase.resource.FileSystemResourceAccessor;
24 import liquibase.resource.ResourceAccessor;
25 import liquibase.Liquibase;
26 import liquibase.integration.ant.AntResourceAccessor;
27 import liquibase.integration.ant.BaseLiquibaseTask;
28 import liquibase.database.Database;
29 import liquibase.database.DatabaseFactory;
30 import liquibase.database.core.H2Database;
31 import liquibase.database.jvm.JdbcConnection;
32 import org.apache.tools.ant.BuildException;
33
34 import org.h2.tools.Backup;
35 import org.h2.tools.DeleteDbFiles;
36
37 import com.rsmart.kuali.tools.liquibase.Diff;
38 import com.rsmart.kuali.tools.liquibase.DiffResult;
39
40 import java.io.File;
41 import java.io.PrintStream;
42
43 import java.sql.Connection;
44 import java.sql.DriverManager;
45 import java.sql.Statement;
46
47 import static org.apache.tools.ant.Project.MSG_DEBUG;
48
49
50
51
52
53 public class GenerateChangeLog extends BaseLiquibaseTask {
54 private String source;
55 private String target;
56 private boolean stateSaved;
57
58 public GenerateChangeLog() { }
59
60 public boolean isStateSaved() {
61 return stateSaved;
62 }
63
64 public void setStateSaved(boolean ss) {
65 stateSaved = ss;
66 }
67
68 public void setSource(String refid) {
69 this.source = refid;
70 }
71
72 public String getSource() {
73 return this.source;
74 }
75
76 public void setTarget(String refid) {
77 this.target = refid;
78 }
79
80 public String getTarget() {
81 return this.target;
82 }
83
84 public void execute() {
85 final RdbmsConfig source = (RdbmsConfig) getProject().getReference(getSource());
86 final RdbmsConfig target = (RdbmsConfig) getProject().getReference(getTarget());
87 Database lbSource = null;
88 Database lbTarget = null;
89 final DatabaseFactory factory = DatabaseFactory.getInstance();
90 try {
91 lbSource = factory.findCorrectDatabaseImplementation(new JdbcConnection(openConnection("source")));
92 lbSource.setDefaultSchemaName(source.getSchema());
93 lbTarget = factory.findCorrectDatabaseImplementation(new JdbcConnection(openConnection("target")));
94 lbTarget.setDefaultSchemaName(target.getSchema());
95
96 exportSchema(lbSource, lbTarget);
97 if (isStateSaved()) {
98 exportData(lbSource, lbTarget);
99 }
100
101 if (lbTarget instanceof H2Database) {
102 final Statement st = ((JdbcConnection) lbTarget.getConnection()).createStatement();
103 st.execute("SHUTDOWN DEFRAG");
104 }
105
106 } catch (Exception e) {
107 throw new BuildException(e);
108 } finally {
109 try {
110 if (lbSource != null) {
111 lbSource.close();
112 }
113 if (lbTarget != null) {
114 lbTarget.close();
115 }
116 }
117 catch (Exception e) {
118 }
119 }
120
121 if (isStateSaved()) {
122 log("Starting data load from schema " + source.getSchema());
123 MigrateData migrateTask = new MigrateData();
124 migrateTask.bindToOwner(this);
125 migrateTask.init();
126 migrateTask.setSource(getSource());
127 migrateTask.setTarget("h2");
128 migrateTask.execute();
129 try {
130 Backup.execute("work/export/data.zip", "work/export", "", true);
131
132
133 DeleteDbFiles.execute("split:22:work/export", "data", true);
134 }
135 catch (Exception e) {
136 throw new BuildException(e);
137 }
138 }
139 }
140
141 protected void exportSchema(Database source, Database target) {
142 try {
143 Diff diff = new Diff(source, source.getDefaultSchemaName());
144 exportTables(diff, target);
145 exportSequences(diff, target);
146 exportViews(diff, target);
147 exportIndexes(diff, target);
148 exportConstraints(diff, target);
149 }
150 catch (Exception e) {
151 throw new BuildException(e);
152 }
153 }
154
155 protected void export(Diff diff, Database target, String diffTypes, String suffix) {
156 diff.setDiffTypes(diffTypes);
157
158 try {
159 DiffResult results = diff.compare();
160 results.printChangeLog(getChangeLogFile() + suffix, target);
161 }
162 catch (Exception e) {
163 throw new BuildException(e);
164 }
165 }
166
167 protected void exportConstraints(Diff diff, Database target) {
168 export(diff, target, "foreignKeys", "-cst.xml");
169 }
170
171 protected void exportIndexes(Diff diff, Database target) {
172 export(diff, target, "indexes", "-idx.xml");
173 }
174
175 protected void exportViews(Diff diff, Database target) {
176 export(diff, target, "views", "-vw.xml");
177 }
178
179 protected void exportTables(Diff diff, Database target) {
180 export(diff, target, "tables, primaryKeys, uniqueConstraints", "-tab.xml");
181 }
182
183 protected void exportSequences(Diff diff, Database target) {
184 export(diff, target, "sequences", "-seq.xml");
185 }
186
187
188 private void exportData(Database source, Database target) {
189 Database h2db = null;
190 RdbmsConfig h2Config = new RdbmsConfig();
191 h2Config.setDriver("org.h2.Driver");
192 h2Config.setUrl("jdbc:h2:split:22:work/export/data");
193 h2Config.setUsername("SA");
194 h2Config.setPassword("");
195 h2Config.setSchema("PUBLIC");
196 getProject().addReference("h2", h2Config);
197
198 final DatabaseFactory factory = DatabaseFactory.getInstance();
199 try {
200 h2db = factory.findCorrectDatabaseImplementation(new JdbcConnection(openConnection("h2")));
201 h2db.setDefaultSchemaName(h2Config.getSchema());
202
203 export(new Diff(source, getDefaultSchemaName()), h2db, "tables", "-dat.xml");
204
205 ResourceAccessor antFO = new AntResourceAccessor(getProject(), classpath);
206 ResourceAccessor fsFO = new FileSystemResourceAccessor();
207
208 String changeLogFile = getChangeLogFile() + "-dat.xml";
209
210 Liquibase liquibase = new Liquibase(changeLogFile, new CompositeResourceAccessor(antFO, fsFO), h2db);
211
212 log("Loading Schema");
213 liquibase.update(getContexts());
214 log("Finished Loading the Schema");
215
216 }
217 catch (Exception e) {
218 throw new BuildException(e);
219 }
220 finally {
221 try {
222 if (h2db != null) {
223
224 log("Closing h2 database");
225 h2db.close();
226 }
227 }
228 catch (Exception e) {
229 if (!(e instanceof java.sql.SQLNonTransientConnectionException)) {
230 e.printStackTrace();
231 }
232 }
233
234 }
235 }
236
237 private void debug(String msg) {
238 log(msg, MSG_DEBUG);
239 }
240
241 private Connection openSource() {
242 return openConnection(getSource());
243 }
244
245 private Connection openTarget() {
246 return openConnection(getTarget());
247 }
248
249 private Connection openConnection(String reference) {
250 final RdbmsConfig config = (RdbmsConfig) getProject().getReference(reference);
251 return openConnection(config);
252 }
253
254
255
256 private Connection openConnection(RdbmsConfig config) {
257 Connection retval = null;
258 int retry_count = 0;
259 final int max_retry = 5;
260 while (retry_count < max_retry) {
261 try {
262 debug("Loading schema " + config.getSchema() + " at url " + config.getUrl());
263 Class.forName(config.getDriver());
264 retval = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword());
265 retval.setAutoCommit(true);
266 }
267 catch (Exception e) {
268 if (!e.getMessage().contains("Database lock acquisition failure") && !(e instanceof NullPointerException)) {
269 throw new BuildException(e);
270 }
271 }
272 finally {
273 retry_count++;
274 }
275 }
276 return retval;
277 }
278 }