aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2014-12-15 14:22:10 +0100
committerJulien HENRY <julien.henry@sonarsource.com>2014-12-17 13:14:49 +0100
commit789df9c9ba0ccdf72e5e5ab24de04b47798e4f72 (patch)
tree224d9625710131d51bc0f23cfbfbb2109b604112
parent597cf003728da27dac4a51a624358263ff8e88f7 (diff)
downloadsonarqube-789df9c9ba0ccdf72e5e5ab24de04b47798e4f72.tar.gz
sonarqube-789df9c9ba0ccdf72e5e5ab24de04b47798e4f72.zip
SONAR-5945 Upload issues in analysis report
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java12
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java11
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java37
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java19
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java5
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/GsonHelper.java (renamed from sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java)25
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/GlobalReferentials.java6
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectReferentials.java9
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/ReportIssue.java275
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/package-info.java24
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportResource.java106
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportResources.java (renamed from sonar-batch/src/main/java/org/sonar/batch/index/SnapshotCache.java)46
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java24
-rw-r--r--sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectReferentialsTest.java6
-rw-r--r--sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/issue/ReportIssueTest.java86
-rw-r--r--sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportResourcesTest.java94
-rw-r--r--sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json41
-rw-r--r--sonar-batch/pom.xml4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/BatchResource.java (renamed from sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java)52
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java48
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java100
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java117
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java30
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java22
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/FileHashesPersister.java18
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java17
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java12
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java42
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java28
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssueStorage.java16
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java29
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java92
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java20
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java99
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java147
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java29
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/ResourcesPublisher.java82
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/package-info.java23
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/rule/QProfileEventsDecorator.java10
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java8
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoader.java11
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java9
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java49
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java10
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java8
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java22
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java7
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java6
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssueStorageTest.java30
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java9
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java (renamed from sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java)40
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/rule/QProfileEventsDecoratorTest.java15
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java20
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java12
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java5
-rw-r--r--sonar-core/src/test/java/org/sonar/core/component/ResourceComponentTest.java1
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java44
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/database/BaseIdentifiable.java5
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java22
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java1
67 files changed, 1521 insertions, 711 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java
index 4b8a0225162..17cee708dd0 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java
@@ -30,6 +30,7 @@ import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.batch.components.TimeMachineConfiguration;
+import org.sonar.batch.index.ResourceCache;
import java.util.List;
@@ -37,24 +38,25 @@ import java.util.List;
public final class TimeMachineConfigurationPersister implements Decorator {
private final TimeMachineConfiguration timeMachineConfiguration;
- private Snapshot projectSnapshot;
+ private ResourceCache resourceCache;
private DatabaseSession session;
- public TimeMachineConfigurationPersister(TimeMachineConfiguration timeMachineConfiguration, Snapshot projectSnapshot, DatabaseSession session) {
+ public TimeMachineConfigurationPersister(TimeMachineConfiguration timeMachineConfiguration, ResourceCache resourceCache, DatabaseSession session) {
this.timeMachineConfiguration = timeMachineConfiguration;
- this.projectSnapshot = projectSnapshot;
+ this.resourceCache = resourceCache;
this.session = session;
}
@Override
public void decorate(Resource resource, DecoratorContext context) {
if (ResourceUtils.isProject(resource)) {
- persistConfiguration();
+ persistConfiguration(resource);
}
}
- void persistConfiguration() {
+ void persistConfiguration(Resource module) {
List<PastSnapshot> pastSnapshots = timeMachineConfiguration.getProjectPastSnapshots();
+ Snapshot projectSnapshot = resourceCache.get(module.getEffectiveKey()).snapshot();
for (PastSnapshot pastSnapshot : pastSnapshots) {
Snapshot snapshot = session.reattach(Snapshot.class, projectSnapshot.getId());
updatePeriodParams(snapshot, pastSnapshot);
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java
index a34e57b340a..4f9ac63c11f 100644
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java
+++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java
@@ -21,9 +21,11 @@ package org.sonar.plugins.core.timemachine;
import org.junit.Test;
import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
import org.sonar.api.utils.DateUtils;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.batch.components.TimeMachineConfiguration;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.jpa.test.AbstractDbUnitTestCase;
import java.util.Arrays;
@@ -45,8 +47,13 @@ public class TimeMachineConfigurationPersisterTest extends AbstractDbUnitTestCas
when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Arrays.asList(vs1, vs3));
Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1000);
- TimeMachineConfigurationPersister persister = new TimeMachineConfigurationPersister(timeMachineConfiguration, projectSnapshot, getSession());
- persister.persistConfiguration();
+ ResourceCache resourceCache = new ResourceCache();
+ Project project = new Project("foo");
+ resourceCache.add(project, projectSnapshot);
+
+ TimeMachineConfigurationPersister persister = new TimeMachineConfigurationPersister(timeMachineConfiguration, resourceCache, getSession());
+
+ persister.persistConfiguration(project);
checkTables("shouldSaveConfigurationInSnapshotsTable", "snapshots");
}
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java
index 2b587690753..d3258bfa7f6 100644
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java
+++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java
@@ -22,14 +22,18 @@ package org.sonar.plugins.cpd.index;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
-import org.sonar.batch.index.ResourcePersister;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.duplication.DuplicationDao;
import org.sonar.core.duplication.DuplicationUnitDto;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.ByteArray;
+import javax.persistence.Query;
+
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -37,28 +41,39 @@ import java.util.Map;
public class DbDuplicationsIndex {
+ private static final String RESOURCE_ID = "resourceId";
+ private static final String LAST = "last";
+
private final Map<ByteArray, Collection<Block>> cache = Maps.newHashMap();
- private final ResourcePersister resourcePersister;
private final int currentProjectSnapshotId;
private final Integer lastSnapshotId;
private final String languageKey;
+ private final DuplicationDao dao;
+ private final DatabaseSession session;
+ private final ResourceCache resourceCache;
- private DuplicationDao dao;
-
- public DbDuplicationsIndex(ResourcePersister resourcePersister, Project currentProject, DuplicationDao dao,
- String language) {
+ public DbDuplicationsIndex(Project currentProject, DuplicationDao dao,
+ String language, DatabaseSession session, ResourceCache resourceCache) {
this.dao = dao;
- this.resourcePersister = resourcePersister;
- Snapshot currentSnapshot = resourcePersister.getSnapshotOrFail(currentProject);
- Snapshot lastSnapshot = resourcePersister.getLastSnapshot(currentSnapshot, false);
- this.currentProjectSnapshotId = currentSnapshot.getId();
+ this.session = session;
+ this.resourceCache = resourceCache;
+ Snapshot lastSnapshot = getLastSnapshot(currentProject.getId());
+ this.currentProjectSnapshotId = resourceCache.get(currentProject.getEffectiveKey()).snapshotId();
this.lastSnapshotId = lastSnapshot == null ? null : lastSnapshot.getId();
this.languageKey = language;
}
+ private Snapshot getLastSnapshot(int resourceId) {
+ String hql = "SELECT s FROM " + Snapshot.class.getSimpleName() + " s WHERE s.last=:last AND s.resourceId=:resourceId";
+ Query query = session.createQuery(hql);
+ query.setParameter(LAST, true);
+ query.setParameter(RESOURCE_ID, resourceId);
+ return session.getSingleResult(query, null);
+ }
+
int getSnapshotIdFor(InputFile inputFile) {
- return resourcePersister.getSnapshotOrFail(inputFile).getId();
+ return resourceCache.get(((DefaultInputFile) inputFile).key()).snapshotId();
}
public void prepareCache(InputFile inputFile) {
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java
index 9830f4b1dd0..34a6110c32f 100644
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java
+++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java
@@ -26,9 +26,10 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
+import org.sonar.api.database.DatabaseSession;
import org.sonar.api.resources.Project;
import org.sonar.batch.bootstrap.AnalysisMode;
-import org.sonar.batch.index.ResourcePersister;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.duplication.DuplicationDao;
import javax.annotation.Nullable;
@@ -38,27 +39,29 @@ public class IndexFactory implements BatchComponent {
private static final Logger LOG = LoggerFactory.getLogger(IndexFactory.class);
private final Settings settings;
- private final ResourcePersister resourcePersister;
private final DuplicationDao dao;
private final AnalysisMode mode;
+ private final DatabaseSession session;
+ private final ResourceCache resourceCache;
- public IndexFactory(AnalysisMode mode, Settings settings, @Nullable ResourcePersister resourcePersister, @Nullable DuplicationDao dao) {
+ public IndexFactory(AnalysisMode mode, Settings settings, @Nullable DuplicationDao dao, @Nullable DatabaseSession session, ResourceCache resourceCache) {
this.mode = mode;
this.settings = settings;
- this.resourcePersister = resourcePersister;
this.dao = dao;
+ this.session = session;
+ this.resourceCache = resourceCache;
}
/**
* Used by new sensor mode
*/
- public IndexFactory(AnalysisMode mode, Settings settings) {
- this(mode, settings, null, null);
+ public IndexFactory(AnalysisMode mode, Settings settings, ResourceCache resourceCache) {
+ this(mode, settings, null, null, resourceCache);
}
public SonarDuplicationsIndex create(@Nullable Project project, String languageKey) {
- if (verifyCrossProject(project, LOG) && dao != null && resourcePersister != null) {
- return new SonarDuplicationsIndex(new DbDuplicationsIndex(resourcePersister, project, dao, languageKey));
+ if (verifyCrossProject(project, LOG) && dao != null && session != null) {
+ return new SonarDuplicationsIndex(new DbDuplicationsIndex(project, dao, languageKey, session, resourceCache));
}
return new SonarDuplicationsIndex();
}
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java
index 7b9fa524fec..e97ab77daf7 100644
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java
+++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java
@@ -24,9 +24,10 @@ import org.junit.Test;
import org.slf4j.Logger;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
+import org.sonar.api.database.DatabaseSession;
import org.sonar.api.resources.Project;
import org.sonar.batch.bootstrap.AnalysisMode;
-import org.sonar.batch.index.ResourcePersister;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.duplication.DuplicationDao;
import static org.fest.assertions.Assertions.assertThat;
@@ -47,7 +48,7 @@ public class IndexFactoryTest {
project = new Project("foo");
settings = new Settings();
analysisMode = mock(AnalysisMode.class);
- factory = new IndexFactory(analysisMode, settings, mock(ResourcePersister.class), mock(DuplicationDao.class));
+ factory = new IndexFactory(analysisMode, settings, mock(DuplicationDao.class), mock(DatabaseSession.class), new ResourceCache());
logger = mock(Logger.class);
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/GsonHelper.java
index 96c2a1033b6..b5ea008a538 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/GsonHelper.java
@@ -17,24 +17,19 @@
* 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.index;
+package org.sonar.batch.protocol;
-import org.junit.Test;
-import org.sonar.api.database.model.Snapshot;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
+public class GsonHelper {
-public class SnapshotCacheTest {
-
- Snapshot snapshot = mock(Snapshot.class);
+ private GsonHelper() {
+ // Utility class
+ }
- @Test
- public void should_cache_snapshots() throws Exception {
- SnapshotCache cache = new SnapshotCache();
- String componentKey = "org.apache.struts:struts-core";
- cache.put(componentKey, snapshot);
- assertThat(cache.get(componentKey)).isSameAs(snapshot);
- assertThat(cache.get("other")).isNull();
+ public static Gson create() {
+ return new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").setPrettyPrinting().create();
}
+
}
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/GlobalReferentials.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/GlobalReferentials.java
index 4fa32d5d68b..e7501e4d1de 100644
--- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/GlobalReferentials.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/GlobalReferentials.java
@@ -19,7 +19,7 @@
*/
package org.sonar.batch.protocol.input;
-import com.google.gson.Gson;
+import org.sonar.batch.protocol.GsonHelper;
import java.util.ArrayList;
import java.util.Collection;
@@ -63,11 +63,11 @@ public class GlobalReferentials {
}
public String toJson() {
- return new Gson().toJson(this);
+ return GsonHelper.create().toJson(this);
}
public static GlobalReferentials fromJson(String json) {
- return new Gson().fromJson(json, GlobalReferentials.class);
+ return GsonHelper.create().fromJson(json, GlobalReferentials.class);
}
}
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectReferentials.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectReferentials.java
index 68d06e73b48..b945da6f7b8 100644
--- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectReferentials.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectReferentials.java
@@ -19,8 +19,7 @@
*/
package org.sonar.batch.protocol.input;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import org.sonar.batch.protocol.GsonHelper;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -114,13 +113,11 @@ public class ProjectReferentials {
}
public String toJson() {
- Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
- return gson.toJson(this);
+ return GsonHelper.create().toJson(this);
}
public static ProjectReferentials fromJson(String json) {
- Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
- return gson.fromJson(json, ProjectReferentials.class);
+ return GsonHelper.create().fromJson(json, ProjectReferentials.class);
}
}
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/ReportIssue.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/ReportIssue.java
new file mode 100644
index 00000000000..3917d54d2a2
--- /dev/null
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/ReportIssue.java
@@ -0,0 +1,275 @@
+/*
+ * 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.protocol.output.issue;
+
+import javax.annotation.Nullable;
+
+import java.util.Date;
+
+public class ReportIssue {
+
+ private long resourceBatchId;
+ private boolean isNew;
+ private String ruleKey;
+ private String ruleRepo;
+ private String key;
+ private Integer line;
+ private String message;
+ private Double effortToFix;
+ private Long debtInMinutes;
+ private String resolution;
+ private String status;
+ private String severity;
+ private String checksum;
+ private boolean manualSeverity;
+ private String reporter;
+ private String assignee;
+ private String actionPlanKey;
+ private String attributes;
+ private String authorLogin;
+ private Date creationDate;
+ private Date closeDate;
+ private Date updateDate;
+ private Long selectedAt;
+ private String diffFields;
+ private boolean isChanged;
+
+ public ReportIssue setKey(String key) {
+ this.key = key;
+ return this;
+ }
+
+ public String key() {
+ return key;
+ }
+
+ public ReportIssue setResourceBatchId(long resourceBatchId) {
+ this.resourceBatchId = resourceBatchId;
+ return this;
+ }
+
+ public long resourceBatchId() {
+ return resourceBatchId;
+ }
+
+ public ReportIssue setNew(boolean isNew) {
+ this.isNew = isNew;
+ return this;
+ }
+
+ public boolean isNew() {
+ return isNew;
+ }
+
+ public ReportIssue setLine(Integer line) {
+ this.line = line;
+ return this;
+ }
+
+ public Integer line() {
+ return line;
+ }
+
+ public ReportIssue setMessage(String message) {
+ this.message = message;
+ return this;
+ }
+
+ public String message() {
+ return message;
+ }
+
+ public ReportIssue setEffortToFix(Double effortToFix) {
+ this.effortToFix = effortToFix;
+ return this;
+ }
+
+ public Double effortToFix() {
+ return effortToFix;
+ }
+
+ public ReportIssue setDebt(Long debtInMinutes) {
+ this.debtInMinutes = debtInMinutes;
+ return this;
+ }
+
+ public Long debt() {
+ return debtInMinutes;
+ }
+
+ public ReportIssue setResolution(String resolution) {
+ this.resolution = resolution;
+ return this;
+ }
+
+ public String resolution() {
+ return resolution;
+ }
+
+ public ReportIssue setStatus(String status) {
+ this.status = status;
+ return this;
+ }
+
+ public String status() {
+ return status;
+ }
+
+ public ReportIssue setSeverity(String severity) {
+ this.severity = severity;
+ return this;
+ }
+
+ public String severity() {
+ return severity;
+ }
+
+ public ReportIssue setChecksum(String checksum) {
+ this.checksum = checksum;
+ return this;
+ }
+
+ public String checksum() {
+ return checksum;
+ }
+
+ public ReportIssue setManualSeverity(boolean manualSeverity) {
+ this.manualSeverity = manualSeverity;
+ return this;
+ }
+
+ public boolean isManualSeverity() {
+ return manualSeverity;
+ }
+
+ public ReportIssue setReporter(String reporter) {
+ this.reporter = reporter;
+ return this;
+ }
+
+ public String reporter() {
+ return reporter;
+ }
+
+ public ReportIssue setAssignee(String assignee) {
+ this.assignee = assignee;
+ return this;
+ }
+
+ public String assignee() {
+ return assignee;
+ }
+
+ public ReportIssue setRuleKey(String ruleRepo, String ruleKey) {
+ this.ruleRepo = ruleRepo;
+ this.ruleKey = ruleKey;
+ return this;
+ }
+
+ public String ruleRepo() {
+ return ruleRepo;
+ }
+
+ public String ruleKey() {
+ return ruleKey;
+ }
+
+ public ReportIssue setActionPlanKey(String actionPlanKey) {
+ this.actionPlanKey = actionPlanKey;
+ return this;
+ }
+
+ public String actionPlanKey() {
+ return actionPlanKey;
+ }
+
+ public ReportIssue setAttributes(String attributes) {
+ this.attributes = attributes;
+ return this;
+ }
+
+ public String issueAttributes() {
+ return attributes;
+ }
+
+ public ReportIssue setAuthorLogin(String authorLogin) {
+ this.authorLogin = authorLogin;
+ return this;
+ }
+
+ public String authorLogin() {
+ return authorLogin;
+ }
+
+ public ReportIssue setCreationDate(Date creationDate) {
+ this.creationDate = creationDate;
+ return this;
+ }
+
+ public Date creationDate() {
+ return creationDate;
+ }
+
+ public ReportIssue setCloseDate(Date closeDate) {
+ this.closeDate = closeDate;
+ return this;
+ }
+
+ public Date closeDate() {
+ return closeDate;
+ }
+
+ public ReportIssue setUpdateDate(Date updateDate) {
+ this.updateDate = updateDate;
+ return this;
+ }
+
+ public Date updateDate() {
+ return updateDate;
+ }
+
+ public ReportIssue setSelectedAt(Long selectedAt) {
+ this.selectedAt = selectedAt;
+ return this;
+ }
+
+ public Long selectedAt() {
+ return selectedAt;
+ }
+
+ public ReportIssue setDiffFields(@Nullable String diffFields) {
+ this.diffFields = diffFields;
+ return this;
+ }
+
+ public String diffFields() {
+ return diffFields;
+ }
+
+ public ReportIssue setChanged(boolean isChanged) {
+ this.isChanged = isChanged;
+ return this;
+ }
+
+ public boolean isChanged() {
+ return isChanged;
+ }
+
+}
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/package-info.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/package-info.java
new file mode 100644
index 00000000000..444216d69f1
--- /dev/null
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/issue/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.protocol.output.issue;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportResource.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportResource.java
new file mode 100644
index 00000000000..44ceb7386ce
--- /dev/null
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportResource.java
@@ -0,0 +1,106 @@
+/*
+ * 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.protocol.output.resource;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ReportResource {
+
+ public enum Type {
+ PRJ,
+ MOD,
+ DIR,
+ FIL
+ }
+
+ private long batchId;
+ private int id;
+ private int snapshotId;
+ private String path;
+ private String name;
+ private Type type;
+
+ private Collection<ReportResource> children = new ArrayList<ReportResource>();
+
+ public ReportResource setBatchId(long batchId) {
+ this.batchId = batchId;
+ return this;
+ }
+
+ public long batchId() {
+ return batchId;
+ }
+
+ public ReportResource setId(int id) {
+ this.id = id;
+ return this;
+ }
+
+ public int id() {
+ return id;
+ }
+
+ public ReportResource setSnapshotId(int snapshotId) {
+ this.snapshotId = snapshotId;
+ return this;
+ }
+
+ public int snapshotId() {
+ return snapshotId;
+ }
+
+ public ReportResource setPath(String path) {
+ this.path = path;
+ return this;
+ }
+
+ public String path() {
+ return path;
+ }
+
+ public ReportResource setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public ReportResource setType(Type type) {
+ this.type = type;
+ return this;
+ }
+
+ public Type type() {
+ return type;
+ }
+
+ public ReportResource addChild(ReportResource child) {
+ this.children.add(child);
+ return this;
+ }
+
+ public Collection<ReportResource> children() {
+ return children;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/SnapshotCache.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportResources.java
index 6e21c2d2200..e78e41c14d8 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/SnapshotCache.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportResources.java
@@ -17,33 +17,41 @@
* 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.index;
+package org.sonar.batch.protocol.output.resource;
-import com.google.common.collect.Maps;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.resources.Library;
+import org.sonar.batch.protocol.GsonHelper;
-import java.util.Map;
-import java.util.Set;
+import java.util.Date;
-/**
- * Does not contains snapshots of {@link Library} as effectiveKey can be the same than a project.
- */
-public class SnapshotCache implements BatchComponent {
- // snapshots by component key
- private final Map<String, Snapshot> snapshots = Maps.newHashMap();
+public class ReportResources {
+
+ private Date analysisDate;
+
+ private ReportResource root;
+
+ public void setAnalysisDate(Date analysisDate) {
+ this.analysisDate = analysisDate;
+ }
- public Snapshot get(String componentKey) {
- return snapshots.get(componentKey);
+ public Date analysisDate() {
+ return analysisDate;
}
- public SnapshotCache put(String componentKey, Snapshot snapshot) {
- snapshots.put(componentKey, snapshot);
+ public ReportResources setRoot(ReportResource r) {
+ this.root = r;
return this;
}
- public Set<Map.Entry<String, Snapshot>> snapshots() {
- return snapshots.entrySet();
+ public ReportResource root() {
+ return root;
}
+
+ public String toJson() {
+ return GsonHelper.create().toJson(this);
+ }
+
+ public static ReportResources fromJson(String json) {
+ return GsonHelper.create().fromJson(json, ReportResources.class);
+ }
+
}
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java
new file mode 100644
index 00000000000..5e45e2dee7a
--- /dev/null
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.protocol.output.resource;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectReferentialsTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectReferentialsTest.java
index 8d55f4054dc..316d59acc31 100644
--- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectReferentialsTest.java
+++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectReferentialsTest.java
@@ -51,6 +51,7 @@ public class ProjectReferentialsTest {
ref.setLastAnalysisDate(new SimpleDateFormat("dd/MM/yyyy").parse("31/10/2014"));
ref.setTimestamp(10);
ref.addFileData("foo", "src/main/java/Foo.java", new FileData("xyz", "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin"));
+ ref.addFileData("foo", "src/main/java/Foo2.java", new FileData("xyz", "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin"));
System.out.println(ref.toJson());
JSONAssert
@@ -59,7 +60,8 @@ public class ProjectReferentialsTest {
+ "qprofilesByLanguage:{java:{key:\"squid-java\",name:Java,language:java,rulesUpdatedAt:\"1984-03-14T00:00:00+0100\"}},"
+ "activeRules:[{repositoryKey:repo,ruleKey:rule,name:Rule,severity:MAJOR,internalKey:rule,language:java,params:{param1:value1}}],"
+ "settingsByModule:{foo:{prop1:value1,prop2:value2,prop:value}},"
- + "fileDataByModuleAndPath:{foo:{\"src/main/java/Foo.java\":{hash:xyz,scmLastCommitDatetimesByLine:\"1\u003d12345,2\u003d3456\",scmRevisionsByLine:\"1\u003d345,2\u003d345\",scmAuthorsByLine:\"1\u003dhenryju,2\u003dgaudin\"}}},"
+ + "fileDataByModuleAndPath:{foo:{\"src/main/java/Foo.java\":{hash:xyz,scmLastCommitDatetimesByLine:\"1\u003d12345,2\u003d3456\",scmRevisionsByLine:\"1\u003d345,2\u003d345\",scmAuthorsByLine:\"1\u003dhenryju,2\u003dgaudin\"},"
+ + "\"src/main/java/Foo2.java\":{hash:xyz,scmLastCommitDatetimesByLine:\"1\u003d12345,2\u003d3456\",scmRevisionsByLine:\"1\u003d345,2\u003d345\",scmAuthorsByLine:\"1\u003dhenryju,2\u003dgaudin\"}}},"
+ "lastAnalysisDate:\"2014-10-31T00:00:00+0100\"}",
ref.toJson(), true);
}
@@ -91,6 +93,8 @@ public class ProjectReferentialsTest {
assertThat(qProfile.rulesUpdatedAt()).isEqualTo(new SimpleDateFormat("dd/MM/yyyy").parse("14/03/1984"));
assertThat(ref.settings("foo")).includes(MapAssert.entry("prop", "value"));
+ assertThat(ref.fileData("foo2", "src/main/java/Foo3.java")).isNull();
+
assertThat(ref.fileData("foo", "src/main/java/Foo.java").hash()).isEqualTo("xyz");
assertThat(ref.fileData("foo", "src/main/java/Foo.java").scmAuthorsByLine()).isEqualTo("1=henryju,2=gaudin");
assertThat(ref.fileData("foo", "src/main/java/Foo.java").scmLastCommitDatetimesByLine()).isEqualTo("1=12345,2=3456");
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/issue/ReportIssueTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/issue/ReportIssueTest.java
new file mode 100644
index 00000000000..06edbf1ab8d
--- /dev/null
+++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/issue/ReportIssueTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.protocol.output.issue;
+
+import org.junit.Test;
+
+import java.text.SimpleDateFormat;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class ReportIssueTest {
+
+ @Test
+ public void testGetterSetter() throws Exception {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ ReportIssue issue = new ReportIssue()
+ .setActionPlanKey("plan")
+ .setAssignee("assignee")
+ .setAuthorLogin("author")
+ .setChanged(true)
+ .setChecksum("checksum")
+ .setDebt(3L)
+ .setDiffFields("diff")
+ .setEffortToFix(2.0)
+ .setAttributes("attributes")
+ .setCloseDate(sdf.parse("11/12/2012"))
+ .setCreationDate(sdf.parse("12/12/2012"))
+ .setUpdateDate(sdf.parse("13/12/2012"))
+ .setKey("key")
+ .setLine(3)
+ .setManualSeverity(true)
+ .setMessage("message")
+ .setNew(true)
+ .setReporter("reporter")
+ .setResolution("resolution")
+ .setResourceBatchId(4L)
+ .setRuleKey("repo", "rule")
+ .setSelectedAt(234L)
+ .setSeverity("severity")
+ .setStatus("status");
+
+ assertThat(issue.actionPlanKey()).isEqualTo("plan");
+ assertThat(issue.assignee()).isEqualTo("assignee");
+ assertThat(issue.authorLogin()).isEqualTo("author");
+ assertThat(issue.isChanged()).isTrue();
+ assertThat(issue.checksum()).isEqualTo("checksum");
+ assertThat(issue.debt()).isEqualTo(3L);
+ assertThat(issue.diffFields()).isEqualTo("diff");
+ assertThat(issue.effortToFix()).isEqualTo(2.0);
+ assertThat(issue.issueAttributes()).isEqualTo("attributes");
+ assertThat(issue.closeDate()).isEqualTo(sdf.parse("11/12/2012"));
+ assertThat(issue.creationDate()).isEqualTo(sdf.parse("12/12/2012"));
+ assertThat(issue.updateDate()).isEqualTo(sdf.parse("13/12/2012"));
+ assertThat(issue.key()).isEqualTo("key");
+ assertThat(issue.line()).isEqualTo(3);
+ assertThat(issue.isManualSeverity()).isTrue();
+ assertThat(issue.message()).isEqualTo("message");
+ assertThat(issue.isNew()).isTrue();
+ assertThat(issue.reporter()).isEqualTo("reporter");
+ assertThat(issue.resolution()).isEqualTo("resolution");
+ assertThat(issue.resourceBatchId()).isEqualTo(4L);
+ assertThat(issue.ruleRepo()).isEqualTo("repo");
+ assertThat(issue.ruleKey()).isEqualTo("rule");
+ assertThat(issue.selectedAt()).isEqualTo(234L);
+ assertThat(issue.severity()).isEqualTo("severity");
+ assertThat(issue.status()).isEqualTo("status");
+ }
+
+}
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportResourcesTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportResourcesTest.java
new file mode 100644
index 00000000000..d48d3ccc76d
--- /dev/null
+++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportResourcesTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.protocol.output.resource;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.sonar.batch.protocol.output.resource.ReportResource.Type;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class ReportResourcesTest {
+
+ @Test
+ public void to_json() throws Exception {
+ ReportResources res = new ReportResources();
+ Date d = new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2012");
+ res.setAnalysisDate(d);
+ ReportResource root = new ReportResource()
+ .setBatchId(1)
+ .setId(11)
+ .setName("Root project")
+ .setSnapshotId(111)
+ .setType(Type.PRJ);
+ ReportResource module = new ReportResource()
+ .setBatchId(2)
+ .setId(22)
+ .setName("Module")
+ .setSnapshotId(222)
+ .setPath("module1")
+ .setType(Type.MOD);
+ root.addChild(module);
+ ReportResource dir = new ReportResource()
+ .setBatchId(3)
+ .setId(33)
+ .setName("src")
+ .setSnapshotId(333)
+ .setPath("src")
+ .setType(Type.DIR);
+ module.addChild(dir);
+ ReportResource file = new ReportResource()
+ .setBatchId(4)
+ .setId(44)
+ .setName("Foo.java")
+ .setSnapshotId(444)
+ .setPath("Foo.java")
+ .setType(Type.FIL);
+ dir.addChild(file);
+ res.setRoot(root);
+
+ JSONAssert
+ .assertEquals(
+ IOUtils.toString(this.getClass().getResourceAsStream("ReportResourceTest/expected.json"), "UTF-8"),
+ res.toJson(), true);
+ }
+
+ @Test
+ public void from_json() throws Exception {
+ ReportResources res = ReportResources
+ .fromJson(
+ IOUtils.toString(this.getClass().getResourceAsStream("ReportResourceTest/expected.json"), "UTF-8"));
+
+ assertThat(res.analysisDate()).isEqualTo(new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2012"));
+ ReportResource root = res.root();
+ assertThat(root.batchId()).isEqualTo(1);
+ assertThat(root.id()).isEqualTo(11);
+ assertThat(root.name()).isEqualTo("Root project");
+ assertThat(root.snapshotId()).isEqualTo(111);
+ assertThat(root.path()).isNull();
+ assertThat(root.type()).isEqualTo(Type.PRJ);
+ assertThat(root.children()).hasSize(1);
+
+ }
+}
diff --git a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json
new file mode 100644
index 00000000000..4c642a06ba0
--- /dev/null
+++ b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json
@@ -0,0 +1,41 @@
+{
+ "analysisDate": "2012-12-12T00:00:00+0100",
+ "root": {
+ "batchId": 1,
+ "id": 11,
+ "snapshotId": 111,
+ "name": "Root project",
+ "type": "PRJ",
+ "children": [
+ {
+ "batchId": 2,
+ "id": 22,
+ "snapshotId": 222,
+ "path": "module1",
+ "name": "Module",
+ "type": "MOD",
+ "children": [
+ {
+ "batchId": 3,
+ "id": 33,
+ "snapshotId": 333,
+ "path": "src",
+ "name": "src",
+ "type": "DIR",
+ "children": [
+ {
+ "batchId": 4,
+ "id": 44,
+ "snapshotId": 444,
+ "path": "Foo.java",
+ "name": "Foo.java",
+ "type": "FIL",
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml
index eadff107bcb..2696cbe7fff 100644
--- a/sonar-batch/pom.xml
+++ b/sonar-batch/pom.xml
@@ -123,6 +123,10 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.github.kevinsawicki</groupId>
+ <artifactId>http-request</artifactId>
+ </dependency>
<!-- unit tests -->
<dependency>
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java
index 0acc0a94232..470f0f79686 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java
@@ -132,18 +132,18 @@ public class ServerClient implements BatchComponent {
return new IllegalStateException(String.format("Fail to execute request [code=%s, url=%s]", he.getResponseCode(), he.getUri()), he);
}
- private String getMessageWhenNotAuthorized() {
+ public String getMessageWhenNotAuthorized() {
if (Strings.isNullOrEmpty(getLogin()) && Strings.isNullOrEmpty(getPassword())) {
return "Not authorized. Analyzing this project requires to be authenticated. Please provide the values of the properties %s and %s.";
}
return "Not authorized. Please check the properties %s and %s.";
}
- private String getLogin() {
+ public String getLogin() {
return props.property(CoreProperties.LOGIN);
}
- private String getPassword() {
+ public String getPassword() {
return props.property(CoreProperties.PASSWORD);
}
@@ -155,4 +155,5 @@ public class ServerClient implements BatchComponent {
throw new IllegalStateException("Encoding not supported", e);
}
}
+
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/BatchResource.java
index 2e5de75acb1..dd3406b824b 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/BatchResource.java
@@ -19,33 +19,55 @@
*/
package org.sonar.batch.index;
-import org.sonar.api.batch.Event;
import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.design.Dependency;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectLink;
import org.sonar.api.resources.Resource;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
-public interface PersistenceManager {
- void clear();
+public class BatchResource {
- void saveProject(Project project, @Nullable Project parent);
+ private final long batchId;
+ private final Resource r;
+ private final Snapshot s;
+ private final BatchResource parent;
+ private final Collection<BatchResource> children = new ArrayList<BatchResource>();
- Snapshot saveResource(Project project, Resource resource, @Nullable Resource parent);
+ public BatchResource(long batchId, Resource r, Snapshot s, @Nullable BatchResource parent) {
+ this.batchId = batchId;
+ this.r = r;
+ this.s = s;
+ this.parent = parent;
+ if (parent != null) {
+ parent.children.add(this);
+ }
+ }
- void saveDependency(Project project, Dependency dependency, Dependency parentDependency);
+ public long batchId() {
+ return batchId;
+ }
- void saveLink(Project project, ProjectLink link);
+ public Resource resource() {
+ return r;
+ }
- void deleteLink(Project project, String key);
+ public int snapshotId() {
+ return s.getId();
+ }
- List<Event> getEvents(Resource resource);
+ public Snapshot snapshot() {
+ return s;
+ }
- void deleteEvent(Event event);
+ @CheckForNull
+ public BatchResource parent() {
+ return parent;
+ }
- void saveEvent(Resource resource, Event event);
+ public Collection<BatchResource> children() {
+ return children;
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
index a3133af5c25..c111c485e49 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
@@ -19,6 +19,7 @@
*/
package org.sonar.batch.index;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -30,7 +31,6 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Event;
import org.sonar.api.batch.SonarIndex;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilter;
@@ -76,7 +76,7 @@ public class DefaultIndex extends SonarIndex {
private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class);
- private PersistenceManager persistence;
+ private ResourcePersister resourcePersister;
private MetricFinder metricFinder;
private final ScanGraph graph;
@@ -91,12 +91,18 @@ public class DefaultIndex extends SonarIndex {
private final DeprecatedViolations deprecatedViolations;
private ModuleIssues moduleIssues;
private final MeasureCache measureCache;
+ private final ResourceKeyMigration migration;
+ private final DependencyPersister dependencyPersister;
+ private final LinkPersister linkPersister;
+ private final EventPersister eventPersister;
- private ResourceKeyMigration migration;
-
- public DefaultIndex(PersistenceManager persistence, ProjectTree projectTree, MetricFinder metricFinder,
+ public DefaultIndex(ResourcePersister resourcePersister, DependencyPersister dependencyPersister,
+ LinkPersister linkPersister, EventPersister eventPersister, ProjectTree projectTree, MetricFinder metricFinder,
ScanGraph graph, DeprecatedViolations deprecatedViolations, ResourceKeyMigration migration, MeasureCache measureCache) {
- this.persistence = persistence;
+ this.resourcePersister = resourcePersister;
+ this.dependencyPersister = dependencyPersister;
+ this.linkPersister = linkPersister;
+ this.eventPersister = eventPersister;
this.projectTree = projectTree;
this.metricFinder = metricFinder;
this.graph = graph;
@@ -116,7 +122,7 @@ public class DefaultIndex extends SonarIndex {
Bucket bucket = new Bucket(rootProject);
addBucket(rootProject, bucket);
migration.checkIfMigrationNeeded(rootProject);
- persistence.saveProject(rootProject, null);
+ resourcePersister.saveProject(rootProject, null);
currentProject = rootProject;
for (Project module : rootProject.getModules()) {
@@ -247,7 +253,13 @@ public class DefaultIndex extends SonarIndex {
@Override
public Dependency addDependency(Dependency dependency) {
- Dependency existingDep = getEdge(dependency.getFrom(), dependency.getTo());
+ // Reload resources
+ Resource from = getResource(dependency.getFrom());
+ Preconditions.checkArgument(from != null, dependency.getFrom() + " is not indexed");
+ Resource to = getResource(dependency.getTo());
+ Preconditions.checkArgument(to != null, dependency.getTo() + " is not indexed");
+
+ Dependency existingDep = getEdge(from, to);
if (existingDep != null) {
return existingDep;
}
@@ -258,7 +270,7 @@ public class DefaultIndex extends SonarIndex {
}
if (registerDependency(dependency)) {
- persistence.saveDependency(currentProject, dependency, parentDependency);
+ dependencyPersister.saveDependency(currentProject, from, to, dependency, parentDependency);
}
return dependency;
}
@@ -439,12 +451,12 @@ public class DefaultIndex extends SonarIndex {
@Override
public void addLink(ProjectLink link) {
- persistence.saveLink(currentProject, link);
+ linkPersister.saveLink(currentProject, link);
}
@Override
public void deleteLink(String key) {
- persistence.deleteLink(currentProject, key);
+ linkPersister.deleteLink(currentProject, key);
}
//
@@ -458,12 +470,16 @@ public class DefaultIndex extends SonarIndex {
@Override
public List<Event> getEvents(Resource resource) {
// currently events are not cached in memory
- return persistence.getEvents(resource);
+ Resource reload = getResource(resource);
+ if (reload == null) {
+ return Collections.emptyList();
+ }
+ return eventPersister.getEvents(reload);
}
@Override
public void deleteEvent(Event event) {
- persistence.deleteEvent(event);
+ eventPersister.deleteEvent(event);
}
@Override
@@ -472,7 +488,7 @@ public class DefaultIndex extends SonarIndex {
event.setDate(date);
event.setCreatedAt(new Date());
- persistence.saveEvent(resource, event);
+ eventPersister.saveEvent(resource, event);
return null;
}
@@ -579,9 +595,9 @@ public class DefaultIndex extends SonarIndex {
addBucket(resource, bucket);
Resource parentResource = parentBucket != null ? parentBucket.getResource() : null;
- Snapshot snapshot = persistence.saveResource(currentProject, resource, parentResource);
+ BatchResource batchResource = resourcePersister.saveResource(currentProject, resource, parentResource);
if (ResourceUtils.isPersistable(resource) && !Qualifiers.LIBRARY.equals(resource.getQualifier())) {
- graph.addComponent(resource, snapshot);
+ graph.addComponent(resource, batchResource.snapshotId());
}
return bucket;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
deleted file mode 100644
index 8e36e703b28..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
+++ /dev/null
@@ -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.index;
-
-import org.sonar.api.batch.Event;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.design.Dependency;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectLink;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-
-import javax.annotation.Nullable;
-
-import java.util.List;
-
-public final class DefaultPersistenceManager implements PersistenceManager {
-
- private ResourcePersister resourcePersister;
- private DependencyPersister dependencyPersister;
- private LinkPersister linkPersister;
- private EventPersister eventPersister;
-
- public DefaultPersistenceManager(ResourcePersister resourcePersister,
- DependencyPersister dependencyPersister, LinkPersister linkPersister, EventPersister eventPersister) {
- this.resourcePersister = resourcePersister;
- this.dependencyPersister = dependencyPersister;
- this.linkPersister = linkPersister;
- this.eventPersister = eventPersister;
- }
-
- @Override
- public void clear() {
- resourcePersister.clear();
- }
-
- @Override
- public void saveProject(Project project, @Nullable Project parent) {
- resourcePersister.saveProject(project, parent);
- }
-
- @Override
- public Snapshot saveResource(Project project, Resource resource, @Nullable Resource parent) {
- if (ResourceUtils.isPersistable(resource)) {
- return resourcePersister.saveResource(project, resource, parent);
- }
- return null;
- }
-
- @Override
- public void saveDependency(Project project, Dependency dependency, Dependency parentDependency) {
- if (ResourceUtils.isPersistable(dependency.getFrom()) && ResourceUtils.isPersistable(dependency.getTo())) {
- dependencyPersister.saveDependency(project, dependency, parentDependency);
- }
- }
-
- @Override
- public void saveLink(Project project, ProjectLink link) {
- linkPersister.saveLink(project, link);
- }
-
- @Override
- public void deleteLink(Project project, String key) {
- linkPersister.deleteLink(project, key);
- }
-
- @Override
- public List<Event> getEvents(Resource resource) {
- return eventPersister.getEvents(resource);
- }
-
- @Override
- public void deleteEvent(Event event) {
- eventPersister.deleteEvent(event);
- }
-
- @Override
- public void saveEvent(Resource resource, Event event) {
- if (ResourceUtils.isPersistable(resource)) {
- eventPersister.saveEvent(resource, event);
- }
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
index 0f7faddb25f..b7d5418555c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
@@ -19,14 +19,11 @@
*/
package org.sonar.batch.index;
-import com.google.common.collect.Maps;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.resources.File;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Library;
import org.sonar.api.resources.Project;
@@ -38,15 +35,12 @@ import org.sonar.api.security.ResourcePermissions;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.internal.Uuids;
-import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import java.util.Date;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
public final class DefaultResourcePersister implements ResourcePersister {
@@ -57,37 +51,26 @@ public final class DefaultResourcePersister implements ResourcePersister {
private static final String QUALIFIER = "qualifier";
private final DatabaseSession session;
- private final Map<Resource, Snapshot> snapshotsByResource = Maps.newHashMap();
private final ResourcePermissions permissions;
- private final SnapshotCache snapshotCache;
private final ResourceCache resourceCache;
- public DefaultResourcePersister(DatabaseSession session, ResourcePermissions permissions, SnapshotCache snapshotCache, ResourceCache resourceCache) {
+ public DefaultResourcePersister(DatabaseSession session, ResourcePermissions permissions, ResourceCache resourceCache) {
this.session = session;
this.permissions = permissions;
- this.snapshotCache = snapshotCache;
this.resourceCache = resourceCache;
}
@Override
- public Snapshot saveProject(Project project, @Nullable Project parent) {
- Snapshot snapshot = snapshotsByResource.get(project);
- if (snapshot == null) {
- snapshot = persistProject(project, parent);
+ public void saveProject(Project project, @Nullable Project parent) {
+ BatchResource batchResource = resourceCache.get(project.getEffectiveKey());
+ if (batchResource == null) {
+ Snapshot snapshot = persistProject(project, parent);
addToCache(project, snapshot);
}
- return snapshot;
}
- private void addToCache(Resource resource, Snapshot snapshot) {
- if (snapshot != null) {
- snapshotsByResource.put(resource, snapshot);
- resourceCache.add(resource);
- if (!(resource instanceof Library)) {
- // Maven libraries can have the same effective key than a project so we can't cache by effectiveKey
- snapshotCache.put(resource.getEffectiveKey(), snapshot);
- }
- }
+ private BatchResource addToCache(Resource resource, Snapshot snapshot) {
+ return resourceCache.add(resource, snapshot);
}
private Snapshot persistProject(Project project, @Nullable Project parent) {
@@ -108,7 +91,7 @@ public final class DefaultResourcePersister implements ResourcePersister {
Snapshot parentSnapshot = null;
if (parent != null) {
// assume that the parent project has already been saved
- parentSnapshot = snapshotsByResource.get(project.getParent());
+ parentSnapshot = resourceCache.get(project.getParent().getEffectiveKey()).snapshot();
model.setRootId((Integer) ObjectUtils.defaultIfNull(parentSnapshot.getRootProjectId(), parentSnapshot.getResourceId()));
} else {
model.setRootId(null);
@@ -132,49 +115,18 @@ public final class DefaultResourcePersister implements ResourcePersister {
}
@Override
- @CheckForNull
- public Snapshot getSnapshot(@Nullable Resource reference) {
- return snapshotsByResource.get(reference);
- }
-
- @Override
- public Snapshot getSnapshotOrFail(Resource resource) {
- Snapshot snapshot = getSnapshot(resource);
- if (snapshot == null) {
- throw new ResourceNotPersistedException(resource);
- }
- return snapshot;
- }
-
- @Override
- public Snapshot getSnapshotOrFail(InputFile inputFile) {
- return getSnapshotOrFail(fromInputFile(inputFile));
- }
-
- private Resource fromInputFile(InputFile inputFile) {
- return File.create(inputFile.relativePath());
- }
-
- /**
- * just for unit tests
- */
- Map<Resource, Snapshot> getSnapshotsByResource() {
- return snapshotsByResource;
- }
-
- @Override
- public Snapshot saveResource(Project project, Resource resource) {
+ public BatchResource saveResource(Project project, Resource resource) {
return saveResource(project, resource, null);
}
@Override
- public Snapshot saveResource(Project project, Resource resource, @Nullable Resource parent) {
- Snapshot snapshot = snapshotsByResource.get(resource);
- if (snapshot == null) {
- snapshot = persist(project, resource, parent);
- addToCache(resource, snapshot);
+ public BatchResource saveResource(Project project, Resource resource, @Nullable Resource parent) {
+ BatchResource batchResource = resourceCache.get(resource.getEffectiveKey());
+ if (batchResource == null || ResourceUtils.isLibrary(resource)) {
+ Snapshot s = persist(project, resource, parent);
+ batchResource = addToCache(resource, s);
}
- return snapshot;
+ return batchResource;
}
private Snapshot persist(Project project, Resource resource, @Nullable Resource parent) {
@@ -237,15 +189,21 @@ public final class DefaultResourcePersister implements ResourcePersister {
* Everything except project and library
*/
private Snapshot persistFileOrDirectory(Project project, Resource resource, @Nullable Resource parentReference) {
- Snapshot moduleSnapshot = snapshotsByResource.get(project);
- Integer moduleId = moduleSnapshot.getResourceId();
+ BatchResource moduleResource = resourceCache.get(project.getEffectiveKey());
+ Integer moduleId = moduleResource.resource().getId();
ResourceModel model = findOrCreateModel(resource, parentReference != null ? parentReference : project);
model.setRootId(moduleId);
model = session.save(model);
resource.setId(model.getId());
resource.setUuid(model.getUuid());
- Snapshot parentSnapshot = (Snapshot) ObjectUtils.defaultIfNull(getSnapshot(parentReference), moduleSnapshot);
+ Snapshot parentSnapshot;
+ if (parentReference != null) {
+ parentSnapshot = resourceCache.get(parentReference.getEffectiveKey()).snapshot();
+ } else {
+ parentSnapshot = moduleResource.snapshot();
+ }
+
Snapshot snapshot = new Snapshot(model, parentSnapshot);
snapshot.setBuildDate(new Date());
snapshot = session.save(snapshot);
@@ -253,33 +211,6 @@ public final class DefaultResourcePersister implements ResourcePersister {
return snapshot;
}
- @Override
- @CheckForNull
- public Snapshot getLastSnapshot(Snapshot snapshot, boolean onlyOlder) {
- String hql = "SELECT s FROM " + Snapshot.class.getSimpleName() + " s WHERE s.last=:last AND s.resourceId=:resourceId";
- if (onlyOlder) {
- hql += " AND s.createdAt<:date";
- }
- Query query = session.createQuery(hql);
- query.setParameter(LAST, true);
- query.setParameter(RESOURCE_ID, snapshot.getResourceId());
- if (onlyOlder) {
- query.setParameter("date", snapshot.getCreatedAt());
- }
- return session.getSingleResult(query, null);
- }
-
- @Override
- public void clear() {
- // we keep cache of projects
- for (Iterator<Map.Entry<Resource, Snapshot>> it = snapshotsByResource.entrySet().iterator(); it.hasNext();) {
- Map.Entry<Resource, Snapshot> entry = it.next();
- if (!ResourceUtils.isSet(entry.getKey())) {
- it.remove();
- }
- }
- }
-
private ResourceModel findOrCreateModel(Resource resource, @Nullable Resource parentResource) {
ResourceModel model;
try {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java
index e20680b10fc..15886b6b4ac 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java
@@ -20,38 +20,38 @@
package org.sonar.batch.index;
import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.design.Dependency;
import org.sonar.api.design.DependencyDto;
import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
public final class DependencyPersister {
- private ResourcePersister resourcePersister;
+ private ResourceCache resourceCache;
private DatabaseSession session;
- public DependencyPersister(ResourcePersister resourcePersister, DatabaseSession session) {
- this.resourcePersister = resourcePersister;
+ public DependencyPersister(ResourceCache resourceCache, DatabaseSession session) {
+ this.resourceCache = resourceCache;
this.session = session;
}
- public void saveDependency(Project project, Dependency dependency, Dependency parentDependency) {
- Snapshot fromSnapshot = resourcePersister.saveResource(project, dependency.getFrom());
- Snapshot toSnapshot = resourcePersister.saveResource(project, dependency.getTo());
- Snapshot projectSnapshot = resourcePersister.getSnapshotOrFail(project);
+ public void saveDependency(Project project, Resource from, Resource to, Dependency dependency, Dependency parentDependency) {
+ BatchResource fromResource = resourceCache.get(from);
+ BatchResource toResource = resourceCache.get(to);
+ BatchResource projectResource = resourceCache.get(project);
DependencyDto model = new DependencyDto();
- model.setProjectSnapshotId(projectSnapshot.getId());
+ model.setProjectSnapshotId(projectResource.snapshotId());
model.setUsage(dependency.getUsage());
model.setWeight(dependency.getWeight());
- model.setFromResourceId(fromSnapshot.getResourceId());
- model.setFromScope(fromSnapshot.getScope());
- model.setFromSnapshotId(fromSnapshot.getId());
+ model.setFromResourceId(fromResource.resource().getId());
+ model.setFromScope(fromResource.resource().getScope());
+ model.setFromSnapshotId(fromResource.snapshotId());
- model.setToResourceId(toSnapshot.getResourceId());
- model.setToSnapshotId(toSnapshot.getId());
- model.setToScope(toSnapshot.getScope());
+ model.setToResourceId(toResource.resource().getId());
+ model.setToScope(toResource.resource().getScope());
+ model.setToSnapshotId(toResource.snapshotId());
if (parentDependency != null) {
// assume that it has been previously saved
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
index ae234e553cf..ce3067839f4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
@@ -22,11 +22,9 @@ package org.sonar.batch.index;
import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.api.database.model.MeasureMapper;
import org.sonar.api.database.model.MeasureModel;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.PersistenceMode;
-import org.sonar.api.resources.Resource;
import org.sonar.api.rules.RuleFinder;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.duplication.DuplicationUtils;
@@ -39,17 +37,14 @@ import java.util.List;
public final class DuplicationPersister implements ScanPersister {
private final MyBatis mybatis;
private final RuleFinder ruleFinder;
- private final SnapshotCache snapshotCache;
private final ResourceCache resourceCache;
private final DuplicationCache duplicationCache;
private final org.sonar.api.measures.MetricFinder metricFinder;
- public DuplicationPersister(MyBatis mybatis, RuleFinder ruleFinder,
- SnapshotCache snapshotCache, ResourceCache resourceCache,
+ public DuplicationPersister(MyBatis mybatis, RuleFinder ruleFinder, ResourceCache resourceCache,
DuplicationCache duplicationCache, org.sonar.api.measures.MetricFinder metricFinder) {
this.mybatis = mybatis;
this.ruleFinder = ruleFinder;
- this.snapshotCache = snapshotCache;
this.resourceCache = resourceCache;
this.duplicationCache = duplicationCache;
this.metricFinder = metricFinder;
@@ -65,11 +60,10 @@ public final class DuplicationPersister implements ScanPersister {
for (Entry<List<DuplicationGroup>> entry : duplicationCache.entries()) {
String effectiveKey = entry.key()[0].toString();
Measure measure = new Measure(duplicationMetricWithId, DuplicationUtils.toXml(entry.value())).setPersistenceMode(PersistenceMode.DATABASE);
- Resource resource = resourceCache.get(effectiveKey);
+ BatchResource batchResource = resourceCache.get(effectiveKey);
- if (MeasurePersister.shouldPersistMeasure(resource, measure)) {
- Snapshot snapshot = snapshotCache.get(effectiveKey);
- MeasureModel measureModel = MeasurePersister.model(measure, ruleFinder).setSnapshotId(snapshot.getId());
+ if (MeasurePersister.shouldPersistMeasure(batchResource.resource(), measure)) {
+ MeasureModel measureModel = MeasurePersister.model(measure, ruleFinder).setSnapshotId(batchResource.snapshotId());
mapper.insert(measureModel);
session.commit();
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
index 3968464c9b1..36ac996ae58 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
@@ -21,27 +21,21 @@ package org.sonar.batch.index;
import org.sonar.api.batch.Event;
import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Resource;
-import java.util.Collections;
import java.util.List;
-public final class EventPersister {
+public class EventPersister {
private DatabaseSession session;
- private ResourcePersister resourcePersister;
+ private ResourceCache resourceCache;
- public EventPersister(DatabaseSession session, ResourcePersister resourcePersister) {
+ public EventPersister(DatabaseSession session, ResourceCache resourceCache) {
this.session = session;
- this.resourcePersister = resourcePersister;
+ this.resourceCache = resourceCache;
}
public List<Event> getEvents(Resource resource) {
- Snapshot snapshot = resourcePersister.getSnapshot(resource);
- if (snapshot == null) {
- return Collections.emptyList();
- }
- return session.getResults(Event.class, "resourceId", snapshot.getResourceId());
+ return session.getResults(Event.class, "resourceId", resource.getId());
}
public void deleteEvent(Event event) {
@@ -50,11 +44,11 @@ public final class EventPersister {
}
public void saveEvent(Resource resource, Event event) {
- Snapshot snapshot = resourcePersister.getSnapshotOrFail(resource);
+ BatchResource batchResource = resourceCache.get(resource.getEffectiveKey());
if (event.getDate() == null) {
- event.setSnapshot(snapshot);
+ event.setSnapshot(batchResource.snapshot());
} else {
- event.setResourceId(snapshot.getResourceId());
+ event.setResourceId(batchResource.resource().getId());
}
session.save(event);
session.commit();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/FileHashesPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/FileHashesPersister.java
index 9ecc91bf0cf..85e182281fa 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/FileHashesPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/FileHashesPersister.java
@@ -19,28 +19,25 @@
*/
package org.sonar.batch.index;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.source.SnapshotDataTypes;
import org.sonar.core.source.db.SnapshotDataDao;
import org.sonar.core.source.db.SnapshotDataDto;
-import java.util.Map;
-
/**
* Store file hashes in snapshot_data for reuse in next analysis to know if a file is modified
*/
public class FileHashesPersister implements ScanPersister {
private final ComponentDataCache data;
- private final SnapshotCache snapshots;
+ private final ResourceCache resourceCache;
private final SnapshotDataDao dao;
private final MyBatis mybatis;
- public FileHashesPersister(ComponentDataCache data, SnapshotCache snapshots,
+ public FileHashesPersister(ComponentDataCache data, ResourceCache resourceCache,
SnapshotDataDao dao, MyBatis mybatis) {
this.data = data;
- this.snapshots = snapshots;
+ this.resourceCache = resourceCache;
this.dao = dao;
this.mybatis = mybatis;
}
@@ -49,14 +46,13 @@ public class FileHashesPersister implements ScanPersister {
public void persist() {
DbSession session = mybatis.openSession(true);
try {
- for (Map.Entry<String, Snapshot> componentEntry : snapshots.snapshots()) {
- String componentKey = componentEntry.getKey();
- Snapshot snapshot = componentEntry.getValue();
+ for (BatchResource batchResource : resourceCache.all()) {
+ String componentKey = batchResource.resource().getEffectiveKey();
String fileHashesdata = data.getStringData(componentKey, SnapshotDataTypes.FILE_HASHES);
if (fileHashesdata != null) {
SnapshotDataDto dto = new SnapshotDataDto();
- dto.setSnapshotId(snapshot.getId());
- dto.setResourceId(snapshot.getResourceId());
+ dto.setSnapshotId(batchResource.snapshotId());
+ dto.setResourceId(batchResource.resource().getId());
dto.setDataType(SnapshotDataTypes.FILE_HASHES);
dto.setData(fileHashesdata);
dao.insert(session, dto);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java
index b29a66d8c9a..3ab649150ae 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java
@@ -21,22 +21,21 @@ package org.sonar.batch.index;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.ResourceModel;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.ProjectLink;
public final class LinkPersister {
private DatabaseSession session;
- private ResourcePersister resourcePersister;
+ private ResourceCache resourceCache;
- public LinkPersister(DatabaseSession session, ResourcePersister resourcePersister) {
+ public LinkPersister(DatabaseSession session, ResourceCache resourcePersister) {
this.session = session;
- this.resourcePersister = resourcePersister;
+ this.resourceCache = resourcePersister;
}
public void saveLink(Project project, ProjectLink link) {
- Snapshot snapshot = resourcePersister.getSnapshotOrFail(project);
- ResourceModel projectDao = session.reattach(ResourceModel.class, snapshot.getResourceId());
+ BatchResource batchResource = resourceCache.get(project.getEffectiveKey());
+ ResourceModel projectDao = session.reattach(ResourceModel.class, batchResource.resource().getId());
ProjectLink dbLink = projectDao.getProjectLink(link.getKey());
if (dbLink == null) {
link.setResource(projectDao);
@@ -52,9 +51,9 @@ public final class LinkPersister {
}
public void deleteLink(Project project, String linkKey) {
- Snapshot snapshot = resourcePersister.getSnapshot(project);
- if (snapshot != null) {
- ResourceModel model = session.reattach(ResourceModel.class, snapshot.getResourceId());
+ BatchResource batchResource = resourceCache.get(project.getEffectiveKey());
+ if (batchResource != null) {
+ ResourceModel model = session.reattach(ResourceModel.class, batchResource.resource().getId());
ProjectLink dbLink = model.getProjectLink(linkKey);
if (dbLink != null) {
session.remove(dbLink);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
index 6c382abfa1a..4d4b2b26433 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
@@ -22,7 +22,6 @@ package org.sonar.batch.index;
import com.google.common.annotations.VisibleForTesting;
import org.sonar.api.database.model.MeasureMapper;
import org.sonar.api.database.model.MeasureModel;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.RuleMeasure;
import org.sonar.api.resources.Resource;
@@ -42,15 +41,13 @@ public final class MeasurePersister implements ScanPersister {
private final MyBatis mybatis;
private final RuleFinder ruleFinder;
private final MeasureCache measureCache;
- private final SnapshotCache snapshotCache;
private final ResourceCache resourceCache;
public MeasurePersister(MyBatis mybatis, RuleFinder ruleFinder,
- MeasureCache measureCache, SnapshotCache snapshotCache, ResourceCache resourceCache) {
+ MeasureCache measureCache, ResourceCache resourceCache) {
this.mybatis = mybatis;
this.ruleFinder = ruleFinder;
this.measureCache = measureCache;
- this.snapshotCache = snapshotCache;
this.resourceCache = resourceCache;
}
@@ -63,11 +60,10 @@ public final class MeasurePersister implements ScanPersister {
for (Entry<Measure> entry : measureCache.entries()) {
String effectiveKey = entry.key()[0].toString();
Measure measure = entry.value();
- Resource resource = resourceCache.get(effectiveKey);
+ BatchResource batchResource = resourceCache.get(effectiveKey);
- if (shouldPersistMeasure(resource, measure)) {
- Snapshot snapshot = snapshotCache.get(effectiveKey);
- MeasureModel measureModel = model(measure, ruleFinder).setSnapshotId(snapshot.getId());
+ if (shouldPersistMeasure(batchResource.resource(), measure)) {
+ MeasureModel measureModel = model(measure, ruleFinder).setSnapshotId(batchResource.snapshotId());
mapper.insert(measureModel);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
index 329a0184b46..088a50de84c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
@@ -23,25 +23,51 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.sonar.api.BatchComponent;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Library;
import org.sonar.api.resources.Resource;
+import javax.annotation.CheckForNull;
+
+import java.util.Collection;
import java.util.Map;
-/**
- * @since 3.6
- */
public class ResourceCache implements BatchComponent {
// resource by component key
- private final Map<String, Resource> resources = Maps.newHashMap();
+ private final Map<String, BatchResource> resources = Maps.newHashMap();
+ // dedicated cache for libraries
+ private final Map<Library, BatchResource> libraries = Maps.newHashMap();
- public Resource get(String componentKey) {
+ @CheckForNull
+ public BatchResource get(String componentKey) {
return resources.get(componentKey);
}
- public ResourceCache add(Resource resource) {
+ @CheckForNull
+ public BatchResource get(Resource resource) {
+ if (!(resource instanceof Library)) {
+ return resources.get(resource.getEffectiveKey());
+ } else {
+ return libraries.get(resource);
+ }
+ }
+
+ public BatchResource add(Resource resource, Snapshot s) {
String componentKey = resource.getEffectiveKey();
Preconditions.checkState(!Strings.isNullOrEmpty(componentKey), "Missing resource effective key");
- resources.put(componentKey, resource);
- return this;
+ Resource parentResource = resource.getParent();
+ BatchResource parent = parentResource != null ? get(parentResource.getEffectiveKey()) : null;
+ BatchResource batchResource = new BatchResource((long) resources.size() + 1, resource, s, parent);
+ if (!(resource instanceof Library)) {
+ // Libraries can have the same effective key than a project so we can't cache by effectiveKey
+ resources.put(componentKey, batchResource);
+ } else {
+ libraries.put((Library) resource, batchResource);
+ }
+ return batchResource;
+ }
+
+ public Collection<BatchResource> all() {
+ return resources.values();
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
index d5a535dc27a..edb47fb6f54 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
@@ -19,41 +19,23 @@
*/
package org.sonar.batch.index;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
-import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
public interface ResourcePersister {
- Snapshot saveProject(Project project, @Nullable Project parent);
+ void saveProject(Project project, @Nullable Project parent);
/**
- * Persist a resource in database. Returns null if the resource must not be persisted (scope lower than file)
+ * Persist a resource in database.
*/
- Snapshot saveResource(Project project, Resource resource, @Nullable Resource parent);
+ BatchResource saveResource(Project project, Resource resource, @Nullable Resource parent);
/**
- * Persist a resource in database. Returns null if the resource must not be persisted (scope lower than file)
+ * Persist a resource in database.
*/
- Snapshot saveResource(Project project, Resource resource);
+ BatchResource saveResource(Project project, Resource resource);
- @CheckForNull
- Snapshot getSnapshot(Resource resource);
-
- Snapshot getSnapshotOrFail(Resource resource);
-
- Snapshot getSnapshotOrFail(InputFile resource);
-
- /**
- * The current snapshot which is flagged as "last", different than the current analysis.
- * @param onlyOlder true if the result must be anterior to the snapshot parameter
- */
- @CheckForNull
- Snapshot getLastSnapshot(Snapshot snapshot, boolean onlyOlder);
-
- void clear();
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java
index 186e37edaa6..5f10cbabf58 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java
@@ -130,7 +130,7 @@ public class SourcePersister implements ScanPersister {
private void persist(DbSession session, FileSourceMapper mapper, InputPath inputPath, Map<String, FileSourceDto> fileSourceDtoByFileUuid) {
DefaultInputFile inputFile = (DefaultInputFile) inputPath;
LOG.debug("Processing {}", inputFile.absolutePath());
- org.sonar.api.resources.File file = (org.sonar.api.resources.File) resourceCache.get(inputFile.key());
+ org.sonar.api.resources.File file = (org.sonar.api.resources.File) resourceCache.get(inputFile.key()).resource();
String fileUuid = file.getUuid();
FileSourceDto previous = fileSourceDtoByFileUuid.get(fileUuid);
String newData = getSourceData(inputFile);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java
index 883c854af76..13e03a3f9c6 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java
@@ -59,7 +59,7 @@ public class DeprecatedViolations implements BatchComponent {
public Violation toViolation(DefaultIssue issue) {
Rule rule = ruleFinder.findByKey(issue.ruleKey());
- Resource resource = resourceCache.get(issue.componentKey());
+ Resource resource = resourceCache.get(issue.componentKey()).resource();
Violation violation = new Violation(rule, resource);
violation.setNew(issue.isNew());
violation.setChecksum(issue.checksum());
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssueStorage.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssueStorage.java
index 040bb9cce0e..87e93205009 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssueStorage.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssueStorage.java
@@ -21,13 +21,13 @@ package org.sonar.batch.issue;
import com.google.common.annotations.VisibleForTesting;
import org.sonar.api.BatchComponent;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.batch.ProjectTree;
-import org.sonar.batch.index.SnapshotCache;
+import org.sonar.batch.index.BatchResource;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.issue.db.IssueDto;
import org.sonar.core.issue.db.IssueMapper;
import org.sonar.core.issue.db.IssueStorage;
@@ -44,14 +44,14 @@ import java.util.List;
public class ScanIssueStorage extends IssueStorage implements BatchComponent {
- private final SnapshotCache snapshotCache;
+ private final ResourceCache resourceCache;
private final ResourceDao resourceDao;
private final ProjectTree projectTree;
private final UpdateConflictResolver conflictResolver = new UpdateConflictResolver();
- public ScanIssueStorage(MyBatis mybatis, RuleFinder ruleFinder, SnapshotCache snapshotCache, ResourceDao resourceDao, ProjectTree projectTree) {
+ public ScanIssueStorage(MyBatis mybatis, RuleFinder ruleFinder, ResourceCache resourceCache, ResourceDao resourceDao, ProjectTree projectTree) {
super(mybatis, ruleFinder);
- this.snapshotCache = snapshotCache;
+ this.resourceCache = resourceCache;
this.resourceDao = resourceDao;
this.projectTree = projectTree;
}
@@ -90,9 +90,9 @@ public class ScanIssueStorage extends IssueStorage implements BatchComponent {
@VisibleForTesting
long componentId(DefaultIssue issue) {
- Snapshot snapshot = snapshotCache.get(issue.componentKey());
- if (snapshot != null) {
- return snapshot.getResourceId();
+ BatchResource resource = resourceCache.get(issue.componentKey());
+ if (resource != null) {
+ return resource.resource().getId();
}
// Load from db when component does not exist in cache (deleted file for example)
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java
index aba3f6fa9e2..286a20476b4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java
@@ -28,9 +28,9 @@ import org.sonar.batch.bootstrap.AnalysisMode;
import org.sonar.batch.events.BatchStepEvent;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
-import org.sonar.batch.index.PersistenceManager;
import org.sonar.batch.index.ScanPersister;
import org.sonar.batch.issue.ignore.scanner.IssueExclusionsLoader;
+import org.sonar.batch.report.PublishReportJob;
import org.sonar.batch.rule.QProfileVerifier;
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.batch.scan.filesystem.FileSystemLogger;
@@ -50,8 +50,7 @@ public final class PhaseExecutor {
private final PostJobsExecutor postJobsExecutor;
private final InitializersExecutor initializersExecutor;
private final SensorsExecutor sensorsExecutor;
- private final UpdateStatusJob updateStatusJob;
- private final PersistenceManager persistenceManager;
+ private final PublishReportJob publishReportJob;
private final SensorContext sensorContext;
private final DefaultIndex index;
private final ProjectInitializer pi;
@@ -66,8 +65,8 @@ public final class PhaseExecutor {
public PhaseExecutor(Phases phases, DecoratorsExecutor decoratorsExecutor,
MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, UpdateStatusJob updateStatusJob, ProjectInitializer pi,
+ SensorContext sensorContext, DefaultIndex index,
+ EventBus eventBus, PublishReportJob publishReportJob, ProjectInitializer pi,
ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
IssueExclusionsLoader issueExclusionsLoader, AnalysisMode analysisMode) {
this.phases = phases;
@@ -76,11 +75,10 @@ public final class PhaseExecutor {
this.postJobsExecutor = postJobsExecutor;
this.initializersExecutor = initializersExecutor;
this.sensorsExecutor = sensorsExecutor;
- this.persistenceManager = persistenceManager;
this.sensorContext = sensorContext;
this.index = index;
this.eventBus = eventBus;
- this.updateStatusJob = updateStatusJob;
+ this.publishReportJob = publishReportJob;
this.pi = pi;
this.persisters = persisters;
this.fsLogger = fsLogger;
@@ -94,7 +92,7 @@ public final class PhaseExecutor {
public static Collection<Class> getPhaseClasses() {
return Lists.<Class>newArrayList(DecoratorsExecutor.class, MavenPluginsConfigurator.class,
PostJobsExecutor.class, SensorsExecutor.class,
- InitializersExecutor.class, ProjectInitializer.class, UpdateStatusJob.class);
+ InitializersExecutor.class, ProjectInitializer.class, PublishReportJob.class);
}
/**
@@ -130,7 +128,7 @@ public final class PhaseExecutor {
jsonReport.execute();
executePersisters();
- updateStatusJob();
+ publishReportJob();
if (phases.isEnabled(Phases.Phase.POSTJOB)) {
postJobsExecutor.execute(sensorContext);
}
@@ -168,13 +166,11 @@ public final class PhaseExecutor {
}
}
- private void updateStatusJob() {
- if (updateStatusJob != null) {
- String stepName = "Update status job";
- eventBus.fireEvent(new BatchStepEvent(stepName, true));
- this.updateStatusJob.execute();
- eventBus.fireEvent(new BatchStepEvent(stepName, false));
- }
+ private void publishReportJob() {
+ String stepName = "Publish report";
+ eventBus.fireEvent(new BatchStepEvent(stepName, true));
+ this.publishReportJob.execute();
+ eventBus.fireEvent(new BatchStepEvent(stepName, false));
}
private void executeInitializersPhase() {
@@ -195,7 +191,6 @@ public final class PhaseExecutor {
private void cleanMemory() {
String cleanMemory = "Clean memory";
eventBus.fireEvent(new BatchStepEvent(cleanMemory, true));
- persistenceManager.clear();
index.clear();
eventBus.fireEvent(new BatchStepEvent(cleanMemory, false));
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java b/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java
deleted file mode 100644
index de7c51bb02b..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java
+++ /dev/null
@@ -1,92 +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.phases;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.resources.Project;
-import org.sonar.batch.bootstrap.AnalysisMode;
-import org.sonar.batch.bootstrap.ServerClient;
-
-public class UpdateStatusJob implements BatchComponent {
-
- private static final Logger LOG = LoggerFactory.getLogger(UpdateStatusJob.class);
-
- private ServerClient server;
- // TODO remove this component
- private Snapshot snapshot;
- private Settings settings;
- private Project project;
- private AnalysisMode analysisMode;
-
- public UpdateStatusJob(Settings settings, ServerClient server,
- Project project, Snapshot snapshot, AnalysisMode analysisMode) {
- this.server = server;
- this.project = project;
- this.snapshot = snapshot;
- this.settings = settings;
- this.analysisMode = analysisMode;
- }
-
- public void execute() {
- uploadReport();
- logSuccess(LoggerFactory.getLogger(getClass()));
- }
-
- @VisibleForTesting
- void uploadReport() {
- if (analysisMode.isPreview()) {
- // If this is a preview analysis then we should not upload reports
- return;
- }
- String url = "/batch/upload_report?project=" + project.getEffectiveKey() + "&snapshot=" + snapshot.getId();
- try {
- LOG.debug("Publish results");
- server.request(url, "POST");
- } catch (Exception e) {
- throw new IllegalStateException("Unable to publish results: " + url, e);
- }
- }
-
- @VisibleForTesting
- void logSuccess(Logger logger) {
- if (analysisMode.isPreview()) {
- logger.info("ANALYSIS SUCCESSFUL");
-
- } else {
- String baseUrl = settings.getString(CoreProperties.SERVER_BASE_URL);
- if (baseUrl.equals(settings.getDefaultValue(CoreProperties.SERVER_BASE_URL))) {
- // If server base URL was not configured in Sonar server then is is better to take URL configured on batch side
- baseUrl = server.getURL();
- }
- if (!baseUrl.endsWith("/")) {
- baseUrl += "/";
- }
- String url = baseUrl + "dashboard/index/" + project.getKey();
- logger.info("ANALYSIS SUCCESSFUL, you can browse {}", url);
- logger.info("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report.");
- }
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java
index 36eabaec79f..bf709694f6f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java
@@ -38,6 +38,7 @@ import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.qualitygate.db.QualityGateConditionDto;
import org.sonar.core.timemachine.Periods;
@@ -59,14 +60,14 @@ public class QualityGateVerifier implements Decorator {
private QualityGate qualityGate;
- private Snapshot snapshot;
private Periods periods;
private I18n i18n;
private Durations durations;
+ private ResourceCache resourceCache;
- public QualityGateVerifier(QualityGate qualityGate, Snapshot snapshot, Periods periods, I18n i18n, Durations durations) {
+ public QualityGateVerifier(QualityGate qualityGate, ResourceCache resourceCache, Periods periods, I18n i18n, Durations durations) {
this.qualityGate = qualityGate;
- this.snapshot = snapshot;
+ this.resourceCache = resourceCache;
this.periods = periods;
this.i18n = i18n;
this.durations = durations;
@@ -99,11 +100,11 @@ public class QualityGateVerifier implements Decorator {
@Override
public void decorate(Resource resource, DecoratorContext context) {
if (ResourceUtils.isRootProject(resource)) {
- checkProjectConditions(context);
+ checkProjectConditions(resource, context);
}
}
- private void checkProjectConditions(DecoratorContext context) {
+ private void checkProjectConditions(Resource project, DecoratorContext context) {
Metric.Level globalLevel = Metric.Level.OK;
QualityGateDetails details = new QualityGateDetails();
List<String> labels = Lists.newArrayList();
@@ -114,7 +115,7 @@ public class QualityGateVerifier implements Decorator {
Metric.Level level = ConditionUtils.getLevel(condition, measure);
measure.setAlertStatus(level);
- String text = getText(condition, level);
+ String text = getText(project, condition, level);
if (!StringUtils.isBlank(text)) {
measure.setAlertText(text);
labels.add(text);
@@ -144,14 +145,14 @@ public class QualityGateVerifier implements Decorator {
}
- private String getText(ResolvedCondition condition, Metric.Level level) {
+ private String getText(Resource project, ResolvedCondition condition, Metric.Level level) {
if (level == Metric.Level.OK) {
return null;
}
- return getAlertLabel(condition, level);
+ return getAlertLabel(project, condition, level);
}
- private String getAlertLabel(ResolvedCondition condition, Metric.Level level) {
+ private String getAlertLabel(Resource project, ResolvedCondition condition, Metric.Level level) {
Integer alertPeriod = condition.period();
String metric = i18n.message(Locale.ENGLISH, "metric." + condition.metricKey() + ".name", condition.metric().getName());
@@ -168,6 +169,7 @@ public class QualityGateVerifier implements Decorator {
.append(alertValue(condition, level));
if (alertPeriod != null) {
+ Snapshot snapshot = resourceCache.get(project.getEffectiveKey()).snapshot();
stringBuilder.append(" ").append(periods.label(snapshot, alertPeriod));
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
new file mode 100644
index 00000000000..2ac67b1f3b2
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
@@ -0,0 +1,99 @@
+/*
+ * 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.report;
+
+import com.google.gson.Gson;
+import com.google.gson.stream.JsonWriter;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.batch.index.ResourceCache;
+import org.sonar.batch.issue.IssueCache;
+import org.sonar.batch.protocol.GsonHelper;
+import org.sonar.batch.protocol.output.issue.ReportIssue;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+public class IssuesPublisher implements ReportPublisher {
+
+ private final ResourceCache resourceCache;
+ private final IssueCache issueCache;
+
+ public IssuesPublisher(ResourceCache resourceCache, IssueCache issueCache) {
+ this.resourceCache = resourceCache;
+ this.issueCache = issueCache;
+ }
+
+ @Override
+ public void export(File reportDir) throws IOException {
+ Gson gson = GsonHelper.create();
+ File issuesFile = new File(reportDir, "issues.json");
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(issuesFile));
+
+ JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
+ writer.setIndent(" ");
+ writer.beginArray();
+ for (DefaultIssue issue : issueCache.all()) {
+ ReportIssue reportIssue = toReportIssue(issue);
+ gson.toJson(reportIssue, ReportIssue.class, writer);
+ }
+ writer.endArray();
+ writer.close();
+ }
+
+ private ReportIssue toReportIssue(DefaultIssue issue) {
+ long componentBatchId = resourceCache.get(issue.componentKey()).batchId();
+ return new ReportIssue()
+ .setKey(issue.key())
+ .setResourceBatchId(componentBatchId)
+ .setNew(issue.isNew())
+ .setLine(issue.line())
+ .setMessage(issue.message())
+ .setEffortToFix(issue.effortToFix())
+ .setDebt(issue.debtInMinutes())
+ .setResolution(issue.resolution())
+ .setStatus(issue.status())
+ .setSeverity(issue.severity())
+ .setChecksum(issue.checksum())
+ .setManualSeverity(issue.manualSeverity())
+ .setReporter(issue.reporter())
+ .setAssignee(issue.assignee())
+ .setRuleKey(issue.ruleKey().repository(), issue.ruleKey().rule())
+ .setActionPlanKey(issue.actionPlanKey())
+ .setAttributes(KeyValueFormat.format(issue.attributes()))
+ .setAuthorLogin(issue.authorLogin())
+ .setCreationDate(issue.creationDate())
+ .setCloseDate(issue.closeDate())
+ .setUpdateDate(issue.updateDate())
+ .setSelectedAt(issue.selectedAt())
+ .setDiffFields(toString(issue.currentChange()))
+ .setChanged(issue.isChanged());
+ }
+
+ private String toString(FieldDiffs currentChange) {
+ return currentChange != null ? currentChange.toString() : null;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java b/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java
new file mode 100644
index 00000000000..16b5dbd59d7
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java
@@ -0,0 +1,147 @@
+/*
+ * 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.report;
+
+import com.github.kevinsawicki.http.HttpRequest;
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.platform.Server;
+import org.sonar.api.resources.Project;
+import org.sonar.api.utils.TempFolder;
+import org.sonar.api.utils.ZipUtils;
+import org.sonar.batch.bootstrap.AnalysisMode;
+import org.sonar.batch.bootstrap.ServerClient;
+import org.sonar.batch.index.ResourceCache;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class PublishReportJob implements BatchComponent {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PublishReportJob.class);
+
+ private final ServerClient serverClient;
+ private final Server server;
+ private final Settings settings;
+ private final Project project;
+ private final AnalysisMode analysisMode;
+ private final ResourceCache resourceCache;
+ private final TempFolder temp;
+
+ private ReportPublisher[] publishers;
+
+ public PublishReportJob(Settings settings, ServerClient serverClient, Server server,
+ Project project, AnalysisMode analysisMode, TempFolder temp, ResourceCache resourceCache, ReportPublisher[] publishers) {
+ this.serverClient = serverClient;
+ this.server = server;
+ this.project = project;
+ this.settings = settings;
+ this.analysisMode = analysisMode;
+ this.temp = temp;
+ this.resourceCache = resourceCache;
+ this.publishers = publishers;
+ }
+
+ public PublishReportJob(Settings settings, ServerClient serverClient, Server server,
+ Project project, AnalysisMode analysisMode, TempFolder temp, ResourceCache resourceCache) {
+ this(settings, serverClient, server, project, analysisMode, temp, resourceCache, new ReportPublisher[0]);
+ }
+
+ public void execute() {
+ // If this is a preview analysis then we should not upload reports
+ if (!analysisMode.isPreview()) {
+ File report = prepareReport();
+ uploadMultiPartReport(report);
+ }
+ logSuccess(LoggerFactory.getLogger(getClass()));
+ }
+
+ private File prepareReport() {
+ try {
+ File reportDir = temp.newDir("batch-report");
+ for (ReportPublisher publisher : publishers) {
+ publisher.export(reportDir);
+ }
+
+ File reportZip = temp.newFile("batch-report", ".zip");
+ ZipUtils.zipDir(reportDir, reportZip);
+ FileUtils.deleteDirectory(reportDir);
+ return reportZip;
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to prepare batch report", e);
+ }
+ }
+
+ @VisibleForTesting
+ void uploadMultiPartReport(File report) {
+ LOG.debug("Publish results");
+ URL url;
+ try {
+ int snapshotId = resourceCache.get(project.getEffectiveKey()).snapshotId();
+ url = new URL(serverClient.getURL() + "/batch/upload_report?project=" + project.getEffectiveKey() + "&snapshot=" + snapshotId);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Invalid URL", e);
+ }
+ HttpRequest request = HttpRequest.post(url);
+ request.trustAllCerts();
+ request.trustAllHosts();
+ request.header("User-Agent", String.format("SonarQube %s", server.getVersion()));
+ request.basic(serverClient.getLogin(), serverClient.getPassword());
+ request.part("report", report);
+ if (!request.ok()) {
+ int responseCode = request.code();
+ if (responseCode == 401) {
+ throw new IllegalStateException(String.format(serverClient.getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD));
+ }
+ if (responseCode == 403) {
+ // SONAR-4397 Details are in response content
+ throw new IllegalStateException(request.body());
+ }
+ throw new IllegalStateException(String.format("Fail to execute request [code=%s, url=%s]: %s", responseCode, url, request.body()));
+ }
+ }
+
+ @VisibleForTesting
+ void logSuccess(Logger logger) {
+ if (analysisMode.isPreview()) {
+ logger.info("ANALYSIS SUCCESSFUL");
+
+ } else {
+ String baseUrl = settings.getString(CoreProperties.SERVER_BASE_URL);
+ if (baseUrl.equals(settings.getDefaultValue(CoreProperties.SERVER_BASE_URL))) {
+ // If server base URL was not configured in Sonar server then is is better to take URL configured on batch side
+ baseUrl = serverClient.getURL();
+ }
+ if (!baseUrl.endsWith("/")) {
+ baseUrl += "/";
+ }
+ String url = baseUrl + "dashboard/index/" + project.getKey();
+ logger.info("ANALYSIS SUCCESSFUL, you can browse {}", url);
+ logger.info("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report.");
+ }
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
new file mode 100644
index 00000000000..c9d42f0a849
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
@@ -0,0 +1,29 @@
+/*
+ * 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.report;
+
+import java.io.File;
+import java.io.IOException;
+
+public interface ReportPublisher {
+
+ void export(File reportDir) throws IOException;
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/ResourcesPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/ResourcesPublisher.java
new file mode 100644
index 00000000000..1bdbf2579a7
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/ResourcesPublisher.java
@@ -0,0 +1,82 @@
+/*
+ * 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.report;
+
+import org.apache.commons.io.FileUtils;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.ResourceUtils;
+import org.sonar.batch.index.BatchResource;
+import org.sonar.batch.index.ResourceCache;
+import org.sonar.batch.protocol.output.resource.ReportResource;
+import org.sonar.batch.protocol.output.resource.ReportResource.Type;
+import org.sonar.batch.protocol.output.resource.ReportResources;
+
+import java.io.File;
+import java.io.IOException;
+
+public class ResourcesPublisher implements ReportPublisher {
+
+ private final ResourceCache resourceCache;
+ private final ProjectReactor reactor;
+
+ public ResourcesPublisher(ProjectReactor reactor, ResourceCache resourceCache) {
+ this.reactor = reactor;
+ this.resourceCache = resourceCache;
+ }
+
+ @Override
+ public void export(File reportDir) throws IOException {
+ ReportResources resources = new ReportResources();
+ BatchResource rootProject = resourceCache.get(reactor.getRoot().getKeyWithBranch());
+ resources.setRoot(buildResourceForReport(rootProject));
+ File resourcesFile = new File(reportDir, "resources.json");
+ FileUtils.write(resourcesFile, resources.toJson());
+ }
+
+ private ReportResource buildResourceForReport(BatchResource batchResource) {
+ Resource r = batchResource.resource();
+ ReportResource result = new ReportResource()
+ .setBatchId(batchResource.batchId())
+ .setSnapshotId(batchResource.snapshotId())
+ .setId(r.getId())
+ .setName(r.getName())
+ .setPath(r.getPath())
+ .setType(getType(r));
+ for (BatchResource child : batchResource.children()) {
+ result.addChild(buildResourceForReport(child));
+ }
+ return result;
+ }
+
+ private Type getType(Resource r) {
+ if (ResourceUtils.isFile(r)) {
+ return ReportResource.Type.FIL;
+ } else if (ResourceUtils.isDirectory(r)) {
+ return ReportResource.Type.DIR;
+ } else if (ResourceUtils.isModuleProject(r)) {
+ return ReportResource.Type.MOD;
+ } else if (ResourceUtils.isRootProject(r)) {
+ return ReportResource.Type.PRJ;
+ }
+ throw new IllegalArgumentException("Unknow resource type: " + r);
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/report/package-info.java
new file mode 100644
index 00000000000..bfaf6f9e767
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.report;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/QProfileEventsDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/rule/QProfileEventsDecorator.java
index 53fb0894817..f3d7bffc035 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/rule/QProfileEventsDecorator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/rule/QProfileEventsDecorator.java
@@ -36,7 +36,7 @@ import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.batch.index.PersistenceManager;
+import org.sonar.batch.index.EventPersister;
import org.sonar.core.UtcDateUtils;
import javax.annotation.CheckForNull;
@@ -49,12 +49,12 @@ public class QProfileEventsDecorator implements Decorator {
private final TimeMachine timeMachine;
private final Languages languages;
- private final PersistenceManager persistenceManager;
+ private final EventPersister eventPersister;
- public QProfileEventsDecorator(TimeMachine timeMachine, Languages languages, PersistenceManager pm) {
+ public QProfileEventsDecorator(TimeMachine timeMachine, Languages languages, EventPersister eventPersister) {
this.timeMachine = timeMachine;
this.languages = languages;
- this.persistenceManager = pm;
+ this.eventPersister = eventPersister;
}
@DependsUpon
@@ -123,7 +123,7 @@ public class QProfileEventsDecorator implements Decorator {
"from", UtcDateUtils.formatDateTime(fixDate(from)),
"to", UtcDateUtils.formatDateTime(fixDate(profile.getRulesUpdatedAt()))));
event.setData(data);
- persistenceManager.saveEvent(context.getResource(), event);
+ eventPersister.saveEvent(context.getResource(), event);
}
/**
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
index 21bb31470bd..5898b9452b7 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
@@ -46,7 +46,6 @@ import org.sonar.batch.debt.SqaleRatingDecorator;
import org.sonar.batch.debt.SqaleRatingSettings;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
-import org.sonar.batch.index.ResourcePersister;
import org.sonar.batch.issue.IssuableFactory;
import org.sonar.batch.issue.IssueFilters;
import org.sonar.batch.issue.ModuleIssues;
@@ -62,6 +61,8 @@ import org.sonar.batch.phases.PhasesTimeProfiler;
import org.sonar.batch.qualitygate.GenerateQualityGateEvents;
import org.sonar.batch.qualitygate.QualityGateProvider;
import org.sonar.batch.qualitygate.QualityGateVerifier;
+import org.sonar.batch.report.IssuesPublisher;
+import org.sonar.batch.report.ResourcesPublisher;
import org.sonar.batch.rule.ActiveRulesProvider;
import org.sonar.batch.rule.ModuleQProfiles;
import org.sonar.batch.rule.QProfileDecorator;
@@ -119,6 +120,8 @@ public class ModuleScanContainer extends ComponentContainer {
PhaseExecutor.class,
PhasesTimeProfiler.class,
PhaseExecutor.getPhaseClasses(),
+ ResourcesPublisher.class,
+ IssuesPublisher.class,
moduleDefinition.getContainerExtensions(),
// file system
@@ -142,9 +145,6 @@ public class ModuleScanContainer extends ComponentContainer {
AnalyzerOptimizer.class,
- // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
- getComponentByType(ResourcePersister.class).getSnapshot(module),
-
TimeMachineConfiguration.class,
DefaultSensorContext.class,
SensorContextAdapter.class,
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index d9f23dc2a39..d364c1ab797 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -46,18 +46,16 @@ import org.sonar.batch.duplication.BlockCache;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.Caches;
import org.sonar.batch.index.ComponentDataCache;
-import org.sonar.batch.index.FileHashesPersister;
import org.sonar.batch.index.DefaultIndex;
-import org.sonar.batch.index.DefaultPersistenceManager;
import org.sonar.batch.index.DefaultResourcePersister;
import org.sonar.batch.index.DependencyPersister;
import org.sonar.batch.index.DuplicationPersister;
import org.sonar.batch.index.EventPersister;
+import org.sonar.batch.index.FileHashesPersister;
import org.sonar.batch.index.LinkPersister;
import org.sonar.batch.index.MeasurePersister;
import org.sonar.batch.index.ResourceCache;
import org.sonar.batch.index.ResourceKeyMigration;
-import org.sonar.batch.index.SnapshotCache;
import org.sonar.batch.index.SourcePersister;
import org.sonar.batch.issue.DefaultProjectIssues;
import org.sonar.batch.issue.DeprecatedViolations;
@@ -133,7 +131,6 @@ public class ProjectScanContainer extends ComponentContainer {
add(
new ProjectReferentialsProvider(),
DefaultResourceCreationLock.class,
- DefaultPersistenceManager.class,
DependencyPersister.class,
EventPersister.class,
LinkPersister.class,
@@ -151,7 +148,6 @@ public class ProjectScanContainer extends ComponentContainer {
ProjectLock.class,
LastLineHashes.class,
Caches.class,
- SnapshotCache.class,
ResourceCache.class,
ComponentDataCache.class,
FileHashesPersister.class,
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoader.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoader.java
index b86b501225e..79b1019e362 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoader.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoader.java
@@ -22,9 +22,11 @@ package org.sonar.batch.scan.filesystem;
import com.google.common.collect.Maps;
import org.sonar.api.BatchComponent;
import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.source.SnapshotDataTypes;
import org.sonar.core.source.db.SnapshotDataDao;
import org.sonar.core.source.db.SnapshotDataDto;
@@ -37,10 +39,12 @@ public class PreviousFileHashLoader implements BatchComponent {
private final SnapshotDataDao dao;
private final PastSnapshotFinder pastSnapshotFinder;
- private final Snapshot snapshot;
+ private final Project project;
+ private final ResourceCache resourceCache;
- public PreviousFileHashLoader(Snapshot snapshot, SnapshotDataDao dao, PastSnapshotFinder pastSnapshotFinder) {
- this.snapshot = snapshot;
+ public PreviousFileHashLoader(Project project, ResourceCache resourceCache, SnapshotDataDao dao, PastSnapshotFinder pastSnapshotFinder) {
+ this.project = project;
+ this.resourceCache = resourceCache;
this.dao = dao;
this.pastSnapshotFinder = pastSnapshotFinder;
}
@@ -49,6 +53,7 @@ public class PreviousFileHashLoader implements BatchComponent {
* Extract hash of the files parsed during the previous analysis
*/
public Map<String, String> hashByRelativePath() {
+ Snapshot snapshot = resourceCache.get(project.getEffectiveKey()).snapshot();
Map<String, String> map = Maps.newHashMap();
PastSnapshot pastSnapshot = pastSnapshotFinder.findPreviousAnalysis(snapshot);
if (pastSnapshot.isRelatedToSnapshot()) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java
index 0da1a2f8d0d..5f796661473 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java
@@ -38,6 +38,7 @@ import org.sonar.batch.duplication.BlockCache;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.Caches;
import org.sonar.batch.index.ComponentDataCache;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.batch.languages.DefaultLanguagesReferential;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.referential.DefaultProjectReferentialsLoader;
@@ -95,6 +96,7 @@ public class ProjectScanContainer extends ComponentContainer {
new ProjectReferentialsProvider(),
ProjectSettings.class,
Caches.class,
+ ResourceCache.class,
// lang
Languages.class,
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
index 9a162fbf425..05efe6cf0ae 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
@@ -23,6 +23,7 @@ import org.junit.Before;
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.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilters;
@@ -49,6 +50,7 @@ import java.io.IOException;
import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -75,7 +77,9 @@ public class DefaultIndexTest {
ruleFinder = mock(RuleFinder.class);
ProjectTree projectTree = mock(ProjectTree.class);
- index = new DefaultIndex(mock(PersistenceManager.class), projectTree, metricFinder, mock(ScanGraph.class), deprecatedViolations, mock(ResourceKeyMigration.class),
+ ResourcePersister resourcePersister = mock(ResourcePersister.class);
+ index = new DefaultIndex(resourcePersister, null, null, null, projectTree, metricFinder, mock(ScanGraph.class), deprecatedViolations,
+ mock(ResourceKeyMigration.class),
mock(MeasureCache.class));
java.io.File baseDir = temp.newFolder();
@@ -88,6 +92,9 @@ public class DefaultIndexTest {
moduleB1 = new Project("moduleB1").setParent(moduleB);
when(projectTree.getProjectDefinition(moduleB1)).thenReturn(ProjectDefinition.create().setBaseDir(new java.io.File(baseDir, "moduleB/moduleB1")));
+ when(resourcePersister.saveResource(any(Project.class), any(Resource.class), any(Resource.class))).thenReturn(
+ new BatchResource(1, mock(Resource.class), new Snapshot().setId(1), null));
+
RulesProfile rulesProfile = RulesProfile.create();
rule = Rule.create("repoKey", "ruleKey", "Rule");
rule.setId(1);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java
index 23ad3689cf6..d99ef18c058 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java
@@ -53,9 +53,6 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import static org.fest.assertions.Assertions.assertThat;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -69,12 +66,13 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- Project singleProject, singleCopyProject, multiModuleProject, moduleA, moduleB, moduleB1, existingProject;
- SnapshotCache snapshotCache = mock(SnapshotCache.class);
- ResourceCache resourceCache = mock(ResourceCache.class);
+ private Project singleProject, singleCopyProject, multiModuleProject, moduleA, moduleB, moduleB1, existingProject;
+ private ResourceCache resourceCache;
@Before
public void before() throws ParseException {
+ resourceCache = new ResourceCache();
+
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
singleProject = newProject("foo", "java");
singleProject.setName("Foo").setDescription("some description").setAnalysisDate(format.parse("25/12/2010"));
@@ -108,7 +106,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
public void shouldSaveNewProject() {
setupData("shared");
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
persister.saveProject(singleProject, null);
checkTables("shouldSaveNewProject", new String[] {"build_date", "created_at", "authorization_updated_at", "uuid", "project_uuid", "module_uuid", "module_uuid_path"},
@@ -134,7 +132,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
public void shouldSaveCopyProject() {
setupData("shared");
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
persister.saveProject(singleCopyProject, null);
checkTables("shouldSaveCopyProject", new String[] {"build_date", "created_at", "authorization_updated_at", "uuid", "project_uuid", "module_uuid", "module_uuid_path"},
@@ -157,7 +155,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
public void shouldSaveNewMultiModulesProject() {
setupData("shared");
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
persister.saveProject(multiModuleProject, null);
persister.saveProject(moduleA, multiModuleProject);
persister.saveProject(moduleB, multiModuleProject);
@@ -221,7 +219,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
java.io.File baseDir = temp.newFolder();
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
ProjectTree projectTree = mock(ProjectTree.class);
when(projectTree.getRootProject()).thenReturn(multiModuleProject);
@@ -230,8 +228,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
when(projectTree.getProjectDefinition(moduleB)).thenReturn(ProjectDefinition.create().setBaseDir(new java.io.File(baseDir, "moduleB")));
when(projectTree.getProjectDefinition(moduleB1)).thenReturn(ProjectDefinition.create().setBaseDir(new java.io.File(baseDir, "moduleB/moduleB1")));
- PersistenceManager persistenceManager = new DefaultPersistenceManager(persister, null, null, null);
- DefaultIndex index = new DefaultIndex(persistenceManager, projectTree, mock(MetricFinder.class), mock(ScanGraph.class), mock(DeprecatedViolations.class),
+ DefaultIndex index = new DefaultIndex(persister, null, null, null, projectTree, mock(MetricFinder.class), mock(ScanGraph.class), mock(DeprecatedViolations.class),
mock(ResourceKeyMigration.class),
mock(MeasureCache.class));
@@ -300,7 +297,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
public void shouldSaveNewDirectory() {
setupData("shared");
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
persister.saveProject(singleProject, null);
persister.saveResource(singleProject,
Directory.create("src/main/java/org/foo", "org.foo").setEffectiveKey("foo:src/main/java/org/foo"));
@@ -337,7 +334,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
public void shouldSaveNewLibrary() {
setupData("shared");
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
persister.saveProject(singleProject, null);
persister.saveResource(singleProject, new Library("junit:junit", "4.8.2").setEffectiveKey("junit:junit"));
persister.saveResource(singleProject, new Library("junit:junit", "4.8.2").setEffectiveKey("junit:junit"));// do nothing, already saved
@@ -362,26 +359,10 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
}
@Test
- public void shouldClearResourcesExceptProjects() {
- setupData("shared");
-
- DefaultResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
- persister.saveProject(multiModuleProject, null);
- persister.saveProject(moduleA, multiModuleProject);
- persister.saveResource(moduleA, new Directory("org/foo").setEffectiveKey("a:org/foo"));
- persister.saveResource(moduleA, new File("org/foo/MyClass.java").setEffectiveKey("a:org/foo/MyClass.java"));
- persister.clear();
-
- assertThat(persister.getSnapshotsByResource().size(), is(2));
- assertThat(persister.getSnapshotsByResource().get(multiModuleProject), notNullValue());
- assertThat(persister.getSnapshotsByResource().get(moduleA), notNullValue());
- }
-
- @Test
public void shouldUpdateExistingResource() {
setupData("shouldUpdateExistingResource");
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
singleProject.setName("new name");
singleProject.setDescription("new description");
persister.saveProject(singleProject, null);
@@ -394,7 +375,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
public void shouldRemoveRootIndexIfResourceIsProject() {
setupData("shouldRemoveRootIndexIfResourceIsProject");
- ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), mock(ResourcePermissions.class), resourceCache);
persister.saveProject(singleProject, null);
checkTables("shouldRemoveRootIndexIfResourceIsProject", new String[] {"build_date", "created_at", "authorization_updated_at"}, "projects", "snapshots");
@@ -407,7 +388,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
ResourcePermissions permissions = mock(ResourcePermissions.class);
when(permissions.hasRoles(singleProject)).thenReturn(false);
- ResourcePersister persister = new DefaultResourcePersister(getSession(), permissions, snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), permissions, resourceCache);
persister.saveProject(singleProject, null);
verify(permissions).grantDefaultRoles(singleProject);
@@ -420,7 +401,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
ResourcePermissions permissions = mock(ResourcePermissions.class);
when(permissions.hasRoles(singleProject)).thenReturn(true);
- ResourcePersister persister = new DefaultResourcePersister(getSession(), permissions, snapshotCache, resourceCache);
+ ResourcePersister persister = new DefaultResourcePersister(getSession(), permissions, resourceCache);
persister.saveProject(singleProject, null);
verify(permissions, never()).grantDefaultRoles(singleProject);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java
index 644d7400999..3517b28789f 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java
@@ -48,7 +48,6 @@ public class DuplicationPersisterTest extends AbstractDaoTestCase {
RuleFinder ruleFinder = mock(RuleFinder.class);
File aFile = new File("org/foo/Bar.java");
Snapshot fileSnapshot = snapshot(FILE_SNAPSHOT_ID);
- SnapshotCache snapshotCache;
private DuplicationCache duplicationCache;
@@ -56,15 +55,16 @@ public class DuplicationPersisterTest extends AbstractDaoTestCase {
public void mockResourcePersister() {
duplicationCache = mock(DuplicationCache.class);
- snapshotCache = mock(SnapshotCache.class);
ResourceCache resourceCache = mock(ResourceCache.class);
- when(snapshotCache.get("foo:org/foo/Bar.java")).thenReturn(fileSnapshot);
- when(resourceCache.get("foo:org/foo/Bar.java")).thenReturn(aFile);
+ BatchResource batchResource = mock(BatchResource.class);
+ when(batchResource.resource()).thenReturn(aFile);
+ when(batchResource.snapshotId()).thenReturn(FILE_SNAPSHOT_ID);
+ when(resourceCache.get("foo:org/foo/Bar.java")).thenReturn(batchResource);
MetricFinder metricFinder = mock(MetricFinder.class);
when(metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY)).thenReturn(CoreMetrics.DUPLICATIONS_DATA.setId(2));
- duplicationPersister = new DuplicationPersister(getMyBatis(), ruleFinder, snapshotCache, resourceCache, duplicationCache, metricFinder);
+ duplicationPersister = new DuplicationPersister(getMyBatis(), ruleFinder, resourceCache, duplicationCache, metricFinder);
}
@Test
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java
index 29c9e0cef1e..3e6c4866245 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java
@@ -25,6 +25,7 @@ import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.source.SnapshotDataTypes;
import org.sonar.core.source.db.SnapshotDataDao;
@@ -34,12 +35,13 @@ public class FileHashesPersisterTest extends AbstractDaoTestCase {
@ClassRule
public static TemporaryFolder temp = new TemporaryFolder();
- SnapshotCache snapshots = new SnapshotCache();
+ ResourceCache resourceCache;
ComponentDataCache data;
Caches caches;
@Before
public void start() throws Exception {
+ resourceCache = new ResourceCache();
caches = CachesTest.createCacheOnTemp(temp);
caches.start();
}
@@ -55,13 +57,13 @@ public class FileHashesPersisterTest extends AbstractDaoTestCase {
Snapshot snapshot = new Snapshot();
snapshot.setId(100);
snapshot.setResourceId(200);
- snapshots.put("myProject", snapshot);
+ resourceCache.add(new Project("myProject").setId(200), snapshot);
data = new ComponentDataCache(caches);
data.setStringData("myProject", SnapshotDataTypes.FILE_HASHES, "org/struts/Action.java=123ABC");
SnapshotDataDao dataDao = new SnapshotDataDao(getMyBatis());
- FileHashesPersister persister = new FileHashesPersister(data, snapshots, dataDao, getMyBatis());
+ FileHashesPersister persister = new FileHashesPersister(data, resourceCache, dataDao, getMyBatis());
persister.persist();
checkTables("should_persist_component_data", new String[] {"id", "created_at", "updated_at"}, "snapshot_data");
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
index fe8a1a45a65..6c4bcc731eb 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
@@ -32,6 +32,7 @@ import org.sonar.api.measures.RuleMeasure;
import org.sonar.api.resources.Directory;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
@@ -61,23 +62,20 @@ public class MeasurePersisterTest extends AbstractDaoTestCase {
Project project = new Project("foo");
Directory aDirectory = new Directory("org/foo");
File aFile = new File("org/foo/Bar.java");
- Snapshot projectSnapshot = snapshot(PROJECT_SNAPSHOT_ID);
- Snapshot packageSnapshot = snapshot(PACKAGE_SNAPSHOT_ID);
- SnapshotCache snapshotCache;
+ BatchResource projectResource = batchResource(project, PROJECT_SNAPSHOT_ID);
+ BatchResource dirResource = batchResource(aDirectory, PACKAGE_SNAPSHOT_ID);
+ BatchResource fileResource = batchResource(aFile, FILE_SNAPSHOT_ID);
MeasureCache measureCache;
@Before
public void mockResourcePersister() {
- snapshotCache = mock(SnapshotCache.class);
measureCache = mock(MeasureCache.class);
ResourceCache resourceCache = mock(ResourceCache.class);
- when(snapshotCache.get("foo")).thenReturn(projectSnapshot);
- when(snapshotCache.get("foo:org/foo")).thenReturn(packageSnapshot);
- when(resourceCache.get("foo")).thenReturn(project);
- when(resourceCache.get("foo:org/foo/Bar.java")).thenReturn(aFile);
- when(resourceCache.get("foo:org/foo")).thenReturn(aDirectory);
+ when(resourceCache.get("foo")).thenReturn(projectResource);
+ when(resourceCache.get("foo:org/foo/Bar.java")).thenReturn(fileResource);
+ when(resourceCache.get("foo:org/foo")).thenReturn(dirResource);
- measurePersister = new MeasurePersister(getMyBatis(), ruleFinder, measureCache, snapshotCache, resourceCache);
+ measurePersister = new MeasurePersister(getMyBatis(), ruleFinder, measureCache, resourceCache);
}
@Test
@@ -193,10 +191,10 @@ public class MeasurePersisterTest extends AbstractDaoTestCase {
assertThat(MeasurePersister.shouldPersistMeasure(aFile, duplicatedLines)).isFalse();
}
- private static Snapshot snapshot(int id) {
+ private static BatchResource batchResource(Resource resource, int id) {
Snapshot snapshot = mock(Snapshot.class);
when(snapshot.getId()).thenReturn(id);
- return snapshot;
+ return new BatchResource(1, resource, snapshot, null);
}
private static Metric ncloc() {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
index 20e04957309..d59709a0bd6 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
@@ -20,6 +20,7 @@
package org.sonar.batch.index;
import org.junit.Test;
+import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Resource;
@@ -32,9 +33,9 @@ public class ResourceCacheTest {
ResourceCache cache = new ResourceCache();
String componentKey = "struts:src/org/struts/Action.java";
Resource resource = new File("org/struts/Action.java").setEffectiveKey(componentKey);
- cache.add(resource);
+ cache.add(resource, new Snapshot());
- assertThat(cache.get(componentKey)).isSameAs(resource);
+ assertThat(cache.get(componentKey).resource()).isSameAs(resource);
assertThat(cache.get("other")).isNull();
}
@@ -43,7 +44,7 @@ public class ResourceCacheTest {
ResourceCache cache = new ResourceCache();
Resource resource = new File("org/struts/Action.java").setEffectiveKey(null);
try {
- cache.add(resource);
+ cache.add(resource, new Snapshot());
fail();
} catch (IllegalStateException e) {
// success
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java
index af2c5474d94..7c69ffb6061 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java
@@ -365,7 +365,7 @@ public class SourcePersisterTest extends AbstractDaoTestCase {
private void mockResourceCache(String relativePathEmpty, String projectKey, String uuid) {
File sonarFile = File.create(relativePathEmpty);
sonarFile.setUuid(uuid);
- when(resourceCache.get(projectKey + ":" + relativePathEmpty)).thenReturn(sonarFile);
+ when(resourceCache.get(projectKey + ":" + relativePathEmpty)).thenReturn(new BatchResource(1, sonarFile, new Snapshot(), null));
}
private byte[] md5(String string) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java
index 43b51226d25..a94578a5769 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java
@@ -20,6 +20,7 @@
package org.sonar.batch.issue;
import org.junit.Test;
+import org.sonar.api.database.model.Snapshot;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.RuleKey;
@@ -28,6 +29,7 @@ import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.Violation;
+import org.sonar.batch.index.BatchResource;
import org.sonar.batch.index.ResourceCache;
import java.util.Arrays;
@@ -48,7 +50,7 @@ public class DeprecatedViolationsTest {
public void test_toViolation() throws Exception {
RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
when(ruleFinder.findByKey(ruleKey)).thenReturn(new Rule("squid", "AvoidCycles"));
- when(resourceCache.get("org.apache:struts")).thenReturn(new Project("org.apache:struts"));
+ when(resourceCache.get("org.apache:struts")).thenReturn(new BatchResource(1, new Project("org.apache:struts"), new Snapshot(), null));
DefaultIssue issue = newIssue(ruleKey);
@@ -78,7 +80,7 @@ public class DeprecatedViolationsTest {
public void test_get() throws Exception {
RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
when(ruleFinder.findByKey(ruleKey)).thenReturn(new Rule("squid", "AvoidCycles"));
- when(resourceCache.get("org.apache:struts")).thenReturn(new Project("org.apache:struts"));
+ when(resourceCache.get("org.apache:struts")).thenReturn(new BatchResource(1, new Project("org.apache:struts"), new Snapshot(), null));
when(issueCache.byComponent("org.apache:struts")).thenReturn(Arrays.asList(newIssue(ruleKey)));
List<Violation> violations = deprecatedViolations.get("org.apache:struts");
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssueStorageTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssueStorageTest.java
index 386c4949251..e76825eaca5 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssueStorageTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssueStorageTest.java
@@ -28,6 +28,7 @@ import org.sonar.api.database.model.Snapshot;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.DefaultIssueComment;
import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
@@ -37,7 +38,8 @@ import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.System2;
import org.sonar.batch.ProjectTree;
-import org.sonar.batch.index.SnapshotCache;
+import org.sonar.batch.index.BatchResource;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.resource.ResourceDao;
@@ -52,7 +54,7 @@ import static org.mockito.Mockito.when;
public class ScanIssueStorageTest extends AbstractDaoTestCase {
@Mock
- SnapshotCache snapshotCache;
+ ResourceCache resourceCache;
@Mock
ProjectTree projectTree;
@@ -61,12 +63,12 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
@Before
public void setUp() throws Exception {
- storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis(), System2.INSTANCE), projectTree);
+ storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), resourceCache, new ResourceDao(getMyBatis(), System2.INSTANCE), projectTree);
}
@Test
public void should_load_component_id_from_cache() throws Exception {
- when(snapshotCache.get("struts:Action.java")).thenReturn(new Snapshot().setResourceId(123));
+ when(resourceCache.get("struts:Action.java")).thenReturn(new BatchResource(1, File.create("Action.java").setId(123), new Snapshot(), null));
long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
@@ -76,7 +78,7 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
@Test
public void should_load_component_id_from_db() throws Exception {
setupData("should_load_component_id_from_db");
- when(snapshotCache.get("struts:Action.java")).thenReturn(null);
+ when(resourceCache.get("struts:Action.java")).thenReturn(null);
long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
@@ -86,7 +88,7 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
@Test
public void should_fail_to_load_component_id_if_unknown_component() throws Exception {
setupData("should_fail_to_load_component_id_if_unknown_component");
- when(snapshotCache.get("struts:Action.java")).thenReturn(null);
+ when(resourceCache.get("struts:Action.java")).thenReturn(null);
try {
storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
@@ -139,7 +141,7 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
storage.save(issue);
- checkTables("should_insert_new_issues", new String[]{"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
+ checkTables("should_insert_new_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
}
@Test
@@ -162,7 +164,7 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
.setNew(false)
.setChanged(true)
- // updated fields
+ // updated fields
.setLine(5000)
.setDebt(Duration.create(10L))
.setChecksum("FFFFF")
@@ -179,13 +181,13 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
.setUpdateDate(date)
.setCloseDate(date)
- // unmodifiable fields
+ // unmodifiable fields
.setRuleKey(RuleKey.of("xxx", "unknown"))
.setComponentKey("not:a:component");
storage.save(issue);
- checkTables("should_update_issues", new String[]{"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
+ checkTables("should_update_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
}
@Test
@@ -206,23 +208,23 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
.setRuleKey(RuleKey.of("squid", "AvoidCycles"))
.setComponentKey("struts:Action")
- // issue in database has been updated in 2015, after the loading by scan
+ // issue in database has been updated in 2015, after the loading by scan
.setSelectedAt(1400000000000L)
- // fields to be updated
+ // fields to be updated
.setLine(444)
.setSeverity("BLOCKER")
.setChecksum("FFFFF")
.setAttribute("JIRA", "http://jira.com")
- // fields overridden by end-user -> do not save
+ // fields overridden by end-user -> do not save
.setAssignee("looser")
.setResolution(null)
.setStatus("REOPEN");
storage.save(issue);
- checkTables("should_resolve_conflicts_on_updates", new String[]{"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues");
+ checkTables("should_resolve_conflicts_on_updates", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues");
}
static class FakeRuleFinder implements RuleFinder {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
index 9dd6a731f12..63a11312309 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
@@ -39,6 +39,7 @@ import org.sonar.api.resources.Resource;
import org.sonar.api.test.IsMeasure;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.qualitygate.db.QualityGateConditionDto;
import org.sonar.core.timemachine.Periods;
@@ -69,6 +70,7 @@ public class QualityGateVerifierTest {
Periods periods;
I18n i18n;
Durations durations;
+ private ResourceCache resourceCache;
@Before
public void before() {
@@ -89,8 +91,13 @@ public class QualityGateVerifierTest {
snapshot = mock(Snapshot.class);
qualityGate = mock(QualityGate.class);
when(qualityGate.isEnabled()).thenReturn(true);
- verifier = new QualityGateVerifier(qualityGate, snapshot, periods, i18n, durations);
+
project = new Project("foo");
+
+ resourceCache = new ResourceCache();
+ resourceCache.add(project, snapshot);
+
+ verifier = new QualityGateVerifier(qualityGate, resourceCache, periods, i18n, durations);
}
@Test
diff --git a/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java
index 6c329eef3a1..e28e0643fb0 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java
@@ -17,31 +17,31 @@
* 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.phases;
+package org.sonar.batch.report;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
-import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.platform.Server;
import org.sonar.api.resources.Project;
+import org.sonar.api.utils.TempFolder;
import org.sonar.batch.bootstrap.AnalysisMode;
import org.sonar.batch.bootstrap.ServerClient;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.jpa.test.AbstractDbUnitTestCase;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.contains;
-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.when;
-public class UpdateStatusJobTest extends AbstractDbUnitTestCase {
+public class PublishReportJobTest extends AbstractDbUnitTestCase {
private AnalysisMode mode;
+ ResourceCache resourceCache = mock(ResourceCache.class);
+
@Before
public void setUp() {
mode = mock(AnalysisMode.class);
@@ -52,7 +52,7 @@ public class UpdateStatusJobTest extends AbstractDbUnitTestCase {
Settings settings = new Settings();
settings.setProperty(CoreProperties.SERVER_BASE_URL, "http://myserver/");
Project project = new Project("struts");
- UpdateStatusJob job = new UpdateStatusJob(settings, mock(ServerClient.class), project, mock(Snapshot.class), mode);
+ PublishReportJob job = new PublishReportJob(settings, mock(ServerClient.class), mock(Server.class), project, mode, mock(TempFolder.class), mock(ResourceCache.class));
Logger logger = mock(Logger.class);
job.logSuccess(logger);
@@ -66,7 +66,7 @@ public class UpdateStatusJobTest extends AbstractDbUnitTestCase {
Settings settings = new Settings();
when(mode.isPreview()).thenReturn(true);
Project project = new Project("struts");
- UpdateStatusJob job = new UpdateStatusJob(settings, mock(ServerClient.class), project, mock(Snapshot.class), mode);
+ PublishReportJob job = new PublishReportJob(settings, mock(ServerClient.class), mock(Server.class), project, mode, mock(TempFolder.class), mock(ResourceCache.class));
Logger logger = mock(Logger.class);
job.logSuccess(logger);
@@ -74,26 +74,4 @@ public class UpdateStatusJobTest extends AbstractDbUnitTestCase {
verify(logger).info("ANALYSIS SUCCESSFUL");
}
- @Test
- public void should_publish_results_for_regular_analysis() throws Exception {
- Settings settings = new Settings();
- Project project = new Project("struts");
- ServerClient serverClient = mock(ServerClient.class);
- UpdateStatusJob job = new UpdateStatusJob(settings, serverClient, project, mock(Snapshot.class), mode);
-
- job.uploadReport();
- verify(serverClient).request(contains("/batch/upload_report"), eq("POST"));
- }
-
- @Test
- public void should_not_publish_results_for_preview_analysis() throws Exception {
- Settings settings = new Settings();
- when(mode.isPreview()).thenReturn(true);
- Project project = new Project("struts");
- ServerClient serverClient = mock(ServerClient.class);
- UpdateStatusJob job = new UpdateStatusJob(settings, serverClient, project, mock(Snapshot.class), mode);
-
- job.uploadReport();
- verify(serverClient, never()).request(anyString());
- }
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/rule/QProfileEventsDecoratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/rule/QProfileEventsDecoratorTest.java
index 6618cc7f832..cc77fe913ef 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/rule/QProfileEventsDecoratorTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/rule/QProfileEventsDecoratorTest.java
@@ -51,7 +51,7 @@ import org.sonar.api.resources.Java;
import org.sonar.api.resources.Languages;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
-import org.sonar.batch.index.PersistenceManager;
+import org.sonar.batch.index.EventPersister;
import java.util.Arrays;
import java.util.Date;
@@ -59,10 +59,13 @@ import java.util.Date;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.*;
-import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class QProfileEventsDecoratorTest {
@@ -74,8 +77,8 @@ public class QProfileEventsDecoratorTest {
DecoratorContext decoratorContext = mock(DecoratorContext.class);
TimeMachine timeMachine = mock(TimeMachine.class);
Languages languages = mock(Languages.class);
- PersistenceManager persistenceManager = mock(PersistenceManager.class);
- QProfileEventsDecorator decorator = new QProfileEventsDecorator(timeMachine, languages, persistenceManager);
+ EventPersister eventPersister = mock(EventPersister.class);
+ QProfileEventsDecorator decorator = new QProfileEventsDecorator(timeMachine, languages, eventPersister);
@Test
public void basic_tests() {
@@ -112,7 +115,7 @@ public class QProfileEventsDecoratorTest {
decorator.decorate(project, decoratorContext);
- verify(persistenceManager).saveEvent(any(Resource.class), argThat(new BaseMatcher<Event>() {
+ verify(eventPersister).saveEvent(any(Resource.class), argThat(new BaseMatcher<Event>() {
@Override
public void describeTo(Description description) {
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java
index 8a4afa2a017..98664860bae 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java
@@ -19,13 +19,16 @@
*/
package org.sonar.batch.scan.filesystem;
+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.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.source.SnapshotDataTypes;
import org.sonar.core.source.db.SnapshotDataDao;
import org.sonar.core.source.db.SnapshotDataDto;
@@ -46,10 +49,19 @@ public class PreviousFileHashLoaderTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
- PastSnapshotFinder pastSnapshotFinder = mock(PastSnapshotFinder.class);
- Snapshot snapshot = mock(Snapshot.class);
- SnapshotDataDao snapshotDataDao = mock(SnapshotDataDao.class);
- PreviousFileHashLoader loader = new PreviousFileHashLoader(snapshot, snapshotDataDao, pastSnapshotFinder);
+ private PastSnapshotFinder pastSnapshotFinder = mock(PastSnapshotFinder.class);
+ private Snapshot snapshot = mock(Snapshot.class);
+ private SnapshotDataDao snapshotDataDao = mock(SnapshotDataDao.class);
+ private Project project = new Project("foo");
+ private ResourceCache resourceCache;
+ private PreviousFileHashLoader loader;
+
+ @Before
+ public void prepare() {
+ resourceCache = new ResourceCache();
+ resourceCache.add(project, snapshot);
+ loader = new PreviousFileHashLoader(project, resourceCache, snapshotDataDao, pastSnapshotFinder);
+ }
@Test
public void should_return_null_if_no_previous_snapshot() throws Exception {
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java b/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java
index 73fde1c1077..cb19d408d47 100644
--- a/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java
+++ b/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java
@@ -37,6 +37,10 @@ public class ResourceComponent implements Component {
private Long resourceId;
public ResourceComponent(Resource resource, @Nullable Snapshot snapshot) {
+ this(resource, snapshot != null ? snapshot.getId() : null);
+ }
+
+ public ResourceComponent(Resource resource, @Nullable Integer snapshotId) {
this.key = resource.getEffectiveKey();
this.path = resource.getPath();
if (Strings.isNullOrEmpty(key)) {
@@ -46,14 +50,14 @@ public class ResourceComponent implements Component {
this.longName = resource.getLongName();
this.qualifier = resource.getQualifier();
this.scope = resource.getScope();
- if (snapshot != null && snapshot.getId() != null) {
- this.snapshotId = snapshot.getId().longValue();
- this.resourceId = snapshot.getResourceId().longValue();
+ if (snapshotId != null) {
+ this.snapshotId = snapshotId.longValue();
+ this.resourceId = resource.getId().longValue();
}
}
public ResourceComponent(Resource resource) {
- this(resource, null);
+ this(resource, (Integer) null);
}
@Override
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java b/sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java
index 93e7529f0eb..bdc7bc2142f 100644
--- a/sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java
+++ b/sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java
@@ -25,7 +25,6 @@ import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
import org.sonar.api.BatchComponent;
import org.sonar.api.component.Component;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Resource;
import org.sonar.core.graph.BeanGraph;
import org.sonar.core.graph.BeanIterable;
@@ -59,8 +58,8 @@ public class ScanGraph extends BeanGraph implements BatchComponent {
return vertex != null ? wrapComponent(vertex) : null;
}
- public ComponentVertex addComponent(Resource resource, @Nullable Snapshot snapshot) {
- return addComponent(new ResourceComponent(resource, snapshot));
+ public ComponentVertex addComponent(Resource resource, @Nullable Integer snapshotId) {
+ return addComponent(new ResourceComponent(resource, snapshotId));
}
public Iterable<ComponentVertex> getComponents() {
diff --git a/sonar-core/src/test/java/org/sonar/core/component/ResourceComponentTest.java b/sonar-core/src/test/java/org/sonar/core/component/ResourceComponentTest.java
index aa83169c91a..5b060c9e1e0 100644
--- a/sonar-core/src/test/java/org/sonar/core/component/ResourceComponentTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/component/ResourceComponentTest.java
@@ -50,6 +50,7 @@ public class ResourceComponentTest {
public void db_ids_should_be_set() {
Snapshot snapshot = new Snapshot();
snapshot.setId(123);
+ file.setId(456);
snapshot.setResourceId(456);
ResourceComponent component = new ResourceComponent(file, snapshot);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java
index 01d17a9fbe8..edafda1b3c8 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java
@@ -23,9 +23,14 @@ import org.apache.commons.lang.builder.ToStringBuilder;
import org.sonar.api.database.BaseIdentifiable;
import org.sonar.api.database.model.Snapshot;
-import java.util.Date;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
-import javax.persistence.*;
+import java.util.Date;
/**
* @since 1.10
@@ -71,29 +76,6 @@ public class Event extends BaseIdentifiable {
this.category = category;
}
- /**
- * @deprecated in 2.5
- */
- @Deprecated
- public Event(String name, String description, String category, Date date, Integer resourceId) {
- this.name = name;
- this.description = description;
- this.category = category;
- this.date = date;
- this.resourceId = resourceId;
- }
-
- /**
- * @deprecated in 2.5
- */
- @Deprecated
- public Event(String name, String description, String category, Snapshot snapshot) {
- this.name = name;
- this.description = description;
- this.category = category;
- setSnapshot(snapshot);
- }
-
public String getName() {
return name;
}
@@ -174,11 +156,11 @@ public class Event extends BaseIdentifiable {
@Override
public String toString() {
return new ToStringBuilder(this)
- .append("name", name)
- .append("categ", category)
- .append("date", date)
- .append("snapshot", snapshot)
- .append("resource", resourceId)
- .toString();
+ .append("name", name)
+ .append("categ", category)
+ .append("date", date)
+ .append("snapshot", snapshot)
+ .append("resource", resourceId)
+ .toString();
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/database/BaseIdentifiable.java b/sonar-plugin-api/src/main/java/org/sonar/api/database/BaseIdentifiable.java
index d9b24868134..a1a4eb688c3 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/database/BaseIdentifiable.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/database/BaseIdentifiable.java
@@ -25,7 +25,7 @@ import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@MappedSuperclass
-public class BaseIdentifiable {
+public class BaseIdentifiable<G> {
@Id
@Column(name = "id")
@@ -36,7 +36,8 @@ public class BaseIdentifiable {
return id;
}
- public void setId(Integer id) {
+ public G setId(Integer id) {
this.id = id;
+ return (G) this;
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java
index 021007dd94b..0912b7d6675 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java
@@ -40,7 +40,7 @@ import java.util.Date;
*/
@Entity
@Table(name = "snapshots")
-public class Snapshot extends BaseIdentifiable implements Serializable {
+public class Snapshot extends BaseIdentifiable<Snapshot> implements Serializable {
/**
* This status is set on the snapshot at the beginning of the batch
@@ -161,10 +161,10 @@ public class Snapshot extends BaseIdentifiable implements Serializable {
this.createdAt = parent.getCreatedAt();
this.depth = parent.getDepth() + 1;
this.path = new StringBuilder()
- .append(parent.getPath())
- .append(parent.getId())
- .append(".")
- .toString();
+ .append(parent.getPath())
+ .append(parent.getId())
+ .append(".")
+ .toString();
}
this.rootProjectId = guessRootProjectId(resource, parent);
}
@@ -702,17 +702,17 @@ public class Snapshot extends BaseIdentifiable implements Serializable {
}
Snapshot other = (Snapshot) obj;
return new EqualsBuilder()
- .append(resourceId, other.getResourceId())
- .append(createdAt, other.getCreatedAt())
- .isEquals();
+ .append(resourceId, other.getResourceId())
+ .append(createdAt, other.getCreatedAt())
+ .isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
- .append(resourceId)
- .append(createdAt)
- .toHashCode();
+ .append(resourceId)
+ .append(createdAt)
+ .toHashCode();
}
@Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java
index 2542aeb19d5..02005504b80 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java
@@ -547,7 +547,6 @@ public class DefaultIssue implements Issue {
}
@Override
- @SuppressWarnings("unchcked")
public List<IssueComment> comments() {
if (comments == null) {
return Collections.emptyList();