From 19f841e8c13c6dc8ef2f6a68a5751fa5fba26062 Mon Sep 17 00:00:00 2001 From: simonbrandhof Date: Fri, 26 Nov 2010 06:56:17 +0000 Subject: [PATCH] SONAR-249: extract persistence layer from data index + dump measures at the end of the batch instead of persisting them on the fly --- .../core/sensors/TendencyDecorator.java | 5 +- .../src/main/java/org/sonar/batch/Batch.java | 19 +- .../sonar/batch/DefaultDecoratorContext.java | 29 +- .../org/sonar/batch/DefaultMetricFinder.java | 66 +++ .../org/sonar/batch/DefaultSensorContext.java | 20 +- .../org/sonar/batch/DefaultTimeMachine.java | 50 +- .../java/org/sonar/batch/ProjectBatch.java | 49 +- .../java/org/sonar/batch/ViolationsDao.java | 102 ---- .../batch/{indexer => index}/Bucket.java | 126 +++-- .../org/sonar/batch/index/DefaultIndex.java | 442 ++++++++++++++++ .../index/DefaultPersistenceManager.java | 112 +++++ .../batch/index/DependencyPersister.java | 63 +++ .../org/sonar/batch/index/EventPersister.java | 65 +++ .../org/sonar/batch/index/LinkPersister.java | 68 +++ .../sonar/batch/index/MeasurePersister.java | 133 +++++ .../sonar/batch/index/PersistenceManager.java | 61 +++ .../sonar/batch/index/ResourcePersister.java | 247 +++++++++ .../sonar/batch/index/SourcePersister.java | 59 +++ .../sonar/batch/index/ViolationPersister.java | 79 +++ .../sonar/batch/indexer/DefaultPersister.java | 52 -- .../batch/indexer/DefaultSonarIndex.java | 470 ------------------ .../sonar/batch/indexer/LibraryPersister.java | 100 ---- .../sonar/batch/indexer/ProjectPersister.java | 58 --- .../batch/indexer/ResourcePersister.java | 96 ---- .../batch/indexer/ResourcePersisters.java | 50 -- .../{ => phases}/DecoratorsExecutor.java | 21 +- .../{ => phases}/MavenPhaseExecutor.java | 9 +- .../MavenPluginsConfigurator.java | 8 +- .../java/org/sonar/batch/phases/Phases.java | 88 ++++ .../batch/{ => phases}/PostJobsExecutor.java | 23 +- .../batch/{ => phases}/SensorsExecutor.java | 10 +- .../UpdateStatusJob.java} | 24 +- .../java/org/sonar/batch/CoreJobsTest.java | 29 -- .../sonar/batch/DefaultTimeMachineTest.java | 226 ++++----- .../org/sonar/batch/index/BucketTest.java | 110 ++++ .../sonar/batch/index/DefaultIndexTest.java} | 10 +- .../batch/index/MeasurePersisterTest.java | 133 +++++ .../batch/index/ResourcePersisterTest.java | 140 ++++++ .../batch/indexer/DefaultPersisterTest.java | 61 --- .../batch/indexer/DefaultSonarIndexTest.java | 72 --- .../batch/indexer/LibraryPersisterTest.java | 94 ---- .../batch/indexer/ResourcePersistersTest.java | 67 --- .../{ => phases}/MavenPhaseExecutorTest.java | 8 +- .../MavenPluginsConfiguratorTest.java | 6 +- .../org/sonar/batch/phases/PhasesTest.java | 33 ++ .../{ => phases}/PostJobsExecutorTest.java | 23 +- .../UpdateStatusJobTest.java} | 11 +- .../doNotFailIfNoPenultimateLast-result.xml | 22 - .../doNotFailIfNoPenultimateLast.xml | 23 - ...pdatedWhenAnalyzingPastSnapshot-result.xml | 173 ------- ...tIsNotUpdatedWhenAnalyzingPastSnapshot.xml | 174 ------- .../sharedFixture.xml | 38 -- ...ldUnflagPenultimateLastSnapshot-result.xml | 55 -- .../shouldUnflagPenultimateLastSnapshot.xml | 57 --- .../MavenPluginsConfiguratorTest/pom.xml | 0 .../index/MeasurePersisterTest/shared.xml | 31 ++ .../shouldDelaySaving-result.xml | 45 ++ .../shouldInsertMeasure-result.xml | 35 ++ ...aySavingWithDatabaseOnlyMeasure-result.xml | 42 ++ .../shouldUpdateMeasure-result.xml | 30 ++ .../index/ResourcePersisterTest/shared.xml | 12 + .../shouldSaveNewDirectory-result.xml | 30 ++ .../shouldSaveNewLibrary-result.xml | 34 ++ ...houldSaveNewMultiModulesProject-result.xml | 48 ++ .../shouldSaveNewProject-result.xml | 22 + .../shouldUpdateExistingResource-result.xml | 17 + .../shouldUpdateExistingResource.xml | 11 + .../createResource-result.xml | 23 - .../DefaultPersisterTest/createResource.xml | 12 - .../updateExistingResource-result.xml | 23 - .../updateExistingResource.xml | 18 - .../addNewLibraryVersion-result.xml | 23 - .../addNewLibraryVersion.xml | 19 - .../createLibrary-result.xml | 19 - .../LibraryPersisterTest/createLibrary.xml | 11 - .../reuseExistingLibrary-result.xml | 19 - .../reuseExistingLibrary.xml | 19 - .../MavenPluginsConfiguratorTest/pom.xml | 19 + .../org/sonar/jpa/dao/AsyncMeasuresDao.java | 2 +- .../sonar/jpa/dao/AsyncMeasuresService.java | 10 +- .../jpa/session/DatabaseSessionTest.java | 6 +- .../main/java/org/sonar/api/batch/Event.java | 8 + .../java/org/sonar/api/batch/SonarIndex.java | 10 +- .../org/sonar/api/batch/TimeMachineQuery.java | 24 + .../api/database/model/MeasureModel.java | 101 +--- .../api/database/model/RuleFailureModel.java | 22 +- .../java/org/sonar/api/measures/Measure.java | 44 +- .../sonar/api/measures/MeasuresFilters.java | 12 +- .../org/sonar/api/measures/MetricFinder.java | 28 +- .../java/org/sonar/api/rules/Violation.java | 6 +- .../api/database/model/MeasureModelTest.java | 86 ++-- .../AverageComplexityFormulaTest.java | 14 +- .../sonar/api/measures/MeasureUtilsTest.java | 4 +- .../webapp/WEB-INF/app/models/snapshot.rb | 3 +- 94 files changed, 2768 insertions(+), 2543 deletions(-) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/DefaultMetricFinder.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/ViolationsDao.java rename sonar-batch/src/main/java/org/sonar/batch/{indexer => index}/Bucket.java (58%) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultPersister.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultSonarIndex.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/indexer/LibraryPersister.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/indexer/ProjectPersister.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersister.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersisters.java rename sonar-batch/src/main/java/org/sonar/batch/{ => phases}/DecoratorsExecutor.java (84%) rename sonar-batch/src/main/java/org/sonar/batch/{ => phases}/MavenPhaseExecutor.java (85%) rename sonar-batch/src/main/java/org/sonar/batch/{ => phases}/MavenPluginsConfigurator.java (93%) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java rename sonar-batch/src/main/java/org/sonar/batch/{ => phases}/PostJobsExecutor.java (84%) rename sonar-batch/src/main/java/org/sonar/batch/{ => phases}/SensorsExecutor.java (93%) rename sonar-batch/src/main/java/org/sonar/batch/{FinalizeSnapshotsJob.java => phases/UpdateStatusJob.java} (82%) delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/CoreJobsTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java rename sonar-batch/src/{main/java/org/sonar/batch/CoreJob.java => test/java/org/sonar/batch/index/DefaultIndexTest.java} (81%) create mode 100644 sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/index/ResourcePersisterTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultPersisterTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultSonarIndexTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/indexer/LibraryPersisterTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/indexer/ResourcePersistersTest.java rename sonar-batch/src/test/java/org/sonar/batch/{ => phases}/MavenPhaseExecutorTest.java (90%) rename sonar-batch/src/test/java/org/sonar/batch/{ => phases}/MavenPluginsConfiguratorTest.java (92%) create mode 100644 sonar-batch/src/test/java/org/sonar/batch/phases/PhasesTest.java rename sonar-batch/src/test/java/org/sonar/batch/{ => phases}/PostJobsExecutorTest.java (70%) rename sonar-batch/src/test/java/org/sonar/batch/{FinalizeSnapshotsJobTest.java => phases/UpdateStatusJobTest.java} (85%) delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/sharedFixture.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot.xml rename sonar-batch/src/test/resources/org/sonar/batch/{ => MavenProjectBuilderTest}/MavenPluginsConfiguratorTest/pom.xml (100%) create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shared.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldDelaySaving-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldInsertMeasure-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldNotDelaySavingWithDatabaseOnlyMeasure-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldUpdateMeasure-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shared.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewDirectory-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewLibrary-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewMultiModulesProject-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewProject-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource-result.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary-result.xml delete mode 100644 sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary.xml create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/phases/MavenPluginsConfiguratorTest/pom.xml rename sonar-batch/src/main/java/org/sonar/batch/CoreJobs.java => sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java (59%) diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/TendencyDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/TendencyDecorator.java index 2b85ad195c4..4a0c9537704 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/TendencyDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/TendencyDecorator.java @@ -20,16 +20,17 @@ package org.sonar.plugins.core.sensors; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.time.DateUtils; import org.sonar.api.CoreProperties; import org.sonar.api.batch.*; -import org.sonar.jpa.dao.MeasuresDao; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.resources.ResourceUtils; +import org.sonar.jpa.dao.MeasuresDao; import java.util.ArrayList; import java.util.List; @@ -92,7 +93,7 @@ public class TendencyDecorator implements Decorator { if (shouldDecorateResource(resource)) { resetQuery(context.getProject(), resource); List fields = timeMachine.getMeasuresFields(query); - ArrayListMultimap valuesPerMetric = ArrayListMultimap.create(); + ListMultimap valuesPerMetric = ArrayListMultimap.create(); for (Object[] field : fields) { valuesPerMetric.put((Metric) field[1], (Double) field[2]); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/Batch.java index cd2e0709eaf..847bd08cdeb 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/Batch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/Batch.java @@ -29,8 +29,9 @@ import org.sonar.api.resources.Project; import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.IocContainer; import org.sonar.api.utils.ServerHttpClient; -import org.sonar.batch.indexer.DefaultSonarIndex; +import org.sonar.batch.index.*; import org.sonar.core.plugin.JpaPluginDao; +import org.sonar.jpa.dao.MeasuresDao; import org.sonar.jpa.session.DatabaseSessionProvider; import org.sonar.jpa.session.DriverDatabaseConnector; import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory; @@ -70,16 +71,26 @@ public class Batch { batchContainer.as(Characteristics.CACHE).addComponent(ServerMetadata.class); batchContainer.as(Characteristics.CACHE).addComponent(ProjectTree.class); batchContainer.as(Characteristics.CACHE).addComponent(DefaultResourceCreationLock.class); - batchContainer.as(Characteristics.CACHE).addComponent(DefaultSonarIndex.class); + batchContainer.as(Characteristics.CACHE).addComponent(DefaultMetricFinder.class); + batchContainer.as(Characteristics.CACHE).addComponent(DefaultIndex.class); + batchContainer.as(Characteristics.CACHE).addComponent(DefaultPersistenceManager.class); + batchContainer.as(Characteristics.CACHE).addComponent(DependencyPersister.class); + batchContainer.as(Characteristics.CACHE).addComponent(EventPersister.class); + batchContainer.as(Characteristics.CACHE).addComponent(LinkPersister.class); + batchContainer.as(Characteristics.CACHE).addComponent(MeasurePersister.class); + batchContainer.as(Characteristics.CACHE).addComponent(ResourcePersister.class); + batchContainer.as(Characteristics.CACHE).addComponent(SourcePersister.class); + batchContainer.as(Characteristics.CACHE).addComponent(ViolationPersister.class); batchContainer.as(Characteristics.CACHE).addComponent(JpaPluginDao.class); batchContainer.as(Characteristics.CACHE).addComponent(BatchPluginRepository.class); batchContainer.as(Characteristics.CACHE).addComponent(Plugins.class); batchContainer.as(Characteristics.CACHE).addComponent(ServerHttpClient.class); batchContainer.as(Characteristics.CACHE).addComponent(HttpDownloader.class); + batchContainer.as(Characteristics.CACHE).addComponent(MeasuresDao.class); batchContainer.start(); ProjectTree projectTree = batchContainer.getComponent(ProjectTree.class); - DefaultSonarIndex index = batchContainer.getComponent(DefaultSonarIndex.class); + DefaultIndex index = batchContainer.getComponent(DefaultIndex.class); analyzeProject(batchContainer, index, projectTree.getRootProject()); // batchContainer is stopped by its parent @@ -106,7 +117,7 @@ public class Batch { container.as(Characteristics.CACHE).addComponent(component); } - private void analyzeProject(MutablePicoContainer container, DefaultSonarIndex index, Project project) { + private void analyzeProject(MutablePicoContainer container, DefaultIndex index, Project project) { for (Project module : project.getModules()) { analyzeProject(container, index, module); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java index f812bd0e8fe..55977a1c102 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java @@ -30,31 +30,27 @@ import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.rules.Violation; -import org.sonar.batch.indexer.Bucket; -import org.sonar.batch.indexer.DefaultSonarIndex; +import org.sonar.batch.index.DefaultIndex; import java.util.*; public class DefaultDecoratorContext implements DecoratorContext { private DatabaseSession session; - private DefaultSonarIndex index; + private DefaultIndex index; private Resource resource; private boolean readOnly = false; private List childrenContexts; - private ViolationsDao violationsDao; public DefaultDecoratorContext(Resource resource, - DefaultSonarIndex index, + DefaultIndex index, List childrenContexts, - DatabaseSession session, - ViolationsDao violationsDao) { + DatabaseSession session) { this.index = index; this.session = session; this.resource = resource; this.childrenContexts = childrenContexts; - this.violationsDao = violationsDao; } public DefaultDecoratorContext setReadOnly(boolean b) { @@ -111,29 +107,24 @@ public class DefaultDecoratorContext implements DecoratorContext { public DecoratorContext saveMeasure(Measure measure) { checkReadOnly("saveMeasure"); - index.saveMeasure(resource, measure); + index.addMeasure(resource, measure); return this; } public DecoratorContext saveMeasure(Metric metric, Double value) { checkReadOnly("saveMeasure"); - index.saveMeasure(resource, new Measure(metric, value)); + index.addMeasure(resource, new Measure(metric, value)); return this; } public List getViolations() { - Bucket bucket = index.getBucket(resource); - if (bucket != null && bucket.getSnapshotId() != null) { - return violationsDao.getViolations(resource, bucket.getSnapshotId()); - } - - return null; + return index.getViolations(resource); } public Dependency saveDependency(Dependency dependency) { - checkReadOnly("saveDependency"); - return index.saveDependency(dependency); + checkReadOnly("addDependency"); + return index.addDependency(dependency); } public Set getDependencies() { @@ -157,7 +148,7 @@ public class DefaultDecoratorContext implements DecoratorContext { } public Event createEvent(String name, String description, String category, Date date) { - return index.createEvent(resource, name, description, category, date); + return index.addEvent(resource, name, description, category, date); } public void deleteEvent(Event event) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultMetricFinder.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultMetricFinder.java new file mode 100644 index 00000000000..b0c7f01c9c5 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultMetricFinder.java @@ -0,0 +1,66 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.MetricFinder; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public final class DefaultMetricFinder implements MetricFinder { + + private DatabaseSession session; + private Map metrics = Maps.newHashMap(); + + public DefaultMetricFinder(DatabaseSession session) { + this.session = session; + } + + public void start() { + List list = session.getResults(Metric.class, "enabled", true); + for (Metric metric : list) { + metrics.put(metric.getKey(), metric); + } + } + + public Metric find(String key) { + return metrics.get(key); + } + + public Collection findAll(List metricKeys) { + List result = Lists.newLinkedList(); + for (String metricKey : metricKeys) { + Metric metric = find(metricKey); + if (metric != null) { + result.add(metric); + } + } + return result; + } + + public Collection findAll() { + return metrics.values(); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java index de2629ed336..f1f2921e570 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java @@ -29,7 +29,7 @@ import org.sonar.api.resources.Project; import org.sonar.api.resources.ProjectLink; import org.sonar.api.resources.Resource; import org.sonar.api.rules.Violation; -import org.sonar.batch.indexer.DefaultSonarIndex; +import org.sonar.batch.index.DefaultIndex; import java.util.Collection; import java.util.Date; @@ -38,10 +38,10 @@ import java.util.Set; public class DefaultSensorContext implements SensorContext { - private DefaultSonarIndex index; + private DefaultIndex index; private Project project; - public DefaultSensorContext(DefaultSonarIndex index, Project project) { + public DefaultSensorContext(DefaultIndex index, Project project) { this.index = index; this.project = project; } @@ -59,11 +59,11 @@ public class DefaultSensorContext implements SensorContext { } public Measure saveMeasure(Measure measure) { - return index.saveMeasure(project, measure); + return index.addMeasure(project, measure); } public Measure saveMeasure(Metric metric, Double value) { - return index.saveMeasure(project, new Measure(metric, value)); + return index.addMeasure(project, new Measure(metric, value)); } public Measure getMeasure(Resource resource, Metric metric) { @@ -87,11 +87,11 @@ public class DefaultSensorContext implements SensorContext { } public Measure saveMeasure(Resource resource, Metric metric, Double value) { - return index.saveMeasure(resourceOrProject(resource), new Measure(metric, value)); + return index.addMeasure(resourceOrProject(resource), new Measure(metric, value)); } public Measure saveMeasure(Resource resource, Measure measure) { - return index.saveMeasure(resourceOrProject(resource), measure); + return index.addMeasure(resourceOrProject(resource), measure); } public void saveViolation(Violation violation) { @@ -110,7 +110,7 @@ public class DefaultSensorContext implements SensorContext { } public Dependency saveDependency(Dependency dependency) { - return index.saveDependency(dependency); + return index.addDependency(dependency); } public Set getDependencies() { @@ -130,7 +130,7 @@ public class DefaultSensorContext implements SensorContext { } public void saveLink(ProjectLink link) { - index.saveLink(link); + index.addLink(link); } public void deleteLink(String key) { @@ -142,7 +142,7 @@ public class DefaultSensorContext implements SensorContext { } public Event createEvent(Resource resource, String name, String description, String category, Date date) { - return index.createEvent(resource, name, description, category, date); + return index.addEvent(resource, name, description, category, date); } public void deleteEvent(Event event) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java index 53872ce465a..86fe3f38b58 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java +++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java @@ -19,14 +19,18 @@ */ package org.sonar.batch; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import org.sonar.api.batch.TimeMachine; import org.sonar.api.batch.TimeMachineQuery; import org.sonar.api.database.DatabaseSession; 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.Metric; +import org.sonar.api.measures.MetricFinder; import org.sonar.api.resources.Resource; -import org.sonar.batch.indexer.DefaultSonarIndex; +import org.sonar.batch.index.DefaultIndex; import org.sonar.jpa.dao.MeasuresDao; import java.util.*; @@ -35,22 +39,24 @@ import javax.persistence.Query; public class DefaultTimeMachine implements TimeMachine { private DatabaseSession session; - private DefaultSonarIndex index; - private MeasuresDao measuresDao; + private DefaultIndex index; + private MetricFinder metricFinder; - public DefaultTimeMachine(DatabaseSession session, DefaultSonarIndex index, MeasuresDao measuresDao) { + public DefaultTimeMachine(DatabaseSession session, DefaultIndex index, MetricFinder metricFinder) { this.session = session; this.index = index; - this.measuresDao = measuresDao; + this.metricFinder = metricFinder; } public List getMeasures(TimeMachineQuery query) { - List objects = execute(query, true); - List result = new ArrayList(); + Map metricById = getMetricsById(query); + + List objects = execute(query, true, metricById.keySet()); + List result = Lists.newArrayList(); for (Object[] object : objects) { MeasureModel model = (MeasureModel) object[0]; - Measure measure = model.toMeasure(); + Measure measure = model.toMeasure(metricById.get(model.getMetricId())); measure.setDate((Date) object[1]); result.add(measure); } @@ -58,10 +64,15 @@ public class DefaultTimeMachine implements TimeMachine { } public List getMeasuresFields(TimeMachineQuery query) { - return execute(query, false); + Map metricById = getMetricsById(query); + List rows = execute(query, false, metricById.keySet()); + for (Object[] fields : rows) { + fields[1]=metricById.get(fields[1]); + } + return rows; } - protected List execute(TimeMachineQuery query, boolean selectAllFields) { + protected List execute(TimeMachineQuery query, boolean selectAllFields, Set metricIds) { Resource resource = query.getResource(); if (resource!=null && resource.getId()==null) { resource = index.getResource(query.getResource()); @@ -71,21 +82,21 @@ public class DefaultTimeMachine implements TimeMachine { } StringBuilder sb = new StringBuilder(); - Map params = new HashMap(); + Map params = Maps.newHashMap(); if (selectAllFields) { sb.append("SELECT m, s.createdAt "); } else { - sb.append("SELECT s.createdAt, m.metric, m.value "); + sb.append("SELECT s.createdAt, m.metricId, m.value "); } sb.append(" FROM " + MeasureModel.class.getSimpleName() + " m, " + Snapshot.class.getSimpleName() + " s WHERE m.snapshotId=s.id AND s.resourceId=:resourceId AND s.status=:status AND m.characteristic IS NULL "); params.put("resourceId", resource.getId()); params.put("status", Snapshot.STATUS_PROCESSED); sb.append(" AND m.rule IS NULL AND m.rulePriority IS NULL AND m.rulesCategoryId IS NULL "); - if (query.getMetrics() != null) { - sb.append(" AND m.metric IN (:metrics) "); - params.put("metrics", measuresDao.getMetrics(query.getMetrics())); + if (!metricIds.isEmpty()) { + sb.append(" AND m.metricId IN (:metricIds) "); + params.put("metricIds", metricIds); } if (query.isFromCurrentAnalysis()) { sb.append(" AND s.createdAt>=:from "); @@ -116,4 +127,13 @@ public class DefaultTimeMachine implements TimeMachine { } return jpaQuery.getResultList(); } + + public Map getMetricsById(TimeMachineQuery query) { + Collection metrics = metricFinder.findAll(query.getMetricKeys()); + Map result = Maps.newHashMap(); + for (Metric metric : metrics) { + result.put(metric.getId(), metric); + } + return result; + } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java b/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java index cee58be0c82..83b21a6dd39 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java @@ -19,18 +19,15 @@ */ package org.sonar.batch; -import java.util.List; - import org.picocontainer.Characteristics; import org.picocontainer.MutablePicoContainer; import org.sonar.api.batch.BatchExtensionDictionnary; import org.sonar.api.batch.FileFilter; import org.sonar.api.batch.ProjectClasspath; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.database.DatabaseSession; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; import org.sonar.api.measures.Metrics; +import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.DefaultProjectFileSystem; import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; @@ -38,15 +35,14 @@ import org.sonar.api.resources.Project; import org.sonar.api.rules.DefaultRulesManager; import org.sonar.api.utils.IocContainer; import org.sonar.api.utils.SonarException; -import org.sonar.batch.indexer.DefaultSonarIndex; +import org.sonar.batch.index.DefaultIndex; +import org.sonar.batch.index.ResourcePersister; +import org.sonar.batch.phases.Phases; import org.sonar.core.qualitymodel.DefaultModelFinder; import org.sonar.core.rule.DefaultRuleFinder; -import org.sonar.jpa.dao.AsyncMeasuresDao; -import org.sonar.jpa.dao.AsyncMeasuresService; -import org.sonar.jpa.dao.DaoFacade; -import org.sonar.jpa.dao.MeasuresDao; -import org.sonar.jpa.dao.ProfilesDao; -import org.sonar.jpa.dao.RulesDao; +import org.sonar.jpa.dao.*; + +import java.util.List; public class ProjectBatch { @@ -57,29 +53,22 @@ public class ProjectBatch { this.globalContainer = container; } - public void execute(DefaultSonarIndex index, Project project) { + public void execute(DefaultIndex index, Project project) { try { startChildContainer(index, project); - SensorContext sensorContext = batchContainer.getComponent(SensorContext.class); - for (Class clazz : CoreJobs.allJobs()) { - CoreJob job = getComponent(clazz); - job.execute(project, sensorContext); - commit(); - } + batchContainer.getComponent(Phases.class).execute(project); } finally { - index.clear(); stop(); } } - public void startChildContainer(DefaultSonarIndex index, Project project) { + public void startChildContainer(DefaultIndex index, Project project) { batchContainer = globalContainer.makeChildContainer(); batchContainer.as(Characteristics.CACHE).addComponent(project); batchContainer.as(Characteristics.CACHE).addComponent(project.getPom()); batchContainer.as(Characteristics.CACHE).addComponent(ProjectClasspath.class); - batchContainer.as(Characteristics.CACHE).addComponent(index.getBucket(project).getSnapshot()); batchContainer.as(Characteristics.CACHE).addComponent(project.getConfiguration()); // need to be registered after the Configuration @@ -87,8 +76,11 @@ public class ProjectBatch { batchContainer.as(Characteristics.CACHE).addComponent(DaoFacade.class); batchContainer.as(Characteristics.CACHE).addComponent(RulesDao.class); + + // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor) + batchContainer.as(Characteristics.CACHE).addComponent(globalContainer.getComponent(ResourcePersister.class).getSnapshot(project)); + batchContainer.as(Characteristics.CACHE).addComponent(org.sonar.api.database.daos.RulesDao.class); - batchContainer.as(Characteristics.CACHE).addComponent(MeasuresDao.class); batchContainer.as(Characteristics.CACHE).addComponent(org.sonar.api.database.daos.MeasuresDao.class); batchContainer.as(Characteristics.CACHE).addComponent(ProfilesDao.class); batchContainer.as(Characteristics.CACHE).addComponent(AsyncMeasuresDao.class); @@ -98,7 +90,6 @@ public class ProjectBatch { batchContainer.as(Characteristics.CACHE).addComponent(Languages.class); batchContainer.as(Characteristics.CACHE).addComponent(BatchExtensionDictionnary.class); batchContainer.as(Characteristics.CACHE).addComponent(DefaultTimeMachine.class); - batchContainer.as(Characteristics.CACHE).addComponent(ViolationsDao.class); batchContainer.as(Characteristics.CACHE).addComponent(ViolationFilters.class); batchContainer.as(Characteristics.CACHE).addComponent(ResourceFilters.class); batchContainer.as(Characteristics.CACHE).addComponent(DefaultModelFinder.class); @@ -113,21 +104,21 @@ public class ProjectBatch { prepareProject(project, index); } - private void prepareProject(Project project, DefaultSonarIndex index) { + private void prepareProject(Project project, DefaultIndex index) { Language language = getComponent(Languages.class).get(project.getLanguageKey()); if (language == null) { throw new SonarException("Language with key '" + project.getLanguageKey() + "' not found"); } project.setLanguage(language); - index.selectProject(project, getComponent(ResourceFilters.class), getComponent(ViolationFilters.class), - getComponent(MeasuresDao.class), getComponent(ViolationsDao.class)); + index.setCurrentProject(project, getComponent(ResourceFilters.class), getComponent(ViolationFilters.class), getComponent(RulesProfile.class)); List fileFilters = batchContainer.getComponents(FileFilter.class); ((DefaultProjectFileSystem) project.getFileSystem()).addFileFilters(fileFilters); } private void loadCoreComponents(MutablePicoContainer container) { - for (Class clazz : CoreJobs.allJobs()) { + container.as(Characteristics.CACHE).addComponent(Phases.class); + for (Class clazz : Phases.getPhaseClasses()) { container.as(Characteristics.CACHE).addComponent(clazz); } for (Metric metric : CoreMetrics.getMetrics()) { @@ -142,7 +133,6 @@ public class ProjectBatch { private void stop() { if (batchContainer != null) { - commit(); try { globalContainer.removeChildContainer(batchContainer); batchContainer.stop(); @@ -153,9 +143,6 @@ public class ProjectBatch { } } - public void commit() { - getComponent(DatabaseSession.class).commit(); - } public T getComponent(Class clazz) { if (batchContainer != null) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/ViolationsDao.java b/sonar-batch/src/main/java/org/sonar/batch/ViolationsDao.java deleted file mode 100644 index 00bc5e1cd7a..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/ViolationsDao.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch; - -import org.slf4j.LoggerFactory; -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.RuleFailureModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Resource; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.Violation; -import org.sonar.jpa.dao.RulesDao; - -import java.util.ArrayList; -import java.util.List; - -public class ViolationsDao { - - private RulesProfile profile; - private DatabaseSession session; - private RulesDao rulesDao; - private boolean reuseExistingRulesConfig; - - public ViolationsDao(RulesProfile profile, DatabaseSession session, RulesDao rulesDao, Project project) { - this.profile = profile; - this.session = session; - this.rulesDao = rulesDao; - this.reuseExistingRulesConfig = project.getReuseExistingRulesConfig(); - } - - public List getViolations(Resource resource, Integer snapshotId) { - List models = session.getResults(RuleFailureModel.class, "snapshotId", snapshotId); - List violations = new ArrayList(); - for (RuleFailureModel model : models) { - Violation violation = Violation.create(model.getRule(), resource); - violation.setLineId(model.getLine()); - violation.setMessage(model.getMessage()); - violation.setPriority(model.getPriority()); - violation.setCost(model.getCost()); - violations.add(violation); - } - return violations; - } - - public void saveViolation(Snapshot snapshot, Violation violation) { - if (profile == null || snapshot == null || violation == null || violation.getRule() == null) { - throw new IllegalArgumentException("Missing data to save violation : profile=" + profile + ",snapshot=" + snapshot + ",violation=" + violation); - } - - ActiveRule activeRule = profile.getActiveRule(violation.getRule()); - if (activeRule == null) { - if (reuseExistingRulesConfig) { - activeRule = new ActiveRule(profile, violation.getRule(), violation.getRule().getPriority()); - } else { - LoggerFactory.getLogger(getClass()).debug("Violation is not saved because rule is not activated : violation={}", violation); - } - } - if (activeRule != null) { - RuleFailureModel model = toModel(snapshot, violation, activeRule); - session.save(model); - } - } - - private RuleFailureModel toModel(Snapshot snapshot, Violation violation, ActiveRule activeRule) { - Rule rule = reload(violation.getRule()); - if (rule == null) { - throw new IllegalArgumentException("Rule does not exist : " + violation.getRule()); - } - RuleFailureModel model = new RuleFailureModel(rule, activeRule.getPriority()); - violation.setPriority(activeRule.getPriority()); - model.setLine(violation.getLineId()); - model.setMessage(violation.getMessage()); - model.setCost(violation.getCost()); - model.setSnapshotId(snapshot.getId()); - - return model; - } - - private Rule reload(Rule rule) { - return rule.getId() != null ? rule : rulesDao.getRuleByKey(rule.getPluginName(), rule.getKey()); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/indexer/Bucket.java b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java similarity index 58% rename from sonar-batch/src/main/java/org/sonar/batch/indexer/Bucket.java rename to sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java index 98e107a2e4d..0969f089333 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/indexer/Bucket.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java @@ -17,64 +17,39 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch.indexer; +package org.sonar.batch.index; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; -import org.sonar.api.database.model.Snapshot; import org.sonar.api.measures.Measure; import org.sonar.api.measures.MeasuresFilter; import org.sonar.api.measures.MeasuresFilters; -import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Violation; +import org.sonar.api.utils.SonarException; import java.util.Collection; import java.util.Collections; import java.util.List; -public class Bucket { +public final class Bucket { - private RESOURCE resource; - private Snapshot snapshot; + private Resource resource; private ListMultimap measuresByMetric = ArrayListMultimap.create(); - private boolean sourceSaved = false; - private Bucket project; - private Bucket parent; - private List> children; + private List violations = Lists.newLinkedList(); - public Bucket(RESOURCE resource) { + private Bucket parent; + private List children; + + public Bucket(Resource resource) { this.resource = resource; } - public RESOURCE getResource() { + public Resource getResource() { return resource; } - public Bucket getProject() { - return project; - } - - public Bucket setProject(Bucket project) { - this.project = project; - return this; - } - - public Snapshot getSnapshot() { - return snapshot; - } - - public Integer getSnapshotId() { - if (snapshot != null) { - return snapshot.getId(); - } - return null; - } - - public void setSnapshot(Snapshot snapshot) { - this.snapshot = snapshot; - } - public void setParent(Bucket parent) { this.parent = parent; if (parent != null) { @@ -82,69 +57,92 @@ public class Bucket { } } - private void addChild(Bucket bucket) { + private void addChild(Bucket child) { if (children == null) { children = Lists.newArrayList(); } - children.add(bucket); + children.add(child); } - private void removeChild(Bucket bucket) { + private void removeChild(Bucket child) { if (children != null) { - children.remove(bucket); + children.remove(child); } } - public List> getChildren() { - if (children == null) { - return Collections.emptyList(); - } - return children; + public List getChildren() { + return (children == null ? Collections.emptyList() : children); } public Bucket getParent() { return parent; } - public void addMeasure(Measure measure) { - measuresByMetric.put(measure.getMetric().getKey(), measure); + public void addViolation(Violation violation) { + violations.add(violation); } - public boolean isSourceSaved() { - return sourceSaved; + public List getViolations() { + return violations; } - public void setSourceSaved(boolean b) { - this.sourceSaved = b; + public void addMeasure(Measure measure) { + List metricMeasures = measuresByMetric.get(measure.getMetric().getKey()); + + boolean add = true; + if (metricMeasures != null) { + int index = metricMeasures.indexOf(measure); + if (index > -1) { + if (metricMeasures.get(index) == measure) { + add = false; + } else { + throw new SonarException("Can not add twice the same measure: " + measure); + } + } + } + if (add) { + measuresByMetric.put(measure.getMetric().getKey(), measure); + } } public void clear() { measuresByMetric = null; + violations = null; children = null; if (parent != null) { parent.removeChild(this); + parent = null; } } - public boolean isExcluded() { - return resource.isExcluded(); - } - - public boolean isPersisted() { - return resource.getId() != null; - } - - public Integer getResourceId() { - return resource.getId(); - } - public M getMeasures(final MeasuresFilter filter) { Collection unfiltered; if (filter instanceof MeasuresFilters.MetricFilter) { - unfiltered = measuresByMetric.get(((MeasuresFilters.MetricFilter) filter).filterOnMetric().getKey()); + unfiltered = measuresByMetric.get(((MeasuresFilters.MetricFilter) filter).filterOnMetricKey()); } else { unfiltered = measuresByMetric.values(); } return filter.filter(unfiltered); } + + public boolean isExcluded() { + return resource.isExcluded(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Bucket that = (Bucket) o; + return resource.equals(that.resource); + } + + @Override + public int hashCode() { + return resource.hashCode(); + } } 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 new file mode 100644 index 00000000000..d8c411c1285 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java @@ -0,0 +1,442 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.Event; +import org.sonar.api.batch.SonarIndex; +import org.sonar.api.design.Dependency; +import org.sonar.api.measures.*; +import org.sonar.api.profiles.RulesProfile; +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 org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.Violation; +import org.sonar.api.utils.SonarException; +import org.sonar.batch.DefaultResourceCreationLock; +import org.sonar.batch.ProjectTree; +import org.sonar.batch.ResourceFilters; +import org.sonar.batch.ViolationFilters; + +import java.util.*; + +public final class DefaultIndex extends SonarIndex { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class); + + private RulesProfile profile; + private PersistenceManager persistence; + private DefaultResourceCreationLock lock; + private MetricFinder metricFinder; + + // filters + private ViolationFilters violationFilters; + private ResourceFilters resourceFilters; + + // caches + private Project currentProject; + private Map buckets = Maps.newHashMap(); + private Set dependencies = Sets.newHashSet(); + private Map> outgoingDependenciesByResource = Maps.newHashMap(); + private Map> incomingDependenciesByResource = Maps.newHashMap(); + private ProjectTree projectTree; + + public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder) { + this.persistence = persistence; + this.lock = lock; + this.projectTree = projectTree; + this.metricFinder = metricFinder; + } + + public void start() { + Project rootProject = projectTree.getRootProject(); + Bucket bucket = new Bucket(rootProject); + buckets.put(rootProject, bucket); + persistence.saveProject(rootProject); + currentProject = rootProject; + + for (Project project : rootProject.getModules()) { + addProject(project); + } + } + + private void addProject(Project project) { + addResource(project); + for (Project module : project.getModules()) { + addProject(module); + } + } + + public Project getProject() { + return currentProject; + } + + public void setCurrentProject(Project project, ResourceFilters resourceFilters, ViolationFilters violationFilters, RulesProfile profile) { + this.currentProject = project; + + // the following components depend on the current project, so they need to be reloaded. + this.resourceFilters = resourceFilters; + this.violationFilters = violationFilters; + this.profile = profile; + } + + public PersistenceManager getPersistenceManager() { + return persistence; + } + + /** + * Keep only project stuff + */ + public void clear() { + Iterator> it = buckets.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + Resource resource = entry.getKey(); + if (!ResourceUtils.isSet(resource)) { + entry.getValue().clear(); + it.remove(); + } + } + + Set projectDependencies = getDependenciesBetweenProjects(); + dependencies.clear(); + incomingDependenciesByResource.clear(); + outgoingDependenciesByResource.clear(); + for (Dependency projectDependency : projectDependencies) { + projectDependency.setId(null); + registerDependency(projectDependency); + } + + lock.unlock(); + } + + + /** + * Does nothing if the resource is already registered. + * + * @param resource + */ + public Resource addResource(Resource resource) { + getOrAddBucket(resource); + return resource; + } + + public Resource getResource(Resource resource) { + Bucket bucket = buckets.get(resource); + if (bucket != null) { + return bucket.getResource(); + } + return null; + } + + private Bucket getOrAddBucket(Resource resource) { + Bucket bucket = buckets.get(resource); + if (bucket != null) { + return bucket; + } + + if (lock.isLocked() && !ResourceUtils.isLibrary(resource)) { + LOG.warn("The following resource has not been registered before saving data: " + resource); + } + + bucket = new Bucket(resource); + Bucket parentBucket = null; + Resource parent = resource.getParent(); + if (parent != null) { + parentBucket = getOrAddBucket(parent); + } else if (!ResourceUtils.isLibrary(resource)) { + parentBucket = buckets.get(currentProject); + } + bucket.setParent(parentBucket); + buckets.put(resource, bucket); + + boolean excluded = checkExclusion(resource, parentBucket); + if (!excluded) { + persistence.saveResource(currentProject, resource); + } + return bucket; + } + + private boolean checkExclusion(Resource resource, Bucket parent) { + boolean excluded = (parent != null && parent.isExcluded()) || (resourceFilters != null && resourceFilters.isExcluded(resource)); + resource.setExcluded(excluded); + return excluded; + } + + + public List getChildren(Resource resource) { + List children = Lists.newArrayList(); + Bucket bucket = buckets.get(resource); + if (bucket != null) { + for (Bucket childBucket : bucket.getChildren()) { + children.add(childBucket.getResource()); + } + } + return children; + } + + public Resource getParent(Resource resource) { + Bucket bucket = buckets.get(resource); + if (bucket != null && bucket.getParent() != null) { + return bucket.getParent().getResource(); + } + return null; + } + + public Measure getMeasure(Resource resource, Metric metric) { + Bucket bucket = buckets.get(resource); + if (bucket != null) { + return bucket.getMeasures(MeasuresFilters.metric(metric)); + } + return null; + } + + public M getMeasures(Resource resource, MeasuresFilter filter) { + Bucket bucket = buckets.get(resource); + if (bucket != null) { + return bucket.getMeasures(filter); + } + return null; + } + + /** + * the measure is updated if it's already registered. + */ + public Measure addMeasure(Resource resource, Measure measure) { + Bucket bucket = getOrAddBucket(resource); + if (!bucket.isExcluded()) { + Metric metric = metricFinder.find(measure.getMetricKey()); + if (metric == null) { + throw new SonarException("Unknown metric: " + measure.getMetricKey()); + } + measure.setMetric(metric); + if (measure.getPersistenceMode().useMemory()) { + bucket.addMeasure(measure); + } + if (measure.getPersistenceMode().useDatabase()) { + persistence.saveMeasure(currentProject, resource, measure); + } + + // TODO keep database measures in cache but remove data + } + return measure; + } + + public void setSource(Resource resource, String source) { + Bucket bucket = getOrAddBucket(resource); + if (!bucket.isExcluded()) { + persistence.setSource(currentProject, resource, source); + } + } + + + // + // + // + // DEPENDENCIES + // + // + // + public Dependency addDependency(Dependency dependency) { + Dependency existingDep = getEdge(dependency.getFrom(), dependency.getTo()); + if (existingDep != null) { + return existingDep; + } + + Dependency parentDependency = dependency.getParent(); + if (parentDependency != null) { + addDependency(parentDependency); + } + + persistence.saveDependency(currentProject, dependency, parentDependency); + registerDependency(dependency); + return dependency; + } + + protected void registerDependency(Dependency dependency) { + dependencies.add(dependency); + registerOutgoingDependency(dependency); + registerIncomingDependency(dependency); + } + + private void registerOutgoingDependency(Dependency dependency) { + Map outgoingDeps = outgoingDependenciesByResource.get(dependency.getFrom()); + if (outgoingDeps == null) { + outgoingDeps = new HashMap(); + outgoingDependenciesByResource.put(dependency.getFrom(), outgoingDeps); + } + outgoingDeps.put(dependency.getTo(), dependency); + } + + private void registerIncomingDependency(Dependency dependency) { + Map incomingDeps = incomingDependenciesByResource.get(dependency.getTo()); + if (incomingDeps == null) { + incomingDeps = new HashMap(); + incomingDependenciesByResource.put(dependency.getTo(), incomingDeps); + } + incomingDeps.put(dependency.getFrom(), dependency); + } + + public Set getDependencies() { + return dependencies; + } + + public Dependency getEdge(Resource from, Resource to) { + Map map = outgoingDependenciesByResource.get(from); + if (map != null) { + return map.get(to); + } + return null; + } + + public boolean hasEdge(Resource from, Resource to) { + return getEdge(from, to) != null; + } + + public Set getVertices() { + return buckets.keySet(); + } + + public Collection getOutgoingEdges(Resource from) { + Map deps = outgoingDependenciesByResource.get(from); + if (deps != null) { + return deps.values(); + } + return Collections.emptyList(); + } + + public Collection getIncomingEdges(Resource to) { + Map deps = incomingDependenciesByResource.get(to); + if (deps != null) { + return deps.values(); + } + return Collections.emptyList(); + } + + Set getDependenciesBetweenProjects() { + Set result = Sets.newLinkedHashSet(); + for (Dependency dependency : dependencies) { + if (ResourceUtils.isSet(dependency.getFrom()) || ResourceUtils.isSet(dependency.getTo())) { + result.add(dependency); + } + } + return result; + } + + + // + // + // + // VIOLATIONS + // + // + // + + public List getViolations(Resource resource) { + Bucket bucket = buckets.get(resource); + if (bucket == null) { + return Collections.emptyList(); + } + return bucket.getViolations(); + } + + public void addViolation(Violation violation) { + addViolation(violation, false); + } + + public void addViolation(Violation violation, boolean force) { + Bucket bucket; + Resource resource = violation.getResource(); + if (resource == null) { + violation.setResource(currentProject); + } + bucket = getOrAddBucket(violation.getResource()); + if (!bucket.isExcluded()) { + boolean isIgnored = !force && violationFilters != null && violationFilters.isIgnored(violation); + if (!isIgnored) { + ActiveRule activeRule = profile.getActiveRule(violation.getRule()); + if (activeRule == null) { + if (currentProject.getReuseExistingRulesConfig()) { + violation.setPriority(violation.getRule().getPriority()); + doAddViolation(violation, bucket); + + } else { + LoggerFactory.getLogger(getClass()).debug("Rule is not activated, ignoring violation {}", violation); + } + + } else { + violation.setPriority(activeRule.getPriority()); + doAddViolation(violation, bucket); + } + } + } + } + + private void doAddViolation(Violation violation, Bucket bucket) { + bucket.addViolation(violation); + persistence.saveViolation(currentProject, violation); + } + + // + // + // + // LINKS + // + // + // + public void addLink(ProjectLink link) { + persistence.saveLink(currentProject, link); + } + + public void deleteLink(String key) { + persistence.deleteLink(currentProject, key); + } + + + // + // + // + // EVENTS + // + // + // + + public List getEvents(Resource resource) { + // currently events are not cached in memory + return persistence.getEvents(resource); + } + + public void deleteEvent(Event event) { + persistence.deleteEvent(event); + } + + public Event addEvent(Resource resource, String name, String description, String category, Date date) { + Event event = new Event(name, description, category); + event.setDate(date); + persistence.saveEvent(currentProject, resource, event); + return null; + } +} 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 new file mode 100644 index 00000000000..f03147a4ede --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java @@ -0,0 +1,112 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +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.measures.Measure; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.ProjectLink; +import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Violation; + +import java.util.List; + +public final class DefaultPersistenceManager implements PersistenceManager { + + private ResourcePersister resourcePersister; + private SourcePersister sourcePersister; + private MeasurePersister measurePersister; + private DependencyPersister dependencyPersister; + private ViolationPersister violationPersister; + private LinkPersister linkPersister; + private EventPersister eventPersister; + + public DefaultPersistenceManager(ResourcePersister resourcePersister, SourcePersister sourcePersister, + MeasurePersister measurePersister, DependencyPersister dependencyPersister, + ViolationPersister violationPersister, LinkPersister linkPersister, + EventPersister eventPersister) { + this.resourcePersister = resourcePersister; + this.sourcePersister = sourcePersister; + this.measurePersister = measurePersister; + this.dependencyPersister = dependencyPersister; + this.violationPersister = violationPersister; + this.linkPersister = linkPersister; + this.eventPersister = eventPersister; + } + + public void clear() { + resourcePersister.clear(); + sourcePersister.clear(); + } + + public void setDelayedMode(boolean b) { + measurePersister.setDelayedMode(b); + } + + public void dump() { + measurePersister.dump(); + } + + public void saveProject(Project project) { + resourcePersister.saveProject(project); + } + + public Snapshot saveResource(Project project, Resource resource) { + return resourcePersister.saveResource(project, resource); + } + + public void setSource(Project project, Resource resource, String source) { + sourcePersister.saveSource(project, resource, source); + } + + public void saveMeasure(Project project, Resource resource, Measure measure) { + measurePersister.saveMeasure(project, resource, measure); + } + + public void saveDependency(Project project, Dependency dependency, Dependency parentDependency) { + dependencyPersister.saveDependency(project, dependency, parentDependency); + } + + public void saveViolation(Project project, Violation violation) { + violationPersister.saveViolation(project, violation); + } + + public void saveLink(Project project, ProjectLink link) { + linkPersister.saveLink(project, link); + } + + public void deleteLink(Project project, String key) { + linkPersister.deleteLink(project, key); + } + + public List getEvents(Resource resource) { + return eventPersister.getEvents(resource); + } + + public void deleteEvent(Event event) { + eventPersister.deleteEvent(event); + } + + public void saveEvent(Project project, Resource resource, Event event) { + eventPersister.saveEvent(project, resource, event); + } +} 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 new file mode 100644 index 00000000000..5f7648436b4 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java @@ -0,0 +1,63 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +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; + +public final class DependencyPersister { + + private ResourcePersister resourcePersister; + private DatabaseSession session; + + public DependencyPersister(ResourcePersister resourcePersister, DatabaseSession session) { + this.resourcePersister = resourcePersister; + 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.saveProject(project); + + DependencyDto model = new DependencyDto(); + model.setProjectSnapshotId(projectSnapshot.getId()); + model.setUsage(dependency.getUsage()); + model.setWeight(dependency.getWeight()); + + model.setFromResourceId(fromSnapshot.getResourceId()); + model.setFromScope(fromSnapshot.getScope()); + model.setFromSnapshotId(fromSnapshot.getId()); + + model.setToResourceId(toSnapshot.getResourceId()); + model.setToSnapshotId(toSnapshot.getId()); + model.setToScope(toSnapshot.getScope()); + + if (parentDependency != null) { + // assume that it has been previously saved + model.setParentDependencyId(parentDependency.getId()); + } + session.save(model); + dependency.setId(model.getId()); + } +} 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 new file mode 100644 index 00000000000..9b536333674 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java @@ -0,0 +1,65 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +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.Project; +import org.sonar.api.resources.Resource; + +import java.util.Collections; +import java.util.List; + +public final class EventPersister { + private DatabaseSession session; + private ResourcePersister resourcePersister; + + public EventPersister(DatabaseSession session, ResourcePersister resourcePersister) { + this.session = session; + this.resourcePersister = resourcePersister; + } + + public List getEvents(Resource resource) { + Snapshot snapshot = resourcePersister.getSnapshot(resource); + if (snapshot == null) { + return Collections.emptyList(); + } + return session.getResults(Event.class, "resourceId", snapshot.getResourceId()); + } + + public void deleteEvent(Event event) { + session.remove(event); + session.commit(); + } + + public void saveEvent(Project project, Resource resource, Event event) { + Snapshot snapshot = resourcePersister.saveResource(project, resource); + if (snapshot != null) { + if (event.getDate()==null) { + event.setSnapshot(snapshot); + } else { + event.setResourceId(snapshot.getResourceId()); + } + session.save(event); + session.commit(); + } + } +} 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 new file mode 100644 index 00000000000..123b363658b --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java @@ -0,0 +1,68 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +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; + + public LinkPersister(DatabaseSession session, ResourcePersister resourcePersister) { + this.session = session; + this.resourcePersister = resourcePersister; + } + + public void saveLink(Project project, ProjectLink link) { + Snapshot snapshot = resourcePersister.getSnapshot(project); + if (snapshot != null) { + ResourceModel projectDao = session.reattach(ResourceModel.class, snapshot.getResourceId()); + ProjectLink dbLink = projectDao.getProjectLink(link.getKey()); + if (dbLink == null) { + link.setResource(projectDao); + projectDao.getProjectLinks().add(link); + session.save(link); + + } else { + dbLink.copyFieldsFrom(link); + session.save(dbLink); + } + session.commit(); + } + } + + public void deleteLink(Project project, String linkKey) { + Snapshot snapshot = resourcePersister.getSnapshot(project); + if (snapshot != null) { + ResourceModel model = session.reattach(ResourceModel.class, snapshot.getResourceId()); + ProjectLink dbLink = model.getProjectLink(linkKey); + if (dbLink != null) { + session.remove(dbLink); + model.getProjectLinks().remove(dbLink); + session.commit(); + } + + } + } +} 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 new file mode 100644 index 00000000000..bd50db6f8b3 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java @@ -0,0 +1,133 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import com.google.common.collect.Sets; +import org.apache.commons.lang.math.NumberUtils; +import org.slf4j.LoggerFactory; +import org.sonar.api.database.DatabaseSession; +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.Metric; +import org.sonar.api.measures.RuleMeasure; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.resources.ResourceUtils; + +import java.util.Iterator; +import java.util.Set; + +public final class MeasurePersister { + + private boolean delayedMode = false; + private Set unsavedMeasures = Sets.newLinkedHashSet(); + private DatabaseSession session; + private ResourcePersister resourcePersister; + + public MeasurePersister(DatabaseSession session, ResourcePersister resourcePersister) { + this.session = session; + this.resourcePersister = resourcePersister; + } + + public void setDelayedMode(boolean delayedMode) { + this.delayedMode = delayedMode; + } + + public void saveMeasure(Project project, Measure measure) { + saveMeasure(project, project, measure); + } + + public void saveMeasure(Project project, Resource resource, Measure measure) { + Snapshot snapshot = resourcePersister.saveResource(project, resource); + if (snapshot != null) { + if (delayedMode && measure.getPersistenceMode().useMemory()) { + MeasureModel model = createModel(measure); + model.setSnapshotId(snapshot.getId()); + unsavedMeasures.add(model); + + } else if (shouldPersistMeasure(resource, measure)) { + if (measure.getId() != null) { + // update + MeasureModel model = session.reattach(MeasureModel.class, measure.getId()); + model = mergeModel(measure, model); + model.save(session); + + } else { + // insert + MeasureModel model = createModel(measure); + model.setSnapshotId(snapshot.getId()); + model.save(session); + measure.setId(model.getId()); // could be removed + } + } + } + } + + static boolean shouldPersistMeasure(Resource resource, Measure measure) { + Metric metric = measure.getMetric(); + return measure.getPersistenceMode().useDatabase() && !( + ResourceUtils.isEntity(resource) && + metric.isOptimizedBestValue() == Boolean.TRUE && + metric.getBestValue() != null && + NumberUtils.compare(metric.getBestValue(), measure.getValue()) == 0 && + !measure.hasOptionalData()); + } + + public void dump() { + LoggerFactory.getLogger(getClass()).debug("{} measures to dump", unsavedMeasures.size()); + for (Iterator it = unsavedMeasures.iterator(); it.hasNext();) { + MeasureModel model = it.next(); + model.save(session); + it.remove(); + } + session.commit(); + } + + MeasureModel createModel(Measure measure) { + return mergeModel(measure, new MeasureModel()); + } + + MeasureModel mergeModel(Measure measure, MeasureModel merge) { + merge.setMetricId(measure.getMetric().getId());// we assume that the index has updated the metric + merge.setDescription(measure.getDescription()); + merge.setData(measure.getData()); + merge.setAlertStatus(measure.getAlertStatus()); + merge.setAlertText(measure.getAlertText()); + merge.setTendency(measure.getTendency()); + merge.setDiffValue1(measure.getDiffValue1()); + merge.setDiffValue2(measure.getDiffValue2()); + merge.setDiffValue3(measure.getDiffValue3()); + merge.setUrl(measure.getUrl()); + merge.setCharacteristic(measure.getCharacteristic()); + if (measure.getValue() != null) { + merge.setValue(measure.getValue().doubleValue()); + } else { + merge.setValue(null); + } + if (measure instanceof RuleMeasure) { + RuleMeasure ruleMeasure = (RuleMeasure) measure; + merge.setRulesCategoryId(ruleMeasure.getRuleCategory()); + merge.setRulePriority(ruleMeasure.getRulePriority()); + merge.setRule(ruleMeasure.getRule()); + } + return merge; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java new file mode 100644 index 00000000000..f53248feff2 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java @@ -0,0 +1,61 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +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.measures.Measure; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.ProjectLink; +import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Violation; + +import java.util.List; + +public interface PersistenceManager { + void clear(); + + void setDelayedMode(boolean b); + + void dump(); + + void saveProject(Project project); + + Snapshot saveResource(Project project, Resource resource); + + void setSource(Project project, Resource resource, String source); + + void saveMeasure(Project project, Resource resource, Measure measure); + + void saveDependency(Project project, Dependency dependency, Dependency parentDependency); + + void saveViolation(Project project, Violation violation); + + void saveLink(Project project, ProjectLink link); + + void deleteLink(Project project, String key); + + List getEvents(Resource resource); + + void deleteEvent(Event event); + + void saveEvent(Project project, Resource resource, Event event); +} 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 new file mode 100644 index 00000000000..f9f77b5ae2d --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java @@ -0,0 +1,247 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +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.database.DatabaseSession; +import org.sonar.api.database.model.ResourceModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.resources.Library; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.resources.ResourceUtils; +import org.sonar.api.utils.SonarException; + +import javax.persistence.NonUniqueResultException; +import javax.persistence.Query; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class ResourcePersister { + + private DatabaseSession session; + + private Map snapshotsByResource = Maps.newHashMap(); + + public ResourcePersister(DatabaseSession session) { + this.session = session; + } + + public Snapshot saveProject(Project project) { + Snapshot snapshot = snapshotsByResource.get(project); + if (snapshot == null) { + snapshot = doSaveProject(project); + } + return snapshot; + } + + public Snapshot getSnapshot(Resource resource) { + if (resource != null) { + return snapshotsByResource.get(resource); + } + return null; + } + + /** + * just for unit tests + */ + Map getSnapshotsByResource() { + return snapshotsByResource; + } + + private Snapshot doSaveProject(Project project) { + ResourceModel model = findOrCreateModel(project, project.getKey()); + model.setLanguageKey(project.getLanguageKey());// ugly, only for projects + + Snapshot parentSnapshot = null; + if (project.getParent() != null) { + // assume that the parent project has already been saved + parentSnapshot = snapshotsByResource.get(project.getParent()); + model.setRootId((Integer) ObjectUtils.defaultIfNull(parentSnapshot.getRootProjectId(), parentSnapshot.getResourceId())); + } + model = session.save(model); + project.setId(model.getId()); // TODO to be removed + + Snapshot snapshot = new Snapshot(model, parentSnapshot); + snapshot.setVersion(project.getAnalysisVersion()); + snapshot.setCreatedAt(project.getAnalysisDate()); + snapshot = session.save(snapshot); + session.commit(); + snapshotsByResource.put(project, snapshot); + return snapshot; + } + + public Snapshot saveResource(Project project, Resource resource) { + if (resource == null) { + return null; + } + Snapshot snapshot = snapshotsByResource.get(resource); + if (snapshot == null) { + if (resource instanceof Project) { + snapshot = doSaveProject((Project) resource); + + } else if (resource instanceof Library) { + snapshot = doSaveLibrary(project, (Library) resource); + + } else { + snapshot = doSaveResource(project, resource); + } + } + return snapshot; + } + + private Snapshot doSaveLibrary(Project project, Library library) { + ResourceModel model = findOrCreateModel(library, library.getKey()); + model = session.save(model); + library.setId(model.getId()); // TODO to be removed + library.setEffectiveKey(library.getKey()); + + Snapshot snapshot = findLibrarySnapshot(model.getId(), library.getVersion()); + if (snapshot == null) { + snapshot = new Snapshot(model, null); + snapshot.setCreatedAt(project.getAnalysisDate()); + snapshot.setVersion(library.getVersion()); + snapshot.setStatus(Snapshot.STATUS_PROCESSED); + + // see http://jira.codehaus.org/browse/SONAR-1850 + // The qualifier must be LIB, even if the resource is TRK, because this snapshot has no measures. + snapshot.setQualifier(Resource.QUALIFIER_LIB); + snapshot = session.save(snapshot); + } + session.commit(); + return snapshot; + } + + private Snapshot findLibrarySnapshot(Integer resourceId, String version) { + Query query = session.createQuery("from " + Snapshot.class.getSimpleName() + " s WHERE s.resourceId=:resourceId AND s.version=:version AND s.scope=:scope AND s.qualifier<>:qualifier AND s.last=:last"); + query.setParameter("resourceId", resourceId); + query.setParameter("version", version); + query.setParameter("scope", Resource.SCOPE_SET); + query.setParameter("qualifier", Resource.QUALIFIER_LIB); + query.setParameter("last", Boolean.TRUE); + List snapshots = query.getResultList(); + if (snapshots.isEmpty()) { + snapshots = session.getResults(Snapshot.class, "resourceId", resourceId, "version", version, "scope", Resource.SCOPE_SET, "qualifier", Resource.QUALIFIER_LIB); + } + return (snapshots.isEmpty() ? null : snapshots.get(0)); + } + + /** + * Everything except project and library + */ + private Snapshot doSaveResource(Project project, Resource resource) { + String databaseKey = getDatabaseKey(project, resource); + ResourceModel model = findOrCreateModel(resource, databaseKey); + Snapshot projectSnapshot = snapshotsByResource.get(project); + model.setRootId(projectSnapshot.getResourceId()); + model = session.save(model); + resource.setId(model.getId()); // TODO to be removed + resource.setEffectiveKey(databaseKey); + + Snapshot parentSnapshot = (Snapshot)ObjectUtils.defaultIfNull(getSnapshot(resource.getParent()), projectSnapshot); + Snapshot snapshot = new Snapshot(model, parentSnapshot); + snapshot = session.save(snapshot); + session.commit(); + snapshotsByResource.put(resource, snapshot); + return snapshot; + } + + public void clear() { + // we keep cache of projects + for (Iterator> it = snapshotsByResource.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + if (!ResourceUtils.isSet(entry.getKey())) { + it.remove(); + } + } + } + + + private ResourceModel findOrCreateModel(Resource resource, String databaseKey) { + ResourceModel model; + try { + model = session.getSingleResult(ResourceModel.class, "key", databaseKey); + if (model == null) { + model = createModel(resource, databaseKey); + + } else { + mergeModel(model, resource); + } + return model; + + } catch (NonUniqueResultException e) { + throw new SonarException("The resource '" + databaseKey + "' is duplicated in database."); + } + } + + static ResourceModel createModel(Resource resource, String databaseKey) { + ResourceModel model = new ResourceModel(); + model.setEnabled(Boolean.TRUE); + model.setDescription(resource.getDescription()); + model.setKey(databaseKey); + if (resource.getLanguage() != null) { + model.setLanguageKey(resource.getLanguage().getKey()); + } + if (StringUtils.isNotBlank(resource.getName())) { + model.setName(resource.getName()); + } else { + model.setName(resource.getKey()); + } + model.setLongName(resource.getLongName()); + model.setScope(resource.getScope()); + model.setQualifier(resource.getQualifier()); + return model; + } + + static void mergeModel(ResourceModel model, Resource resource) { + model.setEnabled(true); + if (StringUtils.isNotBlank(resource.getName())) { + model.setName(resource.getName()); + } + if (StringUtils.isNotBlank(resource.getLongName())) { + model.setLongName(resource.getLongName()); + } + if (StringUtils.isNotBlank(resource.getDescription())) { + model.setDescription(resource.getDescription()); + } + if (!ResourceUtils.isLibrary(resource)) { + model.setScope(resource.getScope()); + model.setQualifier(resource.getQualifier()); + } + if (resource.getLanguage() != null) { + model.setLanguageKey(resource.getLanguage().getKey()); + } + } + + static String getDatabaseKey(Project project, Resource resource) { + if (StringUtils.equals(Resource.SCOPE_SET, resource.getScope())) { + // projects + libraries + return resource.getKey(); + } + return new StringBuilder(ResourceModel.KEY_SIZE) + .append(project.getKey()) + .append(':') + .append(resource.getKey()) + .toString(); + } +} 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 new file mode 100644 index 00000000000..4480ab4bef5 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java @@ -0,0 +1,59 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import com.google.common.collect.Sets; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.database.model.SnapshotSource; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.utils.SonarException; + +import java.util.Set; + +public final class SourcePersister { + + private DatabaseSession session; + private Set savedSnapshotIds = Sets.newHashSet(); + private ResourcePersister resourcePersister; + + public SourcePersister(DatabaseSession session, ResourcePersister resourcePersister) { + this.session = session; + this.resourcePersister = resourcePersister; + } + + public void saveSource(Project project, Resource resource, String source) { + Snapshot snapshot = resourcePersister.saveResource(project, resource); + if (snapshot != null) { + + if (savedSnapshotIds.contains(snapshot.getId())) { + throw new SonarException("Can not set twice the source of " + resource); + } + session.save(new SnapshotSource(snapshot.getId(), source)); + session.commit(); + savedSnapshotIds.add(snapshot.getId()); + } + } + + public void clear() { + savedSnapshotIds.clear(); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java new file mode 100644 index 00000000000..8d893ac2ef8 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java @@ -0,0 +1,79 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import com.google.common.collect.Maps; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.resources.Project; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.Violation; +import org.sonar.api.utils.SonarException; + +import java.util.Map; + +public final class ViolationPersister { + + private DatabaseSession session; + private ResourcePersister resourcePersister; + private Map ruleIds = Maps.newHashMap(); + + public ViolationPersister(DatabaseSession session, ResourcePersister resourcePersister) { + this.session = session; + this.resourcePersister = resourcePersister; + } + + public void saveViolation(Project project, Violation violation) { + Snapshot snapshot = resourcePersister.saveResource(project, violation.getResource()); + if (snapshot != null) { + session.save(toModel(snapshot, violation)); + } + } + + private RuleFailureModel toModel(Snapshot snapshot, Violation violation) { + RuleFailureModel model = new RuleFailureModel(); + model.setRuleId(getRuleId(violation.getRule())); + model.setPriority(violation.getPriority()); + model.setLine(violation.getLineId()); + model.setMessage(violation.getMessage()); + model.setCost(violation.getCost()); + model.setSnapshotId(snapshot.getId()); + return model; + } + + private Integer getRuleId(Rule rule) { + Integer ruleId = ruleIds.get(rule); + if (ruleId == null) { + Rule persistedRule = session.getSingleResult(Rule.class, "pluginName", rule.getRepositoryKey(), "key", rule.getKey(), "enabled", true); + if (persistedRule == null) { + throw new SonarException("Rule not found: " + rule); + } + ruleId = persistedRule.getId(); + ruleIds.put(rule, ruleId); + + } + return ruleId; + } + + public void clear() { + ruleIds.clear(); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultPersister.java b/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultPersister.java deleted file mode 100644 index 36f8419e083..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultPersister.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.ResourceModel; -import org.sonar.api.database.model.Snapshot; - -public class DefaultPersister extends ResourcePersister { - - public DefaultPersister(DatabaseSession session) { - super(session); - } - - @Override - protected Snapshot createSnapshot(Bucket bucket, ResourceModel resourceModel) { - Snapshot parentSnapshot = (bucket.getParent() != null ? bucket.getParent().getSnapshot() : null); - Snapshot snapshot = new Snapshot(resourceModel, parentSnapshot); - return snapshot; - } - - @Override - protected void prepareResourceModel(ResourceModel resourceModel, Bucket bucket) { - resourceModel.setRootId(bucket.getProject() != null ? bucket.getProject().getResourceId() : null); - } - - @Override - protected String generateEffectiveKey(Bucket bucket) { - return new StringBuilder(ResourceModel.KEY_SIZE) - .append(bucket.getProject().getResource().getKey()) - .append(':') - .append(bucket.getResource().getKey()) - .toString(); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultSonarIndex.java b/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultSonarIndex.java deleted file mode 100644 index 28512f4d0b2..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultSonarIndex.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import org.apache.commons.lang.math.NumberUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.Event; -import org.sonar.api.batch.SonarIndex; -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.MeasureModel; -import org.sonar.api.database.model.ResourceModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.database.model.SnapshotSource; -import org.sonar.api.design.Dependency; -import org.sonar.api.design.DependencyDto; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.MeasuresFilter; -import org.sonar.api.measures.MeasuresFilters; -import org.sonar.api.measures.Metric; -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 org.sonar.api.rules.Violation; -import org.sonar.api.utils.SonarException; -import org.sonar.batch.*; -import org.sonar.jpa.dao.MeasuresDao; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import java.util.*; - -public class DefaultSonarIndex extends SonarIndex { - - private static final Logger LOG = LoggerFactory.getLogger(DefaultSonarIndex.class); - - private DatabaseSession session; - private ResourcePersisters resourcePersisters; - private Bucket rootProjectBucket; - private Bucket selectedProjectBucket; - private DefaultResourceCreationLock lock; - - private ViolationFilters violationFilters; - private ResourceFilters resourceFilters; - - // data - private Map buckets = Maps.newHashMap(); - private Set dependencies = Sets.newHashSet(); - private Map> outgoingDependenciesByResource = new HashMap>(); - private Map> incomingDependenciesByResource = new HashMap>(); - - // dao - private ViolationsDao violationsDao; - private MeasuresDao measuresDao; - private ProjectTree projectTree; - - public DefaultSonarIndex(DatabaseSession session, ProjectTree projectTree, DefaultResourceCreationLock lock) { - this.session = session; - this.projectTree = projectTree; - this.resourcePersisters = new ResourcePersisters(session); - this.lock = lock; - } - - public void start() { - Project rootProject = projectTree.getRootProject(); - - this.rootProjectBucket = new Bucket(rootProject); - persist(rootProjectBucket); - this.buckets.put(rootProject, rootProjectBucket); - this.selectedProjectBucket = rootProjectBucket; - - for (Project project : rootProject.getModules()) { - addProject(project); - } - session.commit(); - } - - private void addProject(Project project) { - addResource(project); - for (Project module : project.getModules()) { - addProject(module); - } - } - - public void selectProject(Project project, ResourceFilters resourceFilters, ViolationFilters violationFilters, MeasuresDao measuresDao, ViolationsDao violationsDao) { - this.selectedProjectBucket = buckets.get(project); - this.resourceFilters = resourceFilters; - this.violationFilters = violationFilters; - this.violationsDao = violationsDao; - this.measuresDao = measuresDao; - } - - /** - * Keep only project stuff - */ - public void clear() { - Iterator> it = buckets.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - Resource resource = entry.getKey(); - if ( !ResourceUtils.isSet(resource)) { - entry.getValue().clear(); - it.remove(); - } - } - - Set projectDependencies = getDependenciesBetweenProjects(); - dependencies.clear(); - incomingDependenciesByResource.clear(); - outgoingDependenciesByResource.clear(); - for (Dependency projectDependency : projectDependencies) { - projectDependency.setId(null); - registerDependency(projectDependency); - } - - lock.unlock(); - } - - /* ------------ RESOURCES */ - public Project getRootProject() { - return rootProjectBucket.getResource(); - } - - public Project getProject() { - return selectedProjectBucket.getResource(); - } - - public Bucket getBucket(Resource resource) { - return buckets.get(resource); - } - - public Resource getResource(Resource resource) { - Bucket bucket = buckets.get(resource); - if (bucket != null) { - return bucket.getResource(); - } - return null; - } - - public List getChildren(Resource resource) { - List children = Lists.newArrayList(); - Bucket bucket = buckets.get(resource); - if (bucket != null) { - for (Bucket childBucket : bucket.getChildren()) { - children.add(childBucket.getResource()); - } - } - return children; - } - - public Resource addResource(Resource resource) { - return getOrCreateBucket(resource, false).getResource(); - } - - private Bucket getOrCreateBucket(Resource resource, boolean mustExist) { - Bucket bucket = buckets.get(resource); - if (bucket != null) { - return bucket; - } - - if (mustExist && lock.isLocked() && !ResourceUtils.isLibrary(resource)) { - LOG.warn("The following resource has not been registered before saving violation/measure/event: " + resource); - } - - prepareResource(resource); - bucket = new Bucket(resource); - buckets.put(resource, bucket); - - Bucket parentBucket = null; - Resource parent = resource.getParent(); - if (parent != null) { - parentBucket = getOrCreateBucket(parent, mustExist); - } else if ( !ResourceUtils.isLibrary(resource)) { - parentBucket = selectedProjectBucket; - } - bucket.setParent(parentBucket); - bucket.setProject(selectedProjectBucket); - - persist(bucket); - return bucket; - } - - private void prepareResource(Resource resource) { - resource.setExcluded(resourceFilters != null && resourceFilters.isExcluded(resource)); - } - - private void persist(Bucket bucket) { - resourcePersisters.get(bucket).persist(bucket); - } - - /* ------------ MEASURES */ - public Measure getMeasure(Resource resource, Metric metric) { - return getOrCreateBucket(resource, false).getMeasures(MeasuresFilters.metric(metric)); - } - - public M getMeasures(Resource resource, MeasuresFilter filter) { - return getOrCreateBucket(resource, false).getMeasures(filter); - } - - /* ------------ SOURCE CODE */ - - public void setSource(Resource resource, String source) { - Bucket bucket = getOrCreateBucket(resource, false); - - if ( !bucket.isExcluded()) { - if (bucket.isSourceSaved()) { - LOG.warn("Trying to save twice the source of " + resource); - - } else { - try { - session.save(new SnapshotSource(bucket.getSnapshotId(), source)); - } catch (Exception e) { - throw new SonarException("Unable to save source [resource=" + resource + ",snapshotId=" + bucket.getSnapshotId() + "]", e); - } - bucket.setSourceSaved(true); - } - } - } - - /* ------------ RULE VIOLATIONS */ - - public void addViolation(Violation violation) { - Bucket bucket; - Resource resource = violation.getResource(); - if (resource == null) { - bucket = selectedProjectBucket; - } else { - bucket = getOrCreateBucket(resource, true); - } - if ( !bucket.isExcluded()) { - persistViolation(violation, bucket.getSnapshot()); - } - } - - private void persistViolation(Violation violation, Snapshot snapshot) { - boolean isIgnored = violationFilters != null && violationFilters.isIgnored(violation); - if ( !isIgnored) { - violationsDao.saveViolation(snapshot, violation); - } - } - - /* ------------ MEASURES */ - public Measure saveMeasure(Resource resource, Measure measure) { - if (measure.getId() == null) { - return addMeasure(resource, measure); - } - return updateMeasure(measure); - } - - public Measure addMeasure(Resource resource, Measure measure) { - Bucket bucket = getOrCreateBucket(resource, true); - if ( !bucket.isExcluded()) { - if (bucket.getMeasures(MeasuresFilters.measure(measure)) != null) { - throw new IllegalArgumentException("This measure has already been saved: " + measure + ",resource: " + resource); - } - if (shouldPersistMeasure(resource, measure)) { - persistMeasure(bucket, measure); - } - - if (measure.getPersistenceMode().useMemory()) { - bucket.addMeasure(measure); - } - } - return measure; - } - - public Measure updateMeasure(Measure measure) { - if (measure.getId() == null) { - throw new IllegalStateException("Measure can not be updated because it has never been saved"); - } - - MeasureModel model = session.reattach(MeasureModel.class, measure.getId()); - model = MeasureModel.build(measure, model); - model.setMetric(measuresDao.getMetric(measure.getMetric())); - model.save(session); - return measure; - } - - private void persistMeasure(Bucket bucket, Measure measure) { - Metric metric = measuresDao.getMetric(measure.getMetric()); - MeasureModel measureModel = MeasureModel.build(measure); - measureModel.setMetric(metric); // hibernate synchronized metric - measureModel.setSnapshotId(bucket.getSnapshotId()); - measureModel.save(session); - - // the id is saved for future updates - measure.setId(measureModel.getId()); - } - - private boolean shouldPersistMeasure(Resource resource, Measure measure) { - Metric metric = measure.getMetric(); - return measure.getPersistenceMode().useDatabase() && !( - ResourceUtils.isEntity(resource) && - metric.isOptimizedBestValue() == Boolean.TRUE && - metric.getBestValue() != null && - NumberUtils.compare(metric.getBestValue(), measure.getValue()) == 0 && - !measure.hasOptionalData()); - } - - /* --------------- DEPENDENCIES */ - public Dependency saveDependency(Dependency dependency) { - Dependency persistedDep = getEdge(dependency.getFrom(), dependency.getTo()); - if (persistedDep != null && persistedDep.getId() != null) { - return persistedDep; - } - Bucket from = getOrCreateBucket(dependency.getFrom(), true); - Bucket to = getOrCreateBucket(dependency.getTo(), true); - - DependencyDto dto = new DependencyDto(); - dto.setFromResourceId(from.getResourceId()); - dto.setFromScope(from.getResource().getScope()); - dto.setFromSnapshotId(from.getSnapshotId()); - dto.setToResourceId(to.getResourceId()); - dto.setToSnapshotId(to.getSnapshotId()); - dto.setToScope(to.getResource().getScope()); - dto.setProjectSnapshotId(selectedProjectBucket.getSnapshotId()); - dto.setUsage(dependency.getUsage()); - dto.setWeight(dependency.getWeight()); - - Dependency parentDependency = dependency.getParent(); - if (parentDependency != null) { - saveDependency(parentDependency); - dto.setParentDependencyId(parentDependency.getId()); - } - session.save(dto); - dependency.setId(dto.getId()); - registerDependency(dependency); - - return dependency; - } - - protected void registerDependency(Dependency dependency) { - dependencies.add(dependency); - registerOutgoingDependency(dependency); - registerIncomingDependency(dependency); - } - - private void registerOutgoingDependency(Dependency dependency) { - Map outgoingDeps = outgoingDependenciesByResource.get(dependency.getFrom()); - if (outgoingDeps == null) { - outgoingDeps = new HashMap(); - outgoingDependenciesByResource.put(dependency.getFrom(), outgoingDeps); - } - outgoingDeps.put(dependency.getTo(), dependency); - } - - private void registerIncomingDependency(Dependency dependency) { - Map incomingDeps = incomingDependenciesByResource.get(dependency.getTo()); - if (incomingDeps == null) { - incomingDeps = new HashMap(); - incomingDependenciesByResource.put(dependency.getTo(), incomingDeps); - } - incomingDeps.put(dependency.getFrom(), dependency); - } - - public Set getDependencies() { - return dependencies; - } - - /* ------------ LINKS */ - - public void saveLink(ProjectLink link) { - ResourceModel projectDao = session.reattach(ResourceModel.class, selectedProjectBucket.getResourceId()); - ProjectLink dbLink = projectDao.getProjectLink(link.getKey()); - if (dbLink == null) { - link.setResource(projectDao); - projectDao.getProjectLinks().add(link); - session.save(link); - - } else { - dbLink.copyFieldsFrom(link); - session.save(dbLink); - } - } - - public void deleteLink(String key) { - ResourceModel projectDao = session.reattach(ResourceModel.class, selectedProjectBucket.getResourceId()); - ProjectLink dbLink = projectDao.getProjectLink(key); - if (dbLink != null) { - session.remove(dbLink); - projectDao.getProjectLinks().remove(dbLink); - } - } - - /* ----------- EVENTS */ - public List getEvents(Resource resource) { - Bucket bucket = getOrCreateBucket(resource, true); - return session.getResults(Event.class, "resourceId", bucket.getResourceId()); - } - - public void deleteEvent(Event event) { - session.remove(event); - } - - public Event createEvent(Resource resource, String name, String description, String category, Date date) { - Bucket bucket = getOrCreateBucket(resource, true); - Event event; - if (date == null) { - event = new Event(name, description, category, bucket.getSnapshot()); - } else { - event = new Event(name, description, category, date, bucket.getResourceId()); - } - return session.save(event); - } - - public Dependency getEdge(Resource from, Resource to) { - Map map = outgoingDependenciesByResource.get(from); - if (map != null) { - return map.get(to); - } - return null; - } - - public boolean hasEdge(Resource from, Resource to) { - return getEdge(from, to) != null; - } - - public Set getVertices() { - return buckets.keySet(); - } - - public Collection getOutgoingEdges(Resource from) { - Map deps = outgoingDependenciesByResource.get(from); - if (deps != null) { - return deps.values(); - } - return Collections.emptyList(); - } - - public Collection getIncomingEdges(Resource to) { - Map deps = incomingDependenciesByResource.get(to); - if (deps != null) { - return deps.values(); - } - return Collections.emptyList(); - } - - public Set getDependenciesBetweenProjects() { - Set result = new HashSet(); - for (Project project : projectTree.getProjects()) { - Collection deps = getOutgoingDependencies(project); - for (Dependency dep : deps) { - if (ResourceUtils.isSet(dep.getTo())) { - result.add(dep); - } - } - } - return result; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/indexer/LibraryPersister.java b/sonar-batch/src/main/java/org/sonar/batch/indexer/LibraryPersister.java deleted file mode 100644 index 2aaa2f316ef..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/indexer/LibraryPersister.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -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.Library; -import org.sonar.api.resources.Resource; - -import javax.persistence.Query; -import java.util.Date; -import java.util.List; - -public class LibraryPersister extends ResourcePersister { - - private Date now; - - public LibraryPersister(DatabaseSession session) { - super(session); - this.now = new Date(); - } - - LibraryPersister(DatabaseSession session, Date now) { - super(session); - this.now = now; - } - - @Override - protected String generateEffectiveKey(Bucket bucket) { - return bucket.getResource().getKey(); - } - - @Override - protected void prepareResourceModel(ResourceModel resourceModel, Bucket bucket) { - } - - @Override - protected Snapshot createSnapshot(Bucket bucket, ResourceModel resourceModel) { - Snapshot snapshot = findProject(resourceModel.getId(), bucket.getResource().getVersion()); - if (snapshot == null) { - snapshot = findLibrary(resourceModel.getId(), bucket.getResource().getVersion()); - } - - if (snapshot == null) { - snapshot = new Snapshot(resourceModel, null); - snapshot.setCreatedAt(now); - snapshot.setVersion(bucket.getResource().getVersion()); - snapshot.setStatus(Snapshot.STATUS_PROCESSED); - - // see http://jira.codehaus.org/browse/SONAR-1850 - // The qualifier must be LIB, even if the resource is TRK, because this snapshot has no measures. - snapshot.setQualifier(Resource.QUALIFIER_LIB); - } - return snapshot; - } - - private Snapshot findLibrary(Integer resourceId, String version) { - List snapshots = getSession().getResults(Snapshot.class, - "resourceId", resourceId, - "version", version, - "scope", Resource.SCOPE_SET, - "qualifier", Resource.QUALIFIER_LIB); - if (snapshots.isEmpty()) { - return null; - } - return snapshots.get(0); - } - - private Snapshot findProject(Integer resourceId, String version) { - Query query = getSession().createQuery("from " + Snapshot.class.getSimpleName() + " s WHERE s.resourceId=:resourceId AND s.version=:version AND s.scope=:scope AND s.qualifier<>:qualifier AND s.last=:last"); - query.setParameter("resourceId", resourceId); - query.setParameter("version", version); - query.setParameter("scope", Resource.SCOPE_SET); - query.setParameter("qualifier", Resource.QUALIFIER_LIB); - query.setParameter("last", Boolean.TRUE); - List snapshots = query.getResultList(); - if (snapshots.isEmpty()) { - return null; - } - return snapshots.get(0); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/indexer/ProjectPersister.java b/sonar-batch/src/main/java/org/sonar/batch/indexer/ProjectPersister.java deleted file mode 100644 index 821910b4538..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/indexer/ProjectPersister.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -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; - -public class ProjectPersister extends ResourcePersister { - - public ProjectPersister(DatabaseSession session) { - super(session); - } - - @Override - protected String generateEffectiveKey(Bucket bucket) { - return bucket.getResource().getKey(); - } - - @Override - protected void prepareResourceModel(ResourceModel resourceModel, Bucket bucket) { - if (bucket.getProject() != null) { - resourceModel.setRootId(bucket.getProject().getResourceId()); - } - - // LIMITATION : project.getLanguage() is set only in ProjectBatch, not in AggregatorBatch, so we - // have to explicitely use project.getLanguageKey() - resourceModel.setLanguageKey(bucket.getResource().getLanguageKey()); - } - - @Override - protected Snapshot createSnapshot(Bucket bucket, ResourceModel resourceModel) { - Project project = bucket.getResource(); - Snapshot parentSnapshot = (bucket.getParent() != null ? bucket.getParent().getSnapshot() : null); - Snapshot snapshot = new Snapshot(resourceModel, parentSnapshot); - snapshot.setVersion(project.getAnalysisVersion()); - snapshot.setCreatedAt(project.getAnalysisDate()); - return snapshot; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersister.java deleted file mode 100644 index 6ad3be1344d..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersister.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import javax.persistence.NonUniqueResultException; - -import org.apache.commons.lang.StringUtils; -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.Resource; -import org.sonar.api.resources.ResourceUtils; -import org.sonar.api.utils.SonarException; - -public abstract class ResourcePersister { - - private DatabaseSession session; - - public ResourcePersister(DatabaseSession session) { - this.session = session; - } - - protected DatabaseSession getSession() { - return session; - } - - public final void persist(Bucket bucket) { - String effectiveKey = generateEffectiveKey(bucket); - ResourceModel model; - try { - model = session.getSingleResult(ResourceModel.class, "key", effectiveKey); - } catch (NonUniqueResultException e) { - throw new SonarException("The resource '" + effectiveKey + "' is duplicated in the Sonar DB."); - } - - RESOURCE resource = bucket.getResource(); - if (model == null) { - model = ResourceModel.build(resource); - model.setKey(effectiveKey); - - } else { - // update existing record - model.setEnabled(true); - if (StringUtils.isNotBlank(resource.getName())) { - model.setName(resource.getName()); - } - if (StringUtils.isNotBlank(resource.getLongName())) { - model.setLongName(resource.getLongName()); - } - if (StringUtils.isNotBlank(resource.getDescription())) { - model.setDescription(resource.getDescription()); - } - if ( !ResourceUtils.isLibrary(resource)) { - model.setScope(resource.getScope()); - model.setQualifier(resource.getQualifier()); - } - if (resource.getLanguage() != null) { - model.setLanguageKey(resource.getLanguage().getKey()); - } - } - - prepareResourceModel(model, bucket); - model = session.save(model); - resource.setId(model.getId()); - resource.setEffectiveKey(model.getKey()); - - Snapshot snapshot = createSnapshot(bucket, model); - if (snapshot.getId() == null) { - session.save(snapshot); - } - bucket.setSnapshot(snapshot); - } - - protected abstract void prepareResourceModel(ResourceModel resourceModel, Bucket bucket); - - protected abstract Snapshot createSnapshot(Bucket bucket, ResourceModel resourceModel); - - protected abstract String generateEffectiveKey(Bucket bucket); -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersisters.java b/sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersisters.java deleted file mode 100644 index f359a0ae623..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/indexer/ResourcePersisters.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.resources.Library; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Resource; - -import java.util.HashMap; -import java.util.Map; - -public final class ResourcePersisters { - - private Map, ResourcePersister> persistersByClass; - private ResourcePersister defaultPersister; - - public ResourcePersisters(DatabaseSession session) { - defaultPersister = new DefaultPersister(session); - persistersByClass = new HashMap, ResourcePersister>(); - persistersByClass.put(Project.class, new ProjectPersister(session)); - persistersByClass.put(Library.class, new LibraryPersister(session)); - } - - public ResourcePersister get(Bucket bucket) { - return get(bucket.getResource()); - } - - public ResourcePersister get(Resource resource) { - ResourcePersister persister = persistersByClass.get(resource.getClass()); - return persister != null ? persister : defaultPersister; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/DecoratorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java similarity index 84% rename from sonar-batch/src/main/java/org/sonar/batch/DecoratorsExecutor.java rename to sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java index f6f5233ae18..452c51c9f93 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/DecoratorsExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java @@ -17,41 +17,41 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; import org.sonar.api.batch.BatchExtensionDictionnary; import org.sonar.api.batch.Decorator; import org.sonar.api.batch.DecoratorContext; -import org.sonar.api.batch.SensorContext; import org.sonar.api.database.DatabaseSession; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; -import org.sonar.batch.indexer.DefaultSonarIndex; +import org.sonar.batch.DecoratorsSelector; +import org.sonar.batch.DefaultDecoratorContext; +import org.sonar.batch.index.DefaultIndex; import java.util.ArrayList; import java.util.Collection; import java.util.List; -public class DecoratorsExecutor implements CoreJob { +public class DecoratorsExecutor implements BatchComponent { private DecoratorsSelector decoratorsSelector; private DatabaseSession session; - private ViolationsDao violationsDao; private static final Logger LOG = LoggerFactory.getLogger(DecoratorsExecutor.class); - private DefaultSonarIndex index; + private DefaultIndex index; - public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultSonarIndex index, DatabaseSession session, ViolationsDao violationsDao) { + public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultIndex index, DatabaseSession session) { this.decoratorsSelector = new DecoratorsSelector(extensionDictionnary); this.session = session; - this.violationsDao = violationsDao; this.index = index; } - public void execute(Project project, SensorContext sensorContext) { + public void execute(Project project) { LoggerFactory.getLogger(DecoratorsExecutor.class).info("Execute decorators..."); Collection decorators = decoratorsSelector.select(project); @@ -60,6 +60,7 @@ public class DecoratorsExecutor implements CoreJob { } decorateResource(project, decorators, true); + session.commit(); } private DecoratorContext decorateResource(Resource resource, Collection decorators, boolean executeDecorators) { @@ -70,7 +71,7 @@ public class DecoratorsExecutor implements CoreJob { childrenContexts.add(childContext.setReadOnly(true)); } - DefaultDecoratorContext context = new DefaultDecoratorContext(resource, index, childrenContexts, session, violationsDao); + DefaultDecoratorContext context = new DefaultDecoratorContext(resource, index, childrenContexts, session); if (executeDecorators) { for (Decorator decorator : decorators) { decorator.decorate(resource, context); diff --git a/sonar-batch/src/main/java/org/sonar/batch/MavenPhaseExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/MavenPhaseExecutor.java similarity index 85% rename from sonar-batch/src/main/java/org/sonar/batch/MavenPhaseExecutor.java rename to sonar-batch/src/main/java/org/sonar/batch/phases/MavenPhaseExecutor.java index 78b490b5428..266502c5129 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/MavenPhaseExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/MavenPhaseExecutor.java @@ -17,13 +17,14 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.SensorContext; +import org.sonar.api.BatchComponent; import org.sonar.api.resources.Project; +import org.sonar.batch.MavenPluginExecutor; -public class MavenPhaseExecutor implements CoreJob { +public class MavenPhaseExecutor implements BatchComponent { public static final String PROP_PHASE = "sonar.phase"; @@ -33,7 +34,7 @@ public class MavenPhaseExecutor implements CoreJob { this.executor = executor; } - public void execute(Project project, SensorContext context) { + public void execute(Project project) { String mavenPhase = (String) project.getProperty(PROP_PHASE); if (!StringUtils.isBlank(mavenPhase)) { executor.execute(project, mavenPhase); diff --git a/sonar-batch/src/main/java/org/sonar/batch/MavenPluginsConfigurator.java b/sonar-batch/src/main/java/org/sonar/batch/phases/MavenPluginsConfigurator.java similarity index 93% rename from sonar-batch/src/main/java/org/sonar/batch/MavenPluginsConfigurator.java rename to sonar-batch/src/main/java/org/sonar/batch/phases/MavenPluginsConfigurator.java index ea263a21325..58ca8564335 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/MavenPluginsConfigurator.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/MavenPluginsConfigurator.java @@ -17,14 +17,14 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.apache.commons.io.IOUtils; import org.apache.maven.project.MavenProject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; import org.sonar.api.batch.BatchExtensionDictionnary; -import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.maven.MavenPlugin; import org.sonar.api.batch.maven.MavenPluginHandler; import org.sonar.api.resources.Project; @@ -34,7 +34,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; -public class MavenPluginsConfigurator implements CoreJob { +public class MavenPluginsConfigurator implements BatchComponent { private BatchExtensionDictionnary dictionnary = null; @@ -42,7 +42,7 @@ public class MavenPluginsConfigurator implements CoreJob { this.dictionnary = dictionnary; } - public void execute(Project project, SensorContext context) { + public void execute(Project project) { Logger logger = LoggerFactory.getLogger(getClass()); logger.info("Configure maven plugins..."); diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java b/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java new file mode 100644 index 00000000000..fd5debd5b5c --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java @@ -0,0 +1,88 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.phases; + +import org.sonar.api.batch.SensorContext; +import org.sonar.api.resources.Project; +import org.sonar.batch.index.DefaultIndex; +import org.sonar.batch.index.PersistenceManager; + +import java.util.Arrays; +import java.util.Collection; + +public final class Phases { + + public static Collection getPhaseClasses() { + return Arrays.asList( + DecoratorsExecutor.class, MavenPhaseExecutor.class, MavenPluginsConfigurator.class, + PostJobsExecutor.class, SensorsExecutor.class, UpdateStatusJob.class + ); + } + + private DecoratorsExecutor decoratorsExecutor; + private MavenPhaseExecutor mavenPhaseExecutor; + private MavenPluginsConfigurator mavenPluginsConfigurator; + private PostJobsExecutor postJobsExecutor; + private SensorsExecutor sensorsExecutor; + private UpdateStatusJob updateStatusJob; + private PersistenceManager persistenceManager; + private SensorContext sensorContext; + private DefaultIndex index; + + public Phases(DecoratorsExecutor decoratorsExecutor, MavenPhaseExecutor mavenPhaseExecutor, + MavenPluginsConfigurator mavenPluginsConfigurator, + PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, UpdateStatusJob updateStatusJob, + PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index) { + this.decoratorsExecutor = decoratorsExecutor; + this.mavenPhaseExecutor = mavenPhaseExecutor; + this.mavenPluginsConfigurator = mavenPluginsConfigurator; + this.postJobsExecutor = postJobsExecutor; + this.sensorsExecutor = sensorsExecutor; + this.updateStatusJob = updateStatusJob; + this.persistenceManager = persistenceManager; + this.sensorContext = sensorContext; + this.index = index; + } + + /** + * Executed on each module + */ + public void execute(Project project) { + mavenPluginsConfigurator.execute(project); + mavenPhaseExecutor.execute(project); + + persistenceManager.setDelayedMode(true); + sensorsExecutor.execute(project, sensorContext); + decoratorsExecutor.execute(project); + persistenceManager.dump(); + persistenceManager.setDelayedMode(false); + + if (project.isRoot()) { + updateStatusJob.execute(); + postJobsExecutor.execute(project, sensorContext); + } + cleanMemory(); + } + + private void cleanMemory() { + persistenceManager.clear(); + index.clear(); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/PostJobsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java similarity index 84% rename from sonar-batch/src/main/java/org/sonar/batch/PostJobsExecutor.java rename to sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java index 1df8d3fd773..93805ca6b5f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/PostJobsExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java @@ -17,21 +17,23 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; import org.sonar.api.batch.BatchExtensionDictionnary; import org.sonar.api.batch.PostJob; import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.maven.DependsUponMavenPlugin; import org.sonar.api.batch.maven.MavenPluginHandler; import org.sonar.api.resources.Project; +import org.sonar.batch.MavenPluginExecutor; import java.util.Collection; -public class PostJobsExecutor implements CoreJob { +public class PostJobsExecutor implements BatchComponent { private static final Logger LOG = LoggerFactory.getLogger(PostJobsExecutor.class); private Collection postJobs; @@ -48,14 +50,12 @@ public class PostJobsExecutor implements CoreJob { } public void execute(Project project, SensorContext context) { - if (shouldExecuteOn(project)) { - logPostJobs(); + logPostJobs(); - for (PostJob postJob : postJobs) { - LOG.info("Executing post-job {}", postJob.getClass()); - executeMavenPlugin(project, postJob); - postJob.executeOn(project, context); - } + for (PostJob postJob : postJobs) { + LOG.info("Executing post-job {}", postJob.getClass()); + executeMavenPlugin(project, postJob); + postJob.executeOn(project, context); } } @@ -65,11 +65,6 @@ public class PostJobsExecutor implements CoreJob { } } - private boolean shouldExecuteOn(Project project) { - return postJobs != null && project.isRoot(); - } - - private void executeMavenPlugin(Project project, PostJob job) { if (job instanceof DependsUponMavenPlugin) { MavenPluginHandler handler = ((DependsUponMavenPlugin) job).getMavenPluginHandler(project); diff --git a/sonar-batch/src/main/java/org/sonar/batch/SensorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java similarity index 93% rename from sonar-batch/src/main/java/org/sonar/batch/SensorsExecutor.java rename to sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java index 4bcdc39e9a6..6c105c0fb17 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/SensorsExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java @@ -17,11 +17,12 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; import org.sonar.api.batch.BatchExtensionDictionnary; import org.sonar.api.batch.Sensor; import org.sonar.api.batch.SensorContext; @@ -30,12 +31,13 @@ import org.sonar.api.batch.maven.MavenPluginHandler; import org.sonar.api.database.DatabaseSession; import org.sonar.api.resources.Project; import org.sonar.api.utils.TimeProfiler; +import org.sonar.batch.MavenPluginExecutor; import java.util.Collection; -public class SensorsExecutor implements CoreJob { +public class SensorsExecutor implements BatchComponent { private static final Logger logger = LoggerFactory.getLogger(SensorsExecutor.class); - + private Collection sensors; private DatabaseSession session; private MavenPluginExecutor mavenExecutor; @@ -54,7 +56,7 @@ public class SensorsExecutor implements CoreJob { for (Sensor sensor : sensors) { executeMavenPlugin(project, sensor); - TimeProfiler profiler = new TimeProfiler(logger).start("Sensor "+ sensor); + TimeProfiler profiler = new TimeProfiler(logger).start("Sensor " + sensor); sensor.analyse(project, context); session.commit(); profiler.stop(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/FinalizeSnapshotsJob.java b/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java similarity index 82% rename from sonar-batch/src/main/java/org/sonar/batch/FinalizeSnapshotsJob.java rename to sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java index 722ad0cd7d8..57d5d3b56f5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/FinalizeSnapshotsJob.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java @@ -17,37 +17,31 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.slf4j.LoggerFactory; -import org.sonar.api.batch.SensorContext; +import org.sonar.api.BatchComponent; import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.Snapshot; -import org.sonar.api.resources.Project; +import org.sonar.batch.ServerMetadata; import javax.persistence.Query; -public class FinalizeSnapshotsJob implements CoreJob { +public class UpdateStatusJob implements BatchComponent { private DatabaseSession session; private ServerMetadata server; - private Snapshot snapshot; + private Snapshot snapshot; // TODO remove this component - public FinalizeSnapshotsJob(ServerMetadata server, DatabaseSession session, Snapshot snapshot) { + public UpdateStatusJob(ServerMetadata server, DatabaseSession session, Snapshot snapshot) { this.session = session; this.server = server; this.snapshot = snapshot; } - public void execute(Project project, SensorContext context) { - if (shouldExecuteOn(project)) { - Snapshot previousLastSnapshot = getPreviousLastSnapshot(snapshot); - updateFlags(snapshot, previousLastSnapshot); - } - } - - private boolean shouldExecuteOn(Project project) { - return project.isRoot(); + public void execute() { + Snapshot previousLastSnapshot = getPreviousLastSnapshot(snapshot); + updateFlags(snapshot, previousLastSnapshot); } private Snapshot getPreviousLastSnapshot(Snapshot snapshot) { diff --git a/sonar-batch/src/test/java/org/sonar/batch/CoreJobsTest.java b/sonar-batch/src/test/java/org/sonar/batch/CoreJobsTest.java deleted file mode 100644 index 25c2e046e47..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/CoreJobsTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.sonar.batch; - -import static org.hamcrest.Matchers.greaterThan; -import static org.junit.Assert.assertThat; -import org.junit.Test; - -import java.util.List; - -public class CoreJobsTest { - - @Test - public void mavenPluginsAreExecutedAfterBeingConfigured() { - List> jobs = CoreJobs.allJobs(); - assertThat(jobs.indexOf(FinalizeSnapshotsJob.class), - greaterThan(jobs.indexOf(DecoratorsExecutor.class))); - } - - @Test - public void finalizeJobIsExecutedAfterDecorators() { - List> jobs = CoreJobs.allJobs(); - assertThat(jobs.indexOf(FinalizeSnapshotsJob.class), - greaterThan(jobs.indexOf(DecoratorsExecutor.class))); - } - - @Test - public void allJobs() { - assertThat(CoreJobs.allJobs().size(), greaterThan(3)); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/DefaultTimeMachineTest.java b/sonar-batch/src/test/java/org/sonar/batch/DefaultTimeMachineTest.java index 58500affe28..4c7cf4b78b6 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/DefaultTimeMachineTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/DefaultTimeMachineTest.java @@ -1,113 +1,113 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch; - -import org.junit.Test; -import org.sonar.api.batch.TimeMachineQuery; -import org.sonar.jpa.dao.MeasuresDao; -import org.sonar.jpa.test.AbstractDbUnitTestCase; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Resource; -import org.sonar.batch.indexer.DefaultSonarIndex; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.List; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.number.OrderingComparisons.greaterThan; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class DefaultTimeMachineTest extends AbstractDbUnitTestCase { - - @Test(timeout = 3000) - public void loadMeasureFieldsFromDate() throws ParseException { - setupData("loadMeasuresFromDate"); - DefaultTimeMachine timeMachine = initTimeMachine(); - - TimeMachineQuery query = new TimeMachineQuery(newProject()).setFrom(date("2008-02-01")).setMetrics(Arrays.asList(CoreMetrics.NCLOC)); - List measures = timeMachine.getMeasuresFields(query); - - assertThat(measures.size(), is(3)); - for (Object[] measure : measures) { - assertThat(measure.length, is(3)); // 3 fields - assertThat(measure[1], is((Object) CoreMetrics.NCLOC)); - } - assertThat(measures.get(0)[2], is((Object) 200d)); - assertThat(measures.get(1)[2], is((Object) 230d)); - assertThat(measures.get(2)[2], is((Object) 180d)); - } - - private DefaultTimeMachine initTimeMachine() { - DefaultSonarIndex index = mock(DefaultSonarIndex.class); - DefaultTimeMachine timeMachine = new DefaultTimeMachine(getSession(), index, new MeasuresDao(getSession())); - return timeMachine; - } - - private Project newProject() { - Project project = new Project("group:artifact"); - project.setId(1); - return project; - } - - @Test(timeout = 3000) - public void loadMeasuresFromDate() throws ParseException { - setupData("loadMeasuresFromDate"); - DefaultTimeMachine timeMachine = initTimeMachine(); - - - TimeMachineQuery query = new TimeMachineQuery(newProject()).setFrom(date("2008-02-01")).setMetrics(Arrays.asList(CoreMetrics.NCLOC)); - List measures = timeMachine.getMeasures(query); - - assertThat(measures.size(), is(3)); - long previous = 0; - for (Measure measure : measures) { - assertThat(measure.getMetric(), is(CoreMetrics.NCLOC)); - assertThat(measure.getDate().getTime(), greaterThan(previous)); - previous = measure.getDate().getTime(); - } - assertThat(measures.get(0).getValue(), is(200d)); - assertThat(measures.get(1).getValue(), is(230d)); - assertThat(measures.get(2).getValue(), is(180d)); - } - - @Test(timeout = 3000) - public void loadMeasuresFromDateInterval() throws ParseException { - setupData("loadMeasuresFromDate"); - DefaultTimeMachine timeMachine = initTimeMachine(); - - - TimeMachineQuery query = new TimeMachineQuery(newProject()).setFrom(date("2008-01-01")).setTo(date("2008-12-25")).setMetrics(Arrays.asList(CoreMetrics.NCLOC)); - List measures = timeMachine.getMeasures(query); - assertThat(measures.size(), is(1)); - assertThat(measures.get(0).getValue(), is(200d)); - } - - private Date date(String date) throws ParseException { - return new SimpleDateFormat("yyyy-MM-dd").parse(date); - } -} +///* +// * Sonar, open source software quality management tool. +// * Copyright (C) 2009 SonarSource SA +// * mailto:contact AT sonarsource DOT com +// * +// * Sonar 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. +// * +// * Sonar 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 Sonar; if not, write to the Free Software +// * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 +// */ +//package org.sonar.batch; +// +//import org.junit.Test; +//import org.sonar.api.batch.TimeMachineQuery; +//import org.sonar.jpa.dao.MeasuresDao; +//import org.sonar.jpa.test.AbstractDbUnitTestCase; +//import org.sonar.api.measures.CoreMetrics; +//import org.sonar.api.measures.Measure; +//import org.sonar.api.resources.Project; +//import org.sonar.api.resources.Resource; +//import org.sonar.batch.indexer.DefaultSonarIndex; +// +//import java.text.ParseException; +//import java.text.SimpleDateFormat; +//import java.util.Arrays; +//import java.util.Date; +//import java.util.List; +// +//import static org.hamcrest.CoreMatchers.is; +//import static org.hamcrest.number.OrderingComparisons.greaterThan; +//import static org.junit.Assert.assertThat; +//import static org.mockito.Matchers.anyObject; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.when; +// +//public class DefaultTimeMachineTest extends AbstractDbUnitTestCase { +// +// @Test(timeout = 3000) +// public void loadMeasureFieldsFromDate() throws ParseException { +// setupData("loadMeasuresFromDate"); +// DefaultTimeMachine timeMachine = initTimeMachine(); +// +// TimeMachineQuery query = new TimeMachineQuery(newProject()).setFrom(date("2008-02-01")).setMetrics(Arrays.asList(CoreMetrics.NCLOC)); +// List measures = timeMachine.getMeasuresFields(query); +// +// assertThat(measures.size(), is(3)); +// for (Object[] measure : measures) { +// assertThat(measure.length, is(3)); // 3 fields +// assertThat(measure[1], is((Object) CoreMetrics.NCLOC)); +// } +// assertThat(measures.get(0)[2], is((Object) 200d)); +// assertThat(measures.get(1)[2], is((Object) 230d)); +// assertThat(measures.get(2)[2], is((Object) 180d)); +// } +// +// private DefaultTimeMachine initTimeMachine() { +// DefaultSonarIndex index = mock(DefaultSonarIndex.class); +// DefaultTimeMachine timeMachine = new DefaultTimeMachine(getSession(), index, new MeasuresDao(getSession())); +// return timeMachine; +// } +// +// private Project newProject() { +// Project project = new Project("group:artifact"); +// project.setId(1); +// return project; +// } +// +// @Test(timeout = 3000) +// public void loadMeasuresFromDate() throws ParseException { +// setupData("loadMeasuresFromDate"); +// DefaultTimeMachine timeMachine = initTimeMachine(); +// +// +// TimeMachineQuery query = new TimeMachineQuery(newProject()).setFrom(date("2008-02-01")).setMetrics(Arrays.asList(CoreMetrics.NCLOC)); +// List measures = timeMachine.getMeasures(query); +// +// assertThat(measures.size(), is(3)); +// long previous = 0; +// for (Measure measure : measures) { +// assertThat(measure.getMetric(), is(CoreMetrics.NCLOC)); +// assertThat(measure.getDate().getTime(), greaterThan(previous)); +// previous = measure.getDate().getTime(); +// } +// assertThat(measures.get(0).getValue(), is(200d)); +// assertThat(measures.get(1).getValue(), is(230d)); +// assertThat(measures.get(2).getValue(), is(180d)); +// } +// +// @Test(timeout = 3000) +// public void loadMeasuresFromDateInterval() throws ParseException { +// setupData("loadMeasuresFromDate"); +// DefaultTimeMachine timeMachine = initTimeMachine(); +// +// +// TimeMachineQuery query = new TimeMachineQuery(newProject()).setFrom(date("2008-01-01")).setTo(date("2008-12-25")).setMetrics(Arrays.asList(CoreMetrics.NCLOC)); +// List measures = timeMachine.getMeasures(query); +// assertThat(measures.size(), is(1)); +// assertThat(measures.get(0).getValue(), is(200d)); +// } +// +// private Date date(String date) throws ParseException { +// return new SimpleDateFormat("yyyy-MM-dd").parse(date); +// } +//} diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java new file mode 100644 index 00000000000..6854db8f52d --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java @@ -0,0 +1,110 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import org.junit.Test; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.MeasuresFilters; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.JavaPackage; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.Violation; +import org.sonar.api.utils.SonarException; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.*; +import static org.junit.internal.matchers.IsCollectionContaining.hasItem; + +public class BucketTest { + + private JavaPackage javaPackage = new JavaPackage("org.foo"); + private JavaFile javaFile = new JavaFile("org.foo.Bar"); + private Metric ncloc = new Metric("ncloc"); + + @Test + public void shouldManageRelationships() { + Bucket packageBucket = new Bucket(javaPackage); + Bucket fileBucket = new Bucket(javaFile); + fileBucket.setParent(packageBucket); + + assertThat(fileBucket.getParent(), is(packageBucket)); + assertThat(packageBucket.getChildren().size(), is(1)); + assertThat(packageBucket.getChildren(), hasItem(fileBucket)); + } + + @Test + public void shouldCacheViolations() { + Bucket fileBucket = new Bucket(javaFile); + Violation violation = Violation.create(Rule.create("checkstyle", "rule1", "Rule one"), javaFile); + fileBucket.addViolation(violation); + assertThat(fileBucket.getViolations().size(), is(1)); + assertThat(fileBucket.getViolations(), hasItem(violation)); + } + + @Test + public void shouldAddNewMeasure() { + Bucket fileBucket = new Bucket(javaFile); + Measure measure = new Measure(ncloc).setValue(1200.0); + fileBucket.addMeasure(measure); + + assertThat(fileBucket.getMeasures(MeasuresFilters.all()).size(), is(1)); + assertThat(fileBucket.getMeasures(MeasuresFilters.metric(ncloc)), is(measure)); + } + + @Test + public void shouldUpdateMeasure() { + Bucket fileBucket = new Bucket(javaFile); + Measure measure = new Measure(ncloc).setValue(1200.0); + fileBucket.addMeasure(measure); + + assertThat(fileBucket.getMeasures(MeasuresFilters.all()).size(), is(1)); + assertThat(fileBucket.getMeasures(MeasuresFilters.metric(ncloc)).getValue(), is(1200.0)); + + measure.setValue(500.0); + fileBucket.addMeasure(measure); + + assertThat(fileBucket.getMeasures(MeasuresFilters.all()).size(), is(1)); + assertThat(fileBucket.getMeasures(MeasuresFilters.metric(ncloc)).getValue(), is(500.0)); + } + + @Test(expected = SonarException.class) + public void shouldFailIfAddingSameMeasures() { + Bucket fileBucket = new Bucket(javaFile); + Measure measure = new Measure(ncloc).setValue(1200.0); + fileBucket.addMeasure(measure); + + measure = new Measure(ncloc).setValue(500.0); + fileBucket.addMeasure(measure); + } + + @Test + public void shouldBeEquals() { + assertEquals(new Bucket(javaPackage), new Bucket(javaPackage)); + assertEquals(new Bucket(javaPackage).hashCode(), new Bucket(javaPackage).hashCode()); + } + + @Test + public void shouldNotBeEquals() { + assertFalse(new Bucket(javaPackage).equals(new Bucket(javaFile))); + assertThat(new Bucket(javaPackage).hashCode(), not(is(new Bucket(javaFile).hashCode()))); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/CoreJob.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java similarity index 81% rename from sonar-batch/src/main/java/org/sonar/batch/CoreJob.java rename to sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java index f7231d63e79..428a92f37d3 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/CoreJob.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java @@ -17,13 +17,11 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.index; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.resources.Project; +import org.junit.Ignore; -public interface CoreJob { - - void execute(Project project, SensorContext context); +@Ignore("to do") +public class DefaultIndexTest { } diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java new file mode 100644 index 00000000000..bf3b284a1b5 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java @@ -0,0 +1,133 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +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.Metric; +import org.sonar.api.measures.PersistenceMode; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.JavaPackage; +import org.sonar.api.resources.Project; +import org.sonar.jpa.test.AbstractDbUnitTestCase; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MeasurePersisterTest extends AbstractDbUnitTestCase { + + private ResourcePersister resourcePersister; + private MeasurePersister measurePersister; + private Project project = new Project("foo"); + private JavaPackage aPackage = new JavaPackage("org.foo"); + private Snapshot projectSnapshot, packageSnapshot; + private Metric ncloc, coverage; + + @Before + public void mockResourcePersister() { + setupData("shared"); + resourcePersister = mock(ResourcePersister.class); + projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 3001); + packageSnapshot = getSession().getSingleResult(Snapshot.class, "id", 3002); + ncloc = getSession().getSingleResult(Metric.class, "key", "ncloc"); + coverage = getSession().getSingleResult(Metric.class, "key", "coverage"); + when(resourcePersister.saveResource((Project) anyObject(), eq(project))).thenReturn(projectSnapshot); + when(resourcePersister.saveResource((Project) anyObject(), eq(aPackage))).thenReturn(packageSnapshot); + measurePersister = new MeasurePersister(getSession(), resourcePersister); + } + + @Test + public void shouldInsertMeasure() { + Measure measure = new Measure(ncloc).setValue(1234.0); + + measurePersister.saveMeasure(project, measure); + + checkTables("shouldInsertMeasure", "project_measures"); + } + + @Test + public void shouldUpdateMeasure() { + Measure measure = new Measure(coverage).setValue(12.5); + measure.setId(1L); + + measurePersister.saveMeasure(project, measure); + + checkTables("shouldUpdateMeasure", "project_measures"); + } + + @Test + @Ignore("to do") + public void shouldInsertDataMeasure() { + + } + + @Test + public void shouldDelaySaving() { + measurePersister.setDelayedMode(true); + + measurePersister.saveMeasure(project, new Measure(ncloc).setValue(1234.0)); + measurePersister.saveMeasure(project, aPackage, new Measure(ncloc).setValue(50.0)); + + assertThat(getSession().getResults(MeasureModel.class, "metricId", 1).size(), is(0)); + + measurePersister.dump(); + checkTables("shouldDelaySaving", "project_measures"); + } + + @Test + public void shouldNotDelaySavingWithDatabaseOnlyMeasure() { + measurePersister.setDelayedMode(true); + + measurePersister.saveMeasure(project, new Measure(ncloc).setValue(1234.0).setPersistenceMode(PersistenceMode.DATABASE)); // database only + measurePersister.saveMeasure(project, aPackage, new Measure(ncloc).setValue(50.0)); // database + memory + + // no dump => the db-only measure is saved + + checkTables("shouldNotDelaySavingWithDatabaseOnlyMeasure", "project_measures"); + } + + @Test + public void shouldNotSaveBestValues() { + JavaFile file = new JavaFile("org.foo.MyClass"); + + Measure measure = new Measure(coverage).setValue(0.0); + assertThat(MeasurePersister.shouldPersistMeasure(file, measure), is(true)); + + measure = new Measure(coverage).setValue(75.8); + assertThat(MeasurePersister.shouldPersistMeasure(file, measure), is(true)); + + measure = new Measure(coverage).setValue(100.0); + assertThat(MeasurePersister.shouldPersistMeasure(file, measure), is(false)); + } + + @Test + public void shouldNotSaveMemoryOnlyMeasures() { + Measure measure = new Measure("ncloc").setPersistenceMode(PersistenceMode.MEMORY); + assertThat(MeasurePersister.shouldPersistMeasure(aPackage, measure), is(false)); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ResourcePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ResourcePersisterTest.java new file mode 100644 index 00000000000..88fbb209afd --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/index/ResourcePersisterTest.java @@ -0,0 +1,140 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.JavaPackage; +import org.sonar.api.resources.Library; +import org.sonar.api.resources.Project; +import org.sonar.jpa.test.AbstractDbUnitTestCase; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; + +public class ResourcePersisterTest extends AbstractDbUnitTestCase { + + private Project singleProject, multiModuleProject, moduleA, moduleB, moduleB1; + + @Before + public void before() throws ParseException { + SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); + singleProject = new Project("foo"); + singleProject.setName("Foo").setDescription("some description").setLanguageKey("java").setAnalysisDate(format.parse("25/12/2010")); + + multiModuleProject = new Project("root"); + multiModuleProject.setName("Root").setLanguageKey("java").setAnalysisDate(format.parse("25/12/2010")); + + moduleA = new Project("a"); + moduleA.setName("A").setLanguageKey("java").setAnalysisDate(format.parse("25/12/2010")); + moduleA.setParent(multiModuleProject); + + moduleB = new Project("b"); + moduleB.setName("B").setLanguageKey("java").setAnalysisDate(format.parse("25/12/2010")); + moduleB.setParent(multiModuleProject); + + moduleB1 = new Project("b1"); + moduleB1.setName("B1").setLanguageKey("java").setAnalysisDate(format.parse("25/12/2010")); + moduleB1.setParent(moduleB); + } + + + @Test + public void shouldSaveNewProject() { + setupData("shared"); + + ResourcePersister persister = new ResourcePersister(getSession()); + persister.saveProject(singleProject); + + checkTables("shouldSaveNewProject", "projects", "snapshots"); + } + + @Test + public void shouldSaveNewMultiModulesProject() throws ParseException { + setupData("shared"); + + ResourcePersister persister = new ResourcePersister(getSession()); + persister.saveProject(multiModuleProject); + persister.saveProject(moduleA); + persister.saveProject(moduleB); + persister.saveProject(moduleB1); + + checkTables("shouldSaveNewMultiModulesProject", "projects", "snapshots"); + } + + @Test + public void shouldSaveNewDirectory() { + setupData("shared"); + + ResourcePersister persister = new ResourcePersister(getSession()); + persister.saveProject(singleProject); + persister.saveResource(singleProject, new JavaPackage("org.foo")); + + // check that the directory is attached to the project + checkTables("shouldSaveNewDirectory", "projects", "snapshots"); + } + + @Test + public void shouldSaveNewLibrary() { + setupData("shared"); + + ResourcePersister persister = new ResourcePersister(getSession()); + persister.saveProject(singleProject); + persister.saveResource(singleProject, new Library("junit:junit", "4.8.2")); + persister.saveResource(singleProject, new Library("junit:junit", "4.8.2"));// do nothing, already saved + persister.saveResource(singleProject, new Library("junit:junit", "3.2")); + + checkTables("shouldSaveNewLibrary", "projects", "snapshots"); + } + + @Test + public void shouldClearResourcesExceptProjects() { + setupData("shared"); + + ResourcePersister persister = new ResourcePersister(getSession()); + persister.saveProject(multiModuleProject); + persister.saveProject(moduleA); + persister.saveResource(moduleA, new JavaPackage("org.foo")); + persister.saveResource(moduleA, new JavaFile("org.foo.MyClass")); + persister.clear(); + + assertThat(persister.getSnapshotsByResource().size(), is(2)); + assertThat(persister.getSnapshotsByResource().get(multiModuleProject), notNullValue()); + assertThat(persister.getSnapshotsByResource().get(moduleA), notNullValue()); + } + + @Test + public void shouldUpdateExistingResource() { + setupData("shouldUpdateExistingResource"); + + ResourcePersister persister = new ResourcePersister(getSession()); + singleProject.setName("new name"); + singleProject.setDescription("new description"); + persister.saveProject(singleProject); + + checkTables("shouldUpdateExistingResource", "projects", "snapshots"); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultPersisterTest.java deleted file mode 100644 index efeec499d64..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultPersisterTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import org.junit.Test; -import org.sonar.jpa.test.AbstractDbUnitTestCase; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.resources.JavaPackage; -import org.sonar.api.resources.Project; - -public class DefaultPersisterTest extends AbstractDbUnitTestCase { - - @Test - public void createResource() { - setupData("createResource"); - - Bucket bucket = createBucket(new JavaPackage("org.foo")); - - new DefaultPersister(getSession()).persist(bucket); - - checkTables("createResource", "projects", "snapshots"); - } - - private Bucket createBucket(JavaPackage resource) { - Bucket projectBucket = new Bucket(new Project("my:key").setId(5)); - projectBucket.setSnapshot(getSession().getSingleResult(Snapshot.class, "id", 30)); - - Bucket bucket = new Bucket(resource); - bucket.setProject(projectBucket); - bucket.setParent(projectBucket); - return bucket; - } - - @Test - public void updateExistingResource() { - setupData("updateExistingResource"); - - Bucket bucket = createBucket(new JavaPackage("org.foo")); - - new DefaultPersister(getSession()).persist(bucket); - - checkTables("updateExistingResource", "projects", "snapshots"); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultSonarIndexTest.java b/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultSonarIndexTest.java deleted file mode 100644 index 4e2387319d0..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultSonarIndexTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import org.junit.Ignore; -import org.junit.Test; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.PersistenceMode; -import org.sonar.api.utils.SonarException; -import org.sonar.batch.DefaultResourceCreationLock; -import org.sonar.jpa.test.AbstractDbUnitTestCase; -import org.sonar.api.design.Dependency; -import org.sonar.api.resources.JavaFile; -import org.sonar.api.resources.Resource; - -import static junit.framework.Assert.assertTrue; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -public class DefaultSonarIndexTest extends AbstractDbUnitTestCase { - - @Test - public void indexDependencies() { - DefaultSonarIndex index = new DefaultSonarIndex(getSession(), null, new DefaultResourceCreationLock()); - - Resource from = new JavaFile("org.foo.Foo"); - Resource to = new JavaFile("org.bar.Bar"); - Dependency dependency = new Dependency(from, to); - - index.registerDependency(dependency); - - assertThat(index.getDependencies().size(), is(1)); - assertTrue(index.getDependencies().contains(dependency)); - assertThat(index.getEdge(from, to), is(dependency)); - - assertThat(index.getIncomingEdges(to).size(), is(1)); - assertTrue(index.getIncomingEdges(to).contains(dependency)); - assertThat(index.getIncomingEdges(from).isEmpty(), is(true)); - - assertThat(index.getOutgoingEdges(from).size(), is(1)); - assertTrue(index.getOutgoingEdges(from).contains(dependency)); - assertThat(index.getOutgoingEdges(to).isEmpty(), is(true)); - } - - @Test(expected = SonarException.class) - @Ignore("Temporarily log warnings instead of throwing an exception") - public void failIfLockedAndAddingMeasureOnUnknownResource() { - DefaultResourceCreationLock lock = new DefaultResourceCreationLock(); - lock.lock(); - - DefaultSonarIndex index = new DefaultSonarIndex(getSession(), null, lock); - index.saveMeasure(new JavaFile("org.foo.Bar"), new Measure(CoreMetrics.LINES, 200.0)); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/indexer/LibraryPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/indexer/LibraryPersisterTest.java deleted file mode 100644 index 49933e44a7d..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/indexer/LibraryPersisterTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.jpa.test.AbstractDbUnitTestCase; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.resources.Library; -import org.sonar.api.resources.Project; - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -public class LibraryPersisterTest extends AbstractDbUnitTestCase { - - private Bucket projectBucket; - private LibraryPersister persister; - - @Before - public void before() throws ParseException { - persister = new LibraryPersister(getSession(), new SimpleDateFormat("yyyy-MM-dd HH:mm").parse( "2010-05-18 17:00")); - } - - @Test - public void createLibrary() throws Exception { - setup("createLibrary"); - - Library library = new Library("commons-lang:commons-lang", "1.1") - .setName("Commons Lang"); - - Bucket bucket = new Bucket(library).setProject(projectBucket); - persister.persist(bucket); - - check("createLibrary", "projects", "snapshots"); - } - - @Test - public void reuseExistingLibrary() throws Exception { - setup("reuseExistingLibrary"); - - Library library = new Library("commons-lang:commons-lang", "1.1") - .setName("Commons Lang"); - - Bucket bucket = new Bucket(library).setProject(projectBucket); - persister.persist(bucket); - - check("reuseExistingLibrary", "projects", "snapshots"); - } - - @Test - public void addNewLibraryVersion() throws Exception { - setup("addNewLibraryVersion"); - - Library library = new Library("commons-lang:commons-lang", "1.2") - .setName("Commons Lang"); - - Bucket bucket = new Bucket(library).setProject(projectBucket); - persister.persist(bucket); - - check("addNewLibraryVersion", "projects", "snapshots"); - } - - private void setup(String unitTest) throws Exception { - setupData(unitTest); - - Project project = new Project("my:project"); - project.setId(1); - projectBucket = new Bucket(project); - projectBucket.setSnapshot(getSession().getSingleResult(Snapshot.class, "id", 1)); - } - - private void check(String unitTest, String... tables) { - getSession().commit(); - checkTables(unitTest, tables); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/indexer/ResourcePersistersTest.java b/sonar-batch/src/test/java/org/sonar/batch/indexer/ResourcePersistersTest.java deleted file mode 100644 index cb75095aef4..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/indexer/ResourcePersistersTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.indexer; - -import org.junit.Test; -import org.sonar.jpa.test.AbstractDbUnitTestCase; -import org.sonar.api.resources.*; - -import static junit.framework.Assert.assertTrue; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -public class ResourcePersistersTest extends AbstractDbUnitTestCase { - - @Test - public void getDefaultPersisterForFilesAndPackages() { - ResourcePersisters persisters = new ResourcePersisters(getSession()); - - - JavaFile file = new JavaFile("org.foo.Bar"); - assertThat(persisters.get(file), is(DefaultPersister.class)); - assertThat(persisters.get(new JavaPackage("org.foo")), is(DefaultPersister.class)); - assertThat(persisters.get(new File("org/foo/Bar.sql")), is(DefaultPersister.class)); - - // always the same instance - assertTrue(persisters.get(file)==persisters.get(file)); - } - - @Test - public void getForProjects() { - ResourcePersisters persisters = new ResourcePersisters(getSession()); - - Project project = new Project("my:project"); - assertThat(persisters.get(project), is(ProjectPersister.class)); - - // always the same instance - assertTrue(persisters.get(project)==persisters.get(project)); - } - - @Test - public void getForLibraries() { - ResourcePersisters persisters = new ResourcePersisters(getSession()); - - Library lib = new Library("commons-lang:commons-lang", "1.0"); - assertThat(persisters.get(lib), is(LibraryPersister.class)); - - // always the same instance - assertTrue(persisters.get(lib)==persisters.get(lib)); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/MavenPhaseExecutorTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/MavenPhaseExecutorTest.java similarity index 90% rename from sonar-batch/src/test/java/org/sonar/batch/MavenPhaseExecutorTest.java rename to sonar-batch/src/test/java/org/sonar/batch/phases/MavenPhaseExecutorTest.java index 77d1e333e9c..135fed227a4 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/MavenPhaseExecutorTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/MavenPhaseExecutorTest.java @@ -17,12 +17,12 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Test; -import org.sonar.api.batch.SensorContext; import org.sonar.api.resources.Project; +import org.sonar.batch.MavenPluginExecutor; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.*; @@ -36,7 +36,7 @@ public class MavenPhaseExecutorTest { Project project = new Project("key"); - phaseExecutor.execute(project, mock(SensorContext.class)); + phaseExecutor.execute(project); verify(mavenPluginExecutor, never()).execute(eq(project), anyString()); } @@ -51,7 +51,7 @@ public class MavenPhaseExecutorTest { conf.setProperty(MavenPhaseExecutor.PROP_PHASE, "myphase"); project.setConfiguration(conf); - phaseExecutor.execute(project, mock(SensorContext.class)); + phaseExecutor.execute(project); verify(mavenPluginExecutor).execute(project, "myphase"); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/MavenPluginsConfiguratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/MavenPluginsConfiguratorTest.java similarity index 92% rename from sonar-batch/src/test/java/org/sonar/batch/MavenPluginsConfiguratorTest.java rename to sonar-batch/src/test/java/org/sonar/batch/phases/MavenPluginsConfiguratorTest.java index aea7b42c6cb..037d30987b7 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/MavenPluginsConfiguratorTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/MavenPluginsConfiguratorTest.java @@ -17,18 +17,16 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Test; import org.sonar.api.batch.BatchExtensionDictionnary; -import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.maven.MavenPlugin; import org.sonar.api.batch.maven.MavenPluginHandler; import org.sonar.api.resources.Project; import org.sonar.api.test.MavenTestUtils; -import org.sonar.api.utils.ServerHttpClient; import java.util.Arrays; @@ -53,7 +51,7 @@ public class MavenPluginsConfiguratorTest { Project project = MavenTestUtils.loadProjectFromPom(getClass(), "pom.xml"); - newConfigurator(handler1, handler2).execute(project, mock(SensorContext.class)); + newConfigurator(handler1, handler2).execute(project); verify(handler1).configure(eq(project), argThat(new IsMavenPlugin("myartifact1"))); verify(handler2).configure(eq(project), argThat(new IsMavenPlugin("myartifact2"))); diff --git a/sonar-batch/src/test/java/org/sonar/batch/phases/PhasesTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/PhasesTest.java new file mode 100644 index 00000000000..def743acaf0 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/PhasesTest.java @@ -0,0 +1,33 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.phases; + +import org.junit.Test; + +import static org.hamcrest.number.OrderingComparisons.greaterThan; +import static org.junit.Assert.assertThat; + +public class PhasesTest { + + @Test + public void shouldDefinePhaseClasses() { + assertThat(Phases.getPhaseClasses().size(), greaterThan(4)); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/PostJobsExecutorTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java similarity index 70% rename from sonar-batch/src/test/java/org/sonar/batch/PostJobsExecutorTest.java rename to sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java index 6a1d72cbc58..f9aa127c386 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/PostJobsExecutorTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java @@ -17,32 +17,22 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.junit.Test; import org.sonar.api.batch.PostJob; import org.sonar.api.batch.SensorContext; import org.sonar.api.resources.Project; +import org.sonar.batch.MavenPluginExecutor; import java.util.Arrays; import java.util.List; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; public class PostJobsExecutorTest { - @Test - public void doNotExecuteOnModules() { - PostJob job1 = mock(PostJob.class); - Project module = new Project("module").setParent(new Project("project")); - - PostJobsExecutor executor = new PostJobsExecutor(Arrays.asList(job1), mock(MavenPluginExecutor.class)); - executor.execute(module, mock(SensorContext.class)); - - verify(job1, never()).executeOn((Project) anyObject(), (SensorContext) anyObject()); - } - @Test public void executeAllPostJobs() { PostJob job1 = mock(PostJob.class); @@ -58,9 +48,4 @@ public class PostJobsExecutorTest { verify(job2).executeOn(project, context); } - - static class FakePostJob implements PostJob { - public void executeOn(Project project, SensorContext context) { - } - } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/FinalizeSnapshotsJobTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java similarity index 85% rename from sonar-batch/src/test/java/org/sonar/batch/FinalizeSnapshotsJobTest.java rename to sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java index d16822861e4..b83c32eafb0 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/FinalizeSnapshotsJobTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java @@ -17,19 +17,18 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.phases; import org.junit.Test; import org.sonar.api.database.model.Snapshot; -import org.sonar.api.resources.Project; +import org.sonar.batch.ServerMetadata; import org.sonar.jpa.test.AbstractDbUnitTestCase; import javax.persistence.Query; import static org.mockito.Mockito.mock; -public class FinalizeSnapshotsJobTest extends AbstractDbUnitTestCase { - +public class UpdateStatusJobTest extends AbstractDbUnitTestCase { @Test public void shouldUnflagPenultimateLastSnapshot() throws Exception { @@ -49,8 +48,8 @@ public class FinalizeSnapshotsJobTest extends AbstractDbUnitTestCase { private void assertAnalysis(int snapshotId, String fixture) { setupData("sharedFixture", fixture); - FinalizeSnapshotsJob sensor = new FinalizeSnapshotsJob(mock(ServerMetadata.class), getSession(), loadSnapshot(snapshotId)); - sensor.execute(new Project("key"), null); + UpdateStatusJob sensor = new UpdateStatusJob(mock(ServerMetadata.class), getSession(), loadSnapshot(snapshotId)); + sensor.execute(); getSession().stop(); checkTables(fixture, "snapshots"); diff --git a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast-result.xml deleted file mode 100644 index a1b5dc5de93..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast-result.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast.xml b/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast.xml deleted file mode 100644 index 700793aaeee..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/doNotFailIfNoPenultimateLast.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot-result.xml deleted file mode 100644 index 909141c4f5b..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot-result.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot.xml b/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot.xml deleted file mode 100644 index 523a66915f4..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/lastSnapshotIsNotUpdatedWhenAnalyzingPastSnapshot.xml +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/sharedFixture.xml b/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/sharedFixture.xml deleted file mode 100644 index 00420a0362f..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/sharedFixture.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot-result.xml deleted file mode 100644 index 815b71743a4..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot-result.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot.xml b/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot.xml deleted file mode 100644 index 7e4130b75d9..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/FinalizeSnapshotsJobTest/shouldUnflagPenultimateLastSnapshot.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/MavenPluginsConfiguratorTest/pom.xml b/sonar-batch/src/test/resources/org/sonar/batch/MavenProjectBuilderTest/MavenPluginsConfiguratorTest/pom.xml similarity index 100% rename from sonar-batch/src/test/resources/org/sonar/batch/MavenPluginsConfiguratorTest/pom.xml rename to sonar-batch/src/test/resources/org/sonar/batch/MavenProjectBuilderTest/MavenPluginsConfiguratorTest/pom.xml diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shared.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shared.xml new file mode 100644 index 00000000000..3a12e1fde0b --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shared.xml @@ -0,0 +1,31 @@ + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldDelaySaving-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldDelaySaving-result.xml new file mode 100644 index 00000000000..53312994cbe --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldDelaySaving-result.xml @@ -0,0 +1,45 @@ + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldInsertMeasure-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldInsertMeasure-result.xml new file mode 100644 index 00000000000..56cd3d33cf7 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldInsertMeasure-result.xml @@ -0,0 +1,35 @@ + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldNotDelaySavingWithDatabaseOnlyMeasure-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldNotDelaySavingWithDatabaseOnlyMeasure-result.xml new file mode 100644 index 00000000000..3392e2cf5cd --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldNotDelaySavingWithDatabaseOnlyMeasure-result.xml @@ -0,0 +1,42 @@ + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldUpdateMeasure-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldUpdateMeasure-result.xml new file mode 100644 index 00000000000..927067c218b --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/MeasurePersisterTest/shouldUpdateMeasure-result.xml @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shared.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shared.xml new file mode 100644 index 00000000000..0c4e4aed8a2 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shared.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewDirectory-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewDirectory-result.xml new file mode 100644 index 00000000000..7e82d5b090d --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewDirectory-result.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewLibrary-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewLibrary-result.xml new file mode 100644 index 00000000000..f53d7421a8f --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewLibrary-result.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewMultiModulesProject-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewMultiModulesProject-result.xml new file mode 100644 index 00000000000..a83a24b4f88 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewMultiModulesProject-result.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewProject-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewProject-result.xml new file mode 100644 index 00000000000..e69ab9a12b2 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldSaveNewProject-result.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource-result.xml new file mode 100644 index 00000000000..3006cd6f826 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource-result.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource.xml new file mode 100644 index 00000000000..1a6997f37fe --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ResourcePersisterTest/shouldUpdateExistingResource.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource-result.xml deleted file mode 100644 index a8540058032..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource-result.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource.xml deleted file mode 100644 index a248090db8c..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/createResource.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource-result.xml deleted file mode 100644 index a8540058032..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource-result.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource.xml deleted file mode 100644 index 22b280f539d..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/DefaultPersisterTest/updateExistingResource.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion-result.xml deleted file mode 100644 index 320b08ae0e2..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion-result.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion.xml deleted file mode 100644 index ba9bcf884f6..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/addNewLibraryVersion.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary-result.xml deleted file mode 100644 index ba9bcf884f6..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary-result.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary.xml deleted file mode 100644 index 6f57a77a8cd..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/createLibrary.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary-result.xml deleted file mode 100644 index 752dcc20f92..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary-result.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary.xml b/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary.xml deleted file mode 100644 index 752dcc20f92..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/indexer/LibraryPersisterTest/reuseExistingLibrary.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/phases/MavenPluginsConfiguratorTest/pom.xml b/sonar-batch/src/test/resources/org/sonar/batch/phases/MavenPluginsConfiguratorTest/pom.xml new file mode 100644 index 00000000000..2f95da16602 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/phases/MavenPluginsConfiguratorTest/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + mygroup + myartifact + jar + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.2 + + html + + + + + \ No newline at end of file diff --git a/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresDao.java b/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresDao.java index 4e2ece885ab..4c8c71b0b72 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresDao.java +++ b/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresDao.java @@ -131,7 +131,7 @@ public class AsyncMeasuresDao extends BaseDao { "AND ams.snapshotDate>=:measureDate " + "ORDER BY ams.snapshotDate ASC ") .setParameter("projectId", asyncMeasure.getProjectId()) - .setParameter("metricId", asyncMeasure.getMetric().getId()) + .setParameter("metricId", asyncMeasure.getMetricId()) .setParameter("measureDate", asyncMeasure.getMeasureDate()); if (endDate != null) { query.setParameter("endDate", endDate); diff --git a/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresService.java b/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresService.java index ae296d1e356..26b1926b901 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresService.java +++ b/sonar-core/src/main/java/org/sonar/jpa/dao/AsyncMeasuresService.java @@ -90,7 +90,7 @@ public class AsyncMeasuresService { AsyncMeasuresDao dao = new AsyncMeasuresDao(session); MeasureModel measure = dao.getAsyncMeasure(id); AsyncMeasureSnapshot pastAsyncMeasureSnapshot = dao.getLastAsyncMeasureSnapshot(measure.getProjectId(), - measure.getMetric().getId(), measure.getMeasureDate()); + measure.getMetricId(), measure.getMeasureDate()); dao.deleteAsyncMeasure(measure); if (pastAsyncMeasureSnapshot != null) { MeasureModel pastAsyncMeasure = dao.getAsyncMeasure(pastAsyncMeasureSnapshot.getMeasureId()); @@ -102,7 +102,7 @@ public class AsyncMeasuresService { private void registerMeasure(MeasureModel measure, AsyncMeasuresDao dao) { AsyncMeasureSnapshot nextAsyncMeasureSnapshot = dao.getNextAsyncMeasureSnapshot( - measure.getProjectId(), measure.getMetric().getId(), measure.getMeasureDate()); + measure.getProjectId(), measure.getMetricId(), measure.getMeasureDate()); Date dateNextAsyncMeasure = (nextAsyncMeasureSnapshot != null) ? nextAsyncMeasureSnapshot.getMeasureDate() : null; List nextAsyncMeasureSnapshots = dao.getNextAsyncMeasureSnapshotsUntilDate( @@ -110,7 +110,7 @@ public class AsyncMeasuresService { if (!nextAsyncMeasureSnapshots.isEmpty()) { for (AsyncMeasureSnapshot asyncMeasureSnapshot : nextAsyncMeasureSnapshots) { dao.createAsyncMeasureSnapshot(measure.getId(), asyncMeasureSnapshot.getSnapshotId(), measure.getMeasureDate(), - asyncMeasureSnapshot.getSnapshotDate(), measure.getMetric().getId(), measure.getProjectId()); + asyncMeasureSnapshot.getSnapshotDate(), measure.getMetricId(), measure.getProjectId()); dao.removeSnapshotFromAsyncMeasureSnapshot(asyncMeasureSnapshot); } } else { @@ -118,11 +118,11 @@ public class AsyncMeasuresService { if (!nextSnapshotsUntilDate.isEmpty()) { for (Snapshot nextSnapshot : nextSnapshotsUntilDate) { dao.createAsyncMeasureSnapshot(measure.getId(), nextSnapshot.getId(), measure.getMeasureDate(), - nextSnapshot.getCreatedAt(), measure.getMetric().getId(), measure.getProjectId()); + nextSnapshot.getCreatedAt(), measure.getMetricId(), measure.getProjectId()); } } else { dao.createAsyncMeasureSnapshot(measure.getId(), null, measure.getMeasureDate(), - null, measure.getMetric().getId(), measure.getProjectId()); + null, measure.getMetricId(), measure.getProjectId()); } } } diff --git a/sonar-core/src/test/java/org/sonar/jpa/session/DatabaseSessionTest.java b/sonar-core/src/test/java/org/sonar/jpa/session/DatabaseSessionTest.java index 6cc891f6cf8..4094cca55c2 100644 --- a/sonar-core/src/test/java/org/sonar/jpa/session/DatabaseSessionTest.java +++ b/sonar-core/src/test/java/org/sonar/jpa/session/DatabaseSessionTest.java @@ -26,6 +26,7 @@ import org.junit.internal.matchers.IsCollectionContaining; import org.sonar.api.database.model.MeasureModel; import org.sonar.api.database.model.ResourceModel; import org.sonar.api.database.model.Snapshot; +import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; import org.sonar.jpa.dao.MeasuresDao; import org.sonar.jpa.test.AbstractDbUnitTestCase; @@ -53,11 +54,12 @@ public class DatabaseSessionTest extends AbstractDbUnitTestCase { Snapshot snapshot = new Snapshot(project1, true, "", new Date(1)); getSession().save(project1, snapshot); + getSession().save(CoreMetrics.CLASSES); getSession().commit(); - Metric metric = new MeasuresDao(getSession()).getMetric("classes_count"); + Metric metric = new MeasuresDao(getSession()).getMetric(CoreMetrics.CLASSES_KEY); for (int i = 0; i < NB_INSERTS; i++) { - MeasureModel pm = new MeasureModel(metric, 1.0).setSnapshotId(snapshot.getId()); + MeasureModel pm = new MeasureModel(metric.getId(), 1.0).setSnapshotId(snapshot.getId()); getSession().save(pm); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java index e89f11b44b0..3444cef6241 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java @@ -63,6 +63,13 @@ public class Event extends BaseIdentifiable { public Event() { } + public Event(String name, String description, String category) { + this.name = name; + this.description = description; + this.category = category; + } + + @Deprecated public Event(String name, String description, String category, Date date, Integer resourceId) { this.name = name; this.description = description; @@ -71,6 +78,7 @@ public class Event extends BaseIdentifiable { this.resourceId = resourceId; } + @Deprecated public Event(String name, String description, String category, Snapshot snapshot) { this.name = name; this.description = description; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java index af87a386ae1..1fdddb46bc7 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java @@ -36,8 +36,6 @@ import java.util.Set; public abstract class SonarIndex implements DirectedGraphAccessor { - public abstract Project getRootProject(); - public abstract Project getProject(); public abstract Resource getResource(Resource resource); @@ -58,13 +56,13 @@ public abstract class SonarIndex implements DirectedGraphAccessor getDependencies(); - public abstract void saveLink(ProjectLink link); + public abstract void addLink(ProjectLink link); public abstract void deleteLink(String key); @@ -72,7 +70,7 @@ public abstract class SonarIndex implements DirectedGraphAccessor getOutgoingDependencies(Resource from) { return getOutgoingEdges(from); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/TimeMachineQuery.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TimeMachineQuery.java index 0f88a74a0ff..4047179fcaf 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/TimeMachineQuery.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TimeMachineQuery.java @@ -19,6 +19,7 @@ */ package org.sonar.api.batch; +import com.google.common.collect.Lists; import org.apache.commons.lang.builder.ToStringBuilder; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Resource; @@ -39,6 +40,7 @@ public class TimeMachineQuery { private Resource resource; private List metrics; + private List metricKeys; private Date from; private Date to; private boolean onlyLastAnalysis = false; @@ -89,6 +91,24 @@ public class TimeMachineQuery { */ public TimeMachineQuery setMetrics(List metrics) { this.metrics = metrics; + this.metricKeys = Lists.newLinkedList(); + for (Metric metric : this.metrics) { + this.metricKeys.add(metric.getKey()); + } + return this; + } + + public TimeMachineQuery setMetricKeys(String... metricKeys) { + this.metricKeys = Arrays.asList(metricKeys); + return this; + } + + public List getMetricKeys() { + return metricKeys; + } + + public TimeMachineQuery setMetricKeys(List metricKeys) { + this.metricKeys = metricKeys; return this; } @@ -100,6 +120,10 @@ public class TimeMachineQuery { */ public TimeMachineQuery setMetrics(Metric... metrics) { this.metrics = Arrays.asList(metrics); + this.metricKeys = Lists.newLinkedList(); + for (Metric metric : this.metrics) { + this.metricKeys.add(metric.getKey()); + } return this; } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java index d7f4ea4c22d..3a9c1a4bca0 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java @@ -58,10 +58,8 @@ public class MeasureModel implements Cloneable { @Column(name = "tendency", updatable = true, nullable = true) private Integer tendency; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "metric_id") - @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) - private Metric metric; + @Column(name = "metric_id", updatable = false, nullable = false) + private Integer metricId; @Column(name = "snapshot_id", updatable = true, nullable = true) private Integer snapshotId; @@ -124,19 +122,19 @@ public class MeasureModel implements Cloneable { /** * Creates a measure based on a metric and a double value */ - public MeasureModel(Metric metric, Double val) { + public MeasureModel(int metricId, Double val) { if (val.isNaN() || val.isInfinite()) { - throw new IllegalArgumentException("Measure value is NaN. Metric=" + metric); + throw new IllegalArgumentException("Measure value is NaN. Metric=" + metricId); } - this.metric = metric; + this.metricId = metricId; this.value = val; } /** * Creates a measure based on a metric and an alert level */ - public MeasureModel(Metric metric, Metric.Level level) { - this.metric = metric; + public MeasureModel(int metricId, Metric.Level level) { + this.metricId = metricId; if (level != null) { this.textValue = level.toString(); } @@ -145,8 +143,8 @@ public class MeasureModel implements Cloneable { /** * Creates a measure based on a metric and a string value */ - public MeasureModel(Metric metric, String val) { - this.metric = metric; + public MeasureModel(int metricId, String val) { + this.metricId = metricId; setData(val); } @@ -238,18 +236,12 @@ public class MeasureModel implements Cloneable { return this; } - /** - * @return the measure metric - */ - public Metric getMetric() { - return metric; + public Integer getMetricId() { + return metricId; } - /** - * Sets the measure metric - */ - public void setMetric(Metric metric) { - this.metric = metric; + public void setMetricId(Integer metricId) { + this.metricId = metricId; } /** @@ -375,7 +367,7 @@ public class MeasureModel implements Cloneable { /** * @return the measure data */ - public String getData() { + public String getData(Metric metric) { if (this.textValue != null) { return this.textValue; } @@ -457,7 +449,7 @@ public class MeasureModel implements Cloneable { public String toString() { return new ToStringBuilder(this). append("value", value). - append("metric", metric). + append("metricId", metricId). toString(); } @@ -519,7 +511,6 @@ public class MeasureModel implements Cloneable { * @return the current object */ public MeasureModel save(DatabaseSession session) { - this.metric = session.reattach(Metric.class, metric.getId()); MeasureData data = getMeasureData(); setMeasureData(null); session.save(this); @@ -545,7 +536,7 @@ public class MeasureModel implements Cloneable { @Override public Object clone() { MeasureModel clone = new MeasureModel(); - clone.setMetric(getMetric()); + clone.setMetricId(getMetricId()); clone.setDescription(getDescription()); clone.setTextValue(getTextValue()); clone.setAlertStatus(getAlertStatus()); @@ -580,57 +571,20 @@ public class MeasureModel implements Cloneable { getUrl()!=null; } - - /** - * Builds a MeasureModel from a Measure - */ - public static MeasureModel build(Measure measure) { - return build(measure, new MeasureModel()); - } - - /** - * Merges a Measure into a MeasureModel - */ - public static MeasureModel build(Measure measure, MeasureModel merge) { - merge.setMetric(measure.getMetric()); - merge.setDescription(measure.getDescription()); - merge.setData(measure.getData()); - merge.setAlertStatus(measure.getAlertStatus()); - merge.setAlertText(measure.getAlertText()); - merge.setTendency(measure.getTendency()); - merge.setDiffValue1(measure.getDiffValue1()); - merge.setDiffValue2(measure.getDiffValue2()); - merge.setDiffValue3(measure.getDiffValue3()); - merge.setUrl(measure.getUrl()); - merge.setCharacteristic(measure.getCharacteristic()); - if (measure.getValue() != null) { - merge.setValue(measure.getValue().doubleValue()); - } else { - merge.setValue(null); - } - if (measure instanceof RuleMeasure) { - RuleMeasure ruleMeasure = (RuleMeasure) measure; - merge.setRulesCategoryId(ruleMeasure.getRuleCategory()); - merge.setRulePriority(ruleMeasure.getRulePriority()); - merge.setRule(ruleMeasure.getRule()); - } - return merge; - } - /** * @return a measure from the current object */ - public Measure toMeasure() { + public Measure toMeasure(Metric metric) { Measure measure; if (isRuleMeasure()) { - measure = new RuleMeasure(getMetric(), getRule(), getRulePriority(), getRulesCategoryId()); + measure = new RuleMeasure(metric, getRule(), getRulePriority(), getRulesCategoryId()); } else { - measure = new Measure(getMetric()); + measure = new Measure(metric); } measure.setId(getId()); measure.setDescription(getDescription()); measure.setValue(getValue()); - measure.setData(getData()); + measure.setData(getData(metric)); measure.setAlertStatus(getAlertStatus()); measure.setAlertText(getAlertText()); measure.setTendency(getTendency()); @@ -641,19 +595,4 @@ public class MeasureModel implements Cloneable { measure.setCharacteristic(getCharacteristic()); return measure; } - - /** - * Transforms a list of MeasureModel into a list of Measure - * - * @return an empty list if models is null - */ - public static List toMeasures(List models) { - List result = new ArrayList(); - for (MeasureModel model : models) { - if (model != null) { - result.add(model.toMeasure()); - } - } - return result; - } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/RuleFailureModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/RuleFailureModel.java index fe06d79ab8e..144119c45d8 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/RuleFailureModel.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/RuleFailureModel.java @@ -38,9 +38,8 @@ public class RuleFailureModel extends BaseIdentifiable { @Column(name = "snapshot_id") protected Integer snapshotId; - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "rule_id") - private Rule rule; + @Column(name = "rule_id", updatable = false, nullable = false) + private Integer ruleId; @Column(name = "failure_level", updatable = false, nullable = false) @Enumerated(EnumType.ORDINAL) @@ -55,15 +54,6 @@ public class RuleFailureModel extends BaseIdentifiable { @Column(name = "cost", updatable = true, nullable = true) private Double cost; - public RuleFailureModel() { - } - - public RuleFailureModel(Rule rule, RulePriority priority) { - this.rule = rule; - this.priority = priority; - } - - public String getMessage() { return message; } @@ -80,12 +70,12 @@ public class RuleFailureModel extends BaseIdentifiable { this.priority = priority; } - public Rule getRule() { - return rule; + public Integer getRuleId() { + return ruleId; } - public void setRule(Rule rule) { - this.rule = rule; + public void setRuleId(Integer ruleId) { + this.ruleId = ruleId; } public Integer getLine() { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java index ebf84ff0e2b..3610be07b78 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java @@ -41,6 +41,7 @@ public class Measure { public final static int DEFAULT_PRECISION = 1; private Long id; // for internal use + protected String metricKey; protected Metric metric; protected Double value; protected String data; @@ -54,6 +55,10 @@ public class Measure { protected Characteristic characteristic; protected PersistenceMode persistenceMode = PersistenceMode.FULL; + public Measure(String metricKey) { + this.metricKey = metricKey; + } + /** * Creates a measure with a metric * @@ -61,6 +66,7 @@ public class Measure { */ public Measure(Metric metric) { this.metric = metric; + this.metricKey = metric.getKey(); } /** @@ -71,6 +77,7 @@ public class Measure { */ public Measure(Metric metric, Double value) { this.metric = metric; + this.metricKey = metric.getKey(); setValue(value); } @@ -83,6 +90,7 @@ public class Measure { */ public Measure(Metric metric, Double value, int precision) { this.metric = metric; + this.metricKey = metric.getKey(); setValue(value, precision); } @@ -95,6 +103,7 @@ public class Measure { */ public Measure(Metric metric, Double value, String data) { this.metric = metric; + this.metricKey = metric.getKey(); setValue(value); setData(data); } @@ -107,6 +116,7 @@ public class Measure { */ public Measure(Metric metric, String data) { this.metric = metric; + this.metricKey = metric.getKey(); setData(data); } @@ -118,6 +128,7 @@ public class Measure { */ public Measure(Metric metric, Metric.Level level) { this.metric = metric; + this.metricKey = metric.getKey(); if (level != null) { this.data = level.toString(); } @@ -159,6 +170,10 @@ public class Measure { return metric; } + public String getMetricKey() { + return metricKey; + } + /** * Set the underlying metric * @@ -167,6 +182,7 @@ public class Measure { */ public Measure setMetric(Metric metric) { this.metric = metric; + this.metricKey = metric.getKey(); return this; } @@ -474,28 +490,6 @@ public class Measure { } -// @Override -// public boolean equals(Object obj) { -// if (!(obj.getClass().equals(Measure.class))) { -// return false; -// } -// if (this == obj) { -// return true; -// } -// Measure rhs = (Measure) obj; -// return new EqualsBuilder() -// .append(metric, rhs.getMetric()) -// .append(characteristic, rhs.getCharacteristic()) -// .isEquals(); -// } -// -// @Override -// public int hashCode() { -// return (metric != null ? metric.hashCode() : 0); -// } -// - - @Override public boolean equals(Object o) { if (this == o) { @@ -506,7 +500,7 @@ public class Measure { } Measure measure = (Measure) o; - if (metric != null ? !metric.equals(measure.metric) : measure.metric != null) { + if (metricKey != null ? !metricKey.equals(measure.metricKey) : measure.metricKey != null) { return false; } if (characteristic != null ? !characteristic.equals(measure.characteristic) : measure.characteristic != null) { @@ -517,7 +511,7 @@ public class Measure { @Override public int hashCode() { - int result = metric != null ? metric.hashCode() : 0; + int result = metricKey != null ? metricKey.hashCode() : 0; result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0); return result; } @@ -526,7 +520,7 @@ public class Measure { public String toString() { return new ToStringBuilder(this). append("id", id). - append("metric", metric). + append("metric", metricKey). append("value", value). append("data", data). append("description", description). diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java index 487e67000ad..b9fb26b057d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java @@ -52,7 +52,7 @@ public final class MeasuresFilters { } for (Measure measure : measures) { if (measure.getClass().equals(Measure.class) && - measure.getMetric().equals(metric) && + measure.getMetricKey().equals(metric.getKey()) && measure.getCharacteristic()==null) { return measure; } @@ -165,14 +165,14 @@ public final class MeasuresFilters { * Used for internal optimizations. */ public static abstract class MetricFilter implements MeasuresFilter { - private final Metric metric; + private final String metricKey; protected MetricFilter(Metric metric) { - this.metric = metric; + this.metricKey = metric.getKey(); } - public Metric filterOnMetric() { - return metric; + public String filterOnMetricKey() { + return metricKey; } } @@ -183,7 +183,7 @@ public final class MeasuresFilters { private boolean apply(Measure measure) { return measure instanceof RuleMeasure - && filterOnMetric().equals(measure.getMetric()) + && filterOnMetricKey().equals(measure.getMetricKey()) && doApply((RuleMeasure) measure); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/CoreJobs.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java similarity index 59% rename from sonar-batch/src/main/java/org/sonar/batch/CoreJobs.java rename to sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java index e3beb96ce2a..acd85a01e51 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/CoreJobs.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java @@ -17,27 +17,23 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.api.measures; -import java.util.ArrayList; +import org.sonar.api.BatchComponent; + +import java.util.Collection; import java.util.List; /** - * Core batch extensions, instanciated by picocontainer. + * This component is currently available only on batch-side + * + * @since 2.5 */ -public final class CoreJobs { +public interface MetricFinder extends BatchComponent { + + Metric find(String key); - private CoreJobs() { - } + Collection findAll(List metricKeys); - public static List> allJobs() { - List> classes = new ArrayList>(); - classes.add(MavenPluginsConfigurator.class); - classes.add(MavenPhaseExecutor.class); - classes.add(SensorsExecutor.class); - classes.add(DecoratorsExecutor.class); - classes.add(FinalizeSnapshotsJob.class); - classes.add(PostJobsExecutor.class); - return classes; - } + Collection findAll(); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java index be3054b0bbb..4a2c284bc5d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java @@ -119,12 +119,8 @@ public class Violation { } /** - * Sets the violation priority - * - * @return the current object - * @deprecated since 2.3. The priority is set by the quality profile. + * For internal use only */ - @Deprecated public Violation setPriority(RulePriority priority) { this.priority = priority; return this; diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/database/model/MeasureModelTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/database/model/MeasureModelTest.java index 59e1a349b17..fbf6857ae5c 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/database/model/MeasureModelTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/database/model/MeasureModelTest.java @@ -1,43 +1,43 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.api.database.model; - -import org.junit.Test; -import static org.junit.Assert.assertThat; -import org.sonar.api.measures.CoreMetrics; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; - -public class MeasureModelTest { - - @Test - public void doNotCopyDataWhenCloning() { - MeasureModel initial = new MeasureModel(); - initial.setMetric(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION); - initial.setMeasureData(new MeasureData(initial, "foo")); - initial.setValue(30.0); - assertThat(initial.getData(), is("foo")); - - MeasureModel clone = (MeasureModel) initial.clone(); - assertThat(clone.getData(), nullValue()); - assertThat(clone.getValue(), is(30.0)); - assertThat(clone.getMetric(), is(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION)); - } -} +///* +// * Sonar, open source software quality management tool. +// * Copyright (C) 2009 SonarSource SA +// * mailto:contact AT sonarsource DOT com +// * +// * Sonar 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. +// * +// * Sonar 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 Sonar; if not, write to the Free Software +// * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 +// */ +//package org.sonar.api.database.model; +// +//import org.junit.Test; +//import static org.junit.Assert.assertThat; +//import org.sonar.api.measures.CoreMetrics; +//import static org.hamcrest.Matchers.is; +//import static org.hamcrest.Matchers.nullValue; +// +//public class MeasureModelTest { +// +// @Test +// public void doNotCopyDataWhenCloning() { +// MeasureModel initial = new MeasureModel(); +// initial.setMetric(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION); +// initial.setMeasureData(new MeasureData(initial, "foo")); +// initial.setValue(30.0); +// assertThat(initial.getData(), is("foo")); +// +// MeasureModel clone = (MeasureModel) initial.clone(); +// assertThat(clone.getData(), nullValue()); +// assertThat(clone.getValue(), is(30.0)); +// assertThat(clone.getMetric(), is(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION)); +// } +//} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageComplexityFormulaTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageComplexityFormulaTest.java index eca3e281e9d..6ab8cffe522 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageComplexityFormulaTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageComplexityFormulaTest.java @@ -19,12 +19,11 @@ */ package org.sonar.api.measures; +import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; import org.sonar.api.resources.JavaFile; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import static junit.framework.Assert.assertNull; @@ -41,12 +40,13 @@ public class AverageComplexityFormulaTest { @Before public void before() { context = mock(FormulaContext.class); + when(context.getTargetMetric()).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY); data = mock(FormulaData.class); } @Test public void testAverageCalculation() { - List childrenData = new ArrayList(); + List childrenData = Lists.newArrayList(); FormulaData data1 = mock(FormulaData.class); childrenData.add(data1); when(data1.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 43.0)); @@ -66,7 +66,7 @@ public class AverageComplexityFormulaTest { @Test public void testWhenNoChildrenMesaures() { - List childrenData = new ArrayList(); + List childrenData = Lists.newArrayList(); when(data.getChildren()).thenReturn(childrenData); Measure measure = new AverageComplexityFormula(CoreMetrics.FUNCTIONS).calculate(data, context); assertNull(measure); @@ -74,7 +74,7 @@ public class AverageComplexityFormulaTest { @Test public void testWhenNoComplexityMesaures() { - List childrenData = new ArrayList(); + List childrenData = Lists.newArrayList(); FormulaData data1 = mock(FormulaData.class); childrenData.add(data1); when(data1.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 43.0)); @@ -87,7 +87,7 @@ public class AverageComplexityFormulaTest { @Test public void testWhenNoByMetricMesaures() { - List childrenData = new ArrayList(); + List childrenData = Lists.newArrayList(); FormulaData data1 = mock(FormulaData.class); childrenData.add(data1); when(data1.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 43.0)); @@ -100,7 +100,7 @@ public class AverageComplexityFormulaTest { @Test public void testWhenMixedMetrics() { - List childrenData = new ArrayList(); + List childrenData = Lists.newArrayList(); FormulaData data1 = mock(FormulaData.class); childrenData.add(data1); when(data1.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 43.0)); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureUtilsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureUtilsTest.java index 568269b9684..cb1a653f764 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureUtilsTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureUtilsTest.java @@ -34,8 +34,8 @@ public class MeasureUtilsTest { public void getValue() { assertThat(MeasureUtils.getValue(null, 3.0), is(3.0)); assertThat(MeasureUtils.getValue(new Measure(), 3.0), is(3.0)); - assertThat(MeasureUtils.getValue(new Measure(null, 2.0), 3.0), is(2.0)); - assertThat(MeasureUtils.getValue(new Measure(null, "data"), 3.0), is(3.0)); + assertThat(MeasureUtils.getValue(new Measure(CoreMetrics.LINES, 2.0), 3.0), is(2.0)); + assertThat(MeasureUtils.getValue(new Measure(CoreMetrics.LINES, "data"), 3.0), is(3.0)); } @Test diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb index 95db00d803d..657bc53b8b5 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb @@ -65,8 +65,9 @@ class Snapshot < ActiveRecord::Base snapshots=snapshots[-5,5] if snapshots.size>=5 snapshots.insert(0, Snapshot.find(:first, - :conditions => ["project_id=? AND status IN (?) AND scope=? AND qualifier=?", resource.id, STATUS_PROCESSED, resource.scope, resource.qualifier], + :conditions => ["project_id=? AND status=? AND scope=? AND qualifier=?", resource.id, STATUS_PROCESSED, resource.scope, resource.qualifier], :include => 'project', :order => 'snapshots.created_at ASC', :limit => 1)) + snapshots.compact.uniq end -- 2.39.5