/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2015 Philipp C. Heckel <philipp.heckel@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.syncany.database.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.syncany.database.VectorClock;
import org.syncany.plugins.transfer.files.DatabaseRemoteFile;
/**
* The application data access object (DAO) writes and queries the SQL database for
* general information about the application.
*
* @author Philipp C. Heckel <philipp.heckel@gmail.com>
*/
public class ApplicationSqlDao extends AbstractSqlDao {
protected static final Logger logger = Logger.getLogger(ApplicationSqlDao.class.getSimpleName());
public ApplicationSqlDao(Connection connection) {
super(connection);
}
/**
* Writes a list of {@link DatabaseRemoteFile}s to the database using the given connection.
* <p><b>Note:</b> This method executes, but does not commit the query.
*
* @param remoteDatabases List of remote databases to write to the database
* @throws SQLException If the SQL statement fails
*/
public void writeKnownRemoteDatabases(List<DatabaseRemoteFile> remoteDatabases) throws SQLException {
if (remoteDatabases.size() == 0) {
// Nothing to write
return;
}
PreparedStatement preparedStatement = getStatement("application.insert.all.persistNewKnownRemoteDatabases.sql");
for (DatabaseRemoteFile databaseRemoteFile : remoteDatabases) {
preparedStatement.setString(1, databaseRemoteFile.getClientName());
preparedStatement.setInt(2, (int) databaseRemoteFile.getClientVersion());
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
}
public VectorClock getHighestKnownDatabaseFilenameNumbers() {
VectorClock highestKnownDatabaseFilenameNumbers = new VectorClock();
try (PreparedStatement preparedStatement = getStatement("application.select.all.getHighestKnownDatabaseFilenameNumbers.sql")) {
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String clientName = resultSet.getString("client");
int fileNumber = resultSet.getInt("filenumber");
highestKnownDatabaseFilenameNumbers.put(clientName, (long) fileNumber);
}
return highestKnownDatabaseFilenameNumbers;
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Queries the database for already known {@link DatabaseRemoteFile}s and returns a
* list of all of them.
*
* @return Returns a list of all known/processed remote databases
*/
public List<DatabaseRemoteFile> getKnownDatabases() {
List<DatabaseRemoteFile> knownDatabases = new ArrayList<DatabaseRemoteFile>();
try (PreparedStatement preparedStatement = getStatement("application.select.all.getKnownDatabases.sql")) {
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String clientName = resultSet.getString("client");
int fileNumber = resultSet.getInt("filenumber");
knownDatabases.add(new DatabaseRemoteFile(clientName, fileNumber));
}
return knownDatabases;
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public void removeKnownDatabases() {
try (PreparedStatement preparedStatement = getStatement("application.delete.all.removeKnownDatabases.sql")) {
preparedStatement.execute();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Deletes all metadata, including known databases.
*/
public void deleteAll() {
try {
runScript("script.delete.all.sql");
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Shuts down the HSQL database, i.e. persists all data, closes all connections
* and unlocks the database for other processes.
*
* <p>The command sends the <b><tt>SHUTDOWN</tt></b> SQL command.
*/
public void shutdown() {
try {
connection.prepareStatement("shutdown").execute();
}
catch (SQLException e) {
logger.log(Level.FINE, "Could not shutdown the connection", e);
}
finally {
try {
connection.close();
}
catch (SQLException e) {
logger.log(Level.FINE, "Could not close the connection", e);
}
}
}
public Long getCleanupNumber() {
return readSettingAsLong("cleanupNumber");
}
public Long getCleanupTime() {
return readSettingAsLong("cleanupTime");
}
public void writeCleanupNumber(long cleanupNumber) {
writeSetting("cleanupNumber", "" + cleanupNumber);
}
public void writeCleanupTime(long cleanupTime) {
writeSetting("cleanupTime", "" + cleanupTime);
}
public Long readSettingAsLong(String key) {
try {
String strValue = readSetting(key);
if (strValue != null) {
return Long.parseLong(strValue);
}
else {
return null;
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public String readSetting(String key) {
try (PreparedStatement preparedStatement = getStatement("application.select.all.readGeneralSettings.sql")) {
preparedStatement.setString(1, key);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
if (resultSet.next()) {
String value = resultSet.getString("value");
logger.log(Level.INFO, "SQL (general_settings): Read " + key + " = " + value);
return value;
}
else {
logger.log(Level.INFO, "SQL (general_settings): Read " + key + " = (not set)");
return null;
}
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public void writeSetting(String key, String value) {
logger.log(Level.INFO, "SQL (general_settings): Writing " + key + " = " + value);
try (PreparedStatement preparedStatement = getStatement("application.insert.all.writeGeneralSettings.sql")) {
preparedStatement.setString(1, key);
preparedStatement.setString(2, value);
preparedStatement.execute();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}