]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-1914 reload measures with PersistenceMode.DATABASE on demand
authorsimonbrandhof <simon.brandhof@gmail.com>
Sat, 26 Feb 2011 00:14:52 +0000 (01:14 +0100)
committersimonbrandhof <simon.brandhof@gmail.com>
Sat, 26 Feb 2011 00:14:52 +0000 (01:14 +0100)
16 files changed:
sonar-batch/src/main/java/org/sonar/batch/Batch.java
sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java
sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
sonar-batch/src/test/java/org/sonar/batch/index/MemoryOptimizerTest.java [new file with mode: 0644]
sonar-batch/src/test/resources/org/sonar/batch/index/MemoryOptimizerTest/shouldReloadEvictedMeasure.xml [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java

index 36a702073cde9a46c02111ac7734284878c9e010..c2b15adda09d6d3af6cb9181a5318e119f6dc242 100644 (file)
@@ -19,9 +19,6 @@
  */
 package org.sonar.batch;
 
-import java.net.URLClassLoader;
-import java.util.Arrays;
-
 import org.apache.commons.configuration.Configuration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,6 +40,9 @@ import org.sonar.jpa.session.DatabaseSessionProvider;
 import org.sonar.jpa.session.DriverDatabaseConnector;
 import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
 
+import java.net.URLClassLoader;
+import java.util.Arrays;
+
 public class Batch {
 
   private static final Logger LOG = LoggerFactory.getLogger(Batch.class);
@@ -89,6 +89,7 @@ public class Batch {
       addComponent(EventPersister.class);
       addComponent(LinkPersister.class);
       addComponent(MeasurePersister.class);
+      addComponent(MemoryOptimizer.class);
       addComponent(DefaultResourcePersister.class);
       addComponent(SourcePersister.class);
       addComponent(ViolationPersister.class);
index 5272ab80cb15b2b31eaf8ed4dd713a38f2bb7fe2..dedee60406a59e66ab6072d3f8ee41c01b346a5e 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.batch;
 
+import com.google.common.collect.Lists;
 import org.sonar.api.batch.DecoratorContext;
 import org.sonar.api.batch.Event;
 import org.sonar.api.database.DatabaseSession;
@@ -32,7 +33,10 @@ import org.sonar.api.resources.Resource;
 import org.sonar.api.rules.Violation;
 import org.sonar.batch.index.DefaultIndex;
 
-import java.util.*;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
 
 public class DefaultDecoratorContext implements DecoratorContext {
 
@@ -79,11 +83,11 @@ public class DefaultDecoratorContext implements DecoratorContext {
   }
 
   public Measure getMeasure(Metric metric) {
-    return index.getMeasures(resource, MeasuresFilters.metric(metric));
+    return index.getMeasure(resource, metric);
   }
 
   public Collection<Measure> getChildrenMeasures(MeasuresFilter filter) {
-    List<Measure> result = new ArrayList<Measure>();
+    List<Measure> result = Lists.newArrayList();
     for (DecoratorContext childContext : childrenContexts) {
       Object childResult = childContext.getMeasures(filter);
       if (childResult != null) {
index abafcdb150eb4593931861d2f6005473918aa31b..494e1a84997cc5cbbb59041afb8fc696415a11cc 100644 (file)
@@ -19,8 +19,6 @@
  */
 package org.sonar.batch.index;
 
-import java.util.*;
-
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -43,6 +41,8 @@ import org.sonar.batch.ProjectTree;
 import org.sonar.batch.ResourceFilters;
 import org.sonar.batch.ViolationFilters;
 
+import java.util.*;
+
 public class DefaultIndex extends SonarIndex {
 
   private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class);
@@ -136,7 +136,10 @@ public class DefaultIndex extends SonarIndex {
   public Measure getMeasure(Resource resource, Metric metric) {
     Bucket bucket = buckets.get(resource);
     if (bucket != null) {
-      return bucket.getMeasures(MeasuresFilters.metric(metric));
+      Measure measure = bucket.getMeasures(MeasuresFilters.metric(metric));
+      if (measure!=null) {
+        return persistence.reloadMeasure(measure);
+      }
     }
     return null;
   }
@@ -144,6 +147,7 @@ public class DefaultIndex extends SonarIndex {
   public <M> M getMeasures(Resource resource, MeasuresFilter<M> filter) {
     Bucket bucket = buckets.get(resource);
     if (bucket != null) {
+      // TODO the data measures which are not kept in memory are not reloaded yet. Use getMeasure().
       return bucket.getMeasures(filter);
     }
     return null;
@@ -160,13 +164,11 @@ public class DefaultIndex extends SonarIndex {
         throw new SonarException("Unknown metric: " + measure.getMetricKey());
       }
       measure.setMetric(metric);
-      if (measure.getPersistenceMode().useMemory()) {
-        bucket.addMeasure(measure);
-      }
+      bucket.addMeasure(measure);
+
       if (measure.getPersistenceMode().useDatabase()) {
         persistence.saveMeasure(resource, measure);
       }
-      // TODO keep database measures in cache but remove data
     }
     return measure;
   }
index a89991610e43f8080be5d4cc8b4812562e1b04a7..f5722b7f5a2fc2ebe74b77906028a013e96f8423 100644 (file)
@@ -84,6 +84,10 @@ public final class DefaultPersistenceManager implements PersistenceManager {
     }
   }
 
+  public Measure reloadMeasure(Measure measure) {
+    return measurePersister.reloadMeasure(measure);
+  }
+
   public void saveDependency(Project project, Dependency dependency, Dependency parentDependency) {
     if (ResourceUtils.isPersistable(dependency.getFrom()) && ResourceUtils.isPersistable(dependency.getTo())) {
       dependencyPersister.saveDependency(project, dependency, parentDependency);
index 97942ef8f30546c424ff980c80acc93b8994c43b..e11ab6915095e3d8812e7cf89023c2b23a43378e 100644 (file)
@@ -45,11 +45,14 @@ public final class MeasurePersister {
   private DatabaseSession session;
   private ResourcePersister resourcePersister;
   private RuleFinder ruleFinder;
+  private MemoryOptimizer memoryOptimizer;
 
-  public MeasurePersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder) {
+
+  public MeasurePersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder, MemoryOptimizer memoryOptimizer) {
     this.session = session;
     this.resourcePersister = resourcePersister;
     this.ruleFinder = ruleFinder;
+    this.memoryOptimizer = memoryOptimizer;
   }
 
   public void setDelayedMode(boolean delayedMode) {
@@ -63,22 +66,30 @@ public final class MeasurePersister {
 
     } else {
       Snapshot snapshot = resourcePersister.getSnapshotOrFail(resource);
+      MeasureModel model = null;
       if (measure.getId() != null) {
         // update
-        MeasureModel model = session.reattach(MeasureModel.class, measure.getId());
+        model = session.reattach(MeasureModel.class, measure.getId());
         model = mergeModel(measure, model);
         model.save(session);
 
       } else if (shouldPersistMeasure(resource, measure)) {
         // insert
-        MeasureModel model = createModel(measure);
+        model = createModel(measure);
         model.setSnapshotId(snapshot.getId());
         model.save(session);
         measure.setId(model.getId()); // could be removed
       }
+      if (model != null) {
+        memoryOptimizer.evictDataMeasure(measure, model);
+      }
     }
   }
 
+  public Measure reloadMeasure(Measure measure) {
+    return memoryOptimizer.reloadMeasure(measure);
+  }
+
   static boolean shouldPersistMeasure(Resource resource, Measure measure) {
     Metric metric = measure.getMetric();
     return measure.getPersistenceMode().useDatabase() &&
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java b/sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java
new file mode 100644 (file)
index 0000000..0fa0610
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.MeasureData;
+import org.sonar.api.database.model.MeasureModel;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.PersistenceMode;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @since 2.7
+ */
+public class MemoryOptimizer {
+
+  private static final Logger LOG = LoggerFactory.getLogger(MemoryOptimizer.class);
+
+  private List<Measure> loadedMeasures = Lists.newArrayList();
+  private Map<Long, Integer> dataIdByMeasureId = Maps.newHashMap();
+  private DatabaseSession session;
+
+  public MemoryOptimizer(DatabaseSession session) {
+    this.session = session;
+  }
+
+  /**
+   * Remove data of a database measure from memory.
+   */
+  public void evictDataMeasure(Measure measure, MeasureModel model) {
+    if (PersistenceMode.DATABASE.equals(measure.getPersistenceMode())) {
+      MeasureData data = model.getMeasureData();
+      if (data != null && data.getId() != null) {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Remove data measure from memory: " + measure.getMetricKey() + ", id=" + measure.getId());
+        }
+        measure.unsetData();
+        dataIdByMeasureId.put(measure.getId(), data.getId());
+      }
+    }
+  }
+
+  public Measure reloadMeasure(Measure measure) {
+    if (measure.getId() != null && dataIdByMeasureId.containsKey(measure.getId()) && !measure.hasData()) {
+      Integer dataId = dataIdByMeasureId.get(measure.getId());
+      MeasureData data = session.getSingleResult(MeasureData.class, "id", dataId);
+      if (data == null) {
+        LoggerFactory.getLogger(getClass()).error("The MEASURE_DATA row with id " + dataId + " is lost");
+
+      } else {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Reload the data measure: " + measure.getMetricKey() + ", id=" + measure.getId());
+        }
+        measure.setData(data.getText());
+        loadedMeasures.add(measure);
+      }
+    }
+    return measure;
+  }
+
+  public void flushMemory() {
+    if (LOG.isDebugEnabled() && loadedMeasures.size() > 0) {
+      LOG.debug("Flush " + loadedMeasures.size() + " data measures from memory: ");
+    }
+    for (Measure measure : loadedMeasures) {
+      measure.unsetData();
+    }
+    loadedMeasures.clear();
+  }
+
+  boolean isTracked(Long measureId) {
+    return dataIdByMeasureId.get(measureId)!=null;
+  }
+}
index cef245960c93619d560c8bd31d6e39829595fba7..98de69eb77fa07eb87bd5c2db5f26c03f2006f3c 100644 (file)
@@ -23,7 +23,6 @@ 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.File;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.ProjectLink;
 import org.sonar.api.resources.Resource;
@@ -45,6 +44,8 @@ public interface PersistenceManager {
 
   void saveMeasure(Resource resource, Measure measure);
 
+  Measure reloadMeasure(Measure measure);
+
   void saveDependency(Project project, Dependency dependency, Dependency parentDependency);
 
   void saveLink(Project project, ProjectLink link);
index 74b7179b16abe4bb0e39f6b37f4a67f6bf6e303d..155329947021a2add5037ae9fcea9bc22de92c1e 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.api.resources.Resource;
 import org.sonar.batch.DecoratorsSelector;
 import org.sonar.batch.DefaultDecoratorContext;
 import org.sonar.batch.index.DefaultIndex;
+import org.sonar.batch.index.MemoryOptimizer;
 
 import java.util.Collection;
 import java.util.IdentityHashMap;
@@ -46,11 +47,14 @@ public class DecoratorsExecutor implements BatchComponent {
   private DatabaseSession session;
   private static final Logger LOG = LoggerFactory.getLogger(DecoratorsExecutor.class);
   private DefaultIndex index;
+  private MemoryOptimizer memoryOptimizer;
 
-  public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultIndex index, DatabaseSession session) {
+  public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultIndex index, DatabaseSession session,
+                            MemoryOptimizer memoryOptimizer) {
     this.decoratorsSelector = new DecoratorsSelector(extensionDictionnary);
     this.session = session;
     this.index = index;
+    this.memoryOptimizer = memoryOptimizer;
   }
 
 
@@ -81,6 +85,7 @@ public class DecoratorsExecutor implements BatchComponent {
       for (Decorator decorator : decorators) {
         profiler.start(decorator);
         decorator.decorate(resource, context);
+        memoryOptimizer.flushMemory();
         profiler.stop();
       }
     }
index 707015d2d5a4d41b8c9cc0545df464efa0c13c64..e78a56f25c73c6702d19a17a1d8abf802e37393b 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.api.database.DatabaseSession;
 import org.sonar.api.resources.Project;
 import org.sonar.api.utils.TimeProfiler;
 import org.sonar.batch.MavenPluginExecutor;
+import org.sonar.batch.index.MemoryOptimizer;
 
 import java.util.Collection;
 
@@ -41,11 +42,14 @@ public class SensorsExecutor implements BatchComponent {
   private Collection<Sensor> sensors;
   private DatabaseSession session;
   private MavenPluginExecutor mavenExecutor;
+  private MemoryOptimizer memoryOptimizer;
 
-  public SensorsExecutor(BatchExtensionDictionnary selector, Project project, DatabaseSession session, MavenPluginExecutor mavenExecutor) {
+  public SensorsExecutor(BatchExtensionDictionnary selector, Project project, DatabaseSession session, MavenPluginExecutor mavenExecutor,
+                         MemoryOptimizer memoryOptimizer) {
     this.sensors = selector.select(Sensor.class, project, true);
     this.session = session;
     this.mavenExecutor = mavenExecutor;
+    this.memoryOptimizer = memoryOptimizer;
   }
 
   public void execute(Project project, SensorContext context) {
@@ -58,6 +62,7 @@ public class SensorsExecutor implements BatchComponent {
 
       TimeProfiler profiler = new TimeProfiler(logger).start("Sensor " + sensor);
       sensor.analyse(project, context);
+      memoryOptimizer.flushMemory();
       session.commit();
       profiler.stop();
     }
index 81dd495a9f58e5cf83eccb5cb276d9a03f7caf97..3753b6752e87c35b3fa2f4edcdd7a7fcd47e12df 100644 (file)
@@ -36,11 +36,13 @@ import org.sonar.jpa.test.AbstractDbUnitTestCase;
 
 import java.util.List;
 
+import static org.hamcrest.CoreMatchers.anyOf;
 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.verify;
 import static org.mockito.Mockito.when;
 
 public class MeasurePersisterTest extends AbstractDbUnitTestCase {
@@ -57,6 +59,7 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
   private JavaFile aFile = new JavaFile("org.foo.Bar");
   private Snapshot projectSnapshot, packageSnapshot, fileSnapshot;
   private Metric ncloc, coverage;
+  private MemoryOptimizer memoryOptimizer;
 
   @Before
   public void mockResourcePersister() {
@@ -73,7 +76,8 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
     when(resourcePersister.getSnapshot(project)).thenReturn(projectSnapshot);
     when(resourcePersister.getSnapshot(aPackage)).thenReturn(packageSnapshot);
     when(resourcePersister.getSnapshot(aFile)).thenReturn(fileSnapshot);
-    measurePersister = new MeasurePersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory()));
+    memoryOptimizer = mock(MemoryOptimizer.class);
+    measurePersister = new MeasurePersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory()), memoryOptimizer);
   }
 
   @Test
@@ -85,6 +89,16 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
     checkTables("shouldInsertMeasure", "project_measures");
   }
 
+  @Test
+  public void shouldRegisterPersistedMeasureToMemoryOptimizer() {
+    Measure measure = new Measure(ncloc).setValue(1234.0);
+
+    measurePersister.saveMeasure(project, measure);
+
+    verify(memoryOptimizer).evictDataMeasure(eq(measure), (MeasureModel)anyObject());
+  }
+
+
   @Test
   public void shouldUpdateMeasure() {
     Measure measure = new Measure(coverage).setValue(12.5);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/MemoryOptimizerTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/MemoryOptimizerTest.java
new file mode 100644 (file)
index 0000000..6b3e0b8
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.hamcrest.core.IsNull;
+import org.junit.Test;
+import org.sonar.api.database.model.MeasureData;
+import org.sonar.api.database.model.MeasureModel;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.PersistenceMode;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+
+public class MemoryOptimizerTest extends AbstractDbUnitTestCase {
+
+  @Test
+  public void shouldEvictDatabaseOnlyMeasure() {
+    MemoryOptimizer optimizer = new MemoryOptimizer(getSession());
+    Measure measure = new Measure(CoreMetrics.CONDITIONS_BY_LINE)
+        .setData("10=23")
+        .setPersistenceMode(PersistenceMode.DATABASE)
+        .setId(12345L);
+    MeasureModel model = newPersistedModel();
+
+    optimizer.evictDataMeasure(measure, model);
+
+    assertThat(optimizer.isTracked(12345L),is(true));
+    assertThat(measure.getData(), nullValue());// data has been removed from memory
+  }
+
+  @Test
+  public void shouldNotEvictStandardMeasure() {
+    MemoryOptimizer optimizer = new MemoryOptimizer(getSession());
+    Measure measure = new Measure(CoreMetrics.PROFILE)
+        .setData("Sonar way")
+        .setId(12345L);
+    MeasureModel model = newPersistedModel();
+
+    optimizer.evictDataMeasure(measure, model);
+
+    assertThat(optimizer.isTracked(12345L),is(false));
+    assertThat(measure.getData(), is("Sonar way"));
+  }
+
+  @Test
+  public void shouldReloadEvictedMeasure() {
+    setupData("shouldReloadEvictedMeasure");
+    MemoryOptimizer optimizer = new MemoryOptimizer(getSession());
+    Measure measure = new Measure(CoreMetrics.CONDITIONS_BY_LINE)
+        .setData("initial")
+        .setPersistenceMode(PersistenceMode.DATABASE)
+        .setId(12345L);
+
+    optimizer.evictDataMeasure(measure, newPersistedModel());
+    assertThat(measure.getData(), nullValue());
+
+    optimizer.reloadMeasure(measure);
+
+    assertThat(measure.getData().length(), greaterThan(5));
+
+    optimizer.flushMemory();
+    assertThat(measure.getData(), nullValue());
+  }
+
+  private MeasureModel newPersistedModel() {
+    MeasureModel model = new MeasureModel();
+    model.setId(12345L);
+    MeasureData measureData = new MeasureData();
+    measureData.setId(500);
+    model.setMeasureData(measureData);
+    return model;
+  }
+}
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/MemoryOptimizerTest/shouldReloadEvictedMeasure.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/MemoryOptimizerTest/shouldReloadEvictedMeasure.xml
new file mode 100644 (file)
index 0000000..5f40b82
--- /dev/null
@@ -0,0 +1,8 @@
+<dataset>
+
+  
+  <measure_data id="2" measure_id="2" snapshot_id="2" data="[null]"/>
+  <measure_data id="500" measure_id="12345" snapshot_id="1" data="value from database"/>
+
+
+</dataset>
\ No newline at end of file
index 59c1f66ed9aae8f9761cb9914829bbd142ae2ba9..b33487af40f4815eeeb497d818455d3bc722db9a 100644 (file)
@@ -600,6 +600,7 @@ public final class CoreMetrics {
 
 
   // SCM
+  // These metrics are computed by the SCM Activity plugin, since version 1.2.
 
   public static final String SCM_COMMITS_KEY = "commits";
   public static final Metric SCM_COMMITS = new Metric.Builder(SCM_COMMITS_KEY, Metric.ValueType.INT)
index 3b64b89da3fe9ac12184b61fc624efa9d45a0317..6462db590d5d163a8bb4606c266c049c167c50dd 100644 (file)
@@ -322,6 +322,14 @@ public class Measure {
     return this;
   }
 
+  /**
+   * @since 2.7
+   */
+  public Measure unsetData() {
+    this.data=null;
+    return this;
+  }
+  
   /**
    * @return the description of the measure
    */
index 92050c92d814d6e9051e0ac14a1c58594e4ea21d..e0ec08d89aaa98ccf977f7b72e153aa0d443587d 100644 (file)
@@ -130,7 +130,9 @@ public class Metric implements ServerExtension, BatchExtension {
    * Creates a metric based on its key. Shortcut to Metric(key, ValueType.INT)
    *
    * @param key the metric key
+   * @deprecated since 2.7 use the Builder factory.
    */
+  @Deprecated
   public Metric(String key) {
     this(key, ValueType.INT);
   }
@@ -141,11 +143,17 @@ public class Metric implements ServerExtension, BatchExtension {
    *
    * @param key  the key
    * @param type the type
+   * @deprecated since 2.7 use the Builder factory.
    */
+  @Deprecated
   public Metric(String key, ValueType type) {
     this(key, key, key, type, -1, Boolean.FALSE, null, false);
   }
 
+  /**
+   * @deprecated since 2.7 use the Builder factory.
+   */
+  @Deprecated
   public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain) {
     this(key, name, description, type, direction, qualitative, domain, false);
   }
@@ -164,6 +172,7 @@ public class Metric implements ServerExtension, BatchExtension {
    * @param qualitative whether the metric is qualitative
    * @param domain      the metric domain
    * @param userManaged whether the metric is user managed
+   * @deprecated since 2.7 use the Builder factory.
    */
   @Deprecated
   public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain, boolean userManaged) {
@@ -197,7 +206,9 @@ public class Metric implements ServerExtension, BatchExtension {
    * @param qualitative whether the metric is qualitative
    * @param domain      the metric domain
    * @param formula     the metric formula
+   * @deprecated since 2.7 use the Builder factory.
    */
+  @Deprecated
   public Metric(String key, String name, ValueType type, Integer direction, Boolean qualitative, String domain, Formula formula) {
     this.key = key;
     this.name = name;
index 50f2a329574b44655ded9c3b7ebf2894e2a8f1b6..6a29f0c1c22006768a654cd5b93dee6140e09dc5 100644 (file)
@@ -114,4 +114,17 @@ public class MeasureTest {
     assertFalse(measure.equals(ruleMeasure));
     assertFalse(ruleMeasure.equals(measure));
   }
+
+  @Test
+  public void shouldUnsetData() {
+    String data = "1=10;21=456";
+    Measure measure = new Measure(CoreMetrics.CONDITIONS_BY_LINE).setData( data);
+    assertThat(measure.hasData(), is(true));
+    assertThat(measure.getData(), is(data));
+
+    measure.unsetData();
+
+    assertThat(measure.hasData(), is(false));
+    assertThat(measure.getData(), nullValue());
+  }
 }