aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorsimonbrandhof <simon.brandhof@gmail.com>2010-09-24 16:02:35 +0000
committersimonbrandhof <simon.brandhof@gmail.com>2010-09-24 16:02:35 +0000
commit51c728457cb0ea1763625d3600bddc2c3d7f049b (patch)
treeb5b29779f065bb57d4755a541db08879cb61bfc2 /sonar-batch
parenta5ba257ffd83b0418f12c0dc1ba9542873f0d6e8 (diff)
downloadsonarqube-51c728457cb0ea1763625d3600bddc2c3d7f049b.tar.gz
sonarqube-51c728457cb0ea1763625d3600bddc2c3d7f049b.zip
SONAR-1711 add a lock on SensorContext/DecoratorContext in order to avoid creation of resources in methods saveViolation() and saveMeasure().
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/Batch.java3
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/DefaultResourceCreationLock.java49
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java1
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultSonarIndex.java40
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/DefaultResourceCreationLockTest.java43
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultSonarIndexTest.java16
6 files changed, 133 insertions, 19 deletions
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 cf199af94be..4cd649b3d65 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/Batch.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/Batch.java
@@ -68,6 +68,7 @@ public class Batch {
MutablePicoContainer batchContainer = container.makeChildContainer();
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(JpaPluginDao.class);
batchContainer.as(Characteristics.CACHE).addComponent(BatchPluginRepository.class);
@@ -90,7 +91,7 @@ public class Batch {
URLClassLoader fullClassloader = RemoteClassLoader.createForJdbcDriver(configuration).getClassLoader();
// set as the current context classloader for hibernate, else it does not find the JDBC driver.
Thread.currentThread().setContextClassLoader(fullClassloader);
-
+
register(container, new DriverDatabaseConnector(configuration, fullClassloader));
register(container, ThreadLocalDatabaseSessionFactory.class);
container.as(Characteristics.CACHE).addAdapter(new DatabaseSessionProvider());
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultResourceCreationLock.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultResourceCreationLock.java
new file mode 100644
index 00000000000..93b33f6b53a
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultResourceCreationLock.java
@@ -0,0 +1,49 @@
+/*
+ * 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.sonar.api.batch.ResourceCreationLock;
+
+/**
+ * This lock is used to ensure that Sonar resources (files, packages, directories) are not created by buggy plugins
+ * when saving measures/violations on unknown resources.
+ *
+ * @since 2.3
+ */
+public final class DefaultResourceCreationLock implements ResourceCreationLock {
+
+ private boolean locked = false;
+
+ public boolean isLocked() {
+ return locked;
+ }
+
+ public void lock() {
+ this.locked = true;
+ }
+
+ /**
+ * Unlocking is for internal use only.
+ */
+ public void unlock() {
+ locked = false;
+ }
+
+}
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 c3298085af1..fbe69040a35 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java
@@ -23,6 +23,7 @@ import org.picocontainer.Characteristics;
import org.picocontainer.MutablePicoContainer;
import org.sonar.api.batch.BatchExtensionDictionnary;
import org.sonar.api.batch.ProjectClasspath;
+import org.sonar.api.batch.ResourceCreationLock;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.measures.CoreMetrics;
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
index 48a6bc72997..e6c2c21cd7b 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultSonarIndex.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/indexer/DefaultSonarIndex.java
@@ -27,6 +27,8 @@ 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.utils.SonarException;
+import org.sonar.batch.*;
import org.sonar.jpa.dao.MeasuresDao;
import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.database.model.ResourceModel;
@@ -43,10 +45,6 @@ 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.batch.ProjectTree;
-import org.sonar.batch.ResourceFilters;
-import org.sonar.batch.ViolationFilters;
-import org.sonar.batch.ViolationsDao;
import java.util.*;
@@ -58,6 +56,7 @@ public class DefaultSonarIndex extends SonarIndex {
private ResourcePersisters resourcePersisters;
private Bucket<Project> rootProjectBucket;
private Bucket<Project> selectedProjectBucket;
+ private DefaultResourceCreationLock lock;
private ViolationFilters violationFilters;
private ResourceFilters resourceFilters;
@@ -73,10 +72,11 @@ public class DefaultSonarIndex extends SonarIndex {
private MeasuresDao measuresDao;
private ProjectTree projectTree;
- public DefaultSonarIndex(DatabaseSession session, 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() {
@@ -131,6 +131,8 @@ public class DefaultSonarIndex extends SonarIndex {
projectDependency.setId(null);
registerDependency(projectDependency);
}
+
+ lock.unlock();
}
/* ------------ RESOURCES */
@@ -166,15 +168,19 @@ public class DefaultSonarIndex extends SonarIndex {
}
public Resource addResource(Resource resource) {
- return getOrCreateBucket(resource).getResource();
+ return getOrCreateBucket(resource, false).getResource();
}
- private Bucket<Resource> getOrCreateBucket(Resource resource) {
+ private Bucket<Resource> getOrCreateBucket(Resource resource, boolean mustExist) {
Bucket bucket = buckets.get(resource);
if (bucket != null) {
return bucket;
}
+ if (mustExist && lock.isLocked() && !ResourceUtils.isLibrary(resource)) {
+ throw new SonarException("The following resource has not been registered before saving violation/measure/event: " + resource);
+ }
+
prepareResource(resource);
bucket = new Bucket<Resource>(resource);
buckets.put(resource, bucket);
@@ -182,7 +188,7 @@ public class DefaultSonarIndex extends SonarIndex {
Bucket parentBucket = null;
Resource parent = resource.getParent();
if (parent != null) {
- parentBucket = getOrCreateBucket(parent);
+ parentBucket = getOrCreateBucket(parent, mustExist);
} else if (!ResourceUtils.isLibrary(resource)) {
parentBucket = selectedProjectBucket;
}
@@ -203,18 +209,18 @@ public class DefaultSonarIndex extends SonarIndex {
/* ------------ MEASURES */
public Measure getMeasure(Resource resource, Metric metric) {
- return getOrCreateBucket(resource).getMeasures(MeasuresFilters.metric(metric));
+ return getOrCreateBucket(resource, false).getMeasures(MeasuresFilters.metric(metric));
}
public <M> M getMeasures(Resource resource, MeasuresFilter<M> filter) {
- return getOrCreateBucket(resource).getMeasures(filter);
+ return getOrCreateBucket(resource, false).getMeasures(filter);
}
/* ------------ SOURCE CODE */
public void setSource(Resource resource, String source) {
- Bucket bucket = getOrCreateBucket(resource);
+ Bucket bucket = getOrCreateBucket(resource, false);
if (!bucket.isExcluded()) {
if (bucket.isSourceSaved()) {
@@ -236,7 +242,7 @@ public class DefaultSonarIndex extends SonarIndex {
if (resource == null) {
bucket = selectedProjectBucket;
} else {
- bucket = getOrCreateBucket(resource);
+ bucket = getOrCreateBucket(resource, true);
}
if (!bucket.isExcluded()) {
persistViolation(violation, bucket.getSnapshot());
@@ -260,7 +266,7 @@ public class DefaultSonarIndex extends SonarIndex {
}
public Measure addMeasure(Resource resource, Measure measure) {
- Bucket bucket = getOrCreateBucket(resource);
+ 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);
@@ -316,8 +322,8 @@ public class DefaultSonarIndex extends SonarIndex {
if (persistedDep != null && persistedDep.getId()!=null) {
return persistedDep;
}
- Bucket from = getOrCreateBucket(dependency.getFrom());
- Bucket to = getOrCreateBucket(dependency.getTo());
+ Bucket from = getOrCreateBucket(dependency.getFrom(), true);
+ Bucket to = getOrCreateBucket(dependency.getTo(), true);
DependencyDto dto = new DependencyDto();
dto.setFromResourceId(from.getResourceId());
@@ -399,7 +405,7 @@ public class DefaultSonarIndex extends SonarIndex {
/* ----------- EVENTS */
public List<Event> getEvents(Resource resource) {
- Bucket bucket = getOrCreateBucket(resource);
+ Bucket bucket = getOrCreateBucket(resource, true);
return session.getResults(Event.class, "resourceId", bucket.getResourceId());
}
@@ -408,7 +414,7 @@ public class DefaultSonarIndex extends SonarIndex {
}
public Event createEvent(Resource resource, String name, String description, String category, Date date) {
- Bucket bucket = getOrCreateBucket(resource);
+ Bucket bucket = getOrCreateBucket(resource, true);
Event event;
if (date == null) {
event = new Event(name, description, category, bucket.getSnapshot());
diff --git a/sonar-batch/src/test/java/org/sonar/batch/DefaultResourceCreationLockTest.java b/sonar-batch/src/test/java/org/sonar/batch/DefaultResourceCreationLockTest.java
new file mode 100644
index 00000000000..24918b4326e
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/DefaultResourceCreationLockTest.java
@@ -0,0 +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.batch;
+
+import org.junit.Test;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+public class DefaultResourceCreationLockTest {
+
+ @Test
+ public void shouldNotBeLockedAtStartup() {
+ assertThat(new DefaultResourceCreationLock().isLocked(), is(false));
+ }
+
+ @Test
+ public void shouldLock() {
+ DefaultResourceCreationLock lock = new DefaultResourceCreationLock();
+ lock.lock();
+ assertThat(lock.isLocked(), is(true));
+
+ lock.unlock();
+ assertThat(lock.isLocked(), is(false));
+ }
+}
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
index fdbc09cc47c..c818de86ad5 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultSonarIndexTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/indexer/DefaultSonarIndexTest.java
@@ -20,6 +20,11 @@
package org.sonar.batch.indexer;
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;
@@ -33,7 +38,7 @@ public class DefaultSonarIndexTest extends AbstractDbUnitTestCase {
@Test
public void indexDependencies() {
- DefaultSonarIndex index = new DefaultSonarIndex(getSession(), null);
+ DefaultSonarIndex index = new DefaultSonarIndex(getSession(), null, new DefaultResourceCreationLock());
Resource from = new JavaFile("org.foo.Foo");
Resource to = new JavaFile("org.bar.Bar");
@@ -53,4 +58,13 @@ public class DefaultSonarIndexTest extends AbstractDbUnitTestCase {
assertTrue(index.getOutgoingEdges(from).contains(dependency));
assertThat(index.getOutgoingEdges(to).isEmpty(), is(true));
}
+
+ @Test(expected = SonarException.class)
+ 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));
+ }
}