View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    *
4    *
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.opensource.org/licenses/ecl2.php
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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   * @author Leo Przybylski (przybyls@arizona.edu)
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                 // delete the old database files
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                     // hsqldb.getConnection().createStatement().execute("SHUTDOWN");
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 }