001/* 002 * Syncany, www.syncany.org 003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation, either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018package org.syncany.database.dao; 019 020import java.sql.Connection; 021import java.sql.PreparedStatement; 022import java.sql.ResultSet; 023import java.sql.SQLException; 024import java.util.ArrayList; 025import java.util.List; 026import java.util.logging.Level; 027import java.util.logging.Logger; 028 029import org.syncany.database.VectorClock; 030import org.syncany.plugins.transfer.files.DatabaseRemoteFile; 031 032/** 033 * The application data access object (DAO) writes and queries the SQL database for 034 * general information about the application. 035 * 036 * @author Philipp C. Heckel (philipp.heckel@gmail.com) 037 */ 038public class ApplicationSqlDao extends AbstractSqlDao { 039 protected static final Logger logger = Logger.getLogger(ApplicationSqlDao.class.getSimpleName()); 040 041 public ApplicationSqlDao(Connection connection) { 042 super(connection); 043 } 044 045 /** 046 * Writes a list of {@link DatabaseRemoteFile}s to the database using the given connection. 047 * <p><b>Note:</b> This method executes, but does not commit the query. 048 * 049 * @param remoteDatabases List of remote databases to write to the database 050 * @throws SQLException If the SQL statement fails 051 */ 052 public void writeKnownRemoteDatabases(List<DatabaseRemoteFile> remoteDatabases) throws SQLException { 053 if (remoteDatabases.size() == 0) { 054 // Nothing to write 055 return; 056 } 057 PreparedStatement preparedStatement = getStatement("application.insert.all.persistNewKnownRemoteDatabases.sql"); 058 059 for (DatabaseRemoteFile databaseRemoteFile : remoteDatabases) { 060 preparedStatement.setString(1, databaseRemoteFile.getClientName()); 061 preparedStatement.setInt(2, (int) databaseRemoteFile.getClientVersion()); 062 063 preparedStatement.addBatch(); 064 } 065 066 preparedStatement.executeBatch(); 067 } 068 069 public VectorClock getHighestKnownDatabaseFilenameNumbers() { 070 VectorClock highestKnownDatabaseFilenameNumbers = new VectorClock(); 071 072 try (PreparedStatement preparedStatement = getStatement("application.select.all.getHighestKnownDatabaseFilenameNumbers.sql")) { 073 try (ResultSet resultSet = preparedStatement.executeQuery()) { 074 while (resultSet.next()) { 075 String clientName = resultSet.getString("client"); 076 int fileNumber = resultSet.getInt("filenumber"); 077 078 highestKnownDatabaseFilenameNumbers.put(clientName, (long) fileNumber); 079 } 080 081 return highestKnownDatabaseFilenameNumbers; 082 } 083 } 084 catch (Exception e) { 085 throw new RuntimeException(e); 086 } 087 } 088 089 /** 090 * Queries the database for already known {@link DatabaseRemoteFile}s and returns a 091 * list of all of them. 092 * 093 * @return Returns a list of all known/processed remote databases 094 */ 095 public List<DatabaseRemoteFile> getKnownDatabases() { 096 List<DatabaseRemoteFile> knownDatabases = new ArrayList<DatabaseRemoteFile>(); 097 098 try (PreparedStatement preparedStatement = getStatement("application.select.all.getKnownDatabases.sql")) { 099 try (ResultSet resultSet = preparedStatement.executeQuery()) { 100 while (resultSet.next()) { 101 String clientName = resultSet.getString("client"); 102 int fileNumber = resultSet.getInt("filenumber"); 103 104 knownDatabases.add(new DatabaseRemoteFile(clientName, fileNumber)); 105 } 106 107 return knownDatabases; 108 } 109 } 110 catch (Exception e) { 111 throw new RuntimeException(e); 112 } 113 } 114 115 public void removeKnownDatabases() { 116 try (PreparedStatement preparedStatement = getStatement("application.delete.all.removeKnownDatabases.sql")) { 117 preparedStatement.execute(); 118 } 119 catch (Exception e) { 120 throw new RuntimeException(e); 121 } 122 } 123 124 /** 125 * Deletes all metadata, including known databases. 126 */ 127 public void deleteAll() { 128 try { 129 runScript("script.delete.all.sql"); 130 } 131 catch (Exception e) { 132 throw new RuntimeException(e); 133 } 134 } 135 136 /** 137 * Shuts down the HSQL database, i.e. persists all data, closes all connections 138 * and unlocks the database for other processes. 139 * 140 * <p>The command sends the <b><code>SHUTDOWN</code></b> SQL command. 141 */ 142 public void shutdown() { 143 try { 144 connection.prepareStatement("shutdown").execute(); 145 } 146 catch (SQLException e) { 147 logger.log(Level.FINE, "Could not shutdown the connection", e); 148 } 149 finally { 150 try { 151 connection.close(); 152 } 153 catch (SQLException e) { 154 logger.log(Level.FINE, "Could not close the connection", e); 155 } 156 } 157 } 158 159 public Long getCleanupNumber() { 160 return readSettingAsLong("cleanupNumber"); 161 } 162 163 public Long getCleanupTime() { 164 return readSettingAsLong("cleanupTime"); 165 } 166 167 public void writeCleanupNumber(long cleanupNumber) { 168 writeSetting("cleanupNumber", "" + cleanupNumber); 169 } 170 171 public void writeCleanupTime(long cleanupTime) { 172 writeSetting("cleanupTime", "" + cleanupTime); 173 } 174 175 public Long readSettingAsLong(String key) { 176 try { 177 String strValue = readSetting(key); 178 179 if (strValue != null) { 180 return Long.parseLong(strValue); 181 } 182 else { 183 return null; 184 } 185 } 186 catch (Exception e) { 187 throw new RuntimeException(e); 188 } 189 } 190 191 public String readSetting(String key) { 192 try (PreparedStatement preparedStatement = getStatement("application.select.all.readGeneralSettings.sql")) { 193 preparedStatement.setString(1, key); 194 195 try (ResultSet resultSet = preparedStatement.executeQuery()) { 196 if (resultSet.next()) { 197 String value = resultSet.getString("value"); 198 logger.log(Level.INFO, "SQL (general_settings): Read " + key + " = " + value); 199 200 return value; 201 } 202 else { 203 logger.log(Level.INFO, "SQL (general_settings): Read " + key + " = (not set)"); 204 return null; 205 } 206 } 207 } 208 catch (Exception e) { 209 throw new RuntimeException(e); 210 } 211 } 212 213 public void writeSetting(String key, String value) { 214 logger.log(Level.INFO, "SQL (general_settings): Writing " + key + " = " + value); 215 216 try (PreparedStatement preparedStatement = getStatement("application.insert.all.writeGeneralSettings.sql")) { 217 preparedStatement.setString(1, key); 218 preparedStatement.setString(2, value); 219 220 preparedStatement.execute(); 221 } 222 catch (Exception e) { 223 throw new RuntimeException(e); 224 } 225 } 226}