1
|
// $Id$
|
2
|
/**
|
3
|
* Copyright (C) 2009 EDIT
|
4
|
* European Distributed Institute of Taxonomy
|
5
|
* http://www.e-taxonomy.eu
|
6
|
*
|
7
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
8
|
* See LICENSE.TXT at the top of this package for the full license terms.
|
9
|
*/
|
10
|
package eu.etaxonomy.cdm.database.update;
|
11
|
|
12
|
import java.sql.ResultSet;
|
13
|
|
14
|
import org.apache.log4j.Logger;
|
15
|
|
16
|
import eu.etaxonomy.cdm.common.monitor.DefaultProgressMonitor;
|
17
|
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
|
18
|
import eu.etaxonomy.cdm.database.CdmDataSource;
|
19
|
import eu.etaxonomy.cdm.database.ICdmDataSource;
|
20
|
import eu.etaxonomy.cdm.database.update.v31_33.SchemaUpdater_31_33;
|
21
|
import eu.etaxonomy.cdm.database.update.v31_33.TermUpdater_31_33;
|
22
|
|
23
|
/**
|
24
|
* @author a.mueller
|
25
|
* @date 10.09.2010
|
26
|
*
|
27
|
*/
|
28
|
public class CdmUpdater {
|
29
|
private static final Logger logger = Logger.getLogger(CdmUpdater.class);
|
30
|
|
31
|
public static CdmUpdater NewInstance(){
|
32
|
return new CdmUpdater();
|
33
|
}
|
34
|
|
35
|
/**
|
36
|
* @param datasource
|
37
|
* @param monitor may be <code>null</code>
|
38
|
* @return
|
39
|
*/
|
40
|
public boolean updateToCurrentVersion(ICdmDataSource datasource, IProgressMonitor monitor){
|
41
|
boolean result = true;
|
42
|
if (monitor == null){
|
43
|
monitor = DefaultProgressMonitor.NewInstance();
|
44
|
}
|
45
|
|
46
|
ISchemaUpdater currentSchemaUpdater = getCurrentSchemaUpdater();
|
47
|
// TODO do we really always update the terms??
|
48
|
ITermUpdater currentTermUpdater = getCurrentTermUpdater();
|
49
|
|
50
|
int steps = currentSchemaUpdater.countSteps(datasource, monitor);
|
51
|
steps += currentTermUpdater.countSteps(datasource, monitor);
|
52
|
steps++; //for hibernate_sequences update
|
53
|
|
54
|
String taskName = "Update to schema version " + currentSchemaUpdater.getTargetVersion() + " and to term version " + currentTermUpdater.getTargetVersion(); //+ currentSchemaUpdater.getVersion();
|
55
|
monitor.beginTask(taskName, steps);
|
56
|
|
57
|
try {
|
58
|
datasource.startTransaction();
|
59
|
result &= currentSchemaUpdater.invoke(datasource, monitor);
|
60
|
if (result == true){
|
61
|
result &= currentTermUpdater.invoke(datasource, monitor);
|
62
|
updateHibernateSequence(datasource, monitor);
|
63
|
}
|
64
|
if (result == false){
|
65
|
datasource.rollback();
|
66
|
}else{
|
67
|
datasource.commitTransaction();
|
68
|
}
|
69
|
|
70
|
} catch (Exception e) {
|
71
|
result = false;
|
72
|
monitor.warning("Stopped schema updater");
|
73
|
} finally {
|
74
|
String message = "Update finished " + (result ? "successfully" : "with ERRORS");
|
75
|
monitor.subTask(message);
|
76
|
if (!result){
|
77
|
monitor.warning(message);
|
78
|
monitor.setCanceled(true);
|
79
|
}else{
|
80
|
monitor.done();
|
81
|
}
|
82
|
logger.info(message);
|
83
|
}
|
84
|
|
85
|
return result;
|
86
|
}
|
87
|
|
88
|
|
89
|
/**
|
90
|
* Updating terms often inserts new terms, vocabularies and representations.
|
91
|
* Therefore the counter in hibernate_sequences must be increased.
|
92
|
* We do this once at the end of term updating.
|
93
|
* @return true if update was successful, false otherwise
|
94
|
*/
|
95
|
private boolean updateHibernateSequence(ICdmDataSource datasource, IProgressMonitor monitor) {
|
96
|
boolean result = true;
|
97
|
monitor.subTask("Update hibernate sequences");
|
98
|
try {
|
99
|
String sql = "SELECT * FROM hibernate_sequences ";
|
100
|
ResultSet rs = datasource.executeQuery(sql);
|
101
|
while (rs.next()){
|
102
|
String table = rs.getString("sequence_name");
|
103
|
Integer val = rs.getInt("next_val");
|
104
|
result &= updateSingleValue(datasource,monitor, table, val);
|
105
|
}
|
106
|
} catch (Exception e) {
|
107
|
String message = "Exception occurred when trying to update hibernate_sequences table: " + e.getMessage();
|
108
|
monitor.warning(message, e);
|
109
|
logger.error(message);
|
110
|
result = false;
|
111
|
}finally{
|
112
|
monitor.worked(1);
|
113
|
}
|
114
|
return result;
|
115
|
}
|
116
|
|
117
|
/**
|
118
|
*
|
119
|
* @param datasource
|
120
|
* @param monitor
|
121
|
* @param table
|
122
|
* @param oldVal
|
123
|
* @return
|
124
|
*/
|
125
|
private boolean updateSingleValue(ICdmDataSource datasource, IProgressMonitor monitor, String table, Integer oldVal){
|
126
|
try {
|
127
|
Integer newVal;
|
128
|
try {
|
129
|
String sql = " SELECT max(id) FROM %s ";
|
130
|
newVal = (Integer)datasource.getSingleValue(String.format(sql, table));
|
131
|
} catch (Exception e) {
|
132
|
String message = "Could not retrieve max value for table '%s'. Will not update hibernate_sequence for this table. Usually this will not cause problems, however, if new data has been added to this table by the update script one may encounter 'unique identifier' exceptions when trying to add further data.";
|
133
|
monitor.warning(message, e);
|
134
|
//TODO
|
135
|
return true;
|
136
|
}
|
137
|
|
138
|
//This is how {@link PooledOptimizer#generate(org.hibernate.id.enhanced.AccessCallback)} works
|
139
|
//it substracts the increment size from the value in hibernate_sequences to get the initial value.
|
140
|
//Haven't checked why.
|
141
|
//For the correct increment size see eu.etaxonomy.cdm.model.common.package-info.java
|
142
|
int incrementSize = 10;
|
143
|
newVal = newVal + incrementSize;
|
144
|
if (newVal != null && newVal >= oldVal){
|
145
|
String sql = " UPDATE hibernate_sequences " +
|
146
|
" SET next_val = %d " +
|
147
|
" WHERE sequence_name = '%s' ";
|
148
|
datasource.executeUpdate(String.format(sql, newVal + 1 , table) );
|
149
|
}
|
150
|
return true;
|
151
|
} catch (Exception e) {
|
152
|
String message = "Exception occurred when trying to read or update hibernate_sequences table for value " + table + ": " + e.getMessage();
|
153
|
monitor.warning(message, e);
|
154
|
logger.error(message);
|
155
|
return false;
|
156
|
}
|
157
|
|
158
|
}
|
159
|
|
160
|
|
161
|
private ITermUpdater getCurrentTermUpdater() {
|
162
|
return TermUpdater_31_33.NewInstance();
|
163
|
}
|
164
|
|
165
|
/**
|
166
|
* Returns the current CDM updater
|
167
|
* @return
|
168
|
*/
|
169
|
private ISchemaUpdater getCurrentSchemaUpdater() {
|
170
|
return SchemaUpdater_31_33.NewInstance();
|
171
|
}
|
172
|
|
173
|
/**
|
174
|
* @param args
|
175
|
*/
|
176
|
public static void main(String[] args) {
|
177
|
logger.warn("main method not yet fully implemented (only works with mysql!!!)");
|
178
|
if(args.length < 2){
|
179
|
logger.error("Arguments missing: server database [username [password]]");
|
180
|
}
|
181
|
//TODO better implementation
|
182
|
CdmUpdater myUpdater = new CdmUpdater();
|
183
|
String server = args[0];
|
184
|
String database = args[1];
|
185
|
String username = args.length > 2 ? args[2] : null;
|
186
|
String password = args.length > 3 ? args[3] : null;
|
187
|
|
188
|
ICdmDataSource dataSource = CdmDataSource.NewMySqlInstance(server, database, username, password);
|
189
|
boolean success = myUpdater.updateToCurrentVersion(dataSource, null);
|
190
|
System.out.println("DONE " + (success ? "successfully" : "with ERRORS"));
|
191
|
}
|
192
|
|
193
|
}
|