mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 20:29:52 +01:00
Store schema version in database. Dev task #50.
If the schema of the database is incompatible with the schema expected by the code, the database throws a DbSchemaException. LifecycleManager indicates the error to BriarService, which uses HomeScreenActivity to show a notification and quit the app.
This commit is contained in:
@@ -34,6 +34,7 @@ import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.db.DbClosedException;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.DbSchemaException;
|
||||
import org.briarproject.api.db.MessageHeader;
|
||||
import org.briarproject.api.messaging.Group;
|
||||
import org.briarproject.api.messaging.GroupId;
|
||||
@@ -56,6 +57,14 @@ import org.briarproject.api.transport.TemporarySecret;
|
||||
*/
|
||||
abstract class JdbcDatabase implements Database<Connection> {
|
||||
|
||||
private static final int SCHEMA_VERSION = 1;
|
||||
|
||||
private static final String CREATE_SETTINGS =
|
||||
"CREATE TABLE settings"
|
||||
+ " (key VARCHAR NOT NULL,"
|
||||
+ " value VARCHAR NOT NULL,"
|
||||
+ " PRIMARY KEY (key))";
|
||||
|
||||
// Locking: identity
|
||||
// Dependents: contact, message, retention, subscription, transport, window
|
||||
private static final String CREATE_LOCAL_AUTHORS =
|
||||
@@ -356,7 +365,13 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
// Open the database and create the tables if necessary
|
||||
Connection txn = startTransaction();
|
||||
try {
|
||||
if(!reopen) createTables(txn);
|
||||
if(reopen) {
|
||||
if(!checkSchemaVersion(txn))
|
||||
throw new DbSchemaException();
|
||||
} else {
|
||||
createTables(txn);
|
||||
setSchemaVersion(txn);
|
||||
}
|
||||
commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
abortTransaction(txn);
|
||||
@@ -364,10 +379,53 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkSchemaVersion(Connection txn) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
String value;
|
||||
try {
|
||||
String sql = "SELECT value FROM settings WHERE key = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setString(1, "schemaVersion");
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbStateException();
|
||||
value = rs.getString(1);
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
try {
|
||||
return Integer.valueOf(value) == SCHEMA_VERSION;
|
||||
} catch(NumberFormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToClose(ResultSet rs) {
|
||||
if(rs != null) try {
|
||||
rs.close();
|
||||
} catch(SQLException e) {
|
||||
if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToClose(Statement s) {
|
||||
if(s != null) try {
|
||||
s.close();
|
||||
} catch(SQLException e) {
|
||||
if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createTables(Connection txn) throws DbException {
|
||||
Statement s = null;
|
||||
try {
|
||||
s = txn.createStatement();
|
||||
s.executeUpdate(insertTypeNames(CREATE_SETTINGS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_LOCAL_AUTHORS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUPS));
|
||||
@@ -405,19 +463,19 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
return s;
|
||||
}
|
||||
|
||||
private void tryToClose(Statement s) {
|
||||
if(s != null) try {
|
||||
s.close();
|
||||
private void setSchemaVersion(Connection txn) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "INSERT INTO settings (key, value) VALUES (?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setString(1, "schemaVersion");
|
||||
ps.setString(2, String.valueOf(SCHEMA_VERSION));
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch(SQLException e) {
|
||||
if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToClose(ResultSet rs) {
|
||||
if(rs != null) try {
|
||||
rs.close();
|
||||
} catch(SQLException e) {
|
||||
if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class LifecycleManagerImpl implements LifecycleManager {
|
||||
executors.add(e);
|
||||
}
|
||||
|
||||
public void startServices() {
|
||||
public boolean startServices() {
|
||||
try {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Starting");
|
||||
boolean reopened = db.open();
|
||||
@@ -64,12 +64,16 @@ class LifecycleManagerImpl implements LifecycleManager {
|
||||
if(started) LOG.info("Service started: " + name);
|
||||
else LOG.info("Service failed to start: " + name);
|
||||
}
|
||||
if(!started) return false;
|
||||
}
|
||||
startupLatch.countDown();
|
||||
return true;
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
return false;
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user