Index: Application/Ringtoets/src/Application.Ringtoets.Storage/Properties/Resources.Designer.cs =================================================================== diff -u -rbc9552772d4e6a6bd786dfcaef808da1964e8c53 -r7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753 --- Application/Ringtoets/src/Application.Ringtoets.Storage/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision bc9552772d4e6a6bd786dfcaef808da1964e8c53) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753) @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34209 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -61,30 +61,27 @@ } /// - /// Looks up a localized string similar to /* ---------------------------------------------------- */ - ////* Generated by Enterprise Architect Version 12.0 */ - ////* Created On : 21-apr-2016 15:29:00 */ - ////* DBMS : SQLite */ - ////* ---------------------------------------------------- */ - /// - ////* Drop Tables */ - /// - ///DROP TABLE IF EXISTS 'VersionEntity' - ///; - /// - ///DROP TABLE IF EXISTS 'ProjectEntity' - ///; - /// - ///DROP TABLE IF EXISTS 'AssessmentSectionEntity' - ///; - /// - ///DROP TABLE IF EXISTS 'FailureMechanismEntity' - ///; - /// - ///DROP TABLE IF EXISTS 'HydraulicLocationEntity' - ///; - /// - ///DROP TABL [rest of string was truncated]";. + /// Looks up a localized string similar to /* ---------------------------------------------------- */ + ////* Generated by Enterprise Architect Version 12.0 */ + ////* Created On : 13-jul-2016 16:03:28 */ + ////* DBMS : SQLite */ + ////* ---------------------------------------------------- */ + /// + ////* Drop Tables */ + /// + ///DROP TABLE IF EXISTS 'VersionEntity' + ///; + /// + ///DROP TABLE IF EXISTS 'PipingFailureMechanismMetaEntity' + ///; + /// + ///DROP TABLE IF EXISTS 'ProjectEntity' + ///; + /// + ///DROP TABLE IF EXISTS 'AssessmentSectionEntity' + ///; + /// + ///DROP TABLE IF EXISTS 'FailureMechanismSectionEnti [rest of string was truncated]";. /// internal static string DatabaseStructure { get { @@ -154,5 +151,32 @@ return ResourceManager.GetString("StorageSqLite_LoadProject_Invalid_Ringtoets_database_file", resourceCulture); } } + + /// + /// Looks up a localized string similar to Kon het tijdelijke bestand '{0}' niet aanmaken op de aangewezen locatie.. + /// + internal static string StorageSqLite_TryCreateTemporaryFile_Could_not_create_temporary_file_at_path_0 { + get { + return ResourceManager.GetString("StorageSqLite_TryCreateTemporaryFile_Could_not_create_temporary_file_at_path_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kon het reeds bestaande tijdelijk bestand '{0}' niet verwijderen.. + /// + internal static string StorageSqLite_TryDeleteExistingTemporaryFile_Could_not_delete_existing_file_0 { + get { + return ResourceManager.GetString("StorageSqLite_TryDeleteExistingTemporaryFile_Could_not_delete_existing_file_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kon het bestand '{0}' niet overschrijven.. + /// + internal static string StorageSqLite_TryMoveTemporaryFileToDestination_Could_not_overwrite_file_0 { + get { + return ResourceManager.GetString("StorageSqLite_TryMoveTemporaryFileToDestination_Could_not_overwrite_file_0", resourceCulture); + } + } } } Index: Application/Ringtoets/src/Application.Ringtoets.Storage/Properties/Resources.resx =================================================================== diff -u -rbc9552772d4e6a6bd786dfcaef808da1964e8c53 -r7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753 --- Application/Ringtoets/src/Application.Ringtoets.Storage/Properties/Resources.resx (.../Resources.resx) (revision bc9552772d4e6a6bd786dfcaef808da1964e8c53) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/Properties/Resources.resx (.../Resources.resx) (revision 7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753) @@ -142,4 +142,13 @@ Het bestand is geen geldig Ringtoets bestand. + + Kon het reeds bestaande tijdelijk bestand '{0}' niet verwijderen. + + + Kon het tijdelijke bestand '{0}' niet aanmaken op de aangewezen locatie. + + + Kon het bestand '{0}' niet overschrijven. + \ No newline at end of file Index: Application/Ringtoets/src/Application.Ringtoets.Storage/StorageSqLite.cs =================================================================== diff -u -rfd1d509e55af9d6961d8765545261f47cb61ee4d -r7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753 --- Application/Ringtoets/src/Application.Ringtoets.Storage/StorageSqLite.cs (.../StorageSqLite.cs) (revision fd1d509e55af9d6961d8765545261f47cb61ee4d) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/StorageSqLite.cs (.../StorageSqLite.cs) (revision 7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753) @@ -78,6 +78,7 @@ } SetConnectionToNewFile(databaseFilePath); + using (var dbContext = new RingtoetsEntities(connectionString)) { try @@ -129,7 +130,15 @@ throw new ArgumentNullException("project"); } - SetConnectionToFile(databaseFilePath); + try + { + SetConnectionToExistingFile(databaseFilePath); + } + catch + { + return SaveProjectAs(databaseFilePath, project); + } + using (var dbContext = new RingtoetsEntities(connectionString)) { try @@ -177,14 +186,19 @@ /// public Project LoadProject(string databaseFilePath) { - SetConnectionToFile(databaseFilePath); + SetConnectionToExistingFile(databaseFilePath); try { using (var dbContext = new RingtoetsEntities(connectionString)) { - var projectEntity = GetSingleProject(dbContext); - if (projectEntity == null) + ProjectEntity projectEntity; + + try { + projectEntity = dbContext.ProjectEntities.Single(); + } + catch (InvalidOperationException) + { throw CreateStorageReaderException(Resources.StorageSqLite_LoadProject_Invalid_Ringtoets_database_file); } @@ -227,71 +241,31 @@ return dbContext.ChangeTracker.HasChanges(); } - catch (EntityNotFoundException) {} - catch (SystemException) {} - return false; + catch (EntityNotFoundException) + { + return true; + } + catch (SystemException) + { + return true; + } } } - private ProjectEntity GetSingleProject(RingtoetsEntities dbContext) - { - try - { - return dbContext.ProjectEntities.Single(); - } - catch (InvalidOperationException) - { - return null; - } - } - /// - /// Throws a configured instance of when writing to the storage file failed. - /// - /// The critical error message. - /// Optional: exception that caused this exception to be thrown. - /// Returns a new . - private StorageException CreateStorageWriterException(string errorMessage, Exception innerException = null) - { - var message = new FileWriterErrorMessageBuilder(filePath).Build(errorMessage); - return new StorageException(message, innerException); - } - - /// - /// Throws a configured instance of when reading the storage file failed. - /// - /// The critical error message. - /// Optional: exception that caused this exception to be thrown. - /// Returns a new . - private StorageException CreateStorageReaderException(string errorMessage, Exception innerException = null) - { - var message = new FileReaderErrorMessageBuilder(filePath).Build(errorMessage); - return new StorageException(message, innerException); - } - - /// /// Attempts to set the connection to an existing storage file . /// /// Path to database file. /// is invalid. /// Thrown when: /// does not exist - /// the database does not contain the table version. + /// the database has an invalid schema. /// /// - private void SetConnectionToFile(string databaseFilePath) + private void SetConnectionToExistingFile(string databaseFilePath) { FileUtils.ValidateFilePath(databaseFilePath); - filePath = databaseFilePath; - - if (!File.Exists(databaseFilePath)) - { - throw CreateStorageReaderException(string.Empty, new CouldNotConnectException(UtilsResources.Error_File_does_not_exist)); - } - - connectionString = SqLiteConnectionStringBuilder.BuildSqLiteEntityConnectionString(databaseFilePath); - - ValidateStorage(); + SetConnectionToFile(databaseFilePath); } /// @@ -302,16 +276,31 @@ /// Thrown when: /// was not created /// executing DatabaseStructure script failed - /// the database does not contain the table version. /// /// + /// Thrown when the could not + /// be overwritten. private void SetConnectionToNewFile(string databaseFilePath) { - StorageSqliteCreator.CreateDatabaseStructure(databaseFilePath); - + FileUtils.ValidateFilePath(databaseFilePath); + CreateDatabaseStructureInFile(databaseFilePath); SetConnectionToFile(databaseFilePath); } + private void SetConnectionToFile(string databaseFilePath) + { + filePath = databaseFilePath; + + if (!File.Exists(databaseFilePath)) + { + throw CreateStorageReaderException(string.Empty, new CouldNotConnectException(UtilsResources.Error_File_does_not_exist)); + } + + connectionString = SqLiteConnectionStringBuilder.BuildSqLiteEntityConnectionString(databaseFilePath); + + ValidateStorage(); + } + /// /// Validates if the connected storage is a valid Ringtoets database. /// @@ -331,5 +320,106 @@ } } } + + private static void CreateDatabaseStructureInFile(string databaseFilePath) + { + var temporaryFile = databaseFilePath + "~"; + + if (File.Exists(temporaryFile)) + { + TryDeleteExistingTemporaryFile(temporaryFile); + } + + TryCreateTemporaryFile(temporaryFile); + StorageSqliteCreator.CreateDatabaseStructure(temporaryFile); + TryMoveTemporaryFileToDestination(databaseFilePath, temporaryFile); + } + + private static void TryMoveTemporaryFileToDestination(string databaseFilePath, string temporaryFile) + { + try + { + File.Delete(databaseFilePath); + File.Move(temporaryFile, databaseFilePath); + } + catch (Exception e) + { + if (e is ArgumentException || e is IOException || e is SystemException) + { + var message = string.Format(Resources.StorageSqLite_TryMoveTemporaryFileToDestination_Could_not_overwrite_file_0, databaseFilePath); + throw new IOException(message, e); + } + throw; + } + finally + { + try + { + File.Delete(temporaryFile); + } + catch + { + // ignored + } + } + } + + private static void TryCreateTemporaryFile(string temporaryFile) + { + try + { + using (File.Create(temporaryFile)) {} + } + catch (Exception e) + { + if (e is ArgumentException || e is IOException || e is SystemException) + { + var message = string.Format(Resources.StorageSqLite_TryCreateTemporaryFile_Could_not_create_temporary_file_at_path_0, temporaryFile); + throw new IOException(message, e); + } + throw; + } + } + + private static void TryDeleteExistingTemporaryFile(string temporaryFile) + { + try + { + File.Delete(temporaryFile); + } + catch (Exception e) + { + if (e is ArgumentException || e is IOException || e is SystemException) + { + var message = string.Format(Resources.StorageSqLite_TryDeleteExistingTemporaryFile_Could_not_delete_existing_file_0, temporaryFile); + throw new IOException(message, e); + } + throw; + } + } + + /// + /// Throws a configured instance of when writing to the storage file failed. + /// + /// The critical error message. + /// Optional: exception that caused this exception to be thrown. + /// Returns a new . + private StorageException CreateStorageWriterException(string errorMessage, Exception innerException = null) + { + var message = new FileWriterErrorMessageBuilder(filePath).Build(errorMessage); + return new StorageException(message, innerException); + } + + /// + /// Throws a configured instance of when reading the storage file failed. + /// + /// The critical error message. + /// Optional: exception that caused this exception to be thrown. + /// Returns a new . + private StorageException CreateStorageReaderException(string errorMessage, Exception innerException = null) + { + var message = new FileReaderErrorMessageBuilder(filePath).Build(errorMessage); + return new StorageException(message, innerException); + } } } \ No newline at end of file Index: Application/Ringtoets/test/Application.Ringtoets.Storage.Test/StorageSqLiteTest.cs =================================================================== diff -u -rde4477561032a5d95d5e65e50b719724466648ed -r7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753 --- Application/Ringtoets/test/Application.Ringtoets.Storage.Test/StorageSqLiteTest.cs (.../StorageSqLiteTest.cs) (revision de4477561032a5d95d5e65e50b719724466648ed) +++ Application/Ringtoets/test/Application.Ringtoets.Storage.Test/StorageSqLiteTest.cs (.../StorageSqLiteTest.cs) (revision 7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753) @@ -294,7 +294,7 @@ public void SaveProjectAs_ValidPathToLockedFile_ThrowsUpdateStorageException() { // Setup - var expectedMessage = String.Format(@"Fout bij het schrijven naar bestand '{0}': Een fout is opgetreden met schrijven naar het nieuwe Ringtoets bestand.", tempRingtoetsFile); + var expectedMessage = string.Format(@"Kon het bestand '{0}' niet overschrijven.", tempRingtoetsFile); var project = new Project(); var storage = new StorageSqLite(); @@ -304,15 +304,15 @@ // Call TestDelegate test = () => storage.SaveProjectAs(tempRingtoetsFile, project); - StorageException exception; + IOException exception; using (File.Create(tempRingtoetsFile)) // Locks file { - exception = Assert.Throws(test); + exception = Assert.Throws(test); } // Assert Assert.IsInstanceOf(exception); - Assert.IsInstanceOf(exception.InnerException); + Assert.IsInstanceOf(exception.InnerException); Assert.IsInstanceOf(exception); Assert.AreEqual(expectedMessage, exception.Message); } @@ -369,28 +369,29 @@ } [Test] - public void SaveProject_ValidProjectNonExistingPath_ThrowsStorageExceptionAndCouldNotConnectException() + public void SaveProject_ValidProjectNonExistingPath_NewFileCreated() { // Setup var project = new Project { StorageId = 1234L }; var tempFile = Path.Combine(testDataPath, "DoesNotExist.rtd"); - var expectedMessage = String.Format(@"Fout bij het lezen van bestand '{0}': ", tempFile); - var expectedInnerMessage = "Het bestand bestaat niet."; var storage = new StorageSqLite(); - // Call - TestDelegate test = () => storage.SaveProject(tempFile, project); + try + { + // Call + storage.SaveProject(tempFile, project); - // Assert - StorageException exception = Assert.Throws(test); - Assert.IsInstanceOf(exception); - Assert.AreEqual(expectedMessage, exception.Message); - - Assert.IsInstanceOf(exception.InnerException); - Assert.AreEqual(expectedInnerMessage, exception.InnerException.Message); + // Assert + Assert.IsTrue(File.Exists(tempFile)); + } + finally + { + CallGarbageCollector(); + File.Delete(tempFile); + } } [Test] Index: Core/Common/src/Core.Common.Gui/Commands/StorageCommandHandler.cs =================================================================== diff -u -r223b2a4edc4ac816051c7eeecb735c34a6246574 -r7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753 --- Core/Common/src/Core.Common.Gui/Commands/StorageCommandHandler.cs (.../StorageCommandHandler.cs) (revision 223b2a4edc4ac816051c7eeecb735c34a6246574) +++ Core/Common/src/Core.Common.Gui/Commands/StorageCommandHandler.cs (.../StorageCommandHandler.cs) (revision 7a542dea56b0bcfbbd4dd6f2c6abcafcfaa5f753) @@ -234,8 +234,7 @@ case DialogResult.Cancel: return false; case DialogResult.Yes: - SaveProject(); - break; + return SaveProject(); case DialogResult.No: break; }