aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'sonar-batch/src/main/java/org')
-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.java (renamed from sonar-batch/src/main/java/org/sonar/batch/index/SnapshotCache.java)30
-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
29 files changed, 591 insertions, 495 deletions
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/index/SnapshotCache.java b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
index 6e21c2d2200..c9d42f0a849 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/SnapshotCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
@@ -17,33 +17,13 @@
* 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.report;
-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 java.io.File;
+import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
+public interface ReportPublisher {
-/**
- * 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 Snapshot get(String componentKey) {
- return snapshots.get(componentKey);
- }
-
- public SnapshotCache put(String componentKey, Snapshot snapshot) {
- snapshots.put(componentKey, snapshot);
- return this;
- }
+ void export(File reportDir) throws IOException;
- public Set<Map.Entry<String, Snapshot>> snapshots() {
- return snapshots.entrySet();
- }
}
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,