diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2011-10-26 11:48:24 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2011-10-26 11:49:09 +0200 |
commit | 28e68ed90ba648cd2dcd6491982a7bda227b6bbd (patch) | |
tree | 797c86b2570baa5d379ac25b3370a65976515aa6 /sonar-core | |
parent | 48563f868573a21cac93c8143b36b26200f19a6c (diff) | |
download | sonarqube-28e68ed90ba648cd2dcd6491982a7bda227b6bbd.tar.gz sonarqube-28e68ed90ba648cd2dcd6491982a7bda227b6bbd.zip |
SONAR-2642 do not duplicate derby DDL files
Diffstat (limited to 'sonar-core')
10 files changed, 141 insertions, 23 deletions
diff --git a/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java b/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java index 01df8825f85..1036280044f 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java +++ b/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java @@ -82,7 +82,6 @@ public abstract class AbstractDatabaseConnector implements DatabaseConnector { if (!started) { String jdbcConnectionUrl = testConnection(); dialect = DialectRepository.find(configuration.getString("sonar.jdbc.dialect"), jdbcConnectionUrl); - LoggerFactory.getLogger("org.sonar.INFO").info("Database dialect class " + dialect.getClass().getName()); started = true; } if (!operational) { diff --git a/sonar-core/src/main/java/org/sonar/persistence/Database.java b/sonar-core/src/main/java/org/sonar/persistence/Database.java index ac4fd69506d..028f8e812aa 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/Database.java +++ b/sonar-core/src/main/java/org/sonar/persistence/Database.java @@ -19,6 +19,8 @@ */ package org.sonar.persistence; +import org.sonar.jpa.dialect.Dialect; + import javax.sql.DataSource; /** @@ -29,4 +31,5 @@ public interface Database { Database start(); Database stop(); DataSource getDataSource(); + Dialect getDialect(); } diff --git a/sonar-core/src/main/java/org/sonar/persistence/DatabaseMigrator.java b/sonar-core/src/main/java/org/sonar/persistence/DatabaseMigrator.java new file mode 100644 index 00000000000..6d31f295576 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/persistence/DatabaseMigrator.java @@ -0,0 +1,60 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 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.persistence; + +import org.apache.ibatis.session.SqlSession; +import org.slf4j.LoggerFactory; +import org.sonar.api.ServerComponent; + +import java.sql.Connection; + +/** + * Restore schema by executing DDL scripts. Only Derby database is supported. Other databases are created by Ruby on Rails migrations. + * + * @since 2.12 + */ +public class DatabaseMigrator implements ServerComponent { + + private MyBatis myBatis; + private Database database; + + public DatabaseMigrator(MyBatis myBatis, Database database) { + this.myBatis = myBatis; + this.database = database; + } + + /** + * @return true if the database has been created, false if this database is not supported + */ + public boolean createDatabase() { + if (DdlUtils.supportsDialect(database.getDialect().getId())) { + LoggerFactory.getLogger(getClass()).info("Create database"); + SqlSession session = myBatis.openSession(); + Connection connection = session.getConnection(); + try { + DdlUtils.execute(connection, database.getDialect().getId()); + } finally { + session.close(); + } + return true; + } + return false; + } +} diff --git a/sonar-core/src/main/java/org/sonar/persistence/DdlUtils.java b/sonar-core/src/main/java/org/sonar/persistence/DdlUtils.java index 2b8cc3d22d7..14dd56eef2c 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/DdlUtils.java +++ b/sonar-core/src/main/java/org/sonar/persistence/DdlUtils.java @@ -44,6 +44,9 @@ public final class DdlUtils { return "derby".equals(dialect); } + /** + * The connection is commited in this method but not closed. + */ public static void execute(Connection connection, String dialect) { if (!supportsDialect(dialect)) { throw new IllegalArgumentException("Unsupported dialect: " + dialect); diff --git a/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java b/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java index fae69d957ee..fb5eca5ccaa 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java +++ b/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java @@ -26,6 +26,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; +import org.sonar.jpa.dialect.Dialect; +import org.sonar.jpa.dialect.DialectRepository; import javax.sql.DataSource; import java.sql.SQLException; @@ -42,6 +44,7 @@ public class DefaultDatabase implements Database { private Settings settings; private BasicDataSource datasource; + private Dialect dialect; public DefaultDatabase(Settings settings) { this.settings = settings; @@ -51,8 +54,9 @@ public class DefaultDatabase implements Database { try { doBeforeStart(); - LOG.info("Create JDBC datasource"); - datasource = (BasicDataSource) BasicDataSourceFactory.createDataSource(getCommonsDbcpProperties()); + Properties properties = getProperties(); + dialect = initDialect(properties); + datasource = initDatasource(properties); return this; } catch (Exception e) { @@ -60,6 +64,19 @@ public class DefaultDatabase implements Database { } } + BasicDataSource initDatasource(Properties properties) throws Exception { + LOG.info("Create JDBC datasource"); + return (BasicDataSource) BasicDataSourceFactory.createDataSource(extractCommonsDbcpProperties(properties)); + } + + Dialect initDialect(Properties properties) { + Dialect result = DialectRepository.find(properties.getProperty("sonar.jdbc.dialect"), properties.getProperty("sonar.jdbc.url")); + if (result != null && "derby".equals(result.getId())) { + LoggerFactory.getLogger(getClass()).warn("Derby database should be used for evaluation purpose only"); + } + return result; + } + protected void doBeforeStart() { } @@ -79,6 +96,10 @@ public class DefaultDatabase implements Database { } + public final Dialect getDialect() { + return dialect; + } + public final DataSource getDataSource() { return datasource; } @@ -104,10 +125,9 @@ public class DefaultDatabase implements Database { } } - Properties getCommonsDbcpProperties() { + static Properties extractCommonsDbcpProperties(Properties properties) { Properties result = new Properties(); - Properties props = getProperties(); - for (Map.Entry<Object, Object> entry : props.entrySet()) { + for (Map.Entry<Object, Object> entry : properties.entrySet()) { String key = (String) entry.getKey(); if (StringUtils.startsWith(key, "sonar.jdbc.")) { result.setProperty(StringUtils.removeStart(key, "sonar.jdbc."), (String) entry.getValue()); diff --git a/sonar-core/src/main/java/org/sonar/persistence/InMemoryDatabase.java b/sonar-core/src/main/java/org/sonar/persistence/InMemoryDatabase.java index 7e54f9522a9..80cf8bb4914 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/InMemoryDatabase.java +++ b/sonar-core/src/main/java/org/sonar/persistence/InMemoryDatabase.java @@ -21,6 +21,8 @@ package org.sonar.persistence; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; +import org.sonar.jpa.dialect.Derby; +import org.sonar.jpa.dialect.Dialect; import javax.sql.DataSource; import java.sql.Connection; @@ -95,4 +97,8 @@ public class InMemoryDatabase implements Database { public DataSource getDataSource() { return datasource; } + + public Dialect getDialect() { + return new Derby(); + } } diff --git a/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java index 4a468f8f767..82e23455b70 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java +++ b/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java @@ -25,6 +25,8 @@ import org.apache.ibatis.builder.xml.XMLMapperBuilder; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.*; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.sonar.api.BatchComponent; +import org.sonar.api.ServerComponent; import org.sonar.persistence.model.Duplication; import org.sonar.persistence.model.DuplicationMapper; import org.sonar.persistence.model.Rule; @@ -33,7 +35,7 @@ import org.sonar.persistence.model.RuleMapper; import java.io.IOException; import java.io.InputStream; -public class MyBatis { +public class MyBatis implements BatchComponent, ServerComponent { private Database database; private SqlSessionFactory sessionFactory; diff --git a/sonar-core/src/main/resources/org/sonar/persistence/rows-derby.sql b/sonar-core/src/main/resources/org/sonar/persistence/rows-derby.sql index 5a8a67209a9..825db32a1a6 100644 --- a/sonar-core/src/main/resources/org/sonar/persistence/rows-derby.sql +++ b/sonar-core/src/main/resources/org/sonar/persistence/rows-derby.sql @@ -1,7 +1,7 @@ -- Version 2.11 -- All the rows inserted during Rails migrations. Rows inserted during server startup tasks (Java) are excluded : rules, profiles, metrics, ... --- Note: do not split a request on multiple lines. +-- Note: do not split a request on multiple lines and do not end with ; INSERT INTO ACTIVE_DASHBOARDS(ID, DASHBOARD_ID, USER_ID, ORDER_INDEX) VALUES (1, 1, null, 1) ALTER TABLE ACTIVE_DASHBOARDS ALTER COLUMN ID RESTART WITH 2 @@ -161,6 +161,8 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('214') INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('215') INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('216') INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('217') +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('220') +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('221') INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '2011-09-26 22:27:48.0', '2011-09-26 22:27:48.0', null, null) ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2 diff --git a/sonar-core/src/main/resources/org/sonar/persistence/schema-derby.ddl b/sonar-core/src/main/resources/org/sonar/persistence/schema-derby.ddl index be3e9ffdb6b..df60c0d6d24 100644 --- a/sonar-core/src/main/resources/org/sonar/persistence/schema-derby.ddl +++ b/sonar-core/src/main/resources/org/sonar/persistence/schema-derby.ddl @@ -41,7 +41,7 @@ CREATE TABLE "RULES" ("ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (ST CREATE TABLE "WIDGET_PROPERTIES" ("ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), "WIDGET_ID" INTEGER NOT NULL, "KEE" VARCHAR(100), "TEXT_VALUE" VARCHAR(4000), "VALUE_TYPE" VARCHAR(20)) -CREATE TABLE "EVENTS" ("ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), "NAME" VARCHAR(50), "RESOURCE_ID" INTEGER, "SNAPSHOT_ID" INTEGER, "CATEGORY" VARCHAR(50), "EVENT_DATE" TIMESTAMP, "CREATED_AT" TIMESTAMP, "DESCRIPTION" VARCHAR(3072), "DATA" VARCHAR(4000)) +CREATE TABLE "EVENTS" ("ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), "NAME" VARCHAR(400), "RESOURCE_ID" INTEGER, "SNAPSHOT_ID" INTEGER, "CATEGORY" VARCHAR(50), "EVENT_DATE" TIMESTAMP, "CREATED_AT" TIMESTAMP, "DESCRIPTION" VARCHAR(4000)) CREATE TABLE "ALERTS" ("ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), "PROFILE_ID" INTEGER, "METRIC_ID" INTEGER, "OPERATOR" VARCHAR(3), "VALUE_ERROR" VARCHAR(64), "VALUE_WARNING" VARCHAR(64)) diff --git a/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java b/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java index 94361873195..05922626fae 100644 --- a/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java +++ b/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java @@ -19,10 +19,13 @@ */ package org.sonar.persistence; +import org.apache.commons.dbcp.BasicDataSource; import org.hamcrest.core.Is; import org.junit.Test; import org.sonar.api.config.Settings; +import java.sql.DriverManager; +import java.sql.SQLException; import java.util.Properties; import static org.junit.Assert.assertThat; @@ -52,28 +55,24 @@ public class DefaultDatabaseTest { } @Test - public void shouldGetCommonsDbcpProperties() { - Settings settings = new Settings(); - settings.setProperty("sonar.jdbc.driverClassName", "my.Driver"); - settings.setProperty("sonar.jdbc.username", "me"); - settings.setProperty("sonar.jdbc.maxActive", "5"); - - DefaultDatabase db = new DefaultDatabase(settings); - Properties props = db.getCommonsDbcpProperties(); + public void shouldExtractCommonsDbcpProperties() { + Properties props = new Properties(); + props.setProperty("sonar.jdbc.driverClassName", "my.Driver"); + props.setProperty("sonar.jdbc.username", "me"); + props.setProperty("sonar.jdbc.maxActive", "5"); - assertThat(props.getProperty("username"), Is.is("me")); - assertThat(props.getProperty("driverClassName"), Is.is("my.Driver")); - assertThat(props.getProperty("maxActive"), Is.is("5")); + Properties commonsDbcpProps = DefaultDatabase.extractCommonsDbcpProperties(props); - // default value - assertThat(props.getProperty("password"), Is.is("sonar")); + assertThat(commonsDbcpProps.getProperty("username"), Is.is("me")); + assertThat(commonsDbcpProps.getProperty("driverClassName"), Is.is("my.Driver")); + assertThat(commonsDbcpProps.getProperty("maxActive"), Is.is("5")); } @Test public void shouldCompleteProperties() { Settings settings = new Settings(); - DefaultDatabase db = new DefaultDatabase(settings){ + DefaultDatabase db = new DefaultDatabase(settings) { @Override protected void doCompleteProperties(Properties properties) { properties.setProperty("sonar.jdbc.maxActive", "2"); @@ -84,4 +83,28 @@ public class DefaultDatabaseTest { assertThat(props.getProperty("sonar.jdbc.maxActive"), Is.is("2")); } + + @Test + public void shouldStart() throws SQLException { + Settings settings = new Settings(); + settings.setProperty("sonar.jdbc.url", "jdbc:derby:memory:sonar;create=true;user=sonar;password=sonar"); + settings.setProperty("sonar.jdbc.driverClassName", "org.apache.derby.jdbc.EmbeddedDriver"); + settings.setProperty("sonar.jdbc.username", "sonar"); + settings.setProperty("sonar.jdbc.password", "sonar"); + settings.setProperty("sonar.jdbc.maxActive", "1"); + + try { + DefaultDatabase db = new DefaultDatabase(settings); + db.start(); + + assertThat(db.getDialect().getId(), Is.is("derby")); + assertThat(((BasicDataSource) db.getDataSource()).getMaxActive(), Is.is(1)); + } finally { + try { + DriverManager.getConnection("jdbc:derby:memory:sonar;drop=true"); + } catch (Exception e) { + // silently ignore + } + } + } } |