Browse Source

SONAR-6588 drop db connection from batch

tags/5.2-RC1
Simon Brandhof 9 years ago
parent
commit
29ae9b385a
87 changed files with 46 additions and 4565 deletions
  1. 1
    49
      pom.xml
  2. 0
    4
      server/sonar-server-benchmarks/src/test/resources/logback-test.xml
  3. 0
    3
      server/sonar-server/src/main/java/org/sonar/server/app/WebLogging.java
  4. 0
    22
      sonar-batch/pom.xml
  5. 1
    3
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
  6. 0
    47
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabase.java
  7. 0
    41
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabaseSessionFactory.java
  8. 0
    100
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseCompatibility.java
  9. 0
    4
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/DefaultAnalysisMode.java
  10. 2
    5
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java
  11. 0
    5
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionUtils.java
  12. 1
    41
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
  13. 0
    195
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java
  14. 0
    72
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcLeakPrevention.java
  15. 0
    125
      sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java
  16. 0
    168
      sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java
  17. 0
    164
      sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinder.java
  18. 0
    49
      sonar-batch/src/main/java/org/sonar/batch/components/Period.java
  19. 0
    91
      sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java
  20. 0
    23
      sonar-batch/src/main/java/org/sonar/batch/components/package-info.java
  21. 0
    70
      sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDate.java
  22. 0
    77
      sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDays.java
  23. 0
    62
      sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousAnalysis.java
  24. 0
    63
      sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersion.java
  25. 0
    61
      sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByVersion.java
  26. 0
    95
      sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PeriodsDefinition.java
  27. 1
    1
      sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java
  28. 0
    2
      sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
  29. 0
    12
      sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
  30. 0
    11
      sonar-batch/src/main/resources/org/sonar/batch/bootstrapper/logback.xml
  31. 0
    11
      sonar-batch/src/main/resources/org/sonar/batch/logback.xml
  32. 0
    36
      sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseSessionFactoryTest.java
  33. 0
    42
      sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseTest.java
  34. 0
    136
      sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseCompatibilityTest.java
  35. 1
    16
      sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionUtilsTest.java
  36. 0
    121
      sonar-batch/src/test/java/org/sonar/batch/bootstrap/JdbcDriverHolderTest.java
  37. 0
    108
      sonar-batch/src/test/java/org/sonar/batch/components/PastMeasuresLoaderTest.java
  38. 0
    231
      sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotFinderTest.java
  39. 0
    105
      sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotTest.java
  40. 0
    111
      sonar-batch/src/test/java/org/sonar/batch/components/TimeMachineConfigurationTest.java
  41. 0
    62
      sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDateTest.java
  42. 0
    113
      sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDaysTest.java
  43. 0
    56
      sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousAnalysisTest.java
  44. 0
    73
      sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest.java
  45. 0
    57
      sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByVersionTest.java
  46. 0
    76
      sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PeriodsDefinitionTest.java
  47. 10
    11
      sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java
  48. 6
    8
      sonar-batch/src/test/java/org/sonar/batch/report/CoveragePublisherTest.java
  49. 1
    2
      sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java
  50. 1
    4
      sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
  51. 1
    2
      sonar-batch/src/test/java/org/sonar/batch/report/MetadataPublisherTest.java
  52. 5
    7
      sonar-batch/src/test/java/org/sonar/batch/report/SourcePublisherTest.java
  53. 0
    30
      sonar-core/pom.xml
  54. 1
    5
      sonar-core/src/main/java/org/sonar/core/persistence/Database.java
  55. 6
    28
      sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java
  56. 0
    5
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/Dialect.java
  57. 0
    6
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/H2.java
  58. 0
    30
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/MsSql.java
  59. 0
    19
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/MySql.java
  60. 0
    23
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/Oracle.java
  61. 0
    49
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/OracleSequenceGenerator.java
  62. 0
    62
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/PostgreSQLSequenceGenerator.java
  63. 1
    22
      sonar-core/src/main/java/org/sonar/core/persistence/dialect/PostgreSql.java
  64. 2
    5
      sonar-core/src/main/java/org/sonar/core/qualityprofile/db/ActiveRuleDto.java
  65. 0
    4
      sonar-core/src/main/java/org/sonar/core/timemachine/Periods.java
  66. 0
    80
      sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java
  67. 0
    40
      sonar-core/src/main/java/org/sonar/jpa/session/CustomHibernateConnectionProvider.java
  68. 0
    35
      sonar-core/src/main/java/org/sonar/jpa/session/DatabaseConnector.java
  69. 0
    33
      sonar-core/src/main/java/org/sonar/jpa/session/DatabaseSessionFactory.java
  70. 0
    52
      sonar-core/src/main/java/org/sonar/jpa/session/DefaultDatabaseConnector.java
  71. 0
    301
      sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java
  72. 0
    28
      sonar-core/src/main/resources/META-INF/persistence.xml
  73. 0
    12
      sonar-core/src/test/java/org/sonar/core/persistence/DefaultDatabaseTest.java
  74. 3
    15
      sonar-core/src/test/java/org/sonar/core/persistence/H2Database.java
  75. 0
    49
      sonar-core/src/test/java/org/sonar/core/persistence/dialect/OracleSequenceGeneratorTest.java
  76. 0
    49
      sonar-core/src/test/java/org/sonar/core/persistence/dialect/PostgreSQLSequenceGeneratorTest.java
  77. 0
    90
      sonar-core/src/test/java/org/sonar/jpa/session/DatabaseSessionTest.java
  78. 0
    79
      sonar-core/src/test/java/org/sonar/jpa/session/JpaDatabaseSessionTest.java
  79. 0
    40
      sonar-core/src/test/java/org/sonar/jpa/test/AbstractDbUnitTestCase.java
  80. 1
    5
      sonar-core/src/test/resources/logback-test.xml
  81. 0
    22
      sonar-plugin-api/pom.xml
  82. 0
    37
      sonar-plugin-api/src/main/java/org/sonar/api/batch/RequiresDB.java
  83. 0
    9
      sonar-plugin-api/src/main/java/org/sonar/api/database/BaseIdentifiable.java
  84. 0
    87
      sonar-plugin-api/src/main/java/org/sonar/api/database/DatabaseSession.java
  85. 0
    46
      sonar-plugin-api/src/main/java/org/sonar/api/database/model/ResourceModel.java
  86. 0
    65
      sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java
  87. 1
    50
      sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java

+ 1
- 49
pom.xml View File

@@ -818,49 +818,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
<exclusions>
<exclusion>
<!-- provided by Java 1.7 -->
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.1.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.3.2.GA</version>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
<exclusion>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.4.0.GA</version>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
@@ -1007,11 +964,6 @@
<!-- do not upgrade to 1.7.10, much slower at startup -->
<version>1.7.9</version>
</dependency>
<dependency>
<groupId>geronimo-spec</groupId>
<artifactId>geronimo-spec-jta</artifactId>
<version>1.0-M1</version>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>stax2-api</artifactId>
@@ -1365,7 +1317,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<excludePackageNames>
net.*:org.sonar.application:org.sonar.server:org.sonar.graph:org.sonar.batch:org.sonar.channel:org.sonar.java:org.sonar.maven*:org.sonar.plugins.*:org.sonar.colorizer:org.sonar.core:org.sonar.jpa:org.sonar.duplications:org.sonar.markdown:com.*
net.*:org.sonar.application:org.sonar.server:org.sonar.graph:org.sonar.batch:org.sonar.channel:org.sonar.java:org.sonar.maven*:org.sonar.plugins.*:org.sonar.colorizer:org.sonar.core:org.sonar.duplications:org.sonar.markdown:com.*
</excludePackageNames>
<author>false</author>
<linksource>true</linksource>

+ 0
- 4
server/sonar-server-benchmarks/src/test/resources/logback-test.xml View File

@@ -11,10 +11,6 @@
</encoder>
</appender>

<logger name="org.hibernate">
<level value="WARN"/>
</logger>

<logger name="org.dbunit">
<level value="WARN"/>
</logger>

+ 0
- 3
server/sonar-server/src/main/java/org/sonar/server/app/WebLogging.java View File

@@ -65,9 +65,6 @@ class WebLogging {
private void configureLevels(LoggerContext ctx, Props props) {
// override level of some loggers
helper.configureLogger(ctx, "rails", Level.WARN);
helper.configureLogger(ctx, "org.hibernate.cache.ReadWriteCache", Level.ERROR);
helper.configureLogger(ctx, "org.hibernate", Level.WARN);
helper.configureLogger(ctx, "org.hibernate.SQL", Level.WARN);
helper.configureLogger(ctx, "org.apache.ibatis", Level.WARN);
helper.configureLogger(ctx, "java.sql", Level.WARN);
helper.configureLogger(ctx, "java.sql.ResultSet", Level.WARN);

+ 0
- 22
sonar-batch/pom.xml View File

@@ -107,28 +107,6 @@
<artifactId>freemarker</artifactId>
</dependency>

<!-- hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>geronimo-spec</groupId>
<artifactId>geronimo-spec-jta</artifactId>
</dependency>

<!-- unit tests -->
<dependency>
<groupId>org.codehaus.sonar</groupId>

+ 1
- 3
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java View File

@@ -22,7 +22,6 @@ package org.sonar.batch.bootstrap;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.List;
import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.batch.compute.BranchCoverageDecorator;
import org.sonar.batch.compute.CommentDensityDecorator;
import org.sonar.batch.compute.CoverageDecorator;
@@ -94,8 +93,7 @@ public class BatchComponents {
OverallBranchCoverageDecorator.class,
CommentDensityDecorator.class,
DirectoriesDecorator.class,
FilesDecorator.class,
TimeMachineConfiguration.class
FilesDecorator.class
);
components.addAll(CorePropertyDefinitions.all());
// CPD

+ 0
- 47
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabase.java View File

@@ -1,47 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import java.util.Properties;
import org.sonar.api.config.Settings;
import org.sonar.core.persistence.DefaultDatabase;

/**
* @since 2.12
*/
public class BatchDatabase extends DefaultDatabase {

public BatchDatabase(Settings settings,
// The dependency on JdbcDriverHolder is required to be sure that the JDBC driver
// has been downloaded and injected into classloader
JdbcDriverHolder jdbcDriverHolder) {
super(settings);
}

@Override
protected void doCompleteProperties(Properties properties) {
// two connections are required : one for Hibernate, and one for MyBatis for regular operations
// Note that Hibernate will be removed soon
properties.setProperty("sonar.jdbc.initialSize", "2");
properties.setProperty("sonar.jdbc.maxActive", "2");
// SONAR-2965
properties.setProperty("sonar.jdbc.defaultAutoCommit", "false");
}
}

+ 0
- 41
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabaseSessionFactory.java View File

@@ -1,41 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import org.sonar.api.database.DatabaseSession;
import org.sonar.jpa.session.DatabaseSessionFactory;

public class BatchDatabaseSessionFactory implements DatabaseSessionFactory {

private DatabaseSession session;

public BatchDatabaseSessionFactory(DatabaseSession session) {
this.session = session;
}

@Override
public DatabaseSession getSession() {
return session;
}

@Override
public void clear() {
}
}

+ 0
- 100
sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseCompatibility.java View File

@@ -1,100 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
import org.sonar.api.database.DatabaseProperties;
import org.sonar.api.utils.MessageException;
import org.sonar.core.persistence.DatabaseVersion;
import org.sonar.core.properties.PropertiesDao;

/**
* Detects if database is not up-to-date with the version required by the batch.
*/
@BatchSide
public class DatabaseCompatibility {

private DatabaseVersion version;
private Settings settings;
private PropertiesDao propertiesDao;
private ServerClient server;
private DefaultAnalysisMode analysisMode;

public DatabaseCompatibility(DatabaseVersion version, ServerClient server, Settings settings, PropertiesDao propertiesDao, DefaultAnalysisMode mode) {
this.version = version;
this.server = server;
this.settings = settings;
this.propertiesDao = propertiesDao;
this.analysisMode = mode;
}

public void start() {
if (!analysisMode.isPreview()) {
checkCorrectServerId();
checkDatabaseStatus();
}
}

private void checkCorrectServerId() {
if (!propertiesDao.selectGlobalProperty(CoreProperties.SERVER_ID).getValue().equals(getServerId())) {
StringBuilder message = new StringBuilder("The current batch process and the configured remote server do not share the same DB configuration.\n");
message.append("\t- Batch side: ");
message.append(settings.getString(DatabaseProperties.PROP_URL));
message.append(" (");
String userName = settings.getString(DatabaseProperties.PROP_USER);
message.append(userName == null ? "sonar" : userName);
message.append(" / *****)\n\t- Server side: check the configuration at ");
message.append(server.getURL());
message.append("/system\n");
throw MessageException.of(message.toString());
}
}

private String getServerId() {
String remoteServerInfo = server.request("/api/server");
// don't use JSON utilities to extract ID from such a small string
return extractServerId(remoteServerInfo);
}

@VisibleForTesting
String extractServerId(String remoteServerInfo) {
String partialId = StringUtils.substringAfter(remoteServerInfo, "\"id\":\"");
return StringUtils.substringBefore(partialId, "\"");
}

private void checkDatabaseStatus() {
DatabaseVersion.Status status = version.getStatus();
if (status == DatabaseVersion.Status.REQUIRES_DOWNGRADE) {
throw MessageException.of("Database relates to a more recent version of SonarQube. Please check your settings (JDBC settings, version of Maven plugin)");
}
if (status == DatabaseVersion.Status.REQUIRES_UPGRADE) {
throw MessageException.of("Database must be upgraded. Please browse " + server.getURL() + "/setup");
}
if (status != DatabaseVersion.Status.UP_TO_DATE) {
// Support other future values
throw MessageException.of("Unknown database status: " + status);
}
}

}

+ 0
- 4
sonar-batch/src/main/java/org/sonar/batch/bootstrap/DefaultAnalysisMode.java View File

@@ -43,10 +43,6 @@ public class DefaultAnalysisMode implements AnalysisMode {
init(props);
}

public boolean isDb() {
return !preview && !incremental && !mediumTestMode;
}

@Override
public boolean isPreview() {
return preview || incremental;

+ 2
- 5
sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.batch.bootstrap;

import java.util.List;
import javax.annotation.Nullable;
import org.sonar.api.ExtensionProvider;
import org.sonar.api.Plugin;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
@@ -26,10 +28,6 @@ import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;

import javax.annotation.Nullable;

import java.util.List;

public class ExtensionInstaller {

private final PluginRepository pluginRepository;
@@ -72,7 +70,6 @@ public class ExtensionInstaller {

private void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
if (ExtensionUtils.supportsEnvironment(extension, env)
&& (analysisMode.isDb() || !ExtensionUtils.requiresDB(extension))
&& matcher.accept(extension)) {
container.addExtension(pluginInfo, extension);
} else {

+ 0
- 5
sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionUtils.java View File

@@ -22,7 +22,6 @@ package org.sonar.batch.bootstrap;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.RequiresDB;
import org.sonar.api.batch.SupportedEnvironment;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
@@ -58,10 +57,6 @@ public class ExtensionUtils {
return false;
}

public static boolean requiresDB(Object extension) {
return AnnotationUtils.getAnnotation(extension, RequiresDB.class) != null;
}

public static boolean isMavenExtensionOnly(Object extension) {
SupportedEnvironment env = AnnotationUtils.getAnnotation(extension, SupportedEnvironment.class);
return env != null && env.value().length == 1 && StringUtils.equalsIgnoreCase("maven", env.value()[0]);

+ 1
- 41
sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java View File

@@ -19,22 +19,14 @@
*/
package org.sonar.batch.bootstrap;

import org.sonar.batch.index.CachesManager;

import java.util.List;
import java.util.Map;

import org.sonar.api.CoreProperties;
import org.sonar.api.Plugin;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.UriReader;
import org.sonar.batch.components.PastSnapshotFinder;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByDate;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByDays;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousAnalysis;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousVersion;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByVersion;
import org.sonar.batch.index.CachesManager;
import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader;
import org.sonar.batch.issue.tracking.ServerLineHashesLoader;
import org.sonar.batch.platform.DefaultServer;
@@ -47,21 +39,14 @@ import org.sonar.batch.repository.ProjectRepositoriesLoader;
import org.sonar.batch.repository.ServerIssuesLoader;
import org.sonar.batch.repository.user.UserRepository;
import org.sonar.batch.scan.ProjectScanContainer;
import org.sonar.core.cluster.NullQueue;
import org.sonar.core.config.Logback;
import org.sonar.core.i18n.DefaultI18n;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.persistence.DaoUtils;
import org.sonar.core.persistence.DatabaseVersion;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.PluginClassloaderFactory;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginLoader;
import org.sonar.core.platform.PluginRepository;
import org.sonar.core.util.DefaultHttpDownloader;
import org.sonar.jpa.session.DefaultDatabaseConnector;
import org.sonar.jpa.session.JpaDatabaseSession;

public class GlobalContainer extends ComponentContainer {

@@ -85,10 +70,6 @@ public class GlobalContainer extends ComponentContainer {
DefaultAnalysisMode analysisMode = new DefaultAnalysisMode(bootstrapProps.properties());
add(bootstrapProps, analysisMode);
addBootstrapComponents();
if (analysisMode.isDb()) {
addDatabaseComponents();
}

}

private void addBootstrapComponents() {
@@ -131,27 +112,6 @@ public class GlobalContainer extends ComponentContainer {
}
}

private void addDatabaseComponents() {
add(
JdbcDriverHolder.class,
BatchDatabase.class,
MyBatis.class,
NullQueue.class,
DatabaseVersion.class,
DatabaseCompatibility.class,
DefaultDatabaseConnector.class,
JpaDatabaseSession.class,
BatchDatabaseSessionFactory.class,
DaoUtils.getDaoClasses(),
RuleI18nManager.class,
PastSnapshotFinderByDate.class,
PastSnapshotFinderByDays.class,
PastSnapshotFinderByPreviousAnalysis.class,
PastSnapshotFinderByVersion.class,
PastSnapshotFinderByPreviousVersion.class,
PastSnapshotFinder.class);
}

@Override
protected void doAfterStart() {
installPlugins();

+ 0
- 195
sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java View File

@@ -1,195 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.SonarException;
import org.sonar.home.cache.FileCache;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
* Contains and provides class loader extended with the JDBC Driver hosted on the server-side.
*/
public class JdbcDriverHolder {

private static final Logger LOG = LoggerFactory.getLogger(JdbcDriverHolder.class);

private ServerClient serverClient;
private DefaultAnalysisMode analysisMode;
private FileCache fileCache;

// initialized in start()
private JdbcDriverClassLoader classLoader = null;

public JdbcDriverHolder(FileCache fileCache, DefaultAnalysisMode analysisMode, ServerClient serverClient) {
this.serverClient = serverClient;
this.analysisMode = analysisMode;
this.fileCache = fileCache;
}

public void start() {
if (!analysisMode.isPreview()) {
try {
LOG.info("Install JDBC driver");
String[] nameAndHash = downloadJdbcDriverIndex();
if (nameAndHash.length > 0) {
String filename = nameAndHash[0];
String hash = nameAndHash[1];

File jdbcDriver = fileCache.get(filename, hash, new FileCache.Downloader() {
@Override
public void download(String filename, File toFile) throws IOException {
String url = "/deploy/" + filename;
if (LOG.isDebugEnabled()) {
LOG.debug("Download {} to {}", url, toFile.getAbsolutePath());
} else {
LOG.info("Download {}", filename);
}
serverClient.download(url, toFile);
}
});
classLoader = initClassloader(jdbcDriver);
}
} catch (SonarException e) {
throw e;
} catch (Exception e) {
throw new SonarException("Fail to install JDBC driver", e);
}
}
}

@VisibleForTesting
JdbcDriverClassLoader getClassLoader() {
return classLoader;
}

@VisibleForTesting
static JdbcDriverClassLoader initClassloader(File jdbcDriver) {
JdbcDriverClassLoader classLoader;
try {
ClassLoader parentClassLoader = JdbcDriverHolder.class.getClassLoader();
classLoader = new JdbcDriverClassLoader(jdbcDriver.toURI().toURL(), parentClassLoader);

} catch (MalformedURLException e) {
throw new SonarException("Fail to get URL of : " + jdbcDriver.getAbsolutePath(), e);
}

// set as the current context classloader for hibernate, else it does not find the JDBC driver.
Thread.currentThread().setContextClassLoader(classLoader);
return classLoader;
}

/**
* This method automatically invoked by PicoContainer and unregisters JDBC drivers, which were forgotten.
* <p>
* Dynamically loaded JDBC drivers can not be simply used and this is a well known problem of {@link java.sql.DriverManager},
* so <a href="http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-from-an-arbitrary-location">workaround is to use proxy</a>.
* However DriverManager also contains memory leak, thus not only proxy, but also original driver must be unregistered,
* otherwise our class loader would be kept in memory.
* </p>
* <p>
* This operation contains unnecessary complexity because:
* <ul>
* <li>DriverManager checks the class loader of the calling class. Thus we can't simply ask it about deregistration.</li>
* <li>We can't use reflection against DriverManager, since it would create a dependency on DriverManager implementation,
* which can be changed (like it was done - compare Java 1.5 and 1.6).</li>
* <li>So we use companion - {@link JdbcLeakPrevention}. But we can't just create an instance,
* since it will be loaded by parent class loader and again will not pass DriverManager's check.
* So, we load the bytes via our parent class loader, but define the class with this class loader
* thus JdbcLeakPrevention looks like our class to the DriverManager.</li>
* </li>
* </p>
*/
public void stop() {
if (classLoader != null) {
classLoader.clearReferencesJdbc();
if (Thread.currentThread().getContextClassLoader() == classLoader) {
Thread.currentThread().setContextClassLoader(classLoader.getParent());
}
classLoader = null;
}
}

private String[] downloadJdbcDriverIndex() {
String url = "/deploy/jdbc-driver.txt";
try {
LOG.debug("Download index of jdbc-driver");
String indexContent = serverClient.request(url);
// File is empty when H2 is used
if (Strings.isNullOrEmpty(indexContent)) {
return new String[] {};
}
return indexContent.split("\\|");
} catch (Exception e) {
throw new SonarException("Fail to download jdbc-driver index: " + url, e);
}
}

static class JdbcDriverClassLoader extends URLClassLoader {

public JdbcDriverClassLoader(URL jdbcDriver, ClassLoader parent) {
super(new URL[] {jdbcDriver}, parent);
}

public void clearReferencesJdbc() {
InputStream is = getResourceAsStream("org/sonar/batch/bootstrap/JdbcLeakPrevention.class");
byte[] classBytes = new byte[2048];
int offset = 0;
try {
int read = is.read(classBytes, offset, classBytes.length - offset);
while (read > -1) {
offset += read;
if (offset == classBytes.length) {
// Buffer full - double size
byte[] tmp = new byte[classBytes.length * 2];
System.arraycopy(classBytes, 0, tmp, 0, classBytes.length);
classBytes = tmp;
}
read = is.read(classBytes, offset, classBytes.length - offset);
}

Class<?> lpClass = defineClass("org.sonar.batch.bootstrap.JdbcLeakPrevention", classBytes, 0, offset, this.getClass().getProtectionDomain());
Object obj = lpClass.newInstance();

obj.getClass().getMethod("unregisterDrivers").invoke(obj);
} catch (Exception e) {
LOG.warn("JDBC driver deregistration failed", e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) {
LOG.warn(ioe.getMessage(), ioe);
}
}
}
}
}

}

+ 0
- 72
sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcLeakPrevention.java View File

@@ -1,72 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* Companion of {@link JdbcDriverHolder} and allows it to deregister JDBC drivers.
* <p>
* Some hacks are involved in the loading of the class - see {@link JdbcDriverHolder#stop()},
* so this class can refer to classes only from java.* package and must not be referred from other classes.
* Placement and naming of this class and methods are very important, since it loaded and invoked via reflection.
* </p>
*/
public class JdbcLeakPrevention {

/**
* @return names of the drivers that have been unregistered
*/
public List<String> unregisterDrivers() throws SQLException {
Set<Driver> registeredDrivers = registeredDrivers();

List<String> unregisteredNames = new ArrayList<>();
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver.getClass().getClassLoader() != this.getClass().getClassLoader()) {
continue;
}
if (registeredDrivers.contains(driver)) {
unregisteredNames.add(driver.getClass().getCanonicalName());
}
DriverManager.deregisterDriver(driver);
}
return unregisteredNames;
}

private static Set<Driver> registeredDrivers() {
Set<Driver> registeredDrivers = new HashSet<>();
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
registeredDrivers.add(driver);
}
return registeredDrivers;
}

}

+ 0
- 125
sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java View File

@@ -1,125 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import com.google.common.collect.Maps;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import javax.persistence.Query;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.Resource;

/**
* Can't be moved. Used by devcockpit.
*/
@BatchSide
public class PastMeasuresLoader {

private Map<Integer, Metric> metricByIds;
private DatabaseSession session;

public PastMeasuresLoader(DatabaseSession session, MetricFinder metricFinder) {
this(session, metricFinder.findAll());
}

PastMeasuresLoader(DatabaseSession session, Collection<Metric> metrics) {
this.session = session;
this.metricByIds = Maps.newHashMap();
for (Metric metric : metrics) {
if (metric.isNumericType()) {
metricByIds.put(metric.getId(), metric);
}
}
}

public Collection<Metric> getMetrics() {
return metricByIds.values();
}

public List<Object[]> getPastMeasures(Resource resource, PastSnapshot projectPastSnapshot) {
if (projectPastSnapshot != null && projectPastSnapshot.getProjectSnapshot() != null) {
return getPastMeasures(resource.getEffectiveKey(), resource.getPath(), projectPastSnapshot.getProjectSnapshot());
}
return Collections.emptyList();
}

public List<Object[]> getPastMeasures(String resourceKey, Snapshot projectPastSnapshot) {
return getPastMeasures(resourceKey, null, projectPastSnapshot);
}

public List<Object[]> getPastMeasures(String resourceKey, @Nullable String path, Snapshot projectPastSnapshot) {
String sql = "select m.metric_id, m.characteristic_id, m.person_id, m.rule_id, m.value from project_measures m, snapshots s" +
" where m.snapshot_id=s.id and m.metric_id in (:metricIds) " +
" and (s.root_snapshot_id=:rootSnapshotId or s.id=:rootSnapshotId) " +
" and s.status=:status and s.project_id=(select p.id from projects p where p.kee=:resourceKey"
+ (StringUtils.isNotBlank(path) ? " and p.path=:path" : "")
+ ")";
Query q = session.createNativeQuery(sql)
.setParameter("metricIds", metricByIds.keySet())
.setParameter("rootSnapshotId", ObjectUtils.defaultIfNull(projectPastSnapshot.getRootId(), projectPastSnapshot.getId()))
.setParameter("resourceKey", resourceKey)
.setParameter("status", Snapshot.STATUS_PROCESSED);
if (StringUtils.isNotBlank(path)) {
q.setParameter("path", path);
}
return q.getResultList();
}

public static int getMetricId(Object[] row) {
// can be BigDecimal on Oracle
return ((Number) row[0]).intValue();
}

public static Integer getCharacteristicId(Object[] row) {
// can be BigDecimal on Oracle
Number number = (Number) row[1];
return number != null ? number.intValue() : null;
}

public static Integer getPersonId(Object[] row) {
// can be BigDecimal on Oracle
Number number = (Number) row[2];
return number != null ? number.intValue() : null;
}

public static Integer getRuleId(Object[] row) {
// can be BigDecimal on Oracle
Number number = (Number) row[3];
return number != null ? number.intValue() : null;
}

public static boolean hasValue(Object[] row) {
return row[4] != null;
}

public static double getValue(Object[] row) {
return ((Number) row[4]).doubleValue();
}

}

+ 0
- 168
sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java View File

@@ -1,168 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.utils.DateUtils;

import javax.annotation.Nullable;

import java.util.Calendar;
import java.util.Date;

import static org.sonar.api.utils.DateUtils.longToDate;

/**
* Used by devcockpit
*/
public class PastSnapshot {

private int index;
private String mode;
private String modeParameter;
private Snapshot projectSnapshot;
private Date targetDate = null;

public PastSnapshot(String mode, @Nullable Date targetDate, @Nullable Snapshot projectSnapshot) {
this.mode = mode;
if (targetDate != null) {
this.targetDate = org.apache.commons.lang.time.DateUtils.truncate(targetDate, Calendar.SECOND);
}
this.projectSnapshot = projectSnapshot;
}

public PastSnapshot(String mode, @Nullable Date targetDate) {
this(mode, targetDate, null);
}

/**
* See SONAR-2428 : even if previous analysis does not exist (no snapshot and no target date), we should perform comparison.
*/
public PastSnapshot(String mode) {
this(mode, null, null);
}

public PastSnapshot setIndex(int index) {
this.index = index;
return this;
}

public int getIndex() {
return index;
}

public boolean isRelatedToSnapshot() {
return projectSnapshot != null;
}

public Snapshot getProjectSnapshot() {
return projectSnapshot;
}

public Date getDate() {
return projectSnapshot != null ? longToDate(projectSnapshot.getCreatedAtMs()) : null;
}

public PastSnapshot setMode(String mode) {
this.mode = mode;
return this;
}

public String getMode() {
return mode;
}

public String getModeParameter() {
return modeParameter;
}

public PastSnapshot setModeParameter(String s) {
this.modeParameter = s;
return this;
}

public Integer getProjectSnapshotId() {
return projectSnapshot != null ? projectSnapshot.getId() : null;
}

public String getQualifier() {
return projectSnapshot != null ? projectSnapshot.getQualifier() : null;
}

/**
* @deprecated in 4.2. Target date should only be used in labels.
*/
@Deprecated
public Date getTargetDate() {
return targetDate;
}

public PastSnapshot clonePastSnapshot() {
PastSnapshot clone = new PastSnapshot(mode, targetDate, projectSnapshot);
clone.setIndex(index);
clone.setModeParameter(modeParameter);
return clone;
}

@Override
public String toString() {
if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_VERSION)) {
String label = String.format("Compare to version %s", modeParameter);
if (targetDate != null) {
label += String.format(" (%s)", DateUtils.formatDate(getDate()));
}
return label;
}
if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_DAYS)) {
String label = String.format("Compare over %s days (%s", modeParameter, DateUtils.formatDate(targetDate));
if (isRelatedToSnapshot()) {
label += ", analysis of " + getDate();
}
label += ")";
return label;
}
if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS)) {
String label = "Compare to previous analysis";
if (isRelatedToSnapshot()) {
label += String.format(" (%s)", DateUtils.formatDate(getDate()));
}
return label;
}
if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION)) {
String label = "Compare to previous version";
if (isRelatedToSnapshot()) {
label += String.format(" (%s)", DateUtils.formatDate(getDate()));
}
return label;
}
if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_DATE)) {
String label = "Compare to date " + DateUtils.formatDate(targetDate);
if (isRelatedToSnapshot()) {
label += String.format(" (analysis of %s)", DateUtils.formatDate(getDate()));
}
return label;
}
return ReflectionToStringBuilder.toString(this);
}

}

+ 0
- 164
sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinder.java View File

@@ -1,164 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import com.google.common.base.Strings;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByDate;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByDays;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousAnalysis;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousVersion;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByVersion;

import javax.annotation.Nullable;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* Can't be moved since it is used by devcockpit.
*/
@BatchSide
public class PastSnapshotFinder {

private static final Logger LOG = LoggerFactory.getLogger(PastSnapshotFinder.class);

private PastSnapshotFinderByDays finderByDays;
private PastSnapshotFinderByVersion finderByVersion;
private PastSnapshotFinderByDate finderByDate;
private PastSnapshotFinderByPreviousAnalysis finderByPreviousAnalysis;
private PastSnapshotFinderByPreviousVersion finderByPreviousVersion;

public PastSnapshotFinder(PastSnapshotFinderByDays finderByDays, PastSnapshotFinderByVersion finderByVersion,
PastSnapshotFinderByDate finderByDate, PastSnapshotFinderByPreviousAnalysis finderByPreviousAnalysis,
PastSnapshotFinderByPreviousVersion finderByPreviousVersion) {
this.finderByDays = finderByDays;
this.finderByVersion = finderByVersion;
this.finderByDate = finderByDate;
this.finderByPreviousAnalysis = finderByPreviousAnalysis;
this.finderByPreviousVersion = finderByPreviousVersion;
}

public PastSnapshot find(Snapshot projectSnapshot, @Nullable String rootQualifier, Settings settings, int index) {
String propertyValue = getPropertyValue(rootQualifier, settings, index);
PastSnapshot pastSnapshot = find(projectSnapshot, index, propertyValue);
if (pastSnapshot == null && StringUtils.isNotBlank(propertyValue)) {
LOG.debug("Property " + CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index + " is not valid: " + propertyValue);
}
return pastSnapshot;
}

public PastSnapshot find(Snapshot projectSnapshot, Settings settings, int index) {
return find(projectSnapshot, null, settings, index);
}

static String getPropertyValue(@Nullable String rootQualifier, Settings settings, int index) {
String value = settings.getString(CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index);
// For periods 4 and 5 we're searching for a property prefixed by the qualifier
if (index > 3 && Strings.isNullOrEmpty(value)) {
value = settings.getString(CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index + "." + rootQualifier);
}
return value;
}

public PastSnapshot findPreviousAnalysis(Snapshot projectSnapshot) {
return finderByPreviousAnalysis.findByPreviousAnalysis(projectSnapshot);
}

@Nullable
public PastSnapshot find(Snapshot projectSnapshot, int index, String property) {
if (StringUtils.isBlank(property)) {
return null;
}

PastSnapshot result = findByDays(projectSnapshot, property);
if (result == null) {
result = findByDate(projectSnapshot, property);
if (result == null) {
result = findByPreviousAnalysis(projectSnapshot, property);
if (result == null) {
result = findByPreviousVersion(projectSnapshot, property);
if (result == null) {
result = findByVersion(projectSnapshot, property);
}
}
}
}

if (result != null) {
result.setIndex(index);
}

return result;
}

@Nullable
private PastSnapshot findByPreviousAnalysis(Snapshot projectSnapshot, String property) {
PastSnapshot pastSnapshot = null;
if (StringUtils.equals(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, property)) {
pastSnapshot = finderByPreviousAnalysis.findByPreviousAnalysis(projectSnapshot);
}
return pastSnapshot;
}

@Nullable
private PastSnapshot findByPreviousVersion(Snapshot projectSnapshot, String property) {
PastSnapshot pastSnapshot = null;
if (StringUtils.equals(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, property)) {
pastSnapshot = finderByPreviousVersion.findByPreviousVersion(projectSnapshot);
}
return pastSnapshot;
}

@Nullable
private PastSnapshot findByDate(Snapshot projectSnapshot, String property) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = format.parse(property);
return finderByDate.findByDate(projectSnapshot, date);

} catch (ParseException e) {
return null;
}
}

private PastSnapshot findByVersion(Snapshot projectSnapshot, String property) {
return finderByVersion.findByVersion(projectSnapshot, property);
}

@Nullable
private PastSnapshot findByDays(Snapshot projectSnapshot, String property) {
try {
int days = Integer.parseInt(property);
return finderByDays.findFromDays(projectSnapshot, days);

} catch (NumberFormatException e) {
return null;
}
}

}

+ 0
- 49
sonar-batch/src/main/java/org/sonar/batch/components/Period.java View File

@@ -1,49 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.batch.components;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Date;

/**
* Used by devcockpit
*/
public class Period {

private int index;
private Date date;

public Period(int index, @Nullable Date date) {
this.index = index;
this.date = date;
}

public int getIndex() {
return index;
}

@CheckForNull
public Date getDate() {
return date;
}
}

+ 0
- 91
sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java View File

@@ -1,91 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.batch.RequiresDB;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.deprecated.components.PeriodsDefinition;

import javax.annotation.CheckForNull;

import java.util.List;

import static com.google.common.collect.Lists.newLinkedList;
import static org.sonar.api.utils.DateUtils.longToDate;

@RequiresDB
@BatchSide
public class TimeMachineConfiguration {

private static final Logger LOG = LoggerFactory.getLogger(TimeMachineConfiguration.class);

private final DatabaseSession session;
private final PeriodsDefinition periodsDefinition;

private List<Period> periods;
private List<PastSnapshot> modulePastSnapshots;

public TimeMachineConfiguration(DatabaseSession session, PeriodsDefinition periodsDefinition) {
this.session = session;
this.periodsDefinition = periodsDefinition;
initModulePastSnapshots();
}

private void initModulePastSnapshots() {
periods = newLinkedList();
modulePastSnapshots = newLinkedList();
for (PastSnapshot projectPastSnapshot : periodsDefinition.getRootProjectPastSnapshots()) {
Snapshot snapshot = findSnapshot(projectPastSnapshot.getProjectSnapshot());

PastSnapshot pastSnapshot = projectPastSnapshot.clonePastSnapshot();
modulePastSnapshots.add(pastSnapshot);
// When no snapshot is found, date of the period is null
periods.add(new Period(pastSnapshot.getIndex(), snapshot != null ? longToDate(snapshot.getCreatedAtMs()) : null));
LOG.info(pastSnapshot.toString());
}
}

/**
* Only used to get the real date of the snapshot on the current period.
* The date is used to calculate new_violations measures
*/
@CheckForNull
private Snapshot findSnapshot(Snapshot projectSnapshot) {
String hql = "from " + Snapshot.class.getSimpleName() + " where resourceId=:resourceId and (rootId=:rootSnapshotId or id=:rootSnapshotId)";
List<Snapshot> snapshots = session.createQuery(hql)
.setParameter("resourceId", projectSnapshot.getResourceId())
.setParameter("rootSnapshotId", projectSnapshot.getId())
.setMaxResults(1)
.getResultList();
return snapshots.isEmpty() ? null : snapshots.get(0);
}

public List<Period> periods() {
return periods;
}

public List<PastSnapshot> getProjectPastSnapshots() {
return modulePastSnapshots;
}
}

+ 0
- 23
sonar-batch/src/main/java/org/sonar/batch/components/package-info.java View File

@@ -1,23 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@ParametersAreNonnullByDefault
package org.sonar.batch.components;

import javax.annotation.ParametersAreNonnullByDefault;

+ 0
- 70
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDate.java View File

@@ -1,70 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.annotation.CheckForNull;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.utils.DateUtils;
import org.sonar.batch.components.PastSnapshot;

import static org.sonar.api.utils.DateUtils.dateToLong;

@BatchSide
public class PastSnapshotFinderByDate {

private DatabaseSession session;

public PastSnapshotFinderByDate(DatabaseSession session) {
this.session = session;
}

public PastSnapshot findByDate(Snapshot projectSnapshot, Date date) {
Integer projectId = projectSnapshot != null ? projectSnapshot.getResourceId() : null;
return findByDate(projectId, date);
}

PastSnapshot findByDate(Integer projectId, Date date) {
Snapshot snapshot = null;
if (projectId != null) {
snapshot = findSnapshot(projectId, date);
}
SimpleDateFormat format = new SimpleDateFormat(DateUtils.DATE_FORMAT);
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DATE, date, snapshot).setModeParameter(format.format(date));
}

@CheckForNull
private Snapshot findSnapshot(Integer projectId, Date date) {
String hql = "from " + Snapshot.class.getSimpleName() + " where createdAt>=:date AND resourceId=:resourceId AND status=:status order by createdAt asc";
List<Snapshot> snapshots = session.createQuery(hql)
.setParameter("date", dateToLong(date))
.setParameter("resourceId", projectId)
.setParameter("status", Snapshot.STATUS_PROCESSED)
.setMaxResults(1)
.getResultList();

return snapshots.isEmpty() ? null : snapshots.get(0);
}
}

+ 0
- 77
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDays.java View File

@@ -1,77 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import java.util.Date;
import java.util.List;
import javax.annotation.CheckForNull;
import org.apache.commons.lang.time.DateUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;

@BatchSide
public class PastSnapshotFinderByDays {

private DatabaseSession session;

public PastSnapshotFinderByDays(DatabaseSession session) {
this.session = session;
}

public PastSnapshot findFromDays(Snapshot projectSnapshot, int days) {
Date targetDate = DateUtils.addDays(projectSnapshot.getCreatedAt(), -days);
String hql = "from " + Snapshot.class.getSimpleName() + " where resourceId=:resourceId AND status=:status AND createdAt<:date order by createdAt asc";
List<Snapshot> snapshots = session.createQuery(hql)
.setParameter("date", projectSnapshot.getCreatedAtMs())
.setParameter("resourceId", projectSnapshot.getResourceId())
.setParameter("status", Snapshot.STATUS_PROCESSED)
.getResultList();

Snapshot snapshot = getNearestToTarget(snapshots, targetDate);
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DAYS, targetDate, snapshot).setModeParameter(String.valueOf(days));
}

@CheckForNull
static Snapshot getNearestToTarget(List<Snapshot> snapshots, Date currentDate, int distanceInDays) {
Date targetDate = DateUtils.addDays(currentDate, -distanceInDays);
return getNearestToTarget(snapshots, targetDate);
}

@CheckForNull
static Snapshot getNearestToTarget(List<Snapshot> snapshots, Date targetDate) {
long bestDistance = Long.MAX_VALUE;
Snapshot nearest = null;
for (Snapshot snapshot : snapshots) {
long distance = distance(snapshot.getCreatedAt(), targetDate);
if (distance <= bestDistance) {
bestDistance = distance;
nearest = snapshot;
}
}
return nearest;
}

static long distance(Date d1, Date d2) {
return Math.abs(d1.getTime() - d2.getTime());
}
}

+ 0
- 62
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousAnalysis.java View File

@@ -1,62 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.utils.DateUtils;
import org.sonar.batch.components.PastSnapshot;

import static org.sonar.api.utils.DateUtils.longToDate;

@BatchSide
public class PastSnapshotFinderByPreviousAnalysis {

private DatabaseSession session;

public PastSnapshotFinderByPreviousAnalysis(DatabaseSession session) {
this.session = session;
}

public PastSnapshot findByPreviousAnalysis(Snapshot projectSnapshot) {
String hql = "from " + Snapshot.class.getSimpleName()
+ " where createdAt<:date AND resourceId=:resourceId AND status=:status and last=:last order by createdAt desc";
List<Snapshot> snapshots = session.createQuery(hql)
.setParameter("date", projectSnapshot.getCreatedAtMs())
.setParameter("resourceId", projectSnapshot.getResourceId())
.setParameter("status", Snapshot.STATUS_PROCESSED)
.setParameter("last", true)
.setMaxResults(1)
.getResultList();

if (snapshots.isEmpty()) {
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);
}
Snapshot snapshot = snapshots.get(0);
Date targetDate = longToDate(snapshot.getCreatedAtMs());
SimpleDateFormat format = new SimpleDateFormat(DateUtils.DATE_FORMAT);
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, targetDate, snapshot).setModeParameter(format.format(targetDate));
}
}

+ 0
- 63
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersion.java View File

@@ -1,63 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import org.sonar.api.batch.BatchSide;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.core.event.db.EventMapper;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;

import static org.sonar.api.utils.DateUtils.longToDate;

@BatchSide
public class PastSnapshotFinderByPreviousVersion {

private final DatabaseSession session;
private final MyBatis mybatis;

public PastSnapshotFinderByPreviousVersion(DatabaseSession session, MyBatis mybatis) {
this.session = session;
this.mybatis = mybatis;
}

public PastSnapshot findByPreviousVersion(Snapshot projectSnapshot) {
String currentVersion = projectSnapshot.getVersion();
Integer resourceId = projectSnapshot.getResourceId();
Long snapshotId;
// Commit Hibernate transaction to avoid lock of project table
session.commit();
try (DbSession dbSession = mybatis.openSession(false)) {
snapshotId = dbSession.getMapper(EventMapper.class).findSnapshotIdOfPreviousVersion(resourceId, currentVersion);
}

if (snapshotId == null) {
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
}

Snapshot snapshot = session.getSingleResult(Snapshot.class, "id", snapshotId.intValue());

return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, longToDate(snapshot.getCreatedAtMs()), snapshot).setModeParameter(snapshot.getVersion());
}

}

+ 0
- 61
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByVersion.java View File

@@ -1,61 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import java.util.Date;
import java.util.List;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;

import static org.sonar.api.utils.DateUtils.longToDate;

@BatchSide
public class PastSnapshotFinderByVersion {

private final DatabaseSession session;

public PastSnapshotFinderByVersion(DatabaseSession session) {
this.session = session;
}

public PastSnapshot findByVersion(Snapshot projectSnapshot, String version) {
String hql = "from " + Snapshot.class.getSimpleName() + " where version=:version AND resourceId=:resourceId AND status=:status order by createdAt desc";
List<Snapshot> snapshots = session.createQuery(hql)
.setParameter("version", version)
.setParameter("resourceId", projectSnapshot.getResourceId())
.setParameter("status", Snapshot.STATUS_PROCESSED)
.setMaxResults(1)
.getResultList();

PastSnapshot result;
if (snapshots.isEmpty()) {
result = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION);
} else {
Snapshot snapshot = snapshots.get(0);
Date targetDate = longToDate(snapshot.getCreatedAtMs());
result = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION, targetDate, snapshot).setModeParameter(version);
}
return result;
}

}

+ 0
- 95
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PeriodsDefinition.java View File

@@ -1,95 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.batch.deprecated.components;

import java.util.List;
import javax.persistence.Query;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.config.Settings;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.DefaultProjectTree;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.batch.components.PastSnapshotFinder;

import static com.google.common.collect.Lists.newLinkedList;
import static org.sonar.api.utils.DateUtils.dateToLong;

@BatchSide
public class PeriodsDefinition {

private static final int NUMBER_OF_VARIATION_SNAPSHOTS = 5;

private DatabaseSession session;

private DefaultProjectTree projectTree;
private final Settings settings;

private List<PastSnapshot> projectPastSnapshots;

public PeriodsDefinition(DatabaseSession session, DefaultProjectTree projectTree, Settings settings,
PastSnapshotFinder pastSnapshotFinder) {
this.session = session;
this.projectTree = projectTree;
this.settings = settings;
initPastSnapshots(pastSnapshotFinder, projectTree.getRootProject().getQualifier());
}

private void initPastSnapshots(PastSnapshotFinder pastSnapshotFinder, String rootQualifier) {
Snapshot projectSnapshot = buildProjectSnapshot();
projectPastSnapshots = newLinkedList();
if (projectSnapshot != null) {
for (int index = 1; index <= NUMBER_OF_VARIATION_SNAPSHOTS; index++) {
PastSnapshot pastSnapshot = pastSnapshotFinder.find(projectSnapshot, rootQualifier, settings, index);
// SONAR-4700 Add a past snapshot only if it exists
if (pastSnapshot != null && pastSnapshot.getProjectSnapshot() != null) {
projectPastSnapshots.add(pastSnapshot);
}
}
}
}

private Snapshot buildProjectSnapshot() {
Query query = session
.createNativeQuery("select p.id from projects p where p.kee=:resourceKey and p.enabled=:enabled");
query.setParameter("resourceKey", projectTree.getRootProject().getKey());
query.setParameter("enabled", Boolean.TRUE);

Snapshot snapshot = null;
Number projectId = session.getSingleResult(query, null);
if (projectId != null) {
snapshot = new Snapshot();
snapshot.setResourceId(projectId.intValue());
snapshot.setCreatedAtMs(dateToLong(projectTree.getRootProject().getAnalysisDate()));
snapshot.setBuildDateMs(System.currentTimeMillis());
snapshot.setVersion(projectTree.getRootProject().getAnalysisVersion());
}
return snapshot;
}

/**
* @return past snapshots of root project
*/
public List<PastSnapshot> getRootProjectPastSnapshots() {
return projectPastSnapshots;
}

}

+ 1
- 1
sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java View File

@@ -56,7 +56,7 @@ public class MeasuresPublisher implements ReportPublisherStep {
batchMeasures = Iterables.filter(batchMeasures, new Predicate<Measure>() {
@Override
public boolean apply(Measure input) {
// Reload Metric to have all Hibernate fields populated
// Reload Metric to have all fields populated
input.setMetric(metricFinder.findByKey(input.getMetricKey()));
return shouldPersistMeasure(resource.resource(), input);
}

+ 0
- 2
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java View File

@@ -82,7 +82,6 @@ import org.sonar.batch.sensor.coverage.CoverageExclusions;
import org.sonar.batch.source.HighlightableBuilder;
import org.sonar.batch.source.SymbolizableBuilder;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.timemachine.Periods;

public class ModuleScanContainer extends ComponentContainer {
private static final Logger LOG = LoggerFactory.getLogger(ModuleScanContainer.class);
@@ -113,7 +112,6 @@ public class ModuleScanContainer extends ComponentContainer {

add(
EventBus.class,
Periods.class,
PhaseExecutor.class,
RuleFinderCompatibility.class,
PostJobsExecutor.class,

+ 0
- 12
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java View File

@@ -42,9 +42,7 @@ import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.bootstrap.ExtensionUtils;
import org.sonar.batch.bootstrap.MetricProvider;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.components.PastMeasuresLoader;
import org.sonar.batch.deprecated.components.DefaultResourceCreationLock;
import org.sonar.batch.deprecated.components.PeriodsDefinition;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.BatchComponentCache;
@@ -103,9 +101,6 @@ public class ProjectScanContainer extends ComponentContainer {
add(component);
}
addBatchComponents();
if (analysisMode.isDb()) {
addDataBaseComponents();
}
addBatchExtensions();
Settings settings = getComponentByType(Settings.class);
if (settings != null && settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
@@ -181,9 +176,6 @@ public class ProjectScanContainer extends ComponentContainer {
Languages.class,
DefaultLanguagesRepository.class,

// Differential periods
PeriodsDefinition.class,

// Measures
MeasureCache.class,

@@ -206,10 +198,6 @@ public class ProjectScanContainer extends ComponentContainer {
ScanTaskObservers.class);
}

private void addDataBaseComponents() {
add(PastMeasuresLoader.class);
}

private void addBatchExtensions() {
getComponentByType(ExtensionInstaller.class).install(this, new BatchExtensionFilter());
}

+ 0
- 11
sonar-batch/src/main/resources/org/sonar/batch/bootstrapper/logback.xml View File

@@ -18,14 +18,6 @@
</encoder>
</appender>

<logger name="org.hibernate.cache.ReadWriteCache">
<!-- removing "An item was expired by the cache while it was locked (increase your cache timeout)" msg -->
<level value="ERROR"/>
</logger>
<logger name="org.hibernate">
<level value="WARN"/>
</logger>

<!-- BeanUtils generate to many DEBUG logs when sonar.verbose is set -->
<logger name="org.apache.commons.beanutils.converters">
<level value="WARN"/>
@@ -33,9 +25,6 @@

<!-- sonar.showSql -->
<!-- see also org.sonar.core.persistence.MyBatis#configureLogback() -->
<logger name="org.hibernate.SQL">
<level value="${SQL_LOGGER_LEVEL:-ERROR}"/>
</logger>
<logger name="org.mybatis">
<level value="${SQL_LOGGER_LEVEL:-WARN}"/>
</logger>

+ 0
- 11
sonar-batch/src/main/resources/org/sonar/batch/logback.xml View File

@@ -14,14 +14,6 @@
</encoder>
</appender>

<logger name="org.hibernate.cache.ReadWriteCache">
<!-- removing "An item was expired by the cache while it was locked (increase your cache timeout)" msg -->
<level value="ERROR"/>
</logger>
<logger name="org.hibernate">
<level value="WARN"/>
</logger>

<!-- BeanUtils generate to many DEBUG logs when sonar.verbose is set -->
<logger name="org.apache.commons.beanutils.converters">
<level value="WARN"/>
@@ -29,9 +21,6 @@

<!-- sonar.showSql -->
<!-- see also org.sonar.core.persistence.MyBatis#configureLogback() -->
<logger name="org.hibernate.SQL">
<level value="ERROR"/>
</logger>
<logger name="org.apache.ibatis">
<level value="WARN"/>
</logger>

+ 0
- 36
sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseSessionFactoryTest.java View File

@@ -1,36 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import org.junit.Test;
import org.sonar.api.database.DatabaseSession;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class BatchDatabaseSessionFactoryTest {
@Test
public void getSession() {
DatabaseSession session = mock(DatabaseSession.class);
BatchDatabaseSessionFactory factory = new BatchDatabaseSessionFactory(session);

assertThat(factory.getSession()).isSameAs(session);
}
}

+ 0
- 42
sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseTest.java View File

@@ -1,42 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import org.junit.Test;
import org.sonar.api.config.Settings;

import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class BatchDatabaseTest {
@Test
public void should_init_at_least_two_connections() {
BatchDatabase db = new BatchDatabase(new Settings(), mock(JdbcDriverHolder.class));
Properties props = new Properties();

db.doCompleteProperties(props);

assertThat(Integer.parseInt(props.getProperty("sonar.jdbc.initialSize"))).isGreaterThanOrEqualTo(2);
assertThat(Integer.parseInt(props.getProperty("sonar.jdbc.maxActive"))).isGreaterThanOrEqualTo(2);
}

}

+ 0
- 136
sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseCompatibilityTest.java View File

@@ -1,136 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
import org.sonar.api.database.DatabaseProperties;
import org.sonar.api.utils.MessageException;
import org.sonar.core.persistence.DatabaseVersion;
import org.sonar.core.properties.PropertiesDao;
import org.sonar.core.properties.PropertyDto;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class DatabaseCompatibilityTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

DatabaseVersion databaseVersion;
ServerClient server;
Settings settings;
PropertiesDao propertiesDao;

private DefaultAnalysisMode mode;

@Before
public void init() {
server = mock(ServerClient.class);
when(server.getURL()).thenReturn("http://localhost:9000");
when(server.request("/api/server")).thenReturn("{\"id\":\"123456\",\"version\":\"3.1\",\"status\":\"UP\"}");

settings = new Settings();
settings.setProperty(DatabaseProperties.PROP_URL, "jdbc:postgresql://localhost/foo");
settings.setProperty(DatabaseProperties.PROP_USER, "bar");

propertiesDao = mock(PropertiesDao.class);
when(propertiesDao.selectGlobalProperty(CoreProperties.SERVER_ID)).thenReturn(new PropertyDto().setValue("123456"));

mode = mock(DefaultAnalysisMode.class);

databaseVersion = mock(DatabaseVersion.class);
}

@Test
public void shouldFailIfRequiresDowngrade() {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_DOWNGRADE);

thrown.expect(MessageException.class);
thrown.expectMessage("Database relates to a more recent version of SonarQube. Please check your settings (JDBC settings, version of Maven plugin)");

new DatabaseCompatibility(databaseVersion, server, settings, propertiesDao, mode).start();
}

@Test
public void shouldFailIfRequiresUpgrade() {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);

thrown.expect(MessageException.class);
thrown.expectMessage("Database must be upgraded.");

new DatabaseCompatibility(databaseVersion, server, settings, propertiesDao, mode).start();
}

@Test
public void shouldFailIfNotSameServerId() {
when(propertiesDao.selectGlobalProperty(CoreProperties.SERVER_ID)).thenReturn(new PropertyDto().setValue("11111111"));

thrown.expect(MessageException.class);
thrown.expectMessage("The current batch process and the configured remote server do not share the same DB configuration.");
thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (bar / *****)");
thrown.expectMessage("- Server side: check the configuration at http://localhost:9000/system");

new DatabaseCompatibility(databaseVersion, server, settings, propertiesDao, mode).start();
}

@Test
public void shouldUseDefaultUserNameWhenFaillingIfNotSameServerIdAndNoUserNameFound() {
when(propertiesDao.selectGlobalProperty(CoreProperties.SERVER_ID)).thenReturn(new PropertyDto().setValue("11111111"));

settings.removeProperty(DatabaseProperties.PROP_USER);

thrown.expect(MessageException.class);
thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (sonar / *****)");

new DatabaseCompatibility(databaseVersion, server, settings, propertiesDao, mode).start();
}

@Test
public void shouldFailIfCantGetServerId() {
when(server.request("/api/server")).thenThrow(new IllegalStateException());

thrown.expect(IllegalStateException.class);

new DatabaseCompatibility(mock(DatabaseVersion.class), server, settings, propertiesDao, mode).start();
}

@Test
public void shouldDoNothingIfUpToDate() {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE);
new DatabaseCompatibility(databaseVersion, server, settings, propertiesDao, mode).start();
// no error
}

@Test
public void should_not_verify_compatibility_if_preview() {
settings.setProperty(CoreProperties.SERVER_ID, "11111111");
when(mode.isPreview()).thenReturn(true);

new DatabaseCompatibility(databaseVersion, server, settings, propertiesDao, mode).start();

// no failure
}
}

+ 1
- 16
sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionUtilsTest.java View File

@@ -22,10 +22,9 @@ package org.sonar.batch.bootstrap;
import org.junit.Test;
import org.sonar.api.BatchComponent;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.server.ServerSide;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.RequiresDB;
import org.sonar.api.batch.SupportedEnvironment;
import org.sonar.api.server.ServerSide;
import org.sonar.batch.bootstrapper.EnvironmentInformation;

import static org.assertj.core.api.Assertions.assertThat;
@@ -81,14 +80,6 @@ public class ExtensionUtilsTest {
assertThat(ExtensionUtils.isMavenExtensionOnly(new BuildToolService())).isFalse();
}

@Test
public void shouldRequiresDB() {
assertThat(ExtensionUtils.requiresDB(BatchService.class)).isFalse();
assertThat(ExtensionUtils.requiresDB(new BatchService())).isFalse();
assertThat(ExtensionUtils.requiresDB(PersistentService.class)).isTrue();
assertThat(ExtensionUtils.requiresDB(new PersistentService())).isTrue();
}

@BatchSide
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
public static class BatchService {
@@ -126,10 +117,4 @@ public class ExtensionUtilsTest {
public static class BuildToolService {

}

@BatchSide
@RequiresDB
public static class PersistentService {

}
}

+ 0
- 121
sonar-batch/src/test/java/org/sonar/batch/bootstrap/JdbcDriverHolderTest.java View File

@@ -1,121 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrap;

import com.google.common.io.Resources;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.home.cache.FileCache;

import java.io.File;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

public class JdbcDriverHolderTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Rule
public ExpectedException thrown = ExpectedException.none();

ClassLoader initialThreadClassloader;
private DefaultAnalysisMode mode;

@Before
public void before() {
initialThreadClassloader = Thread.currentThread().getContextClassLoader();
mode = mock(DefaultAnalysisMode.class);
}

@After
public void after() {
Thread.currentThread().setContextClassLoader(initialThreadClassloader);
}

@Test
public void extend_classloader_with_jdbc_driver() {
FileCache cache = mock(FileCache.class);

File fakeDriver = new File(Resources.getResource(JdbcDriverHolderTest.class, "JdbcDriverHolderTest/jdbc-driver.jar").getFile());
when(cache.get(eq("ojdbc14.jar"), eq("fakemd5"), any(FileCache.Downloader.class))).thenReturn(fakeDriver);

/* jdbc-driver.jar has just one file /foo/foo.txt */
assertThat(Thread.currentThread().getContextClassLoader().getResource("foo/foo.txt")).isNull();

ServerClient server = mock(ServerClient.class);
when(server.request("/deploy/jdbc-driver.txt")).thenReturn("ojdbc14.jar|fakemd5");
when(server.request("/deploy/ojdbc14.jar")).thenReturn("fakecontent");

JdbcDriverHolder holder = new JdbcDriverHolder(cache, mode, server);
holder.start();

assertThat(holder.getClassLoader().getResource("foo/foo.txt")).isNotNull();
assertThat(Thread.currentThread().getContextClassLoader()).isSameAs(holder.getClassLoader());
assertThat(holder.getClassLoader().getParent()).isSameAs(getClass().getClassLoader());

holder.stop();
assertThat(Thread.currentThread().getContextClassLoader()).isSameAs(getClass().getClassLoader());
assertThat(holder.getClassLoader()).isNull();
}

@Test
public void do_nothing_when_jdbc_driver_file_is_empty() {
FileCache cache = mock(FileCache.class);

ServerClient server = mock(ServerClient.class);
when(server.request("/deploy/jdbc-driver.txt")).thenReturn("");

JdbcDriverHolder holder = new JdbcDriverHolder(cache, mode, server);
holder.start();

verify(server, never()).download(anyString(), any(File.class));
verifyZeroInteractions(cache);
assertThat(holder.getClassLoader()).isNull();
}

@Test
public void be_disabled_if_preview() {
FileCache cache = mock(FileCache.class);
when(mode.isPreview()).thenReturn(true);
ServerClient server = mock(ServerClient.class);
JdbcDriverHolder holder = new JdbcDriverHolder(cache, mode, server);

holder.start();

assertThat(holder.getClassLoader()).isNull();
verifyZeroInteractions(server);

// no error during stop
holder.stop();
}
}

+ 0
- 108
sonar-batch/src/test/java/org/sonar/batch/components/PastMeasuresLoaderTest.java View File

@@ -1,108 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import org.junit.Test;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.Metric;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import java.util.Arrays;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;

public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase {

private static final int PROJECT_SNAPSHOT_ID = 1000;
private static final String PROJECT_KEY = "project";
private static final String FILE_KEY = "project:org.foo.Bar";

@Test
public void shouldGetPastResourceMeasures() {
setupData("shared");

List<Metric> metrics = selectMetrics();
Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);

PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics);
List<Object[]> measures = loader.getPastMeasures(FILE_KEY, projectSnapshot);
assertThat(measures.size(), is(2));

Object[] pastMeasure = measures.get(0);
assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(1));
assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getPersonId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getValue(pastMeasure), is(5.0));

pastMeasure = measures.get(1);
assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(2));
assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getPersonId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getValue(pastMeasure), is(60.0));
}

@Test
public void shouldGetPastProjectMeasures() {
setupData("shared");

List<Metric> metrics = selectMetrics();
Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);

PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics);
List<Object[]> measures = loader.getPastMeasures(PROJECT_KEY, projectSnapshot);
assertThat(measures.size(), is(2));

Object[] pastMeasure = measures.get(0);
assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(1));
assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getPersonId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getValue(pastMeasure), is(60.0));

pastMeasure = measures.get(1);
assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(2));
assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getPersonId(pastMeasure), nullValue());
assertThat(PastMeasuresLoader.getValue(pastMeasure), is(80.0));
}

@Test
public void shouldKeepOnlyNumericalMetrics() {
Metric ncloc = new Metric("ncloc", Metric.ValueType.INT);
ncloc.setId(1);
Metric complexity = new Metric("complexity", Metric.ValueType.INT);
complexity.setId(2);
Metric data = new Metric("data", Metric.ValueType.DATA);
data.setId(3);
List<Metric> metrics = Arrays.asList(ncloc, complexity, data);

PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics);

assertThat(loader.getMetrics().size(), is(2));
assertThat(loader.getMetrics(), hasItems(ncloc, complexity));
}

private List<Metric> selectMetrics() {
return getSession().getResults(Metric.class);
}
}

+ 0
- 231
sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotFinderTest.java View File

@@ -1,231 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.utils.DateUtils;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByDate;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByDays;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousAnalysis;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousVersion;
import org.sonar.batch.deprecated.components.PastSnapshotFinderByVersion;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import static junit.framework.Assert.assertNull;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class PastSnapshotFinderTest {

@Mock
private PastSnapshotFinderByDays finderByDays;
@Mock
private PastSnapshotFinderByDate finderByDate;
@Mock
private PastSnapshotFinderByVersion finderByVersion;
@Mock
private PastSnapshotFinderByPreviousAnalysis finderByPreviousAnalysis;
@Mock
private PastSnapshotFinderByPreviousVersion finderByPreviousVersion;

private PastSnapshotFinder finder;

@Before
public void initFinders() {
MockitoAnnotations.initMocks(this);

finder = new PastSnapshotFinder(finderByDays, finderByVersion, finderByDate, finderByPreviousAnalysis, finderByPreviousVersion);
}

@Test
public void should_find() {
Settings settings = new Settings().setProperty("sonar.timemachine.period5", "1.2");

when(finderByVersion.findByVersion(null, "1.2")).thenReturn(new PastSnapshot("version", new Date(), new Snapshot()));

PastSnapshot variationSnapshot = finder.find(null, null, settings, 5);

verify(finderByVersion).findByVersion(null, "1.2");
assertThat(variationSnapshot.getIndex(), is(5));
assertThat(variationSnapshot.getMode(), is("version"));
assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
}

@Test
public void should_find_with_qualifier_suffix() {
Settings settings = new Settings().setProperty("sonar.timemachine.period5.TRK", "1.2");

when(finderByVersion.findByVersion(null, "1.2")).thenReturn(new PastSnapshot("version", new Date(), new Snapshot()));

PastSnapshot variationSnapshot = finder.find(null, "TRK", settings, 5);

verify(finderByVersion).findByVersion(null, "1.2");
assertThat(variationSnapshot.getIndex(), is(5));
assertThat(variationSnapshot.getMode(), is("version"));
assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
}

@Test
public void should_find_by_number_of_days() {
when(finderByDays.findFromDays(null, 30)).thenReturn(new PastSnapshot("days", null).setModeParameter("30"));

PastSnapshot variationSnapshot = finder.find(null, 1, "30");

verify(finderByDays).findFromDays(null, 30);
assertNotNull(variationSnapshot);
assertThat(variationSnapshot.getIndex(), is(1));
assertThat(variationSnapshot.getMode(), is("days"));
assertThat(variationSnapshot.getModeParameter(), is("30"));
}

@Test
public void should_not_find_by_number_of_days() {
PastSnapshot variationSnapshot = finder.find(null, 1, "30");

verify(finderByDays).findFromDays(null, 30);
assertNull(variationSnapshot);
}

@Test
public void should_find_by_date() throws ParseException {
final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
final Date date = format.parse("2010-05-18");
when(finderByDate.findByDate((Snapshot) null, date)).thenReturn(new PastSnapshot("date", date, new Snapshot()));

PastSnapshot variationSnapshot = finder.find(null, 2, "2010-05-18");

verify(finderByDate).findByDate(any(Snapshot.class), argThat(new ArgumentMatcher<Date>() {
@Override
public boolean matches(Object o) {
return o.equals(date);
}
}));
assertThat(variationSnapshot.getIndex(), is(2));
assertThat(variationSnapshot.getMode(), is("date"));
assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
}

@Test
public void should_not_find_by_date() {
when(finderByDate.findByDate(any(Snapshot.class), any(Date.class))).thenReturn(null);

PastSnapshot variationSnapshot = finder.find(null, 2, "2010-05-18");

verify(finderByDate).findByDate(any(Snapshot.class), any(Date.class));
assertNull(variationSnapshot);
}

@Test
public void should_find_by_previous_analysis() {
final Date date = DateUtils.parseDate("2010-05-18");
Snapshot snapshot = new Snapshot();
snapshot.setCreatedAtMs(date.getTime());
when(finderByPreviousAnalysis.findByPreviousAnalysis(null)).thenReturn(new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, date, snapshot));

PastSnapshot variationSnapshot = finder.find(null, 2, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);

verify(finderByPreviousAnalysis).findByPreviousAnalysis(null);
assertThat(variationSnapshot.getIndex(), is(2));
assertThat(variationSnapshot.getMode(), is(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS));
assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
}

@Test
public void should_not_find_previous_analysis() {
when(finderByPreviousAnalysis.findByPreviousAnalysis(null)).thenReturn(null);

PastSnapshot variationSnapshot = finder.find(null, 2, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);

verify(finderByPreviousAnalysis).findByPreviousAnalysis(null);

assertNull(variationSnapshot);
}

@Test
public void should_find_by_previous_version() throws ParseException {
final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
final Date date = format.parse("2010-05-18");
Snapshot snapshot = new Snapshot();
snapshot.setCreatedAtMs(date.getTime());
when(finderByPreviousVersion.findByPreviousVersion(null)).thenReturn(new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, date, snapshot));

PastSnapshot variationSnapshot = finder.find(null, 2, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);

verify(finderByPreviousVersion).findByPreviousVersion(null);
assertThat(variationSnapshot.getIndex(), is(2));
assertThat(variationSnapshot.getMode(), is(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION));
assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
}

@Test
public void should_find_by_version() {
when(finderByVersion.findByVersion(null, "1.2")).thenReturn(new PastSnapshot("version", new Date(), new Snapshot()));

PastSnapshot variationSnapshot = finder.find(null, 2, "1.2");

verify(finderByVersion).findByVersion(null, "1.2");
assertThat(variationSnapshot.getIndex(), is(2));
assertThat(variationSnapshot.getMode(), is("version"));
assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
}

@Test
public void should_not_find_version() {
when(finderByVersion.findByVersion(null, "1.2")).thenReturn(null);

PastSnapshot variationSnapshot = finder.find(null, 2, "1.2");

verify(finderByVersion).findByVersion(null, "1.2");
assertNull(variationSnapshot);
}

@Test
public void should_not_fail_if_unknown_format() {
// should not be called
when(finderByPreviousAnalysis.findByPreviousAnalysis(null)).thenReturn(new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new Date(), new Snapshot()));

assertNull(finder.find(null, 2, "foooo"));
}

@Test
public void should_get_property_value() {
Settings settings = new Settings().setProperty("sonar.timemachine.period1", "5");

assertThat(PastSnapshotFinder.getPropertyValue("FIL", settings, 1), is("5"));
assertThat(PastSnapshotFinder.getPropertyValue("FIL", settings, 999), nullValue());
}
}

+ 0
- 105
sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotTest.java View File

@@ -1,105 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import org.junit.Test;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Qualifiers;

import java.util.Date;

import static org.assertj.core.api.Assertions.assertThat;

public class PastSnapshotTest {

@Test
public void test_some_setters_and_getters() {
Snapshot snapshot = new Snapshot().setQualifier(Qualifiers.FILE).setCreatedAtMs(System.currentTimeMillis());
snapshot.setId(10);
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION, new Date(),
snapshot)
.setModeParameter("2.3")
.setIndex(1);

assertThat(pastSnapshot.getModeParameter()).isEqualTo("2.3");
assertThat(pastSnapshot.getIndex()).isEqualTo(1);
assertThat(pastSnapshot.getQualifier()).isEqualTo(Qualifiers.FILE);
assertThat(pastSnapshot.getDate()).isNotNull();
assertThat(pastSnapshot.getProjectSnapshotId()).isEqualTo(10);
}

@Test
public void test_some_setters_and_getters_with_empty_snapshot() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION);

assertThat(pastSnapshot.getQualifier()).isNull();
assertThat(pastSnapshot.getDate()).isNull();
assertThat(pastSnapshot.getProjectSnapshotId()).isNull();
}

@Test
public void testToStringForVersion() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION, new Date(), new Snapshot().setCreatedAtMs(System.currentTimeMillis())).setModeParameter("2.3");
assertThat(pastSnapshot.toString()).startsWith("Compare to version 2.3");
}

@Test
public void testToStringForVersionWithoutDate() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION).setModeParameter("2.3");
assertThat(pastSnapshot.toString()).isEqualTo("Compare to version 2.3");
}

@Test
public void testToStringForNumberOfDays() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DAYS, new Date()).setModeParameter("30");
assertThat(pastSnapshot.toString()).startsWith("Compare over 30 days (");
}

@Test
public void testToStringForNumberOfDaysWithSnapshot() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DAYS, new Date(), new Snapshot().setCreatedAtMs(System.currentTimeMillis())).setModeParameter("30");
assertThat(pastSnapshot.toString()).startsWith("Compare over 30 days (");
}

@Test
public void testToStringForDate() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DATE, new Date());
assertThat(pastSnapshot.toString()).startsWith("Compare to date ");
}

@Test
public void testToStringForDateWithSnapshot() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DATE, new Date(), new Snapshot().setCreatedAtMs(System.currentTimeMillis()));
assertThat(pastSnapshot.toString()).startsWith("Compare to date ");
}

@Test
public void testToStringForPreviousAnalysis() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new Date(), new Snapshot().setCreatedAtMs(System.currentTimeMillis()));
assertThat(pastSnapshot.toString()).startsWith("Compare to previous analysis ");
}

@Test
public void testToStringForPreviousAnalysisWithoutDate() {
PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);
assertThat(pastSnapshot.toString()).isEqualTo("Compare to previous analysis");
}
}

+ 0
- 111
sonar-batch/src/test/java/org/sonar/batch/components/TimeMachineConfigurationTest.java View File

@@ -1,111 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.components;

import org.junit.Before;
import org.junit.Test;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.deprecated.components.PeriodsDefinition;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import java.util.Date;

import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class TimeMachineConfigurationTest extends AbstractDbUnitTestCase {

private PeriodsDefinition periodsDefinition;

@Before
public void before() {
setupData("shared");
periodsDefinition = mock(PeriodsDefinition.class);
}

@Test
public void get_project_past_snapshot() {
Snapshot projectSnapshot = new Snapshot();
projectSnapshot.setId(1010);
projectSnapshot.setResourceId(1);
PastSnapshot projectPastSnapshot = new PastSnapshot("mode", new Date(), projectSnapshot);

when(periodsDefinition.getRootProjectPastSnapshots()).thenReturn(newArrayList(projectPastSnapshot));

TimeMachineConfiguration timeMachineConfiguration = new TimeMachineConfiguration(getSession(), periodsDefinition);
assertThat(timeMachineConfiguration.periods()).hasSize(1);
assertThat(timeMachineConfiguration.periods().get(0).getDate()).isNotNull();
assertThat(timeMachineConfiguration.getProjectPastSnapshots()).hasSize(1);
assertThat(timeMachineConfiguration.getProjectPastSnapshots().get(0).getProjectSnapshot().getId()).isEqualTo(1010);
}

@Test
public void get_module_past_snapshot() {
Snapshot projectSnapshot = new Snapshot();
projectSnapshot.setId(1010);
projectSnapshot.setResourceId(2);
PastSnapshot projectPastSnapshot = new PastSnapshot("mode", new Date(), projectSnapshot);

when(periodsDefinition.getRootProjectPastSnapshots()).thenReturn(newArrayList(projectPastSnapshot));

TimeMachineConfiguration timeMachineConfiguration = new TimeMachineConfiguration(getSession(), periodsDefinition);
assertThat(timeMachineConfiguration.periods()).hasSize(1);
assertThat(timeMachineConfiguration.periods().get(0).getDate()).isNotNull();
assertThat(timeMachineConfiguration.getProjectPastSnapshots()).hasSize(1);
assertThat(timeMachineConfiguration.getProjectPastSnapshots().get(0).getProjectSnapshot().getId()).isEqualTo(1010);
}

@Test
public void complete_past_snapshot_from_project_past_snapshot() {
Snapshot projectSnapshot = new Snapshot();
projectSnapshot.setId(1010);

PastSnapshot projectPastSnapshot = new PastSnapshot("mode", new Date(), projectSnapshot);
projectPastSnapshot.setIndex(1);
projectPastSnapshot.setMode("mode");
projectPastSnapshot.setModeParameter("modeParam");

when(periodsDefinition.getRootProjectPastSnapshots()).thenReturn(newArrayList(projectPastSnapshot));

TimeMachineConfiguration timeMachineConfiguration = new TimeMachineConfiguration(getSession(), periodsDefinition);
assertThat(timeMachineConfiguration.getProjectPastSnapshots()).hasSize(1);
assertThat(timeMachineConfiguration.getProjectPastSnapshots().get(0).getProjectSnapshot().getId()).isEqualTo(1010);
assertThat(timeMachineConfiguration.getProjectPastSnapshots().get(0).getIndex()).isEqualTo(1);
assertThat(timeMachineConfiguration.getProjectPastSnapshots().get(0).getMode()).isEqualTo("mode");
assertThat(timeMachineConfiguration.getProjectPastSnapshots().get(0).getModeParameter()).isEqualTo("modeParam");
}

@Test
public void get_no_date_on_new_project() {
Snapshot projectSnapshot = new Snapshot();
projectSnapshot.setId(1010);

PastSnapshot projectPastSnapshot = new PastSnapshot("mode", new Date(), projectSnapshot);

when(periodsDefinition.getRootProjectPastSnapshots()).thenReturn(newArrayList(projectPastSnapshot));

TimeMachineConfiguration timeMachineConfiguration = new TimeMachineConfiguration(getSession(), periodsDefinition);
assertThat(timeMachineConfiguration.periods()).hasSize(1);
assertThat(timeMachineConfiguration.periods().get(0).getDate()).isNull();
}

}

+ 0
- 62
sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDateTest.java View File

@@ -1,62 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import org.junit.Test;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

public class PastSnapshotFinderByDateTest extends AbstractDbUnitTestCase {
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

@Test
public void shouldFindDate() throws ParseException {
setupData("shared");

Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
PastSnapshotFinderByDate finder = new PastSnapshotFinderByDate(getSession());

Date date = DATE_FORMAT.parse("2008-11-22");

PastSnapshot pastSnapshot = finder.findByDate(projectSnapshot, date);
assertThat(pastSnapshot.getProjectSnapshotId(), is(1006));
}

@Test
public void shouldFindNearestLaterDate() throws ParseException {
setupData("shared");

Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
PastSnapshotFinderByDate finder = new PastSnapshotFinderByDate(getSession());

Date date = DATE_FORMAT.parse("2008-11-24");
PastSnapshot pastSnapshot = finder.findByDate(projectSnapshot, date);
assertThat(pastSnapshot.getProjectSnapshotId(), is(1009));
}
}

+ 0
- 113
sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByDaysTest.java View File

@@ -1,113 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import org.hamcrest.core.IsNull;
import org.junit.Test;
import org.sonar.api.database.model.Snapshot;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;

public class PastSnapshotFinderByDaysTest extends AbstractDbUnitTestCase {

private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

@Test
public void shouldGetNextSnapshot() {
setupData("shared");

Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1009); // 2008-11-16
PastSnapshotFinderByDays finder = new PastSnapshotFinderByDays(getSession());

assertThat(finder.findFromDays(projectSnapshot, 50).getProjectSnapshotId(), is(1000));
}

@Test
public void shouldIgnoreUnprocessedSnapshots() {
setupData("shared");

Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1009); // 2008-11-16
PastSnapshotFinderByDays finder = new PastSnapshotFinderByDays(getSession());

assertThat(finder.findFromDays(projectSnapshot, 7).getProjectSnapshotId(), is(1006));
}

@Test
public void shouldNotFindSelf() {
setupData("shouldNotFindSelf");

Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1009); // 2008-11-16
PastSnapshotFinderByDays finder = new PastSnapshotFinderByDays(getSession());

assertThat(finder.findFromDays(projectSnapshot, 1).getProjectSnapshot(), nullValue());
}

@Test
public void shouldLocateNearestSnapshotBefore() throws ParseException {
Date current = dateFormat.parse("2010-10-20");
// distance: 15 => target is 2010-10-05

List<Snapshot> snapshots = Arrays.asList(
newSnapshot(1, "2010-09-30"),
newSnapshot(2, "2010-10-03"),// -2 days
newSnapshot(3, "2010-10-08"),// +3 days
newSnapshot(4, "2010-10-12") // + 7 days
);
assertThat(PastSnapshotFinderByDays.getNearestToTarget(snapshots, current, 15).getId(), is(2));
}

@Test
public void shouldLocateNearestSnapshotAfter() throws ParseException {
Date current = dateFormat.parse("2010-10-20");
// distance: 15 => target is 2010-10-05

List<Snapshot> snapshots = Arrays.asList(
newSnapshot(1, "2010-09-30"),
newSnapshot(2, "2010-10-01"),// -4 days
newSnapshot(3, "2010-10-08"),// +3 days
newSnapshot(4, "2010-10-12") // + 7 days
);
assertThat(PastSnapshotFinderByDays.getNearestToTarget(snapshots, current, 15).getId(), is(3));
}

@Test
public void shouldReturnNullIfNoSnapshots() throws ParseException {
Date current = dateFormat.parse("2010-10-20");
List<Snapshot> snapshots = Collections.emptyList();
assertThat(PastSnapshotFinderByDays.getNearestToTarget(snapshots, current, 15), IsNull.nullValue());
}

private Snapshot newSnapshot(int id, String date) throws ParseException {
Snapshot snapshot = new Snapshot();
snapshot.setId(id);
snapshot.setCreatedAtMs(dateFormat.parse(date).getTime());
return snapshot;
}
}

+ 0
- 56
sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousAnalysisTest.java View File

@@ -1,56 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import org.junit.Test;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;

public class PastSnapshotFinderByPreviousAnalysisTest extends AbstractDbUnitTestCase {

@Test
public void shouldFindPreviousAnalysis() {
setupData("shouldFindPreviousAnalysis");

Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
PastSnapshotFinderByPreviousAnalysis finder = new PastSnapshotFinderByPreviousAnalysis(getSession());

PastSnapshot pastSnapshot = finder.findByPreviousAnalysis(projectSnapshot);
assertThat(pastSnapshot.getProjectSnapshotId(), is(1009));
}

@Test
public void shouldReturnPastSnapshotEvenWhenNoPreviousAnalysis() {
setupData("shouldNotFindPreviousAnalysis");

Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
PastSnapshotFinderByPreviousAnalysis finder = new PastSnapshotFinderByPreviousAnalysis(getSession());

PastSnapshot pastSnapshot = finder.findByPreviousAnalysis(projectSnapshot);
assertThat(pastSnapshot.isRelatedToSnapshot(), is(false));
assertThat(pastSnapshot.getProjectSnapshot(), nullValue());
assertThat(pastSnapshot.getDate(), nullValue());
}
}

+ 0
- 73
sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest.java View File

@@ -1,73 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import org.junit.Before;
import org.junit.Test;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import static org.assertj.core.api.Assertions.assertThat;

public class PastSnapshotFinderByPreviousVersionTest extends AbstractDbUnitTestCase {

private PastSnapshotFinderByPreviousVersion finder;

@Before
public void before() {
finder = new PastSnapshotFinderByPreviousVersion(getSession(), getMyBatis());
}

@Test
public void shouldFindByPreviousVersion() {
setupData("with-previous-version");

Snapshot currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1003);
PastSnapshot foundSnapshot = finder.findByPreviousVersion(currentProjectSnapshot);
assertThat(foundSnapshot.getProjectSnapshotId()).isEqualTo(1001);
assertThat(foundSnapshot.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
assertThat(foundSnapshot.getModeParameter()).isEqualTo("1.1");
}

@Test
public void shouldFindByPreviousVersionWhenPreviousVersionDeleted() {
setupData("with-previous-version-deleted");

Snapshot currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1003);
PastSnapshot foundSnapshot = finder.findByPreviousVersion(currentProjectSnapshot);
assertThat(foundSnapshot.getProjectSnapshotId()).isEqualTo(1000);
assertThat(foundSnapshot.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
assertThat(foundSnapshot.getModeParameter()).isEqualTo("1.0");
}

@Test
public void testWithNoPreviousVersion() {
setupData("no-previous-version");

Snapshot currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1003);
PastSnapshot foundSnapshot = finder.findByPreviousVersion(currentProjectSnapshot);
assertThat(foundSnapshot.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
assertThat(foundSnapshot.getProjectSnapshot()).isNull();
assertThat(foundSnapshot.getModeParameter()).isNull();
}

}

+ 0
- 57
sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByVersionTest.java View File

@@ -1,57 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.deprecated.components;

import org.junit.Test;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import static org.assertj.core.api.Assertions.assertThat;

public class PastSnapshotFinderByVersionTest extends AbstractDbUnitTestCase {

@Test
public void shouldFindByVersion() {
setupData("shared");

Snapshot currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
PastSnapshotFinderByVersion finder = new PastSnapshotFinderByVersion(getSession());

PastSnapshot foundSnapshot = finder.findByVersion(currentProjectSnapshot, "1.1");
assertThat(foundSnapshot.getProjectSnapshotId()).isEqualTo(1009);
assertThat(foundSnapshot.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_VERSION);
}

@Test
public void testIfNoVersionFound() {
setupData("shared");

Snapshot currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
PastSnapshotFinderByVersion finder = new PastSnapshotFinderByVersion(getSession());

PastSnapshot foundSnapshot = finder.findByVersion(currentProjectSnapshot, "2.1");
assertThat(foundSnapshot.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_VERSION);
assertThat(foundSnapshot.getProjectSnapshot()).isNull();
assertThat(foundSnapshot.getModeParameter()).isNull();
}

}

+ 0
- 76
sonar-batch/src/test/java/org/sonar/batch/deprecated/components/PeriodsDefinitionTest.java View File

@@ -1,76 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.batch.deprecated.components;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.sonar.api.config.Settings;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
import org.sonar.batch.DefaultProjectTree;
import org.sonar.batch.components.PastSnapshotFinder;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

public class PeriodsDefinitionTest extends AbstractDbUnitTestCase {

private Settings settings;
private PastSnapshotFinder pastSnapshotFinder;

@Before
public void before() {
setupData("shared");
settings = new Settings();
pastSnapshotFinder = mock(PastSnapshotFinder.class);
}

@Test
public void should_init_past_snapshots() {
DefaultProjectTree projectTree = mock(DefaultProjectTree.class);
when(projectTree.getRootProject()).thenReturn(new Project("my:project"));
new PeriodsDefinition(getSession(), projectTree, settings, pastSnapshotFinder);

verify(pastSnapshotFinder).find(argThat(new ArgumentMatcher<Snapshot>() {
@Override
public boolean matches(Object o) {
return ((Snapshot) o).getResourceId() == 1 /* see database in shared.xml */;
}
}), anyString(), eq(settings), eq(1));
}

@Test
public void should_not_init_past_snapshots_if_first_analysis() {
DefaultProjectTree projectTree = mock(DefaultProjectTree.class);
when(projectTree.getRootProject()).thenReturn(new Project("new:project"));

new PeriodsDefinition(getSession(), projectTree, settings, pastSnapshotFinder);

verifyZeroInteractions(pastSnapshotFinder);
}
}

+ 10
- 11
sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java View File

@@ -26,7 +26,6 @@ import org.junit.rules.TemporaryFolder;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Directory;
import org.sonar.api.resources.Java;
import org.sonar.api.resources.Project;
@@ -56,33 +55,33 @@ public class ComponentsPublisherTest {
Project root = new Project("foo").setName("Root project").setDescription("Root description")
.setAnalysisDate(DateUtils.parseDate(("2012-12-12")));
root.setId(1).setUuid("PROJECT_UUID");
resourceCache.add(root, null).setSnapshot(new Snapshot().setId(11));
resourceCache.add(root, null);

Project module1 = new Project("module1").setName("Module1").setDescription("Module description");
module1.setParent(root);
module1.setId(2).setUuid("MODULE_UUID");
resourceCache.add(module1, root).setSnapshot(new Snapshot().setId(12));
resourceCache.add(module1, root);
rootDef.addSubProject(ProjectDefinition.create().setKey("module1"));

Directory dir = Directory.create("src");
dir.setEffectiveKey("module1:src");
dir.setId(3).setUuid("DIR_UUID");
resourceCache.add(dir, module1).setSnapshot(new Snapshot().setId(13));
resourceCache.add(dir, module1);

org.sonar.api.resources.File file = org.sonar.api.resources.File.create("src/Foo.java", Java.INSTANCE, false);
file.setEffectiveKey("module1:src/Foo.java");
file.setId(4).setUuid("FILE_UUID");
resourceCache.add(file, dir).setSnapshot(new Snapshot().setId(14)).setInputPath(new DefaultInputFile("module1", "src/Foo.java").setLines(2));
resourceCache.add(file, dir).setInputPath(new DefaultInputFile("module1", "src/Foo.java").setLines(2));

org.sonar.api.resources.File fileWithoutLang = org.sonar.api.resources.File.create("src/make", null, false);
fileWithoutLang.setEffectiveKey("module1:src/make");
fileWithoutLang.setId(5).setUuid("FILE_WITHOUT_LANG_UUID");
resourceCache.add(fileWithoutLang, dir).setSnapshot(new Snapshot().setId(15)).setInputPath(new DefaultInputFile("module1", "src/make").setLines(10));
resourceCache.add(fileWithoutLang, dir).setInputPath(new DefaultInputFile("module1", "src/make").setLines(10));

org.sonar.api.resources.File testFile = org.sonar.api.resources.File.create("test/FooTest.java", Java.INSTANCE, true);
testFile.setEffectiveKey("module1:test/FooTest.java");
testFile.setId(6).setUuid("TEST_FILE_UUID");
resourceCache.add(testFile, dir).setSnapshot(new Snapshot().setId(16)).setInputPath(new DefaultInputFile("module1", "test/FooTest.java").setLines(4));
resourceCache.add(testFile, dir).setInputPath(new DefaultInputFile("module1", "test/FooTest.java").setLines(4));

ImmutableProjectReactor reactor = new ImmutableProjectReactor(rootDef);

@@ -123,14 +122,14 @@ public class ComponentsPublisherTest {
Project root = new Project("foo:my_branch").setName("Root project")
.setAnalysisDate(DateUtils.parseDate(("2012-12-12")));
root.setId(1).setUuid("PROJECT_UUID");
resourceCache.add(root, null).setSnapshot(new Snapshot().setId(11));
resourceCache.add(root, null);
rootDef.properties().put(CoreProperties.LINKS_HOME_PAGE, "http://home");
rootDef.properties().put(CoreProperties.PROJECT_BRANCH_PROPERTY, "my_branch");

Project module1 = new Project("module1:my_branch").setName("Module1");
module1.setParent(root);
module1.setId(2).setUuid("MODULE_UUID");
resourceCache.add(module1, root).setSnapshot(new Snapshot().setId(12));
resourceCache.add(module1, root);
ProjectDefinition moduleDef = ProjectDefinition.create().setKey("module1");
moduleDef.properties().put(CoreProperties.LINKS_CI, "http://ci");
rootDef.addSubProject(moduleDef);
@@ -138,12 +137,12 @@ public class ComponentsPublisherTest {
Directory dir = Directory.create("src");
dir.setEffectiveKey("module1:my_branch:my_branch:src");
dir.setId(3).setUuid("DIR_UUID");
resourceCache.add(dir, module1).setSnapshot(new Snapshot().setId(13));
resourceCache.add(dir, module1);

org.sonar.api.resources.File file = org.sonar.api.resources.File.create("src/Foo.java", Java.INSTANCE, false);
file.setEffectiveKey("module1:my_branch:my_branch:src/Foo.java");
file.setId(4).setUuid("FILE_UUID");
resourceCache.add(file, dir).setSnapshot(new Snapshot().setId(14)).setInputPath(new DefaultInputFile("module1", "src/Foo.java").setLines(2));
resourceCache.add(file, dir).setInputPath(new DefaultInputFile("module1", "src/Foo.java").setLines(2));

ImmutableProjectReactor reactor = new ImmutableProjectReactor(rootDef);


+ 6
- 8
sonar-batch/src/test/java/org/sonar/batch/report/CoveragePublisherTest.java View File

@@ -19,13 +19,17 @@
*/
package org.sonar.batch.report;

import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.resources.Project;
@@ -36,12 +40,6 @@ import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.measure.MeasureCache;

import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
@@ -62,7 +60,7 @@ public class CoveragePublisherTest {
Project p = new Project("foo").setAnalysisDate(new Date(1234567L));
BatchComponentCache resourceCache = new BatchComponentCache();
sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
resourceCache.add(p, null).setSnapshot(new Snapshot().setId(2));
resourceCache.add(p, null);
resourceCache.add(sampleFile, null).setInputPath(new DefaultInputFile("foo", "src/Foo.php").setLines(5));
measureCache = mock(MeasureCache.class);
when(measureCache.byMetric(anyString(), anyString())).thenReturn(Collections.<Measure>emptyList());

+ 1
- 2
sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java View File

@@ -28,7 +28,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.RuleKey;
import org.sonar.batch.index.BatchComponentCache;
@@ -60,7 +59,7 @@ public class IssuesPublisherTest {
project = new Project("foo").setAnalysisDate(new Date(1234567L));
BatchComponentCache componentCache = new BatchComponentCache();
org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
componentCache.add(project, null).setSnapshot(new Snapshot().setId(2));
componentCache.add(project, null);
componentCache.add(sampleFile, project);
issueCache = mock(IssueCache.class);
when(issueCache.byComponent(anyString())).thenReturn(Collections.<DefaultIssue>emptyList());

+ 1
- 4
sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java View File

@@ -20,7 +20,6 @@
package org.sonar.batch.report;

import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -28,11 +27,9 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metric.Level;
import org.sonar.api.measures.Metric.ValueType;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.Project;
@@ -64,7 +61,7 @@ public class MeasuresPublisherTest {
Project p = new Project("foo").setAnalysisDate(new Date(1234567L));
BatchComponentCache resourceCache = new BatchComponentCache();
sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
resourceCache.add(p, null).setSnapshot(new Snapshot().setId(2));
resourceCache.add(p, null);
resourceCache.add(sampleFile, null);
measureCache = mock(MeasureCache.class);
when(measureCache.byResource(any(Resource.class))).thenReturn(Collections.<Measure>emptyList());

+ 1
- 2
sonar-batch/src/test/java/org/sonar/batch/report/MetadataPublisherTest.java View File

@@ -31,7 +31,6 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.batch.rule.internal.NewActiveRule;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.protocol.output.BatchReport;
@@ -58,7 +57,7 @@ public class MetadataPublisherTest {
project = new Project("foo").setAnalysisDate(new Date(1234567L));
BatchComponentCache componentCache = new BatchComponentCache();
org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
componentCache.add(project, null).setSnapshot(new Snapshot().setId(2));
componentCache.add(project, null);
componentCache.add(sampleFile, project);
underTest = new MetadataPublisher(componentCache, new ImmutableProjectReactor(projectDef), activeRules);
}

+ 5
- 7
sonar-batch/src/test/java/org/sonar/batch/report/SourcePublisherTest.java View File

@@ -19,23 +19,21 @@
*/
package org.sonar.batch.report;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.protocol.output.BatchReportWriter;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;

import static org.assertj.core.api.Assertions.assertThat;

public class SourcePublisherTest {
@@ -57,7 +55,7 @@ public class SourcePublisherTest {
BatchComponentCache resourceCache = new BatchComponentCache();
sampleFile = org.sonar.api.resources.File.create("src/Foo.php");
sampleFile.setEffectiveKey("foo:src/Foo.php");
resourceCache.add(p, null).setSnapshot(new Snapshot().setId(2));
resourceCache.add(p, null);
File baseDir = temp.newFolder();
sourceFile = new File(baseDir, "src/Foo.php");
resourceCache.add(sampleFile, null).setInputPath(

+ 0
- 30
sonar-core/pom.xml View File

@@ -58,36 +58,6 @@
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-home</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<!-- provided only by batch -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<!-- provided only by batch -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<!-- provided only by batch -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<!-- provided only by batch -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>geronimo-spec</groupId>
<artifactId>geronimo-spec-jta</artifactId>
<!-- provided only by batch -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>

+ 1
- 5
sonar-core/src/main/java/org/sonar/core/persistence/Database.java View File

@@ -19,12 +19,10 @@
*/
package org.sonar.core.persistence;

import javax.sql.DataSource;
import org.picocontainer.Startable;
import org.sonar.core.persistence.dialect.Dialect;

import javax.sql.DataSource;
import java.util.Properties;

/**
* @since 2.12
*/
@@ -38,6 +36,4 @@ public interface Database extends Startable {
* @return the dialect or null if start() has not been executed
*/
Dialect getDialect();

Properties getHibernateProperties();
}

+ 6
- 28
sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java View File

@@ -20,11 +20,16 @@
package org.sonar.core.persistence;

import com.google.common.annotations.VisibleForTesting;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.cfg.Environment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.config.Settings;
@@ -32,15 +37,6 @@ import org.sonar.api.database.DatabaseProperties;
import org.sonar.core.persistence.dialect.Dialect;
import org.sonar.core.persistence.dialect.DialectUtils;
import org.sonar.core.persistence.profiling.ProfiledDataSource;
import org.sonar.jpa.session.CustomHibernateConnectionProvider;

import javax.sql.DataSource;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
* @since 2.12
@@ -51,7 +47,6 @@ public class DefaultDatabase implements Database {

private static final String DEFAULT_URL = "jdbc:h2:tcp://localhost/sonar";
private static final String SONAR_JDBC = "sonar.jdbc.";
private static final String SONAR_HIBERNATE = "sonar.hibernate.";
private static final String SONAR_JDBC_DIALECT = "sonar.jdbc.dialect";
private static final String SONAR_JDBC_URL = "sonar.jdbc.url";
private static final String VALIDATE = "validate";
@@ -89,7 +84,6 @@ public class DefaultDatabase implements Database {
void initSettings() {
properties = new Properties();
completeProperties(settings, properties, SONAR_JDBC);
completeProperties(settings, properties, SONAR_HIBERNATE);
completeDefaultProperties(properties);
doCompleteProperties(properties);

@@ -136,21 +130,6 @@ public class DefaultDatabase implements Database {
return dialect;
}

@Override
public Properties getHibernateProperties() {
Properties props = new Properties();

List<String> hibernateKeys = settings.getKeysStartingWith(SONAR_HIBERNATE);
for (String hibernateKey : hibernateKeys) {
props.put(StringUtils.removeStart(hibernateKey, "sonar."), settings.getString(hibernateKey));
}
props.put(Environment.DIALECT, getDialect().getHibernateDialectClass().getName());
props.put("hibernate.generate_statistics", "false");
props.put(Environment.CONNECTION_PROVIDER, CustomHibernateConnectionProvider.class.getName());

return props;
}

@Override
public final DataSource getDataSource() {
return datasource;
@@ -195,7 +174,6 @@ public class DefaultDatabase implements Database {
completeDefaultProperty(props, DatabaseProperties.PROP_URL, DEFAULT_URL);
completeDefaultProperty(props, DatabaseProperties.PROP_USER, props.getProperty(DatabaseProperties.PROP_USER_DEPRECATED, DatabaseProperties.PROP_USER_DEFAULT_VALUE));
completeDefaultProperty(props, DatabaseProperties.PROP_PASSWORD, DatabaseProperties.PROP_PASSWORD_DEFAULT_VALUE);
completeDefaultProperty(props, "sonar.jdbc.hibernate.hbm2ddl", VALIDATE);
}

private static void completeDefaultProperty(Properties props, String key, String defaultValue) {

+ 0
- 5
sonar-core/src/main/java/org/sonar/core/persistence/dialect/Dialect.java View File

@@ -31,11 +31,6 @@ public interface Dialect {
*/
String getId();

/**
* @return the hibernate dialect class to be used
*/
Class<? extends org.hibernate.dialect.Dialect> getHibernateDialectClass();

/**
* @return the activerecord dialect to be used
*/

+ 0
- 6
sonar-core/src/main/java/org/sonar/core/persistence/dialect/H2.java View File

@@ -20,7 +20,6 @@
package org.sonar.core.persistence.dialect;

import org.apache.commons.lang.StringUtils;
import org.hibernate.dialect.H2Dialect;

/**
* @since 1.12
@@ -33,11 +32,6 @@ public class H2 extends AbstractDialect {
super(ID, ".h2.", "org.h2.Driver", "true", "false", "SELECT 1");
}

@Override
public Class<? extends org.hibernate.dialect.Dialect> getHibernateDialectClass() {
return H2Dialect.class;
}

@Override
public boolean matchesJdbcURL(String jdbcConnectionURL) {
return StringUtils.startsWithIgnoreCase(jdbcConnectionURL, "jdbc:h2:");

+ 0
- 30
sonar-core/src/main/java/org/sonar/core/persistence/dialect/MsSql.java View File

@@ -20,10 +20,6 @@
package org.sonar.core.persistence.dialect;

import org.apache.commons.lang.StringUtils;
import org.hibernate.dialect.SQLServerDialect;
import org.sonar.api.database.DatabaseProperties;

import java.sql.Types;

public class MsSql extends AbstractDialect {

@@ -33,11 +29,6 @@ public class MsSql extends AbstractDialect {
super(ID, "sqlserver", "net.sourceforge.jtds.jdbc.Driver", "1", "0", "SELECT 1");
}

@Override
public Class<? extends org.hibernate.dialect.Dialect> getHibernateDialectClass() {
return MsSqlDialect.class;
}

@Override
public boolean matchesJdbcURL(String jdbcConnectionURL) {
return StringUtils.startsWithIgnoreCase(jdbcConnectionURL, "jdbc:microsoft:sqlserver:")
@@ -48,25 +39,4 @@ public class MsSql extends AbstractDialect {
public boolean supportsMigration() {
return true;
}

public static class MsSqlDialect extends SQLServerDialect {
public MsSqlDialect() {
super();
registerColumnType(Types.DOUBLE, "decimal");
registerColumnType(Types.VARCHAR, 255, "nvarchar($l)");
registerColumnType(Types.VARCHAR, DatabaseProperties.MAX_TEXT_SIZE, "nvarchar(max)");
registerColumnType(Types.CHAR, "nchar(1)");
registerColumnType(Types.CLOB, "nvarchar(max)");
}

@Override
public String getTypeName(int code, int length, int precision, int scale) {
if (code != 2005) {
return super.getTypeName(code, length, precision, scale);
} else {
return "ntext";
}
}
}
}


+ 0
- 19
sonar-core/src/main/java/org/sonar/core/persistence/dialect/MySql.java View File

@@ -20,10 +20,6 @@
package org.sonar.core.persistence.dialect;

import org.apache.commons.lang.StringUtils;
import org.hibernate.dialect.MySQLDialect;
import org.sonar.api.database.DatabaseProperties;

import java.sql.Types;

/**
* @since 1.12
@@ -36,26 +32,11 @@ public class MySql extends AbstractDialect {
super(ID, "mysql", "com.mysql.jdbc.Driver", "true", "false", "SELECT 1");
}

@Override
public Class<? extends org.hibernate.dialect.Dialect> getHibernateDialectClass() {
return MySqlWithDecimalDialect.class;
}

@Override
public boolean matchesJdbcURL(String jdbcConnectionURL) {
return StringUtils.startsWithIgnoreCase(jdbcConnectionURL, "jdbc:mysql:");
}

public static class MySqlWithDecimalDialect extends MySQLDialect {
public MySqlWithDecimalDialect() {
super();
registerColumnType(Types.DOUBLE, "decimal precision");
registerColumnType(Types.VARCHAR, DatabaseProperties.MAX_TEXT_SIZE, "longtext");
registerColumnType(Types.CLOB, "longtext");
registerColumnType(Types.BLOB, "blob");
}
}

@Override
public int getScrollDefaultFetchSize() {
return Integer.MIN_VALUE;

+ 0
- 23
sonar-core/src/main/java/org/sonar/core/persistence/dialect/Oracle.java View File

@@ -20,10 +20,6 @@
package org.sonar.core.persistence.dialect;

import org.apache.commons.lang.StringUtils;
import org.hibernate.dialect.Oracle10gDialect;
import org.sonar.api.database.DatabaseProperties;

import java.sql.Types;

/**
* @since 1.12
@@ -36,11 +32,6 @@ public class Oracle extends AbstractDialect {
super(ID, "oracle", "oracle.jdbc.OracleDriver", "1", "0", "SELECT 1 FROM DUAL");
}

@Override
public Class<? extends org.hibernate.dialect.Dialect> getHibernateDialectClass() {
return Oracle10gWithDecimalDialect.class;
}

@Override
public boolean matchesJdbcURL(String jdbcConnectionURL) {
return StringUtils.startsWithIgnoreCase(jdbcConnectionURL, "jdbc:oracle:");
@@ -50,18 +41,4 @@ public class Oracle extends AbstractDialect {
public boolean supportsMigration() {
return true;
}

public static class Oracle10gWithDecimalDialect extends Oracle10gDialect {
public Oracle10gWithDecimalDialect() {
super();
registerColumnType(Types.DOUBLE, "number($p,$s)");
registerColumnType(Types.VARCHAR, DatabaseProperties.MAX_TEXT_SIZE, "clob");
registerColumnType(Types.VARBINARY, "blob");
}

@Override
public Class getNativeIdentifierGeneratorClass() {
return OracleSequenceGenerator.class;
}
}
}

+ 0
- 49
sonar-core/src/main/java/org/sonar/core/persistence/dialect/OracleSequenceGenerator.java View File

@@ -1,49 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.core.persistence.dialect;

import org.apache.commons.lang.StringUtils;
import org.hibernate.dialect.Dialect;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.SequenceGenerator;
import org.hibernate.type.Type;

import java.util.Properties;

/**
* @since 1.10
*/
public class OracleSequenceGenerator extends SequenceGenerator {

public static final String SEQUENCE_NAME_SUFFIX = "_SEQ";

@Override
public void configure(Type type, Properties params, Dialect dialect) {
String tableName = params.getProperty(PersistentIdentifierGenerator.TABLE);
if (tableName != null) {
StringBuilder sequenceNameBuilder = new StringBuilder();
sequenceNameBuilder.append(tableName);
sequenceNameBuilder.append(SEQUENCE_NAME_SUFFIX);
params.setProperty(SEQUENCE, StringUtils.upperCase(sequenceNameBuilder.toString()));
}
super.configure(type, params, dialect);
}

}

+ 0
- 62
sonar-core/src/main/java/org/sonar/core/persistence/dialect/PostgreSQLSequenceGenerator.java View File

@@ -1,62 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.core.persistence.dialect;

import org.hibernate.dialect.Dialect;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.SequenceGenerator;
import org.hibernate.type.Type;

import java.util.Properties;

/**
* if the underlying database is PostgreSQL, the sequence
* naming convention is different and includes the primary key
* column name
*
* @since 1.10
*/
public class PostgreSQLSequenceGenerator extends SequenceGenerator {

public static final String SEQUENCE_NAME_SEPARATOR = "_";
public static final String SEQUENCE_NAME_SUFFIX = "seq";

@Override
public void configure(Type type, Properties params, Dialect dialect) {

String tableName = params.getProperty(PersistentIdentifierGenerator.TABLE);
String columnName = params.getProperty(PersistentIdentifierGenerator.PK);

if (tableName != null && columnName != null) {
StringBuilder sequenceNameBuilder = new StringBuilder();

sequenceNameBuilder.append(tableName);
sequenceNameBuilder.append(SEQUENCE_NAME_SEPARATOR);
sequenceNameBuilder.append(columnName);
sequenceNameBuilder.append(SEQUENCE_NAME_SEPARATOR);
sequenceNameBuilder.append(SEQUENCE_NAME_SUFFIX);

params.setProperty(SEQUENCE, sequenceNameBuilder.toString());
}

super.configure(type, params, dialect);
}

}

+ 1
- 22
sonar-core/src/main/java/org/sonar/core/persistence/dialect/PostgreSql.java View File

@@ -20,11 +20,8 @@
package org.sonar.core.persistence.dialect;

import com.google.common.collect.ImmutableList;
import org.apache.commons.lang.StringUtils;
import org.hibernate.dialect.PostgreSQLDialect;

import java.sql.Types;
import java.util.List;
import org.apache.commons.lang.StringUtils;

/**
* @since 1.12
@@ -38,11 +35,6 @@ public class PostgreSql extends AbstractDialect {
super(ID, "postgre", "org.postgresql.Driver", "true", "false", "SELECT 1");
}

@Override
public Class<? extends org.hibernate.dialect.Dialect> getHibernateDialectClass() {
return PostgreSQLWithDecimalDialect.class;
}

@Override
public boolean matchesJdbcURL(String jdbcConnectionURL) {
return StringUtils.startsWithIgnoreCase(jdbcConnectionURL, "jdbc:postgresql:");
@@ -57,17 +49,4 @@ public class PostgreSql extends AbstractDialect {
public boolean supportsMigration() {
return true;
}

public static class PostgreSQLWithDecimalDialect extends PostgreSQLDialect {

public PostgreSQLWithDecimalDialect() {
super();
registerColumnType(Types.DOUBLE, "numeric($p,$s)");
}
@Override
public Class getNativeIdentifierGeneratorClass() {
return PostgreSQLSequenceGenerator.class;
}

}
}

+ 2
- 5
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/ActiveRuleDto.java View File

@@ -21,6 +21,8 @@
package org.sonar.core.qualityprofile.db;

import com.google.common.base.Preconditions;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
@@ -30,10 +32,6 @@ import org.sonar.core.persistence.Dto;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.SeverityUtil;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.persistence.Transient;

public class ActiveRuleDto extends Dto<ActiveRuleKey> {

public static final String INHERITED = ActiveRule.INHERITED;
@@ -66,7 +64,6 @@ public class ActiveRuleDto extends Dto<ActiveRuleKey> {
}

// This field do not exists in db, it's only retrieve by joins
@Transient
private Integer parentId;

public Integer getId() {

+ 0
- 4
sonar-core/src/main/java/org/sonar/core/timemachine/Periods.java View File

@@ -27,8 +27,6 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.batch.RequiresDB;
import org.sonar.api.config.Settings;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.i18n.I18n;
@@ -36,8 +34,6 @@ import org.sonar.api.server.ServerSide;

import static org.sonar.api.utils.DateUtils.longToDate;

@RequiresDB
@BatchSide
@ServerSide
public class Periods {


+ 0
- 80
sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java View File

@@ -1,80 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.core.persistence.Database;
import org.sonar.core.persistence.dialect.Dialect;

public abstract class AbstractDatabaseConnector implements DatabaseConnector {
protected static final Logger LOG = LoggerFactory.getLogger(AbstractDatabaseConnector.class);

protected Database database;
private EntityManagerFactory factory = null;

protected AbstractDatabaseConnector(Database database) {
this.database = database;
}

public void start() {
LOG.info("Initializing Hibernate");
factory = createEntityManagerFactory();

}

public void stop() {
if (factory != null && factory.isOpen()) {
factory.close();
factory = null;
}
database = null;
}

protected EntityManagerFactory createEntityManagerFactory() {
// other settings are stored into /META-INF/persistence.xml
Properties props = database.getHibernateProperties();
logHibernateSettings(props);
return Persistence.createEntityManagerFactory("sonar", props);
}

private void logHibernateSettings(Properties props) {
if (LOG.isDebugEnabled()) {
for (Map.Entry<Object, Object> entry : props.entrySet()) {
LOG.debug(entry.getKey() + ": " + entry.getValue());
}
}
}

@Override
public EntityManager createEntityManager() {
return factory.createEntityManager();
}

@Override
public final Dialect getDialect() {
return database.getDialect();
}
}

+ 0
- 40
sonar-core/src/main/java/org/sonar/jpa/session/CustomHibernateConnectionProvider.java View File

@@ -1,40 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider;

import javax.sql.DataSource;
import java.util.Properties;

public class CustomHibernateConnectionProvider extends InjectedDataSourceConnectionProvider {

private static DataSource datasourceForConfig;

static void setDatasourceForConfig(DataSource ds) {
CustomHibernateConnectionProvider.datasourceForConfig = ds;
}

@Override
public void configure(Properties props) {
setDataSource(datasourceForConfig);
super.configure(props);
}
}

+ 0
- 35
sonar-core/src/main/java/org/sonar/jpa/session/DatabaseConnector.java View File

@@ -1,35 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import java.sql.Connection;
import java.sql.SQLException;
import javax.persistence.EntityManager;
import org.sonar.core.persistence.dialect.Dialect;

public interface DatabaseConnector {

Dialect getDialect();

Connection getConnection() throws SQLException;

EntityManager createEntityManager();

}

+ 0
- 33
sonar-core/src/main/java/org/sonar/jpa/session/DatabaseSessionFactory.java View File

@@ -1,33 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import org.sonar.api.database.DatabaseSession;

/**
* @deprecated replaced by mybatis
*/
@Deprecated
public interface DatabaseSessionFactory {

DatabaseSession getSession();

void clear();
}

+ 0
- 52
sonar-core/src/main/java/org/sonar/jpa/session/DefaultDatabaseConnector.java View File

@@ -1,52 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import org.sonar.api.utils.SonarException;
import org.sonar.core.persistence.Database;

import java.sql.Connection;
import java.sql.SQLException;

public class DefaultDatabaseConnector extends AbstractDatabaseConnector {

public DefaultDatabaseConnector(Database database) {
super(database);
}

@Override
public void start() {
createDatasource();
super.start();
}

private void createDatasource() {
try {
CustomHibernateConnectionProvider.setDatasourceForConfig(database.getDataSource());
} catch (Exception e) {
throw new SonarException("Fail to connect to database", e);
}
}

@Override
public Connection getConnection() throws SQLException {
return database != null && database.getDataSource() != null ? database.getDataSource().getConnection() : null;
}
}

+ 0
- 301
sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java View File

@@ -1,301 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.database.DatabaseSession;

public class JpaDatabaseSession extends DatabaseSession {

private final DatabaseConnector connector;
private EntityManager entityManager = null;
private int index = 0;
private boolean inTransaction = false;

public JpaDatabaseSession(DatabaseConnector connector) {
this.connector = connector;
}

/**
* Note that usage of this method is discouraged, because it allows to construct and execute queries without additional exception handling,
* which done in methods of this class.
*/
@Override
public EntityManager getEntityManager() {
if (entityManager == null) {
entityManager = connector.createEntityManager();
}
return entityManager;
}

@Override
public void start() {
getEntityManager();
index = 0;
}

@Override
public void stop() {
commitAndClose();
}

@Override
public void commitAndClose() {
commit();
if (entityManager != null && entityManager.isOpen()) {
entityManager.close();
entityManager = null;
}
}

@Override
public void commit() {
if (inTransaction) {
if (getEntityManager().isOpen()) {
if (getEntityManager().getTransaction().getRollbackOnly()) {
getEntityManager().getTransaction().rollback();
} else {
getEntityManager().getTransaction().commit();
}
getEntityManager().clear();
index = 0;
}
inTransaction = false;
}
}

@Override
public void rollback() {
if (inTransaction) {
getEntityManager().getTransaction().rollback();
inTransaction = false;
}
}

@Override
public <T> T save(T model) {
startTransaction();
internalSave(model, true);
return model;
}

@Override
public Object saveWithoutFlush(Object model) {
startTransaction();
internalSave(model, false);
return model;
}

@Override
public boolean contains(Object model) {
startTransaction();
return getEntityManager().contains(model);
}

@Override
public void save(Object... models) {
startTransaction();
for (Object model : models) {
save(model);
}
}

private void internalSave(Object model, boolean flushIfNeeded) {
try {
getEntityManager().persist(model);
} catch (PersistenceException e) {
/*
* See http://jira.sonarsource.com/browse/SONAR-2234
* In some cases Hibernate can throw exceptions without meaningful information about context, so we improve them here.
*/
throw new PersistenceException("Unable to persist : " + model, e);
}
if (flushIfNeeded && (++index % BATCH_SIZE == 0)) {
commit();
}
}

@Override
public Object merge(Object model) {
startTransaction();
return getEntityManager().merge(model);
}

@Override
public void remove(Object model) {
startTransaction();
getEntityManager().remove(model);
if (++index % BATCH_SIZE == 0) {
commit();
}
}

@Override
public void removeWithoutFlush(Object model) {
startTransaction();
getEntityManager().remove(model);
}

@Override
public <T> T reattach(Class<T> entityClass, Object primaryKey) {
startTransaction();
return getEntityManager().getReference(entityClass, primaryKey);
}

private void startTransaction() {
if (!inTransaction) {
getEntityManager().getTransaction().begin();
inTransaction = true;
}
}

/**
* Note that not recommended to directly execute {@link Query#getSingleResult()}, because it will bypass exception handling,
* which done in {@link #getSingleResult(Query, Object)}.
*/
@Override
public Query createQuery(String hql) {
startTransaction();
return getEntityManager().createQuery(hql);
}

@Override
public Query createNativeQuery(String sql) {
startTransaction();
return getEntityManager().createNativeQuery(sql);
}

/**
* @return the result or <code>defaultValue</code>, if not found
* @throws NonUniqueResultException if more than one result
*/
@Override
public <T> T getSingleResult(Query query, T defaultValue) {
/*
* See http://jira.sonarsource.com/browse/SONAR-2225
* By default Hibernate throws NonUniqueResultException without meaningful information about context,
* so we improve it here by adding all results in error message.
* Note that in some rare situations we can receive too many results, which may lead to OOME,
* but actually it will mean that database is corrupted as we don't expect more than one result
* and in fact org.hibernate.ejb.QueryImpl#getSingleResult() anyway does loading of several results under the hood.
*/
List<T> result = query.getResultList();

if (result.size() == 1) {
return result.get(0);

} else if (result.isEmpty()) {
return defaultValue;

} else {
Set<T> uniqueResult = new HashSet<>(result);
if (uniqueResult.size() > 1) {
throw new NonUniqueResultException("Expected single result, but got : " + result.toString());
} else {
return uniqueResult.iterator().next();
}
}
}

@Override
public <T> T getEntity(Class<T> entityClass, Object id) {
startTransaction();
return getEntityManager().find(entityClass, id);
}

/**
* @return the result or <code>null</code>, if not found
* @throws NonUniqueResultException if more than one result
*/
@Override
public <T> T getSingleResult(Class<T> entityClass, Object... criterias) {
try {
return getSingleResult(getQueryForCriterias(entityClass, true, criterias), (T) null);

} catch (NonUniqueResultException ex) {
NonUniqueResultException e = new NonUniqueResultException("Expected single result for entitiy " + entityClass.getSimpleName()
+ " with criterias : " + StringUtils.join(criterias, ","));
throw (NonUniqueResultException) e.initCause(ex);
}
}

@Override
public <T> List<T> getResults(Class<T> entityClass, Object... criterias) {
return getQueryForCriterias(entityClass, true, criterias).getResultList();
}

@Override
public <T> List<T> getResults(Class<T> entityClass) {
return getQueryForCriterias(entityClass, false, (Object[]) null).getResultList();
}

private Query getQueryForCriterias(Class<?> entityClass, boolean raiseError, Object... criterias) {
if (criterias == null && raiseError) {
throw new IllegalStateException("criterias parameter must be provided");
}
startTransaction();
StringBuilder hql = new StringBuilder("SELECT o FROM ").append(entityClass.getSimpleName()).append(" o");
if (criterias != null) {
hql.append(" WHERE ");
Map<String, Object> mappedCriterias = Maps.newHashMap();
for (int i = 0; i < criterias.length; i += 2) {
mappedCriterias.put((String) criterias[i], criterias[i + 1]);
}
buildCriteriasHQL(hql, mappedCriterias);
Query query = getEntityManager().createQuery(hql.toString());

for (Map.Entry<String, Object> entry : mappedCriterias.entrySet()) {
if (entry.getValue() != null) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
return query;
}
return getEntityManager().createQuery(hql.toString());
}

@VisibleForTesting
void buildCriteriasHQL(StringBuilder hql, Map<String, Object> mappedCriterias) {
for (Iterator<Map.Entry<String, Object>> i = mappedCriterias.entrySet().iterator(); i.hasNext();) {
Map.Entry<String, Object> entry = i.next();
hql.append("o.").append(entry.getKey());
if (entry.getValue() == null) {
hql.append(" IS NULL");
} else {
hql.append("=:").append(entry.getKey());
}
if (i.hasNext()) {
hql.append(" AND ");
}
}
}

}

+ 0
- 28
sonar-core/src/main/resources/META-INF/persistence.xml View File

@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="sonar" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>

<class>org.sonar.api.database.model.Snapshot</class>
<class>org.sonar.api.measures.Metric</class>
<class>org.sonar.api.database.model.ResourceModel</class>

<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.current_session_context_class" value="thread"/>
<property name="hibernate.connection.release_mode" value="after_transaction"/>
<property name="hibernate.bytecode.use_reflection_optimizer" value="true"/>
<property name="hibernate.query.factory_class" value="org.hibernate.hql.ast.ASTQueryTranslatorFactory"/>
<property name="hibernate.jdbc.batch_size" value="30"/>
<property name="hibernate.connection.useUnicode" value="true"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
<property name="hibernate.connection.characterEncoding" value="UTF-8"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="false"/>
<property name="hibernate.cache.use_query_cache" value="false"/>
</properties>
</persistence-unit>
</persistence>

+ 0
- 12
sonar-core/src/test/java/org/sonar/core/persistence/DefaultDatabaseTest.java View File

@@ -125,16 +125,4 @@ public class DefaultDatabaseTest {

assertThat(database.getProperties().getProperty("sonar.jdbc.driverClassName")).isEqualTo("org.postgresql.Driver");
}

@Test
public void shouldSetHibernateProperties() {
Settings settings = new Settings();
settings.setProperty("sonar.jdbc.url", "jdbc:postgresql://localhost/sonar");
DefaultDatabase database = new DefaultDatabase(settings);
database.initSettings();

Properties hibernateProps = database.getHibernateProperties();

assertThat(hibernateProps.getProperty("hibernate.generate_statistics")).isEqualTo("false");
}
}

+ 3
- 15
sonar-core/src/test/java/org/sonar/core/persistence/H2Database.java View File

@@ -19,18 +19,13 @@
*/
package org.sonar.core.persistence;

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbutils.DbUtils;
import org.hibernate.cfg.Environment;
import org.sonar.core.persistence.dialect.Dialect;
import org.sonar.core.persistence.dialect.H2;
import org.sonar.jpa.session.CustomHibernateConnectionProvider;

import javax.sql.DataSource;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
* H2 in-memory database, used for unit tests only.
@@ -113,13 +108,6 @@ public class H2Database implements Database {
return new H2();
}

public Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", "validate");
properties.put(Environment.CONNECTION_PROVIDER, CustomHibernateConnectionProvider.class.getName());
return properties;
}

@Override
public String toString() {
return "H2 Database[" + name + "]";

+ 0
- 49
sonar-core/src/test/java/org/sonar/core/persistence/dialect/OracleSequenceGeneratorTest.java View File

@@ -1,49 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.core.persistence.dialect;

import org.hibernate.id.PersistentIdentifierGenerator;
import org.junit.Test;

import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;

public class OracleSequenceGeneratorTest {

@Test
public void sequenceNameShouldFollowRailsConventions() {
Properties props = new Properties();
props.setProperty(PersistentIdentifierGenerator.TABLE, "my_table");
props.setProperty(PersistentIdentifierGenerator.PK, "id");

OracleSequenceGenerator generator = new OracleSequenceGenerator();
generator.configure(null, props, new Oracle.Oracle10gWithDecimalDialect());
assertThat(generator.getSequenceName()).isEqualTo("MY_TABLE_SEQ");
}

@Test
public void should_not_fail_if_table_name_can_not_be_loaded() {
Properties props = new Properties();
OracleSequenceGenerator generator = new OracleSequenceGenerator();
generator.configure(null, props, new Oracle.Oracle10gWithDecimalDialect());
assertThat(generator.getSequenceName()).isNotEmpty();
}
}

+ 0
- 49
sonar-core/src/test/java/org/sonar/core/persistence/dialect/PostgreSQLSequenceGeneratorTest.java View File

@@ -1,49 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.core.persistence.dialect;

import org.hibernate.id.PersistentIdentifierGenerator;
import org.junit.Test;

import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;

public class PostgreSQLSequenceGeneratorTest {

@Test
public void sequenceNameShouldFollowRailsConventions() {
Properties props = new Properties();
props.setProperty(PersistentIdentifierGenerator.TABLE, "my_table");
props.setProperty(PersistentIdentifierGenerator.PK, "id");

PostgreSQLSequenceGenerator generator = new PostgreSQLSequenceGenerator();
generator.configure(null, props, new PostgreSql.PostgreSQLWithDecimalDialect());
assertThat(generator.getSequenceName()).isEqualTo("my_table_id_seq");
}

@Test
public void should_not_fail_if_table_name_can_not_be_loaded() {
Properties props = new Properties();
PostgreSQLSequenceGenerator generator = new PostgreSQLSequenceGenerator();
generator.configure(null, props, new PostgreSql.PostgreSQLWithDecimalDialect());
assertThat(generator.getSequenceName()).isNotEmpty();
}
}

+ 0
- 90
sonar-core/src/test/java/org/sonar/jpa/session/DatabaseSessionTest.java View File

@@ -1,90 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import java.util.List;
import javax.persistence.NonUniqueResultException;
import org.hamcrest.Matchers;
import org.hamcrest.core.IsCollectionContaining;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.database.model.ResourceModel;
import org.sonar.jpa.test.AbstractDbUnitTestCase;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public class DatabaseSessionTest extends AbstractDbUnitTestCase {

private ResourceModel project1;
private ResourceModel project2;

@Before
public void setup() {
project1 = new ResourceModel(ResourceModel.SCOPE_PROJECT, "mygroup:myartifact", "JAV", null, "my name");
project2 = new ResourceModel(ResourceModel.SCOPE_PROJECT, "mygroup:myartifact1", "JAV", null, "my name 2");
}

@Test
public void testGetSingleResultWithNoResults() {
assertNull(getSession().getSingleResult(ResourceModel.class, "name", "test"));
}

@Test(expected = IllegalStateException.class)
public void testGetSingleResultWithNoCriterias() {
assertNull(getSession().getSingleResult(ResourceModel.class, (Object[]) null));
}

@Test
public void testGetSingleResultWithOneResult() {
getSession().save(project1);
ResourceModel hit = getSession().getSingleResult(ResourceModel.class, "name", "my name");
assertNotNull(hit);
assertEquals(project1, hit);
}

@Test(expected = NonUniqueResultException.class)
public void testGetSingleResultWithTwoResults() {
getSession().save(project1, project2);
getSession().getSingleResult(ResourceModel.class, "qualifier", "JAV");
}

@Test
public void testGetResultsWithNoResults() {
List<ResourceModel> hits = getSession().getResults(ResourceModel.class, "name", "foo");
assertTrue(hits.isEmpty());
}

@Test
public void testGetResultsWithMultipleResults() {
ResourceModel project3 = new ResourceModel(ResourceModel.SCOPE_PROJECT, "mygroup:myartifact3", "BRC", null, "my name 3");
getSession().save(project1, project2, project3);

List<ResourceModel> hits = getSession().getResults(ResourceModel.class, "qualifier", "JAV");
assertFalse(hits.isEmpty());
assertThat(hits, IsCollectionContaining.hasItems(project1, project2));
assertThat(hits, Matchers.not(IsCollectionContaining.hasItem(project3)));
}

}

+ 0
- 79
sonar-core/src/test/java/org/sonar/jpa/session/JpaDatabaseSessionTest.java View File

@@ -1,79 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.jpa.session;

import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Test;

import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class JpaDatabaseSessionTest {

private JpaDatabaseSession session;

@Before
public void setUp() {
session = new JpaDatabaseSession(null);
}

@Test(expected = NonUniqueResultException.class)
public void shouldThrowNonUniqueResultException() {
Query query = mock(Query.class);
when(query.getResultList()).thenReturn(Arrays.asList("foo", "bar"));
session.getSingleResult(query, null);
}

@Test
public void shouldReturnSingleResult() {
Query query = mock(Query.class);

when(query.getResultList()).thenReturn(Arrays.asList("foo", "foo"), Arrays.asList("bar"));
assertThat(session.getSingleResult(query, "default"), is("foo"));
assertThat(session.getSingleResult(query, "default"), is("bar"));
}

@Test
public void shouldReturnDefaultValue() {
Query query = mock(Query.class);
when(query.getResultList()).thenReturn(Collections.emptyList());
assertThat(session.getSingleResult(query, "default"), is("default"));
}

@Test
public void shouldBuildCriteriasHQL() {
StringBuilder hql = new StringBuilder();
Map<String, Object> mappedCriterias = Maps.newLinkedHashMap();
mappedCriterias.put("foo", "value");
mappedCriterias.put("bar", null);
session.buildCriteriasHQL(hql, mappedCriterias);
assertThat(hql.toString(), is("o.foo=:foo AND o.bar IS NULL"));
}

}

+ 0
- 40
sonar-core/src/test/java/org/sonar/jpa/test/AbstractDbUnitTestCase.java View File

@@ -37,10 +37,8 @@ import org.dbunit.dataset.filter.DefaultColumnFilter;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.ext.mssql.InsertIdentityOperation;
import org.dbunit.operation.DatabaseOperation;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.sonar.api.database.DatabaseSession;
import org.sonar.core.cluster.NullQueue;
import org.sonar.core.config.Logback;
import org.sonar.core.persistence.Database;
@@ -49,14 +47,10 @@ import org.sonar.core.persistence.DatabaseVersion;
import org.sonar.core.persistence.H2Database;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.persistence.SchemaMigrationMapper;
import org.sonar.jpa.session.DatabaseSessionFactory;
import org.sonar.jpa.session.DefaultDatabaseConnector;
import org.sonar.jpa.session.JpaDatabaseSession;

import static org.junit.Assert.fail;

/**
* Heavily duplicates AbstractDaoTestCase as long as Hibernate is in use.
* @deprecated this class does not support non-H2 databases
*/
@Deprecated
@@ -64,9 +58,7 @@ public abstract class AbstractDbUnitTestCase {
private static Database database;
private static MyBatis myBatis;
private static DatabaseCommands databaseCommands;
private static DefaultDatabaseConnector dbConnector;
private IDatabaseTester databaseTester;
private JpaDatabaseSession session;

@BeforeClass
public static void startDatabase() throws SQLException {
@@ -82,9 +74,6 @@ public abstract class AbstractDbUnitTestCase {
session.getMapper(SchemaMigrationMapper.class).insert(String.valueOf(DatabaseVersion.LAST_VERSION));
session.commit();
}

dbConnector = new DefaultDatabaseConnector(database);
dbConnector.start();
}
}

@@ -92,19 +81,6 @@ public abstract class AbstractDbUnitTestCase {
public void startDbUnit() throws Exception {
databaseCommands.truncateDatabase(database.getDataSource());
databaseTester = new DataSourceDatabaseTester(database.getDataSource());
session = new JpaDatabaseSession(dbConnector);
session.start();
}

@After
public void stopDbUnit() throws Exception {
if (session != null) {
session.rollback();
}
}

protected DatabaseSession getSession() {
return session;
}

protected MyBatis getMyBatis() {
@@ -115,17 +91,6 @@ public abstract class AbstractDbUnitTestCase {
return database;
}

protected DatabaseSessionFactory getSessionFactory() {
return new DatabaseSessionFactory() {
public DatabaseSession getSession() {
return session;
}

public void clear() {
}
};
}

protected void setupData(String... testNames) {
InputStream[] streams = new InputStream[testNames.length];
try {
@@ -262,9 +227,4 @@ public abstract class AbstractDbUnitTestCase {
runtimeException.setStackTrace(cause.getStackTrace());
return runtimeException;
}

protected Long getHQLCount(Class<?> hqlClass) {
String hqlCount = "SELECT count(o) from " + hqlClass.getSimpleName() + " o";
return (Long) getSession().createQuery(hqlCount).getSingleResult();
}
}

+ 1
- 5
sonar-core/src/test/resources/logback-test.xml View File

@@ -11,10 +11,6 @@
</encoder>
</appender>

<logger name="org.hibernate">
<level value="WARN"/>
</logger>

<logger name="org.dbunit">
<level value="WARN"/>
</logger>
@@ -39,4 +35,4 @@
<appender-ref ref="STDOUT"/>
</root>

</configuration>
</configuration>

+ 0
- 22
sonar-plugin-api/pom.xml View File

@@ -124,28 +124,6 @@
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>


<!-- TODO we can't remove hibernate-annotations, because currently it's used
moreover it contains transitive dependency on dom4j, which is used in some plugins
-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>


<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>

+ 0
- 37
sonar-plugin-api/src/main/java/org/sonar/api/batch/RequiresDB.java View File

@@ -1,37 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.batch;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* The presence of this annotation on an extension class indicates that the extension
* requires database access. As a result such extension will be disabled in preview mode.
*
*
* @since 5.1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RequiresDB {
}

+ 0
- 9
sonar-plugin-api/src/main/java/org/sonar/api/database/BaseIdentifiable.java View File

@@ -19,17 +19,8 @@
*/
package org.sonar.api.database;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public class BaseIdentifiable<G> {

@Id
@Column(name = "id")
@GeneratedValue
private Integer id;

public Integer getId() {

+ 0
- 87
sonar-plugin-api/src/main/java/org/sonar/api/database/DatabaseSession.java View File

@@ -1,87 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.database;

import org.sonar.api.batch.BatchSide;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import java.util.List;

/**
* This component should not be accessed by plugins. Database is not an API.
*
* @since 1.10
*/
@BatchSide
public abstract class DatabaseSession {

// IMPORTANT : this value must be the same than the property
// hibernate.jdbc.batch_size from /META-INF/persistence.xml (module sonar-database)
public static final int BATCH_SIZE = 30;

public abstract EntityManager getEntityManager();

public abstract void start();

public abstract void stop();

public abstract void commit();

/**
* This method should be called before a long period were database will not be accessed
* in order to close database connection and avoid timeout. Next use of the
* database will automatically open a new connection.
*/
public abstract void commitAndClose();

public abstract void rollback();

public abstract <T> T save(T entity);

public abstract Object saveWithoutFlush(Object entity);

public abstract boolean contains(Object entity);

public abstract void save(Object... entities);

public abstract Object merge(Object entity);

public abstract void remove(Object entity);

public abstract void removeWithoutFlush(Object entity);

public abstract <T> T reattach(Class<T> entityClass, Object primaryKey);

public abstract Query createQuery(String hql);

public abstract Query createNativeQuery(String sql);

public abstract <T> T getSingleResult(Query query, T defaultValue);

public abstract <T> T getEntity(Class<T> entityClass, Object id);

public abstract <T> T getSingleResult(Class<T> entityClass, Object... criterias);

public abstract <T> List<T> getResults(Class<T> entityClass, Object... criterias);

public abstract <T> List<T> getResults(Class<T> entityClass);
}

+ 0
- 46
sonar-plugin-api/src/main/java/org/sonar/api/database/model/ResourceModel.java View File

@@ -22,22 +22,12 @@ package org.sonar.api.database.model;
import java.io.Serializable;
import java.util.Date;
import javax.annotation.Nullable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.sonar.api.database.BaseIdentifiable;

/**
* Class to map resource with hibernate model
*/
@Entity
@Table(name = "projects")
public class ResourceModel extends BaseIdentifiable implements Cloneable, Serializable {

public static final String SCOPE_PROJECT = "PRJ";
@@ -48,59 +38,23 @@ public class ResourceModel extends BaseIdentifiable implements Cloneable, Serial
public static final int KEY_SIZE = 400;
public static final int PATH_SIZE = 2000;

@Column(name = "name", updatable = true, nullable = true, length = NAME_COLUMN_SIZE)
private String name;

@Column(name = "long_name", updatable = true, nullable = true, length = NAME_COLUMN_SIZE)
private String longName;

@Column(name = "description", updatable = true, nullable = true, length = DESCRIPTION_COLUMN_SIZE)
private String description;

@Column(name = "enabled", updatable = true, nullable = false)
private Boolean enabled = Boolean.TRUE;

@Column(name = "scope", updatable = true, nullable = false, length = 3)
private String scope;

@Column(name = "qualifier", updatable = true, nullable = false, length = 10)
private String qualifier;

@Column(name = "kee", updatable = true, nullable = false, length = KEY_SIZE)
private String key;

@Column(name = "deprecated_kee", updatable = true, nullable = true, length = KEY_SIZE)
private String deprecatedKey;

@Column(name = "language", updatable = true, nullable = true, length = 20)
private String languageKey;

@Column(name = "root_id", updatable = true, nullable = true)
private Integer rootId;

@Column(name = "path", updatable = true, nullable = true, length = PATH_SIZE)
private String path;

@Column(name = "copy_resource_id", updatable = true, nullable = true)
private Integer copyResourceId;

@Column(name = "person_id", updatable = true, nullable = true)
private Integer personId;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_at", updatable = true, nullable = true)
private Date createdAt;

@Column(name = "uuid", updatable = false, nullable = true, length = 50)
private String uuid;

@Column(name = "project_uuid", updatable = true, nullable = true, length = 50)
private String projectUuid;

@Column(name = "module_uuid", updatable = true, nullable = true, length = 50)
private String moduleUuid;

@Column(name = "module_uuid_path", updatable = true, nullable = true, length = 4000)
private String moduleUuidPath;

/**

+ 0
- 65
sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java View File

@@ -21,9 +21,6 @@ package org.sonar.api.database.model;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
@@ -33,11 +30,6 @@ import org.sonar.api.database.BaseIdentifiable;
import static org.sonar.api.utils.DateUtils.dateToLong;
import static org.sonar.api.utils.DateUtils.longToDate;

/**
* A class to map a snapshot with its hibernate model
*/
@Entity
@Table(name = "snapshots")
public class Snapshot extends BaseIdentifiable<Snapshot> implements Serializable {

/**
@@ -50,91 +42,34 @@ public class Snapshot extends BaseIdentifiable<Snapshot> implements Serializable
*/
public static final String STATUS_PROCESSED = "P";

@Column(name = "project_id", updatable = true, nullable = true)
private Integer resourceId;

@Column(name = "build_date", updatable = true, nullable = true)
private Long buildDate;

@Column(name = "created_at", updatable = true, nullable = true)
private Long createdAt;

@Column(name = "version", updatable = true, nullable = true, length = 500)
private String version;

@Column(name = "islast")
private Boolean last = Boolean.FALSE;

@Column(name = "status")
private String status = STATUS_UNPROCESSED;

@Column(name = "purge_status", updatable = true, nullable = true)
private Integer purgeStatus;

@Column(name = "scope", updatable = true, nullable = true, length = 3)
private String scope;

@Column(name = "path", updatable = true, nullable = true, length = 500)
private String path;

@Column(name = "depth", updatable = true, nullable = true)
private Integer depth;

@Column(name = "qualifier", updatable = true, nullable = true, length = 10)
private String qualifier;

@Column(name = "root_snapshot_id", updatable = true, nullable = true)
private Integer rootId;

@Column(name = "parent_snapshot_id", updatable = true, nullable = true)
private Integer parentId;

@Column(name = "root_project_id", updatable = true, nullable = true)
private Integer rootProjectId;

@Column(name = "period1_mode", updatable = true, nullable = true, length = 100)
private String period1Mode;

@Column(name = "period2_mode", updatable = true, nullable = true, length = 100)
private String period2Mode;

@Column(name = "period3_mode", updatable = true, nullable = true, length = 100)
private String period3Mode;

@Column(name = "period4_mode", updatable = true, nullable = true, length = 100)
private String period4Mode;

@Column(name = "period5_mode", updatable = true, nullable = true, length = 100)
private String period5Mode;

@Column(name = "period1_param", updatable = true, nullable = true, length = 100)
private String period1Param;

@Column(name = "period2_param", updatable = true, nullable = true, length = 100)
private String period2Param;

@Column(name = "period3_param", updatable = true, nullable = true, length = 100)
private String period3Param;

@Column(name = "period4_param", updatable = true, nullable = true, length = 100)
private String period4Param;

@Column(name = "period5_param", updatable = true, nullable = true, length = 100)
private String period5Param;

@Column(name = "period1_date", updatable = true, nullable = true)
private Long period1Date;

@Column(name = "period2_date", updatable = true, nullable = true)
private Long period2Date;

@Column(name = "period3_date", updatable = true, nullable = true)
private Long period3Date;

@Column(name = "period4_date", updatable = true, nullable = true)
private Long period4Date;

@Column(name = "period5_date", updatable = true, nullable = true)
private Long period5Date;

public Snapshot() {

+ 1
- 50
sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java View File

@@ -27,14 +27,6 @@ import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
@@ -42,13 +34,6 @@ import org.sonar.api.batch.BatchSide;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.server.ServerSide;

/**
* This class represents the definition of a metric in Sonar.
*
* @since 1.10
*/
@Table(name = "metrics")
@Entity(name = "Metric")
@BatchSide
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
@ServerSide
@@ -125,55 +110,21 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a
}
}

@Id
@Column(name = "id")
@GeneratedValue
private Integer id;

@Transient
private transient Formula formula;

@Column(name = "name", updatable = false, nullable = false, length = 64)
private String key;

@Column(name = "description", updatable = true, nullable = true, length = 255)
private String description;

@Column(name = "val_type", updatable = true, nullable = true)
@Enumerated(EnumType.STRING)
private ValueType type;

@Column(name = "direction", updatable = true, nullable = true)
private Integer direction;

@Column(name = "domain", updatable = true, nullable = true, length = 60)
private String domain;

@Column(name = "short_name", updatable = true, nullable = true, length = 64)
private String name;

@Column(name = "qualitative", updatable = true, nullable = true)
private Boolean qualitative = Boolean.FALSE;

@Column(name = "user_managed", updatable = true, nullable = true)
private Boolean userManaged = Boolean.FALSE;

@Column(name = "enabled", updatable = true, nullable = true)
private Boolean enabled = Boolean.TRUE;

@Column(name = "worst_value", updatable = true, nullable = true, precision = 30, scale = 20)
private Double worstValue;

@Column(name = "best_value", updatable = true, nullable = true, precision = 30, scale = 20)
private Double bestValue;

@Column(name = "optimized_best_value", updatable = true, nullable = true)
private Boolean optimizedBestValue;

@Column(name = "hidden", updatable = true, nullable = true)
private Boolean hidden = Boolean.FALSE;

@Column(name = "delete_historical_data", updatable = true, nullable = true)
private Boolean deleteHistoricalData;

private Metric(Builder builder) {
@@ -195,7 +146,7 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a
}

/**
* Creates an empty metric. Required for Hibernate.
* Creates an empty metric
*
* @deprecated in 1.12. Use the {@link Builder} factory.
*/

Loading…
Cancel
Save