From 668ae5ac9f25658068ed85bde17cebe6b0a28749 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Tue, 19 Jun 2007 13:13:01 +0000
Subject: [PATCH] LMS-34 Move SQL code to create DATABSE_VERSION_LOG into a
 separate script file

SVN: 592
---
 .../cisd/dbmigration/DBMigrationEngine.java   |  21 +++-
 .../dbmigration/DatabaseVersionLogDAO.java    |  14 +--
 .../dbmigration/IDatabaseVersionLogDAO.java   |   4 +-
 .../cisd/dbmigration/ISqlScriptProvider.java  |   8 ++
 .../cisd/dbmigration/SqlScriptProvider.java   |  10 +-
 .../dbmigration/DBMigrationEngineTest.java    | 103 +++++++++++++++++-
 .../dbmigration/SqlScriptExecutorTest.java    |  15 +++
 7 files changed, 155 insertions(+), 20 deletions(-)

diff --git a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DBMigrationEngine.java b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DBMigrationEngine.java
index 051c0899b93..61a3b7827af 100644
--- a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DBMigrationEngine.java
+++ b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DBMigrationEngine.java
@@ -22,6 +22,7 @@ import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.utilities.OSUtilities;
 
 /**
  * Class for creating and migrating a database.
@@ -30,6 +31,9 @@ import ch.systemsx.cisd.common.logging.LogFactory;
  */
 public class DBMigrationEngine
 {
+    //@Private
+    static final String CREATE_LOG_SQL = "createLog.sql";
+
     private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, DBMigrationEngine.class);
 
     private final boolean shouldCreateFromScratch;
@@ -141,7 +145,22 @@ public class DBMigrationEngine
     private void createEmptyDatabase(String version)
     {
         adminDAO.createDatabase();
-        logDAO.createTable();
+        Script createScript = scriptProvider.getScript(CREATE_LOG_SQL);
+        if (createScript == null)
+        {
+            String message = "Missing script " + CREATE_LOG_SQL;
+            operationLog.error(message);
+            throw new EnvironmentFailureException(message);
+        }
+        try
+        {
+            logDAO.createTable(createScript);
+        } catch (RuntimeException e)
+        {
+            operationLog.error("Script '" + createScript.getName() + "' failed:" + OSUtilities.LINE_SEPARATOR 
+                               + createScript.getCode(), e);
+            throw e;
+        }
         
         Script script = scriptProvider.getSchemaScript(version);
         if (script == null)
diff --git a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseVersionLogDAO.java b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseVersionLogDAO.java
index 421800232ba..39faa93fe3c 100644
--- a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseVersionLogDAO.java
+++ b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseVersionLogDAO.java
@@ -67,16 +67,6 @@ class DatabaseVersionLogDAO extends SimpleJdbcDaoSupport implements IDatabaseVer
 
     private static final String DB_VERSION_LOG = "database_version_logs";
     
-    private static final String CREATE_DB_VERSION_TABLE =
-            "create table " + DB_VERSION_LOG 
-            + " (" + DB_VERSION + "           varchar(4) not null" 
-            + " ," + MODULE_NAME + "          varchar(250)"
-            + " ," + RUN_STATUS + "           varchar(10)"
-            + " ," + RUN_STATUS_TIMESTAMP + " timestamp"
-            + " ," + MODULE_CODE + "          bytea"
-            + " ," + RUN_EXCEPTION + "        bytea"
-            + ")";
-    
     private static final class LogEntryRowMapper implements ParameterizedRowMapper<LogEntry>
     {
         private final LobHandler lobHandler;
@@ -145,10 +135,10 @@ class DatabaseVersionLogDAO extends SimpleJdbcDaoSupport implements IDatabaseVer
         }
     }
 
-    public void createTable()
+    public void createTable(Script script)
     {
         JdbcTemplate template = getJdbcTemplate();
-        template.execute(CREATE_DB_VERSION_TABLE);
+        template.execute(script.getCode());
     }
     
     public LogEntry getLastEntry()
diff --git a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/IDatabaseVersionLogDAO.java b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/IDatabaseVersionLogDAO.java
index 7b97f40a512..4cbf496e47b 100644
--- a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/IDatabaseVersionLogDAO.java
+++ b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/IDatabaseVersionLogDAO.java
@@ -30,9 +30,9 @@ public interface IDatabaseVersionLogDAO
     public boolean canConnectToDatabase();
     
     /**
-     * Creates the table DATABASE_VERSION_LOG.
+     * Creates the table DATABASE_VERSION_LOG by using the specified script.
      */
-    public void createTable();
+    public void createTable(Script script);
     
     /**
      * Returns the last log entry found.
diff --git a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/ISqlScriptProvider.java b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/ISqlScriptProvider.java
index a32de7ca80f..1442bef42c3 100644
--- a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/ISqlScriptProvider.java
+++ b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/ISqlScriptProvider.java
@@ -47,4 +47,12 @@ public interface ISqlScriptProvider
      * @return <code>null</code> if there isn't such a migration script. 
      */
     public Script getMigrationScript(String fromVersion, String toVersion);
+    
+    /**
+     * Returns the specified script.
+     * 
+     * @param scriptName The name of the script file. File extension has to be included.
+     * @return <code>null</code> if there isn't such a script. 
+     */
+    public Script getScript(String scriptName);
 }
diff --git a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SqlScriptProvider.java b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SqlScriptProvider.java
index 07d95de3371..07252b2a466 100644
--- a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SqlScriptProvider.java
+++ b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SqlScriptProvider.java
@@ -76,7 +76,7 @@ public class SqlScriptProvider implements ISqlScriptProvider
     }
 
     /**
-     * Returns the schmea script for the specified version. 
+     * Returns the schema script for the specified version. 
      * The name of the script is expected to be
      * <pre>&lt;schema script folder&gt;/&lt;version&gt;/schema-&lt;version&gt;.sql</pre>
      */
@@ -85,6 +85,14 @@ public class SqlScriptProvider implements ISqlScriptProvider
         return loadScript(schemaScriptFolder + "/" + version, "schema-" + version + SQL_FILE_TYPE);
     }
 
+    /**
+     * Returns the specified script relative to the schema script folder.
+     */
+    public Script getScript(String scriptName)
+    {
+        return loadScript(schemaScriptFolder, scriptName);
+    }
+
     private Script loadScript(String folder, String scriptName)
     {
         String fullScriptName = folder + "/" + scriptName;
diff --git a/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/DBMigrationEngineTest.java b/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/DBMigrationEngineTest.java
index 6441fd6dd80..91fb59dca15 100644
--- a/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/DBMigrationEngineTest.java
+++ b/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/DBMigrationEngineTest.java
@@ -57,6 +57,14 @@ public class DBMigrationEngineTest
             one(scriptExecutor).execute(script.getCode());
             one(logDAO).logSuccess(version, script.getName());
         }
+        
+        protected void expectCreateLogDAOTable()
+        {
+            one(scriptProvider).getScript(DBMigrationEngine.CREATE_LOG_SQL);
+            Script script = new Script(DBMigrationEngine.CREATE_LOG_SQL, "create log");
+            will(returnValue(script));
+            one(logDAO).createTable(with(same(script)));
+        }
     }
     
     private Mockery context;
@@ -128,7 +136,8 @@ public class DBMigrationEngineTest
                 will(returnValue("my 1. database"));
                 one(adminDAO).createOwner();
                 one(adminDAO).createDatabase();
-                one(logDAO).createTable();
+                
+                expectCreateLogDAOTable();
                 one(scriptProvider).getSchemaScript(version);
                 expectSuccessfulExecution(new Script("schema", "schema code"), version);
                 one(scriptProvider).getDataScript(version);
@@ -210,7 +219,7 @@ public class DBMigrationEngineTest
                 will(returnValue("my 1. database"));
                 one(adminDAO).createOwner();
                 one(adminDAO).createDatabase();
-                one(logDAO).createTable();
+                expectCreateLogDAOTable();
                 one(scriptProvider).getSchemaScript(version);
                 expectSuccessfulExecution(new Script("schema", "schema code"), version);
                 one(scriptProvider).getDataScript(version);
@@ -251,7 +260,7 @@ public class DBMigrationEngineTest
                 will(returnValue("my 1. database"));
                 one(adminDAO).createOwner();
                 one(adminDAO).createDatabase();
-                one(logDAO).createTable();
+                expectCreateLogDAOTable();
                 one(scriptProvider).getSchemaScript(version);
                 expectSuccessfulExecution(new Script("schema", "schema code"), version);
                 one(scriptProvider).getDataScript(version);
@@ -291,7 +300,7 @@ public class DBMigrationEngineTest
                 will(returnValue("my 1. database"));
                 one(adminDAO).createOwner();
                 one(adminDAO).createDatabase();
-                one(logDAO).createTable();
+                expectCreateLogDAOTable();
                 one(scriptProvider).getSchemaScript(version);
             }
         });
@@ -314,6 +323,92 @@ public class DBMigrationEngineTest
         context.assertIsSatisfied();
     }
     
+    @Test
+    public void testCreateFromScratchWithMissingCreateLogScript()
+    {
+        final String version = "042";
+        context.checking(new MyExpectations()
+        {
+            {
+                one(daoFactory).getDatabaseDAO();
+                will(returnValue(adminDAO));
+                one(daoFactory).getDatabaseVersionLogDAO();
+                will(returnValue(logDAO));
+                one(daoFactory).getSqlScriptExecutor();
+                will(returnValue(scriptExecutor));
+                
+                one(logDAO).canConnectToDatabase();
+                will(returnValue(false));
+                one(adminDAO).getDatabaseName();
+                will(returnValue("my 1. database"));
+                one(adminDAO).createOwner();
+                one(adminDAO).createDatabase();
+                one(scriptProvider).getScript(DBMigrationEngine.CREATE_LOG_SQL);
+            }
+        });
+        DBMigrationEngine migrationEngine = new DBMigrationEngine(daoFactory, scriptProvider, false);
+        
+        logRecorder.reset();
+        String message = "Missing script createLog.sql";
+        try
+        {
+            migrationEngine.migrateTo(version);
+            fail("EnvironmentFailureException expected because of missing log creation script");
+        } catch (EnvironmentFailureException e)
+        {
+            assertEquals(message, e.getMessage());
+        }
+        assertEquals("INFO  OPERATION.ch.systemsx.cisd.dbmigration.DBMigrationEngine - "
+                + "Database 'my 1. database' does not exist." + OSUtilities.LINE_SEPARATOR
+                + "ERROR OPERATION.ch.systemsx.cisd.dbmigration.DBMigrationEngine - " + message, getLogContent());
+        
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testCreateFromScratchWithCreateLogScriptWhichFails()
+    {
+        final String version = "042";
+        final RuntimeException exception = new RuntimeException();
+        context.checking(new MyExpectations()
+        {
+            {
+                one(daoFactory).getDatabaseDAO();
+                will(returnValue(adminDAO));
+                one(daoFactory).getDatabaseVersionLogDAO();
+                will(returnValue(logDAO));
+                one(daoFactory).getSqlScriptExecutor();
+                will(returnValue(scriptExecutor));
+                
+                one(logDAO).canConnectToDatabase();
+                will(returnValue(false));
+                one(adminDAO).getDatabaseName();
+                will(returnValue("my database"));
+                one(adminDAO).createOwner();
+                one(adminDAO).createDatabase();
+                expectCreateLogDAOTable();
+                will(throwException(exception));
+            }
+        });
+        DBMigrationEngine migrationEngine = new DBMigrationEngine(daoFactory, scriptProvider, false);
+        
+        logRecorder.reset();
+        try
+        {
+            migrationEngine.migrateTo(version);
+            fail("RuntimeException expected because of failing log creation script");
+        } catch (RuntimeException e)
+        {
+            assertSame(exception, e);
+        }
+        assertEquals("INFO  OPERATION.ch.systemsx.cisd.dbmigration.DBMigrationEngine - "
+                + "Database 'my database' does not exist." + OSUtilities.LINE_SEPARATOR
+                + "ERROR OPERATION.ch.systemsx.cisd.dbmigration.DBMigrationEngine - Script 'createLog.sql' failed:" + OSUtilities.LINE_SEPARATOR 
+                + "create log" + OSUtilities.LINE_SEPARATOR + getStackTrace(exception), getLogContent());
+        
+        context.assertIsSatisfied();
+    }
+    
     @Test
     public void testCaseNoMigrationNeeded()
     {
diff --git a/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/SqlScriptExecutorTest.java b/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/SqlScriptExecutorTest.java
index c9fd88e5004..fff6cfb0cb7 100644
--- a/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/SqlScriptExecutorTest.java
+++ b/dbmigration/sourceTest/java/ch/systemsx/cisd/dbmigration/SqlScriptExecutorTest.java
@@ -49,6 +49,7 @@ public class SqlScriptExecutorTest
     public void setUpTestFiles() throws IOException
     {
         TEMP_SCHEMA_SCRIPT_FOLDER.mkdir();
+        write(new File(TEMP_SCHEMA_SCRIPT_FOLDER, "hello.script"), "hello world!");
         File schemaVersionFolder = new File(TEMP_SCHEMA_SCRIPT_FOLDER, VERSION);
         schemaVersionFolder.mkdir();
         write(new File(schemaVersionFolder, "schema-" + VERSION + ".sql"), "code: schema");
@@ -141,4 +142,18 @@ public class SqlScriptExecutorTest
         assertEquals(null, sqlScriptProvider.getMigrationScript("000", "001"));
     }
     
+    @Test
+    public void testGetScript()
+    {
+        Script script = sqlScriptProvider.getScript("hello.script");
+        assertEquals(TEMPORARY_SCHEMA_SCRIPT_FOLDER_NAME + "/hello.script", script.getName());
+        assertEquals("hello world!", script.getCode().trim());
+    }
+
+    @Test
+    public void testGetNonExistingScript()
+    {
+        assertEquals(null, sqlScriptProvider.getScript("blabla.sql"));
+    }
+    
 }
-- 
GitLab