diff options
Diffstat (limited to 'sonar-batch/src/main/java/org')
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, |