1 package org.riverock.dbrevision.manager;
2
3 import java.io.File;
4 import java.io.FileFilter;
5 import java.io.FileInputStream;
6 import java.io.FileNotFoundException;
7 import java.io.IOException;
8 import java.io.Serializable;
9 import java.sql.SQLException;
10 import java.util.ArrayList;
11 import java.util.List;
12
13 import javax.xml.bind.JAXBException;
14
15 import org.apache.commons.lang.StringUtils;
16 import org.apache.log4j.Logger;
17
18 import org.riverock.dbrevision.Constants;
19 import org.riverock.dbrevision.annotation.schema.db.DbSchema;
20 import org.riverock.dbrevision.annotation.schema.db.Patch;
21 import org.riverock.dbrevision.annotation.schema.db.Patches;
22 import org.riverock.dbrevision.db.Database;
23 import org.riverock.dbrevision.exception.DbRevisionException;
24 import org.riverock.dbrevision.exception.InitStructureFileNotFoundException;
25 import org.riverock.dbrevision.exception.NoChildPatchFoundException;
26 import org.riverock.dbrevision.exception.PatchParseException;
27 import org.riverock.dbrevision.exception.PatchPrepareException;
28 import org.riverock.dbrevision.exception.TwoPatchesWithEmptyPreviousPatchException;
29 import org.riverock.dbrevision.exception.VersionPathNotFoundException;
30 import org.riverock.dbrevision.manager.dao.ManagerDaoFactory;
31 import org.riverock.dbrevision.manager.patch.PatchService;
32 import org.riverock.dbrevision.manager.patch.PatchSorter;
33 import org.riverock.dbrevision.system.DbStructureImport;
34 import org.riverock.dbrevision.utils.DbUtils;
35 import org.riverock.dbrevision.utils.Utils;
36
37
38
39
40
41
42 public class Version implements Serializable {
43 private final static Logger log = Logger.getLogger(Version.class);
44
45 private Version previousVersion=null;
46 private Version nextVersion=null;
47
48 List<Patch> patches=null;
49
50 Database database =null;
51
52 private boolean isComplete = false;
53
54 private String versionName;
55
56 private File versionPath=null;
57
58 private File initStructureFile=null;
59
60 private File patchPath=null;
61
62 private File modulePath=null;
63
64 public Version(Database database, File modulePath, String versionName) {
65 this.database = database;
66 this.modulePath = modulePath;
67 this.versionName = versionName;
68 this.versionPath = new File(modulePath, this.versionName);
69 if (!versionPath.exists()) {
70 throw new VersionPathNotFoundException("Version path not found: " + versionPath.getAbsolutePath() );
71 }
72 this.initStructureFile = new File(versionPath, Constants.INIT_STRUCTURE_FILE_NAME);
73 if (!initStructureFile.exists()) {
74 throw new InitStructureFileNotFoundException("Init structure file not found: " + initStructureFile.getAbsolutePath() );
75 }
76 this.patchPath = new File(versionPath, Constants.PATCH_DIR_NAME);
77 initPatches();
78 }
79
80 public void destroy() {
81 this.setPreviousVersion(null);
82 this.setNextVersion(null);
83 if (database!=null) {
84 if (database.getConnection()!=null) {
85 DbUtils.close(database.getConnection());
86 database.setConnection(null);
87 }
88 database=null;
89 }
90 if (this.patches!=null) {
91 this.patches.clear();
92 }
93 }
94
95 private void initPatches() {
96 File[] files = patchPath.listFiles(
97 new FileFilter() {
98 public boolean accept(File pathname) {
99 return pathname.isFile();
100 }
101 }
102 );
103 if (files==null) {
104 patches = new ArrayList<Patch>();
105 return;
106 }
107 List<Patch> list = new ArrayList<Patch>();
108 try {
109 for (File file : files) {
110 FileInputStream inputStream=null;
111 Patches patches;
112 try {
113 inputStream = new FileInputStream(file);
114 try {
115 patches = Utils.getObjectFromXml(Patches.class, inputStream);
116 }
117 catch (JAXBException e) {
118 throw new PatchParseException("Patch file: " + file.getAbsolutePath(), e);
119 }
120 list.addAll(patches.getPatches());
121 }
122 finally {
123 if (inputStream!=null) {
124 try {
125 inputStream.close();
126 }
127 catch (IOException e1) {
128 log.error("Error close input stream", e1);
129 }
130 }
131 }
132 }
133 try {
134 patches = PatchSorter.sort(list);
135 }
136 catch (TwoPatchesWithEmptyPreviousPatchException e) {
137 String s="";
138 for (File file : files) {
139 s+=("\n"+file.getAbsolutePath());
140 }
141 throw new TwoPatchesWithEmptyPreviousPatchException(s, e);
142 }
143 catch (NoChildPatchFoundException e) {
144 String s="";
145 for (File file : files) {
146 s+=("\n"+file.getAbsolutePath());
147 }
148 throw new NoChildPatchFoundException(s, e);
149 }
150 }
151 catch (Exception e) {
152 throw new PatchPrepareException(e);
153 }
154 }
155
156 public void applyInitStructure() {
157 if (isComplete) {
158 return;
159 }
160 DbSchema dbSchema;
161 FileInputStream inputStream=null;
162 try {
163 inputStream = new FileInputStream(initStructureFile);
164 dbSchema = Utils.getObjectFromXml(DbSchema.class, inputStream);
165 }
166 catch (JAXBException e) {
167 throw new PatchParseException("Init structure file: " + initStructureFile.getAbsolutePath(), e);
168 }
169 catch (FileNotFoundException e) {
170 throw new InitStructureFileNotFoundException(e);
171 }
172 finally {
173 if (inputStream!=null) {
174 try {
175 inputStream.close();
176 }
177 catch (IOException e1) {
178 log.error("Error close input stream", e1);
179 }
180 }
181 }
182 DbStructureImport.importStructure(database, dbSchema, true);
183 ManagerDaoFactory.getManagerDao().makrCurrentVersion(database, modulePath.getName(), versionName, null);
184 try {
185 database.getConnection().commit();
186 }
187 catch (SQLException e) {
188 throw new DbRevisionException(e);
189 }
190 isComplete=true;
191
192 }
193
194 public void apply() {
195 if (isComplete) {
196 return;
197 }
198
199 if (DbRevisionChecker.isModuleReleased(database, modulePath.getName())) {
200 for (Patch patch : patches) {
201 if (patch.isProcessed()) {
202 continue;
203 }
204 PatchService.processPatch(database, patch);
205 ManagerDaoFactory.getManagerDao().makrCurrentVersion(database, modulePath.getName(), versionName, patch.getName());
206 try {
207 database.getConnection().commit();
208 }
209 catch (SQLException e) {
210 throw new DbRevisionException(e);
211 }
212 }
213 ManagerDaoFactory.getManagerDao().makrCurrentVersion(database, modulePath.getName(), versionName, null);
214 try {
215 database.getConnection().commit();
216 }
217 catch (SQLException e) {
218 throw new DbRevisionException(e);
219 }
220 }
221 else {
222 applyInitStructure();
223
224 }
225 isComplete=true;
226 }
227
228 public void applayPatch(String patchName) throws SQLException {
229 if (isComplete || StringUtils.isBlank(patchName)) {
230 return;
231 }
232 Patch firstNotProcessed=null;
233 for (Patch patch : patches) {
234 if (!patch.isProcessed()) {
235 firstNotProcessed = patch;
236 break;
237 }
238 }
239
240 if (firstNotProcessed!=null && firstNotProcessed.getName().equals(patchName)) {
241 PatchService.processPatch(database, firstNotProcessed);
242 ManagerDaoFactory.getManagerDao().makrCurrentVersion(database, modulePath.getName(), versionName, firstNotProcessed.getName());
243 database.getConnection().commit();
244 }
245 }
246
247 public Version getPreviousVersion() {
248 return previousVersion;
249 }
250
251 void setPreviousVersion(Version previousVersion) {
252 this.previousVersion = previousVersion;
253 }
254
255 public String getVersionName() {
256 return versionName;
257 }
258
259 public File getPatchPath() {
260 return patchPath;
261 }
262
263 public void setPatchPath(File patchPath) {
264 this.patchPath = patchPath;
265 }
266
267 public Patch getLastPatch() {
268 if (patches.isEmpty()) {
269 return null;
270 }
271 return patches.get(patches.size()-1);
272 }
273
274 public boolean isComplete() {
275 return isComplete;
276 }
277
278 void setComplete(boolean complete) {
279 isComplete = complete;
280 }
281
282 public List<Patch> getPatches() {
283 return patches;
284 }
285
286 void setPatches(List<Patch> patches) {
287 this.patches = patches;
288 }
289
290 Version getNextVersion() {
291 return nextVersion;
292 }
293
294 void setNextVersion(Version nextVersion) {
295 this.nextVersion = nextVersion;
296 }
297
298 public String toString() {
299 return "["+versionName+";"+isComplete+"]";
300 }
301 }