]> source.dussan.org Git - sonarqube.git/commitdiff
Fix support of sonar.showSqlResults with MyBatis 3.1
authorSimon Brandhof <simon.brandhof@gmail.com>
Wed, 11 Jul 2012 15:02:59 +0000 (17:02 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Wed, 11 Jul 2012 15:03:17 +0000 (17:03 +0200)
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java
sonar-batch/src/main/resources/org/sonar/batch/bootstrapper/logback.xml
sonar-batch/src/main/resources/org/sonar/batch/logback.xml
sonar-core/src/main/java/org/sonar/core/config/Logback.java
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
sonar-core/src/test/java/org/sonar/core/persistence/AbstractDaoTestCase.java
sonar-core/src/test/java/org/sonar/core/persistence/MyBatisTest.java
sonar-server/src/main/java/org/sonar/server/platform/Platform.java

index 61a01cb36cf225ac99faa9723b1e2b2166683ee5..11adc8adcd3b3454353e8af7780907f5739f5485 100644 (file)
@@ -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
index 13135d01be97b31a6122233248fee1c84093125f..12a7e1db673cb43e42ffc1ab2e74af62b64d57aa 100644 (file)
   <logger name="org.hibernate.SQL">
     <level value="${SQL_LOGGER_LEVEL:-ERROR}"/>
   </logger>
-  <logger name="org.apache.ibatis">
-    <level value="${SQL_LOGGER_LEVEL:-WARN}"/>
-  </logger>
-  <logger name="java.sql">
-    <level value="${SQL_LOGGER_LEVEL:-WARN}"/>
-  </logger>
-  <logger name="java.sql.ResultSet">
-    <level value="${SQL_RESULTS_LOGGER_LEVEL:-WARN}"/>
-  </logger>
+  <logger name="org.mybatis">
+      <level value="${SQL_LOGGER_LEVEL:-WARN}"/>
+    </logger>
+  <!-- see also org.sonar.core.persistence.MyBatis#configureLogback() -->
 
   <root>
     <!-- sonar.verbose -->
index 8c2d0cefc910ed3b6a1159e8acd3ce0d36b38961..4171dcb6e3493bb0e2298e24a1e9dd629710fc18 100644 (file)
@@ -41,6 +41,9 @@
   <logger name="org.apache.ibatis">
     <level value="${SQL_LOGGER_LEVEL:-WARN}"/>
   </logger>
+  <logger name="org.mybatis">
+      <level value="${SQL_LOGGER_LEVEL:-WARN}"/>
+    </logger>
   <logger name="java.sql">
     <level value="${SQL_LOGGER_LEVEL:-WARN}"/>
   </logger>
index df2892ceaf4fe04430071ee9e84ab78edd56cf78..fc4569378eab64c1eba2ca3d66becd0a9662ae3c 100644 (file)
@@ -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<String, String> 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);
+  }
 }
index 0eb092054588e1d62ad11b7ebc4c1447112f0f1b..d5c238093010c68f8046d5d67a77d1088ddf28a5 100644 (file)
  */
 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");
     }
index 39926b21b6ff236a448c1e69ca38941a96c061cb..b7646afb3cd87b33631822c27ca54e1a01f5ab74 100644 (file)
@@ -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());
index bff3c199a5e48b4646e0a0c6fa2c3ec5ad95e9db..fff30b032a758584621ec8425aa26c9de8383572 100644 (file)
  */
 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);
+  }
 }
index e318db2b62592c2f2c2528e84a3c70bce56b2ef0..2ce18b2e8814444b589ba89f93c6a1c36e98ba82 100644 (file)
@@ -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);