From: David Gageot Date: Fri, 26 Oct 2012 14:36:13 +0000 (+0200) Subject: SONAR-3895 Remove Local Mode and fix Dry Run on postgresql X-Git-Tag: 3.4~439 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=7342e90d136081c7b4a8780f0ef0fb4401301ac3;p=sonarqube.git SONAR-3895 Remove Local Mode and fix Dry Run on postgresql --- diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java index 0c7e9bd997d..fa787fa78a6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java @@ -28,7 +28,8 @@ import org.sonar.batch.FakeMavenPluginExecutor; import org.sonar.batch.MavenPluginExecutor; import org.sonar.batch.config.BatchDatabaseSettingsLoader; import org.sonar.batch.config.BootstrapSettings; -import org.sonar.batch.local.LocalDatabase; +import org.sonar.batch.local.DryRunDatabase; +import org.sonar.batch.local.DryRunExporter; import org.sonar.core.config.Logback; import org.sonar.core.i18n.I18nManager; import org.sonar.core.i18n.RuleI18nManager; @@ -60,6 +61,7 @@ public class BootstrapModule extends Module { container.addSingleton(BatchPluginRepository.class); container.addSingleton(ExtensionInstaller.class); container.addSingleton(DryRun.class); + container.addSingleton(DryRunExporter.class); container.addSingleton(Logback.class); container.addSingleton(ServerClient.class); container.addSingleton(TempDirectories.class); @@ -81,7 +83,7 @@ public class BootstrapModule extends Module { private void addDatabaseComponents() { container.addSingleton(JdbcDriverHolder.class); - container.addSingleton(LocalDatabase.class); + container.addSingleton(DryRunDatabase.class); // mybatis container.addSingleton(BatchDatabase.class); diff --git a/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java new file mode 100644 index 00000000000..172d6b1196e --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java @@ -0,0 +1,81 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.local; + +import org.sonar.api.BatchComponent; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.config.Settings; +import org.sonar.api.database.DatabaseProperties; +import org.sonar.batch.bootstrap.DryRun; +import org.sonar.batch.bootstrap.ServerClient; +import org.sonar.batch.bootstrap.TempDirectories; + +import java.io.File; + +/** + * @since 3.4 + */ +public class DryRunDatabase implements BatchComponent { + private static final String API_SYNCHRO = "/api/synchro"; + private static final String DIALECT = "h2"; + private static final String DRIVER = "org.h2.Driver"; + private static final String URL = "jdbc:h2:"; + private static final String USER = "sonar"; + private static final String PASSWORD = "sonar"; + + private final DryRun dryRun; + private final Settings settings; + private final ServerClient server; + private final TempDirectories tempDirectories; + private final ProjectReactor reactor; + + public DryRunDatabase(DryRun dryRun, Settings settings, ServerClient server, TempDirectories tempDirectories, ProjectReactor reactor) { + this.dryRun = dryRun; + this.settings = settings; + this.server = server; + this.tempDirectories = tempDirectories; + this.reactor = reactor; + } + + public void start() { + if (!dryRun.isEnabled()) { + return; + } + + File file = tempDirectories.getFile("dry_run", "db.h2.db"); + String h2DatabasePath = file.getAbsolutePath().replaceAll(".h2.db", ""); + + downloadDatabase(reactor.getRoot().getKey(), file); + replaceSettings(h2DatabasePath); + } + + private void downloadDatabase(String projectKey, File toFile) { + server.download(API_SYNCHRO + "?resource=" + projectKey, toFile); + } + + private void replaceSettings(String h2DatabasePath) { + settings + .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT) + .setProperty(DatabaseProperties.PROP_DRIVER, DRIVER) + .setProperty(DatabaseProperties.PROP_USER, USER) + .setProperty(DatabaseProperties.PROP_PASSWORD, PASSWORD) + .setProperty(DatabaseProperties.PROP_URL, URL + h2DatabasePath); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/local/DryRunExporter.java b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunExporter.java new file mode 100644 index 00000000000..25d9649961d --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunExporter.java @@ -0,0 +1,47 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.local; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; +import org.sonar.api.batch.SensorContext; +import org.sonar.batch.bootstrap.DryRun; + +/** + * @since 3.4 + */ +public class DryRunExporter implements BatchComponent { + private static final Logger LOG = LoggerFactory.getLogger(DryRunExporter.class); + + private final DryRun dryRun; + + public DryRunExporter(DryRun dryRun) { + this.dryRun = dryRun; + } + + public void execute(SensorContext context) { + if (!dryRun.isEnabled()) { + return; + } + + LOG.info("Exporting dry run results"); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java b/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java deleted file mode 100644 index 42b466ffe8b..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.local; - -import org.sonar.api.BatchComponent; -import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.api.config.Settings; -import org.sonar.api.database.DatabaseProperties; -import org.sonar.batch.bootstrap.DryRun; -import org.sonar.batch.bootstrap.ServerClient; -import org.sonar.batch.bootstrap.TempDirectories; - -import java.io.File; - -/** - * @since 3.4 - */ -public class LocalDatabase implements BatchComponent { - private static final String API_SYNCHRO = "/api/synchro"; - private static final String DIALECT = "h2"; - private static final String DRIVER = "org.h2.Driver"; - private static final String URL = "jdbc:h2:"; - private static final String USER = "sonar"; - private static final String PASSWORD = "sonar"; - - private final DryRun dryRun; - private final Settings settings; - private final ServerClient server; - private ProjectReactor reactor; - private final TempDirectories tempDirectories; - - public LocalDatabase(DryRun dryRun, Settings settings, ServerClient server, TempDirectories tempDirectories, ProjectReactor reactor) { - this.dryRun = dryRun; - this.settings = settings; - this.server = server; - this.reactor = reactor; - this.tempDirectories = tempDirectories; - } - - public void start() { - if (!dryRun.isEnabled()) { - return; - } - - File file = tempDirectories.getFile("local", "db.h2.db"); - String h2DatabasePath = file.getAbsolutePath().replaceAll(".h2.db", ""); - - downloadDatabase(reactor.getRoot().getKey(), file); - replaceSettings(h2DatabasePath); - } - - private void downloadDatabase(String projectKey, File toFile) { - server.download(API_SYNCHRO + "?resource=" + projectKey, toFile); - } - - private void replaceSettings(String h2DatabasePath) { - settings - .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT) - .setProperty(DatabaseProperties.PROP_DRIVER, DRIVER) - .setProperty(DatabaseProperties.PROP_USER, USER) - .setProperty(DatabaseProperties.PROP_PASSWORD, PASSWORD) - .setProperty(DatabaseProperties.PROP_URL, URL + h2DatabasePath); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java index 9ac28d6b6d7..f5530102336 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java @@ -31,30 +31,35 @@ import org.sonar.api.batch.maven.DependsUponMavenPlugin; import org.sonar.api.batch.maven.MavenPluginHandler; import org.sonar.api.resources.Project; import org.sonar.batch.MavenPluginExecutor; +import org.sonar.batch.local.DryRunExporter; import java.util.Collection; public class PostJobsExecutor implements BatchComponent { private static final Logger LOG = LoggerFactory.getLogger(PostJobsExecutor.class); - private MavenPluginExecutor mavenExecutor; - private ProjectDefinition projectDefinition; - private Project project; - private BatchExtensionDictionnary selector; + private final BatchExtensionDictionnary selector; + private final Project project; + private final ProjectDefinition projectDefinition; + private final MavenPluginExecutor mavenExecutor; + private final DryRunExporter localModeExporter; - public PostJobsExecutor(BatchExtensionDictionnary selector, Project project, ProjectDefinition projectDefinition, MavenPluginExecutor mavenExecutor) { + public PostJobsExecutor(BatchExtensionDictionnary selector, Project project, ProjectDefinition projectDefinition, MavenPluginExecutor mavenExecutor, + DryRunExporter localModeExporter) { this.selector = selector; - this.mavenExecutor = mavenExecutor; this.project = project; this.projectDefinition = projectDefinition; + this.mavenExecutor = mavenExecutor; + this.localModeExporter = localModeExporter; } public void execute(SensorContext context) { Collection postJobs = selector.select(PostJob.class, project, true); execute(context, postJobs); + exportLocalModeResults(context); } - void execute(SensorContext context, Collection postJobs) { + private void execute(SensorContext context, Collection postJobs) { logPostJobs(postJobs); for (PostJob postJob : postJobs) { @@ -78,4 +83,8 @@ public class PostJobsExecutor implements BatchComponent { } } } + + private void exportLocalModeResults(SensorContext context) { + localModeExporter.execute(context); + } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java index 9a7334ae542..1af0a26cc9e 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java @@ -19,35 +19,53 @@ */ package org.sonar.batch.phases; +import org.junit.Before; import org.junit.Test; +import org.sonar.api.batch.BatchExtensionDictionnary; import org.sonar.api.batch.PostJob; import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.resources.Project; import org.sonar.batch.MavenPluginExecutor; +import org.sonar.batch.local.DryRunExporter; import java.util.Arrays; -import java.util.List; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class PostJobsExecutorTest { + PostJobsExecutor executor; + + Project project = new Project("project"); + BatchExtensionDictionnary selector = mock(BatchExtensionDictionnary.class); + MavenPluginExecutor mavenPluginExecutor = mock(MavenPluginExecutor.class); + DryRunExporter localModeExporter = mock(DryRunExporter.class); + PostJob job1 = mock(PostJob.class); + PostJob job2 = mock(PostJob.class); + SensorContext context = mock(SensorContext.class); + + @Before + public void setUp() { + executor = new PostJobsExecutor(selector, project, ProjectDefinition.create(), mavenPluginExecutor, localModeExporter); + } @Test - public void executeAllPostJobs() { - PostJob job1 = mock(PostJob.class); - PostJob job2 = mock(PostJob.class); - List jobs = Arrays.asList(job1, job2); + public void should_execute_post_jobs() { + when(selector.select(PostJob.class, project, true)).thenReturn(Arrays.asList(job1, job2)); - Project project = new Project("project"); - ProjectDefinition projectDefinition = ProjectDefinition.create(); - PostJobsExecutor executor = new PostJobsExecutor(null, project, projectDefinition, mock(MavenPluginExecutor.class)); - SensorContext context = mock(SensorContext.class); - executor.execute(context, jobs); + executor.execute(context); verify(job1).executeOn(project, context); verify(job2).executeOn(project, context); } + + @Test + public void should_export_local_mode_results() { + executor.execute(context); + + verify(localModeExporter).execute(context); + } } diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java b/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java index 9dec7ff067f..bca98d80f8e 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java @@ -40,8 +40,6 @@ public class DbTemplate implements ServerComponent { public DbTemplate copyTable(DataSource source, DataSource dest, String table, String query) { LOG.info("Copy table " + table); - int colCount = getColumnCount(source, table); - truncate(dest, table); Connection sourceConnection = null; @@ -49,29 +47,35 @@ public class DbTemplate implements ServerComponent { ResultSet sourceResultSet = null; Connection destConnection = null; ResultSet destResultSet = null; + PreparedStatement destStatement = null; try { sourceConnection = source.getConnection(); sourceStatement = sourceConnection.createStatement(); sourceResultSet = sourceStatement.executeQuery(query); - destConnection = dest.getConnection(); - destConnection.setAutoCommit(false); + if (sourceResultSet.next()) { + int colCount = sourceResultSet.getMetaData().getColumnCount(); - PreparedStatement destStatement = destConnection.prepareStatement("INSERT INTO " + table + " VALUES(" + StringUtils.repeat("?", ",", colCount) + ")"); - while (sourceResultSet.next()) { - for (int col = 1; col <= colCount; col++) { - Object value = sourceResultSet.getObject(col); - destStatement.setObject(col, value); - } - destStatement.addBatch(); - } + destConnection = dest.getConnection(); + destConnection.setAutoCommit(false); - destStatement.executeBatch(); - destConnection.commit(); - destStatement.close(); + destStatement = destConnection.prepareStatement("INSERT INTO " + table + " VALUES(" + StringUtils.repeat("?", ",", colCount) + ")"); + do { + for (int col = 1; col <= colCount; col++) { + Object value = sourceResultSet.getObject(col); + destStatement.setObject(col, value); + } + destStatement.addBatch(); + } while (sourceResultSet.next()); + + destStatement.executeBatch(); + destConnection.commit(); + } } catch (SQLException e) { + LOG.error("Fail to copy table " + table, e); throw new SonarException("Fail to copy table " + table, e); } finally { + DatabaseUtils.closeQuietly(destStatement); DatabaseUtils.closeQuietly(destResultSet); DatabaseUtils.closeQuietly(destConnection); DatabaseUtils.closeQuietly(sourceResultSet); @@ -82,28 +86,7 @@ public class DbTemplate implements ServerComponent { return this; } - public int getColumnCount(DataSource dataSource, String table) { - Connection connection = null; - ResultSet metaData = null; - try { - connection = dataSource.getConnection(); - metaData = connection.getMetaData().getColumns(null, null, table, null); - - int nbColumns = 0; - while (metaData.next()) { - nbColumns++; - } - - return nbColumns; - } catch (SQLException e) { - throw new SonarException("Fail to get column count for table " + table, e); - } finally { - DatabaseUtils.closeQuietly(metaData); - DatabaseUtils.closeQuietly(connection); - } - } - - public int getRowCount(BasicDataSource dataSource, String table) { + public int getRowCount(DataSource dataSource, String table) { Connection connection = null; Statement statement = null; ResultSet resultSet = null; @@ -114,6 +97,7 @@ public class DbTemplate implements ServerComponent { return resultSet.next() ? resultSet.getInt(1) : 0; } catch (SQLException e) { + LOG.error("Fail to get row count for table " + table, e); throw new SonarException("Fail to get row count for table " + table, e); } finally { DatabaseUtils.closeQuietly(resultSet); @@ -130,6 +114,7 @@ public class DbTemplate implements ServerComponent { statement = connection.createStatement(); statement.executeUpdate("TRUNCATE TABLE " + table); } catch (SQLException e) { + LOG.error("Fail to truncate table " + table, e); throw new SonarException("Fail to truncate table " + table, e); } finally { DatabaseUtils.closeQuietly(statement); @@ -154,6 +139,7 @@ public class DbTemplate implements ServerComponent { connection = dataSource.getConnection(); DdlUtils.createSchema(connection, dialect); } catch (SQLException e) { + LOG.error("Fail to createSchema local database schema", e); throw new SonarException("Fail to createSchema local database schema", e); } finally { DatabaseUtils.closeQuietly(connection); diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DryRunDatabaseFactory.java b/sonar-core/src/main/java/org/sonar/core/persistence/DryRunDatabaseFactory.java new file mode 100644 index 00000000000..156db8ab830 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DryRunDatabaseFactory.java @@ -0,0 +1,100 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.core.persistence; + +import com.google.common.io.Files; +import org.apache.commons.dbcp.BasicDataSource; +import org.sonar.api.ServerComponent; +import org.sonar.api.platform.ServerFileSystem; +import org.sonar.api.utils.SonarException; + +import javax.sql.DataSource; + +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; + +public class DryRunDatabaseFactory implements ServerComponent { + private static final String DIALECT = "h2"; + private static final String DRIVER = "org.h2.Driver"; + private static final String URL = "jdbc:h2:"; + private static final String USER = "sonar"; + private static final String PASSWORD = "sonar"; + + private final Database database; + private final ServerFileSystem serverFileSystem; + + public DryRunDatabaseFactory(Database database, ServerFileSystem serverFileSystem) { + this.database = database; + this.serverFileSystem = serverFileSystem; + } + + public byte[] createDatabaseForDryRun(int resourceId) { + String name = serverFileSystem.getTempDir().getAbsolutePath() + "db-" + System.nanoTime(); + + try { + BasicDataSource destination = create(DIALECT, DRIVER, USER, PASSWORD, URL + name); + copy(database.getDataSource(), destination, resourceId); + close(destination); + + return dbFileContent(name); + } catch (SQLException e) { + throw new SonarException("Unable to create database for dry run", e); + } + } + + private void copy(DataSource source, DataSource dest, int resourceId) { + new DbTemplate() + .copyTable(source, dest, "PROPERTIES", + "SELECT * FROM PROPERTIES WHERE (((USER_ID IS NULL) AND (RESOURCE_ID IS NULL)) OR (RESOURCE_ID='" + resourceId + + "')) AND NOT (PROP_KEY LIKE '%.secured')") + .copyTable(source, dest, "RULES_PROFILES", "SELECT * FROM RULES_PROFILES") + .copyTable(source, dest, "RULES", "SELECT * FROM RULES") + .copyTable(source, dest, "RULES_PARAMETERS", "SELECT * FROM RULES_PARAMETERS") + .copyTable(source, dest, "ACTIVE_RULES", "SELECT * FROM ACTIVE_RULES") + .copyTable(source, dest, "ACTIVE_RULE_PARAMETERS", "SELECT * FROM ACTIVE_RULE_PARAMETERS") + .copyTable(source, dest, "METRICS", "SELECT * FROM METRICS") + .copyTable(source, dest, "CHARACTERISTICS", "SELECT * FROM CHARACTERISTICS") + .copyTable(source, dest, "CHARACTERISTIC_PROPERTIES", "SELECT * FROM CHARACTERISTIC_PROPERTIES") + .copyTable(source, dest, "CHARACTERISTIC_EDGES", "SELECT * FROM CHARACTERISTIC_EDGES") + .copyTable(source, dest, "QUALITY_MODELS", "SELECT * FROM QUALITY_MODELS"); + } + + private BasicDataSource create(String dialect, String driver, String user, String password, String url) { + BasicDataSource dataSource = new DbTemplate().dataSource(driver, user, password, url); + new DbTemplate().createSchema(dataSource, dialect); + return dataSource; + } + + private void close(BasicDataSource dest) throws SQLException { + dest.close(); + } + + private byte[] dbFileContent(String name) { + try { + File dbFile = new File(name + ".h2.db"); + byte[] content = Files.toByteArray(dbFile); + dbFile.delete(); + return content; + } catch (IOException e) { + throw new SonarException("Unable to read h2 database file", e); + } + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java b/sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java deleted file mode 100644 index edebb896eef..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.core.persistence; - -import com.google.common.io.Files; -import org.apache.commons.dbcp.BasicDataSource; -import org.sonar.api.ServerComponent; -import org.sonar.api.platform.ServerFileSystem; -import org.sonar.api.utils.SonarException; - -import javax.sql.DataSource; - -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; - -public class LocalDatabaseFactory implements ServerComponent { - private static final String DIALECT = "h2"; - private static final String DRIVER = "org.h2.Driver"; - private static final String URL = "jdbc:h2:"; - private static final String USER = "sonar"; - private static final String PASSWORD = "sonar"; - - private final Database database; - private final ServerFileSystem serverFileSystem; - - public LocalDatabaseFactory(Database database, ServerFileSystem serverFileSystem) { - this.database = database; - this.serverFileSystem = serverFileSystem; - } - - public byte[] createDatabaseForLocalMode(int resourceId) { - String name = serverFileSystem.getTempDir().getAbsolutePath() + "db-" + System.nanoTime(); - - try { - BasicDataSource destination = create(DIALECT, DRIVER, USER, PASSWORD, URL + name); - copy(database.getDataSource(), destination, resourceId); - close(destination); - - return dbFileContent(name); - } catch (SQLException e) { - throw new SonarException("Unable to create database for local mode", e); - } - } - - private void copy(DataSource source, DataSource dest, int resourceId) { - new DbTemplate() - .copyTable(source, dest, "PROPERTIES", - "SELECT * FROM PROPERTIES WHERE (((USER_ID IS NULL) AND (RESOURCE_ID IS NULL)) OR (RESOURCE_ID='" + resourceId + "')) AND NOT (PROP_KEY LIKE '%.secured')") - .copyTable(source, dest, "RULES_PROFILES", "SELECT * FROM RULES_PROFILES") - .copyTable(source, dest, "RULES", "SELECT * FROM RULES") - .copyTable(source, dest, "RULES_PARAMETERS", "SELECT * FROM RULES_PARAMETERS") - .copyTable(source, dest, "ACTIVE_RULES", "SELECT * FROM ACTIVE_RULES") - .copyTable(source, dest, "ACTIVE_RULE_PARAMETERS", "SELECT * FROM ACTIVE_RULE_PARAMETERS") - .copyTable(source, dest, "METRICS", "SELECT * FROM METRICS") - .copyTable(source, dest, "CHARACTERISTICS", "SELECT * FROM CHARACTERISTICS") - .copyTable(source, dest, "CHARACTERISTIC_PROPERTIES", "SELECT * FROM CHARACTERISTIC_PROPERTIES") - .copyTable(source, dest, "CHARACTERISTIC_EDGES", "SELECT * FROM CHARACTERISTIC_EDGES") - .copyTable(source, dest, "QUALITY_MODELS", "SELECT * FROM QUALITY_MODELS"); - } - - private BasicDataSource create(String dialect, String driver, String user, String password, String url) { - BasicDataSource dataSource = new DbTemplate().dataSource(driver, user, password, url); - new DbTemplate().createSchema(dataSource, dialect); - return dataSource; - } - - private void close(BasicDataSource dest) throws SQLException { - dest.close(); - } - - private byte[] dbFileContent(String name) { - try { - File dbFile = new File(name + ".h2.db"); - byte[] content = Files.toByteArray(dbFile); - dbFile.delete(); - return content; - } catch (IOException e) { - throw new SonarException("Unable to read h2 database file", e); - } - } -} diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java new file mode 100644 index 00000000000..b44340a1fc5 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java @@ -0,0 +1,82 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.core.persistence; + +import com.google.common.io.Files; +import org.apache.commons.dbcp.BasicDataSource; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.platform.ServerFileSystem; + +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase { + private DryRunDatabaseFactory localDatabaseFactory; + + private ServerFileSystem serverFileSystem = mock(ServerFileSystem.class); + private BasicDataSource dataSource; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void setUp() { + localDatabaseFactory = new DryRunDatabaseFactory(getDatabase(), serverFileSystem); + } + + @After + public void closeDatabase() throws SQLException { + if (dataSource != null) { + dataSource.close(); + } + } + + @Test + public void should_create_database() throws IOException, SQLException { + setupData("should_create_database"); + + when(serverFileSystem.getTempDir()).thenReturn(temporaryFolder.getRoot()); + + byte[] database = localDatabaseFactory.createDatabaseForDryRun(1); + dataSource = createDatabase(database); + + assertThat(rowCount("PROPERTIES")).isEqualTo(2); + assertThat(rowCount("PROJECTS")).isZero(); + } + + private BasicDataSource createDatabase(byte[] db) throws IOException { + File file = temporaryFolder.newFile("db.h2.db"); + Files.write(db, file); + return new DbTemplate().dataSource("org.h2.Driver", "sonar", "sonar", "jdbc:h2:" + file.getAbsolutePath().replaceAll(".h2.db", "")); + } + + private int rowCount(String table) { + return new DbTemplate().getRowCount(dataSource, table); + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java deleted file mode 100644 index 3eb0d75c300..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.core.persistence; - -import com.google.common.io.Files; -import org.apache.commons.dbcp.BasicDataSource; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.platform.ServerFileSystem; - -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; - -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class LocalDatabaseFactoryTest extends AbstractDaoTestCase { - private LocalDatabaseFactory localDatabaseFactory; - - private ServerFileSystem serverFileSystem = mock(ServerFileSystem.class); - private BasicDataSource dataSource; - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Before - public void setUp() { - localDatabaseFactory = new LocalDatabaseFactory(getDatabase(), serverFileSystem); - } - - @After - public void closeDatabase() throws SQLException { - if (dataSource != null) { - dataSource.close(); - } - } - - @Test - public void should_create_database() throws IOException { - setupData("should_create_database"); - - when(serverFileSystem.getTempDir()).thenReturn(temporaryFolder.getRoot()); - - byte[] database = localDatabaseFactory.createDatabaseForLocalMode(1); - dataSource = createDatabase(database); - - assertThat(rowCount("PROPERTIES")).isEqualTo(2); - assertThat(rowCount("PROJECTS")).isZero(); - } - - private BasicDataSource createDatabase(byte[] db) throws IOException { - File file = temporaryFolder.newFile("db.h2.db"); - Files.write(db, file); - return new DbTemplate().dataSource("org.h2.Driver", "sonar", "sonar", "jdbc:h2:" + file.getAbsolutePath().replaceAll(".h2.db", "")); - } - - private int rowCount(String table) { - return new DbTemplate().getRowCount(dataSource, table); - } -} diff --git a/sonar-core/src/test/resources/org/sonar/core/persistence/DryRunDatabaseFactoryTest/should_create_database.xml b/sonar-core/src/test/resources/org/sonar/core/persistence/DryRunDatabaseFactoryTest/should_create_database.xml new file mode 100644 index 00000000000..0e266518906 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/persistence/DryRunDatabaseFactoryTest/should_create_database.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml b/sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml deleted file mode 100644 index 30343973116..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index b5d69bd2890..eb261aa6f7a 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -51,6 +51,7 @@ import org.sonar.core.persistence.DaoUtils; import org.sonar.core.persistence.DatabaseMigrator; import org.sonar.core.persistence.DatabaseVersion; import org.sonar.core.persistence.DefaultDatabase; +import org.sonar.core.persistence.DryRunDatabaseFactory; import org.sonar.core.persistence.MyBatis; import org.sonar.core.qualitymodel.DefaultModelFinder; import org.sonar.core.rule.DefaultRuleFinder; @@ -68,7 +69,6 @@ import org.sonar.server.charts.ChartFactory; import org.sonar.server.configuration.Backup; import org.sonar.server.configuration.ProfilesManager; import org.sonar.server.database.EmbeddedDatabaseFactory; -import org.sonar.core.persistence.LocalDatabaseFactory; import org.sonar.server.notifications.NotificationService; import org.sonar.server.notifications.reviews.ReviewsNotificationManager; import org.sonar.server.plugins.ApplicationDeployer; @@ -180,7 +180,7 @@ public final class Platform { rootContainer.addSingleton(I18nManager.class); rootContainer.addSingleton(RuleI18nManager.class); rootContainer.addSingleton(GwtI18n.class); - rootContainer.addSingleton(LocalDatabaseFactory.class); + rootContainer.addSingleton(DryRunDatabaseFactory.class); rootContainer.startComponents(); } @@ -249,7 +249,7 @@ public final class Platform { servicesContainer.addSingleton(MeasureFilterDecoder.class); servicesContainer.addSingleton(MeasureFilterExecutor.class); servicesContainer.addSingleton(MeasureFilterEngine.class); - servicesContainer.addSingleton(LocalDatabaseFactory.class); + servicesContainer.addSingleton(DryRunDatabaseFactory.class); // Notifications servicesContainer.addSingleton(EmailSettings.class); diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index 7fa81d9328e..8fb4fc40ae0 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -39,7 +39,11 @@ import org.sonar.api.resources.ResourceTypes; import org.sonar.api.rules.RulePriority; import org.sonar.api.rules.RuleRepository; import org.sonar.api.utils.ValidationMessages; -import org.sonar.api.web.*; +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.workflow.Review; import org.sonar.api.workflow.internal.DefaultReview; import org.sonar.api.workflow.internal.DefaultWorkflowContext; @@ -49,6 +53,7 @@ import org.sonar.core.measure.MeasureFilterEngine; import org.sonar.core.measure.MeasureFilterRow; import org.sonar.core.persistence.Database; import org.sonar.core.persistence.DatabaseMigrator; +import org.sonar.core.persistence.DryRunDatabaseFactory; import org.sonar.core.purge.PurgeDao; import org.sonar.core.resource.ResourceIndexerDao; import org.sonar.core.resource.ResourceKeyUpdaterDao; @@ -57,13 +62,22 @@ import org.sonar.markdown.Markdown; import org.sonar.server.configuration.Backup; import org.sonar.server.configuration.ProfilesManager; import org.sonar.server.notifications.reviews.ReviewsNotificationManager; -import org.sonar.server.platform.*; -import org.sonar.server.plugins.*; +import org.sonar.server.platform.NewUserNotifier; +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.DefaultServerPluginRepository; +import org.sonar.server.plugins.PluginDeployer; +import org.sonar.server.plugins.PluginDownloader; +import org.sonar.server.plugins.UpdateCenterMatrix; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; import org.sonar.server.rules.ProfilesConsole; import org.sonar.server.rules.RulesConsole; import org.sonar.updatecenter.common.Version; import javax.annotation.Nullable; + import java.net.InetAddress; import java.sql.Connection; import java.util.Collection; @@ -300,7 +314,7 @@ public final class JRubyFacade { public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userName) { getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId], - RulePriority.values()[newSeverityId], userName); + RulePriority.values()[newSeverityId], userName); } public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userName) { @@ -496,10 +510,14 @@ public final class JRubyFacade { // notifier is null when creating the administrator in the migration script 011. if (notifier != null) { notifier.onNewUser(NewUserHandler.Context.builder() - .setLogin(fields.get("login")) - .setName(fields.get("name")) - .setEmail(fields.get("email")) - .build()); + .setLogin(fields.get("login")) + .setName(fields.get("name")) + .setEmail(fields.get("email")) + .build()); } } + + public byte[] createDatabaseForDryRun(int resourceId) { + return get(DryRunDatabaseFactory.class).createDatabaseForDryRun(resourceId); + } } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb index c4f7298b66b..0dc1be27f8b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb @@ -27,8 +27,7 @@ class Api::SynchroController < Api::ApiController require_parameters :resource load_resource() - database_factory = java_facade.getCoreComponentByClassname('org.sonar.core.persistence.LocalDatabaseFactory') - dbFileContent = database_factory.createDatabaseForLocalMode(@resource.id) + dbFileContent = java_facade.createDatabaseForDryRun(@resource.id) send_data String.from_java_bytes(dbFileContent) end