]> source.dussan.org Git - sonarqube.git/commitdiff
When using H2, database migration is now automatically done
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 18 Apr 2014 10:15:13 +0000 (12:15 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 18 Apr 2014 14:15:32 +0000 (16:15 +0200)
sonar-server/src/main/java/org/sonar/server/db/EmbeddedDatabase.java
sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrator.java
sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
sonar-server/src/main/webapp/WEB-INF/lib/database_version.rb
sonar-server/src/test/java/org/sonar/server/db/migrations/DatabaseMigratorTest.java
sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java

index ced29614549bdb854a1d15d2602f581a4e5a7ffe..2ed48e023e920be5cd3230377d23fd67f6fe3be7 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.lang.StringUtils;
 import org.h2.Driver;
 import org.h2.tools.Server;
+import org.picocontainer.Startable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.CoreProperties;
@@ -34,7 +35,7 @@ import java.io.File;
 import java.sql.DriverManager;
 import java.sql.SQLException;
 
-public class EmbeddedDatabase {
+public class EmbeddedDatabase implements Startable  {
   private static final Logger LOG = LoggerFactory.getLogger(EmbeddedDatabase.class);
   private final Settings settings;
   private Server server;
@@ -43,6 +44,7 @@ public class EmbeddedDatabase {
     this.settings = settings;
   }
 
+  @Override
   public void start() {
     File dbHome = getDataDirectory(settings);
     if (!dbHome.exists()) {
@@ -71,6 +73,7 @@ public class EmbeddedDatabase {
     }
   }
 
+  @Override
   public void stop() {
     if (server != null) {
       server.stop();
index 833389ad924a0139c2e7e294ed217d91460d38f1..a5e3d44cd49c59897a1a1edec473ddaad76540e1 100644 (file)
@@ -22,11 +22,14 @@ package org.sonar.server.db.migrations;
 import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.dbutils.DbUtils;
 import org.apache.ibatis.session.SqlSession;
+import org.picocontainer.Startable;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.platform.ServerUpgradeStatus;
 import org.sonar.core.persistence.Database;
 import org.sonar.core.persistence.DdlUtils;
 import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.plugins.ServerPluginRepository;
 
 import java.sql.Connection;
 
@@ -36,41 +39,57 @@ import java.sql.Connection;
  *
  * @since 2.12
  */
-public class DatabaseMigrator implements ServerComponent {
+public class DatabaseMigrator implements ServerComponent, Startable {
 
   private final MyBatis myBatis;
   private final Database database;
   private final DatabaseMigration[] migrations;
+  private final ServerUpgradeStatus serverUpgradeStatus;
 
-  public DatabaseMigrator(MyBatis myBatis, Database database, DatabaseMigration[] migrations) {
+  /**
+   * ServerPluginRepository is used to ensure H2 schema creation is done only after copy of bundle plugins have been done
+   */
+  public DatabaseMigrator(MyBatis myBatis, Database database, DatabaseMigration[] migrations, ServerUpgradeStatus serverUpgradeStatus,
+                          ServerPluginRepository serverPluginRepository) {
     this.myBatis = myBatis;
     this.database = database;
     this.migrations = migrations;
+    this.serverUpgradeStatus = serverUpgradeStatus;
+  }
+
+  @Override
+  public void start(){
+    createDatabase();
+  }
+
+  @Override
+  public void stop(){
+    // Nothing to do
   }
 
   /**
-   * @return true if the database has been created, false if this database is not supported
+   * @return true if the database has been created, false if this database is not supported or if database has already been created
    */
-  public boolean createDatabase() {
-    if (!DdlUtils.supportsDialect(database.getDialect().getId())) {
-      return false;
-    }
-
-    LoggerFactory.getLogger(getClass()).info("Create database");
-    SqlSession session = null;
-    Connection connection = null;
-    try {
-      session = myBatis.openSession();
-      connection = session.getConnection();
-      createSchema(connection, database.getDialect().getId());
-      return true;
-    } finally {
-      MyBatis.closeQuietly(session);
+  @VisibleForTesting
+  boolean createDatabase() {
+    if (DdlUtils.supportsDialect(database.getDialect().getId()) && serverUpgradeStatus.isFreshInstall()) {
+      LoggerFactory.getLogger(getClass()).info("Create database");
+      SqlSession session = null;
+      Connection connection = null;
+      try {
+        session = myBatis.openSession();
+        connection = session.getConnection();
+        createSchema(connection, database.getDialect().getId());
+        return true;
+      } finally {
+        MyBatis.closeQuietly(session);
 
-      // The connection is probably already closed by session.close()
-      // but it's not documented in mybatis javadoc.
-      DbUtils.closeQuietly(connection);
+        // The connection is probably already closed by session.close()
+        // but it's not documented in mybatis javadoc.
+        DbUtils.closeQuietly(connection);
+      }
     }
+    return false;
   }
 
   public void executeMigration(String className) {
index e7f9d4d9385ec94c684b0545f6f7a66461e75821..333305896a58df4d7f0f0a9d22d85b31a93a9c78 100644 (file)
@@ -152,7 +152,6 @@ class ServerComponents {
       DefaultDatabase.class,
       MyBatis.class,
       DatabaseServerCompatibility.class,
-      DatabaseMigrator.class,
       DatabaseVersion.class,
       PurgeProfiler.class,
       DefaultServerFileSystem.class,
@@ -176,6 +175,8 @@ class ServerComponents {
   Collection level2Components() {
     return Lists.newArrayList(
       DefaultServerUpgradeStatus.class,
+      DatabaseMigrator.class,
+
       // plugins
       ServerPluginJarsInstaller.class,
       ServerPluginJarInstaller.class,
index 222fbe111dba3fa1c613342caf3e823ff6c907ae..b3f764ebc58f0466d2319b64d0bfa7bc2dd96e89 100644 (file)
@@ -35,11 +35,7 @@ import org.sonar.api.test.MutableTestPlan;
 import org.sonar.api.test.MutableTestable;
 import org.sonar.api.test.TestPlan;
 import org.sonar.api.test.Testable;
-import org.sonar.api.web.Footer;
-import org.sonar.api.web.NavigationSection;
-import org.sonar.api.web.Page;
-import org.sonar.api.web.RubyRailsWebservice;
-import org.sonar.api.web.Widget;
+import org.sonar.api.web.*;
 import org.sonar.core.component.SnapshotPerspectives;
 import org.sonar.core.measure.MeasureFilterEngine;
 import org.sonar.core.measure.MeasureFilterResult;
@@ -54,11 +50,7 @@ import org.sonar.server.platform.Platform;
 import org.sonar.server.platform.ServerIdGenerator;
 import org.sonar.server.platform.ServerSettings;
 import org.sonar.server.platform.SettingsChangeNotifier;
-import org.sonar.server.plugins.InstalledPluginReferentialFactory;
-import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
-import org.sonar.server.plugins.ServerPluginRepository;
-import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.plugins.*;
 import org.sonar.server.rule.RuleRepositories;
 import org.sonar.server.source.CodeColorizers;
 import org.sonar.server.user.NewUserNotifier;
@@ -68,6 +60,7 @@ import org.sonar.updatecenter.common.Version;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+
 import java.net.InetAddress;
 import java.sql.Connection;
 import java.util.Collection;
@@ -243,6 +236,7 @@ public final class JRubyFacade {
     return get(Database.class);
   }
 
+  // Only used by Java migration
   public DatabaseMigrator databaseMigrator() {
     return get(DatabaseMigrator.class);
   }
index eec43b437415e456c7b0b547b99c04ca8c5e09d7..24415ce1c0e373c2d658782560133fb5068f17d2 100644 (file)
@@ -70,7 +70,6 @@ class DatabaseVersion
 
   def self.automatic_setup
     if current_version<=0
-      try_restore_structure_dump()
       upgrade_and_start()
     elsif uptodate?
       load_java_web_services
@@ -84,20 +83,6 @@ class DatabaseVersion
     ActiveRecord::Base.connected?
   end
 
-  def self.try_restore_structure_dump()
-    ::Java::OrgSonarServerUi::JRubyFacade.getInstance().databaseMigrator().createDatabase()
-  end
-
-  def self.execute_sql_requests(requests)
-    requests.each do |request|
-      unless request.blank? || request.start_with?('--')
-        request.chomp!
-        request.chop! if request.end_with?(';')
-        ActiveRecord::Base.connection.execute(request)
-      end
-    end
-  end
-
   def self.dialect
     ::Java::OrgSonarServerUi::JRubyFacade.getInstance().getDatabase().getDialect().getActiveRecordDialectCode()
   end
index 84ebdd355b7d2209da642ded5ef17bdf20a094f9..423e54a100a119390c393652cf9c0d7318fdd856 100644 (file)
 package org.sonar.server.db.migrations;
 
 import org.apache.ibatis.session.SqlSession;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.sonar.api.platform.ServerUpgradeStatus;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.Database;
 import org.sonar.core.persistence.MyBatis;
@@ -43,13 +45,19 @@ public class DatabaseMigratorTest extends AbstractDaoTestCase {
   MyBatis mybatis = mock(MyBatis.class);
   Database database = mock(Database.class);
   DatabaseMigration[] migrations = new DatabaseMigration[]{new FakeMigration()};
+  ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class);
+
+  DatabaseMigrator migrator;
+
+  @Before
+  public void setUp() throws Exception {
+    migrator = new DatabaseMigrator(mybatis, database, migrations, serverUpgradeStatus, null);
+  }
 
   @Test
   public void should_support_only_creation_of_h2_database() throws Exception {
     when(database.getDialect()).thenReturn(new MySql());
 
-    DatabaseMigrator migrator = new DatabaseMigrator(mybatis, database, migrations);
-
     assertThat(migrator.createDatabase()).isFalse();
     verifyZeroInteractions(mybatis);
   }
@@ -59,13 +67,11 @@ public class DatabaseMigratorTest extends AbstractDaoTestCase {
     thrown.expect(IllegalArgumentException.class);
     thrown.expectMessage("Database migration not found: org.xxx.UnknownMigration");
 
-    DatabaseMigrator migrator = new DatabaseMigrator(mybatis, database, migrations);
     migrator.executeMigration("org.xxx.UnknownMigration");
   }
 
   @Test
   public void execute_migration() throws Exception {
-    DatabaseMigrator migrator = new DatabaseMigrator(mybatis, database, migrations);
     assertThat(FakeMigration.executed).isFalse();
     migrator.executeMigration(FakeMigration.class.getName());
     assertThat(FakeMigration.executed).isTrue();
@@ -73,15 +79,15 @@ public class DatabaseMigratorTest extends AbstractDaoTestCase {
 
   @Test
   public void should_create_schema_on_h2() throws Exception {
-
     Dialect supportedDialect = new H2();
     when(database.getDialect()).thenReturn(supportedDialect);
     Connection connection = mock(Connection.class);
     SqlSession session = mock(SqlSession.class);
     when(session.getConnection()).thenReturn(connection);
     when(mybatis.openSession()).thenReturn(session);
+    when(serverUpgradeStatus.isFreshInstall()).thenReturn(true);
 
-    DatabaseMigrator databaseMigrator = new DatabaseMigrator(mybatis, database, migrations) {
+    DatabaseMigrator databaseMigrator = new DatabaseMigrator(mybatis, database, migrations, serverUpgradeStatus, null) {
       @Override
       protected void createSchema(Connection connection, String dialectId) {
       }
index 5f2f1f26f1eafa47a5de731e5688ba4ea1b6d6ea..4a92e0a79b3ed4eb8ef4d344928558256e0ac05d 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.server.tester;
 
 import org.apache.commons.io.FileUtils;
 import org.sonar.api.CoreProperties;
-import org.sonar.server.db.migrations.DatabaseMigrator;
 import org.sonar.server.platform.Platform;
 
 import java.io.File;
@@ -49,7 +48,6 @@ public class ServerTester {
     properties.setProperty("sonar.jdbc.url", "jdbc:h2:" + temp.getAbsolutePath() + "/h2");
 
     platform.init(properties);
-    ((DatabaseMigrator) platform.getComponent(DatabaseMigrator.class)).createDatabase();
     platform.doStart();
   }