From 713a024a1cc38874b5fb709ede64c13a4f21ec53 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Wed, 11 Jul 2012 17:02:59 +0200 Subject: [PATCH] Fix support of sonar.showSqlResults with MyBatis 3.1 --- .../batch/bootstrap/BootstrapModule.java | 2 + .../org/sonar/batch/bootstrapper/logback.xml | 13 +-- .../resources/org/sonar/batch/logback.xml | 3 + .../java/org/sonar/core/config/Logback.java | 13 ++- .../org/sonar/core/persistence/MyBatis.java | 109 +++++++----------- .../core/persistence/AbstractDaoTestCase.java | 3 +- .../sonar/core/persistence/MyBatisTest.java | 38 +++++- .../org/sonar/server/platform/Platform.java | 2 + 8 files changed, 99 insertions(+), 84 deletions(-) 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 61a01cb36cf..11adc8adcd3 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 @@ -29,6 +29,7 @@ import org.sonar.batch.RemoteServerMetadata; import org.sonar.batch.ServerMetadata; import org.sonar.batch.config.BatchDatabaseSettingsLoader; import org.sonar.batch.config.BatchSettings; +import org.sonar.core.config.Logback; import org.sonar.core.i18n.I18nManager; import org.sonar.core.i18n.RuleI18nManager; import org.sonar.core.persistence.DaoUtils; @@ -59,6 +60,7 @@ public class BootstrapModule extends Module { addCoreSingleton(new PropertiesConfiguration()); addCoreSingleton(BatchSettings.class); addCoreSingleton(DryRun.class); + addCoreSingleton(Logback.class); addCoreSingleton(ServerMetadata.class);// registered here because used by BootstrapClassLoader addCoreSingleton(TempDirectories.class);// registered here because used by BootstrapClassLoader addCoreSingleton(HttpDownloader.class);// registered here because used by BootstrapClassLoader diff --git a/sonar-batch/src/main/resources/org/sonar/batch/bootstrapper/logback.xml b/sonar-batch/src/main/resources/org/sonar/batch/bootstrapper/logback.xml index 13135d01be9..12a7e1db673 100644 --- a/sonar-batch/src/main/resources/org/sonar/batch/bootstrapper/logback.xml +++ b/sonar-batch/src/main/resources/org/sonar/batch/bootstrapper/logback.xml @@ -42,15 +42,10 @@ - - - - - - - - - + + + + diff --git a/sonar-batch/src/main/resources/org/sonar/batch/logback.xml b/sonar-batch/src/main/resources/org/sonar/batch/logback.xml index 8c2d0cefc91..4171dcb6e34 100644 --- a/sonar-batch/src/main/resources/org/sonar/batch/logback.xml +++ b/sonar-batch/src/main/resources/org/sonar/batch/logback.xml @@ -41,6 +41,9 @@ + + + diff --git a/sonar-core/src/main/java/org/sonar/core/config/Logback.java b/sonar-core/src/main/java/org/sonar/core/config/Logback.java index df2892ceaf4..fc4569378ea 100644 --- a/sonar-core/src/main/java/org/sonar/core/config/Logback.java +++ b/sonar-core/src/main/java/org/sonar/core/config/Logback.java @@ -19,6 +19,7 @@ */ package org.sonar.core.config; +import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; @@ -26,6 +27,8 @@ import ch.qos.logback.core.util.StatusPrinter; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; +import org.sonar.api.ServerComponent; import java.io.File; import java.io.FileInputStream; @@ -38,11 +41,7 @@ import java.util.Map; * * @since 2.12 */ -public final class Logback { - - private Logback() { - // only static methods - } +public class Logback implements BatchComponent, ServerComponent { public static void configure(String classloaderPath, Map substitutionVariables) { InputStream input = Logback.class.getResourceAsStream(classloaderPath); @@ -85,4 +84,8 @@ public final class Logback { } return context; } + + public void setLoggerLevel(String loggerName, Level level) { + ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(loggerName)).setLevel(level); + } } diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java index 0eb09205458..d5c23809301 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java @@ -19,55 +19,36 @@ */ package org.sonar.core.persistence; -import org.apache.ibatis.type.JdbcType; - +import ch.qos.logback.classic.Level; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.ibatis.builder.xml.XMLMapperBuilder; import org.apache.ibatis.logging.LogFactory; import org.apache.ibatis.mapping.Environment; -import org.apache.ibatis.session.Configuration; -import org.apache.ibatis.session.ExecutorType; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.session.*; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.apache.ibatis.type.JdbcType; import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; +import org.sonar.api.config.Settings; import org.sonar.api.database.model.MeasureMapper; import org.sonar.api.database.model.MeasureModel; -import org.sonar.core.dashboard.ActiveDashboardDto; -import org.sonar.core.dashboard.ActiveDashboardMapper; -import org.sonar.core.dashboard.DashboardDto; -import org.sonar.core.dashboard.DashboardMapper; -import org.sonar.core.dashboard.WidgetDto; -import org.sonar.core.dashboard.WidgetMapper; -import org.sonar.core.dashboard.WidgetPropertyDto; -import org.sonar.core.dashboard.WidgetPropertyMapper; +import org.sonar.core.config.Logback; +import org.sonar.core.dashboard.*; import org.sonar.core.dependency.DependencyDto; import org.sonar.core.dependency.DependencyMapper; import org.sonar.core.dependency.ResourceSnapshotDto; import org.sonar.core.dependency.ResourceSnapshotMapper; import org.sonar.core.duplication.DuplicationMapper; import org.sonar.core.duplication.DuplicationUnitDto; -import org.sonar.core.filter.CriterionDto; -import org.sonar.core.filter.CriterionMapper; -import org.sonar.core.filter.FilterColumnDto; -import org.sonar.core.filter.FilterColumnMapper; -import org.sonar.core.filter.FilterDto; -import org.sonar.core.filter.FilterMapper; +import org.sonar.core.filter.*; import org.sonar.core.properties.PropertiesMapper; import org.sonar.core.properties.PropertyDto; import org.sonar.core.purge.PurgeMapper; import org.sonar.core.purge.PurgeVendorMapper; import org.sonar.core.purge.PurgeableSnapshotDto; -import org.sonar.core.resource.ResourceDto; -import org.sonar.core.resource.ResourceIndexDto; -import org.sonar.core.resource.ResourceIndexerMapper; -import org.sonar.core.resource.ResourceKeyUpdaterMapper; -import org.sonar.core.resource.ResourceMapper; -import org.sonar.core.resource.SnapshotDto; +import org.sonar.core.resource.*; import org.sonar.core.review.ReviewCommentDto; import org.sonar.core.review.ReviewCommentMapper; import org.sonar.core.review.ReviewDto; @@ -76,24 +57,21 @@ import org.sonar.core.rule.RuleDto; import org.sonar.core.rule.RuleMapper; import org.sonar.core.template.LoadedTemplateDto; import org.sonar.core.template.LoadedTemplateMapper; -import org.sonar.core.user.AuthorDto; -import org.sonar.core.user.AuthorMapper; -import org.sonar.core.user.GroupDto; -import org.sonar.core.user.GroupRoleDto; -import org.sonar.core.user.RoleMapper; -import org.sonar.core.user.UserDto; -import org.sonar.core.user.UserMapper; -import org.sonar.core.user.UserRoleDto; +import org.sonar.core.user.*; import java.io.InputStream; public class MyBatis implements BatchComponent, ServerComponent { private final Database database; + private final Settings settings; + private final Logback logback; private SqlSessionFactory sessionFactory; - public MyBatis(Database database) { + public MyBatis(Database database, Settings settings, Logback logback) { this.database = database; + this.settings = settings; + this.logback = logback; } public MyBatis start() { @@ -133,32 +111,13 @@ public class MyBatis implements BatchComponent, ServerComponent { loadAlias(conf, "WidgetProperty", WidgetPropertyDto.class); loadAlias(conf, "MeasureModel", MeasureModel.class); - loadMapper(conf, ActiveDashboardMapper.class); - loadMapper(conf, AuthorMapper.class); - loadMapper(conf, FilterMapper.class); - loadMapper(conf, CriterionMapper.class); - loadMapper(conf, FilterColumnMapper.class); - loadMapper(conf, DashboardMapper.class); - loadMapper(conf, DependencyMapper.class); - loadMapper(conf, DuplicationMapper.class); - loadMapper(conf, LoadedTemplateMapper.class); - loadMapper(conf, PropertiesMapper.class); - loadMapper(conf, PurgeMapper.class); - loadMapper(conf, PurgeVendorMapper.class); - loadMapper(conf, ResourceKeyUpdaterMapper.class); - loadMapper(conf, ResourceIndexerMapper.class); - loadMapper(conf, ResourceMapper.class); - loadMapper(conf, ResourceSnapshotMapper.class); - loadMapper(conf, ReviewCommentMapper.class); - loadMapper(conf, ReviewMapper.class); - loadMapper(conf, RoleMapper.class); - loadMapper(conf, RuleMapper.class); - loadMapper(conf, SchemaMigrationMapper.class); - loadMapper(conf, UserMapper.class); - loadMapper(conf, WidgetMapper.class); - loadMapper(conf, WidgetPropertyMapper.class); - loadMapper(conf, MeasureMapper.class); - + Class[] mappers = {ActiveDashboardMapper.class, AuthorMapper.class, FilterMapper.class, CriterionMapper.class, FilterColumnMapper.class, DashboardMapper.class, + DependencyMapper.class, DuplicationMapper.class, LoadedTemplateMapper.class, PropertiesMapper.class, PurgeMapper.class, PurgeVendorMapper.class, + ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceMapper.class, ResourceSnapshotMapper.class, ReviewCommentMapper.class, + ReviewMapper.class, RoleMapper.class, RuleMapper.class, SchemaMigrationMapper.class, UserMapper.class, WidgetMapper.class, WidgetPropertyMapper.class, + MeasureMapper.class}; + loadMappers(conf, mappers); + configureLogback(mappers); sessionFactory = new SqlSessionFactoryBuilder().build(conf); return this; } @@ -187,13 +146,31 @@ public class MyBatis implements BatchComponent, ServerComponent { } } - private void loadMapper(Configuration conf, Class mapperClass) { + private void loadMappers(Configuration mybatisConf, Class... mapperClasses) { + for (Class mapperClass : mapperClasses) { + loadMapper(mybatisConf, mapperClass); + } + } + + /** + * See http://www.mybatis.org/core/logging.html : + */ + private void configureLogback(Class[] mapperClasses) { + if (settings.getBoolean("sonar.showSql")) { + Level level = (settings.getBoolean("sonar.showSqlResults") ? Level.TRACE : Level.DEBUG); + for (Class mapperClass : mapperClasses) { + logback.setLoggerLevel(mapperClass.getName(), level); + } + } + } + + private void loadMapper(Configuration mybatisConf, Class mapperClass) { // trick to use database-specific XML files for a single Mapper Java interface InputStream input = getPathToMapper(mapperClass); try { - XMLMapperBuilder mapperParser = new XMLMapperBuilder(input, conf, mapperClass.getName(), conf.getSqlFragments()); + XMLMapperBuilder mapperParser = new XMLMapperBuilder(input, mybatisConf, mapperClass.getName(), mybatisConf.getSqlFragments()); mapperParser.parse(); - conf.addLoadedResource(mapperClass.getName()); + mybatisConf.addLoadedResource(mapperClass.getName()); } finally { IOUtils.closeQuietly(input); @@ -202,7 +179,7 @@ public class MyBatis implements BatchComponent, ServerComponent { private InputStream getPathToMapper(Class mapperClass) { InputStream input = getClass().getResourceAsStream( - "/" + StringUtils.replace(mapperClass.getName(), ".", "/") + "-" + database.getDialect().getId() + ".xml"); + "/" + StringUtils.replace(mapperClass.getName(), ".", "/") + "-" + database.getDialect().getId() + ".xml"); if (input == null) { input = getClass().getResourceAsStream("/" + StringUtils.replace(mapperClass.getName(), ".", "/") + ".xml"); } diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/AbstractDaoTestCase.java b/sonar-core/src/test/java/org/sonar/core/persistence/AbstractDaoTestCase.java index 39926b21b6f..b7646afb3cd 100644 --- a/sonar-core/src/test/java/org/sonar/core/persistence/AbstractDaoTestCase.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/AbstractDaoTestCase.java @@ -35,6 +35,7 @@ import org.dbunit.dataset.filter.DefaultColumnFilter; import org.dbunit.dataset.xml.FlatXmlDataSet; import org.junit.*; import org.sonar.api.config.Settings; +import org.sonar.core.config.Logback; import java.io.InputStream; import java.sql.SQLException; @@ -61,7 +62,7 @@ public abstract class AbstractDaoTestCase { } database.start(); - myBatis = new MyBatis(database); + myBatis = new MyBatis(database, settings, new Logback()); myBatis.start(); databaseCommands = DatabaseCommands.forDialect(database.getDialect()); diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/MyBatisTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/MyBatisTest.java index bff3c199a5e..fff30b032a7 100644 --- a/sonar-core/src/test/java/org/sonar/core/persistence/MyBatisTest.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/MyBatisTest.java @@ -19,27 +19,30 @@ */ package org.sonar.core.persistence; +import ch.qos.logback.classic.Level; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; import org.hamcrest.core.Is; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.sonar.api.config.Settings; +import org.sonar.core.config.Logback; import org.sonar.core.rule.RuleMapper; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; public class MyBatisTest { - private static MyBatis myBatis; private static H2Database database; @BeforeClass public static void start() { database = new H2Database(); - myBatis = new MyBatis(database.start()); - myBatis.start(); + database.start(); } @AfterClass @@ -49,6 +52,9 @@ public class MyBatisTest { @Test public void shouldConfigureMyBatis() { + MyBatis myBatis = new MyBatis(database, new Settings(), new Logback()); + myBatis.start(); + Configuration conf = myBatis.getSessionFactory().getConfiguration(); assertThat(conf.isUseGeneratedKeys(), Is.is(true)); assertThat(conf.hasMapper(RuleMapper.class), Is.is(true)); @@ -57,6 +63,9 @@ public class MyBatisTest { @Test public void shouldOpenBatchSession() { + MyBatis myBatis = new MyBatis(database, new Settings(), new Logback()); + myBatis.start(); + SqlSession session = myBatis.openBatchSession(); try { assertThat(session.getConnection(), notNullValue()); @@ -65,4 +74,27 @@ public class MyBatisTest { session.close(); } } + + @Test + public void log_sql_requests() { + Logback logback = mock(Logback.class); + Settings settings = new Settings(); + settings.setProperty("sonar.showSql", true); + MyBatis myBatis = new MyBatis(database, settings, logback); + myBatis.start(); + + verify(logback).setLoggerLevel("org.sonar.core.resource.ResourceIndexerMapper", Level.DEBUG); + } + + @Test + public void log_sql_requests_and_responses() { + Logback logback = mock(Logback.class); + Settings settings = new Settings(); + settings.setProperty("sonar.showSql", true); + settings.setProperty("sonar.showSqlResults", true); + MyBatis myBatis = new MyBatis(database, settings, logback); + myBatis.start(); + + verify(logback).setLoggerLevel("org.sonar.core.resource.ResourceIndexerMapper", Level.TRACE); + } } 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 e318db2b625..2ce18b2e881 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 @@ -38,6 +38,7 @@ import org.sonar.api.utils.IocContainer; import org.sonar.api.utils.TimeProfiler; import org.sonar.api.workflow.internal.DefaultWorkflow; import org.sonar.core.PicoUtils; +import org.sonar.core.config.Logback; import org.sonar.core.i18n.GwtI18n; import org.sonar.core.i18n.I18nManager; import org.sonar.core.i18n.RuleI18nManager; @@ -158,6 +159,7 @@ public final class Platform { rootContainer.addSingleton(new BaseConfiguration()); rootContainer.addSingleton(ServerSettings.class); rootContainer.addSingleton(ServerImpl.class); + rootContainer.addSingleton(Logback.class); rootContainer.addSingleton(EmbeddedDatabaseFactory.class); rootContainer.addSingleton(DefaultDatabase.class); rootContainer.addSingleton(MyBatis.class); -- 2.39.5