@Override
public void put(Value value, Object object, CoderContext context) {
DuplicationGroup c = (DuplicationGroup) object;
- value.put(c.originBlock());
+ blockCoder.put(value, c.originBlock(), context);
value.put(c.duplicates().size());
for (DuplicationGroup.Block block : c.duplicates()) {
blockCoder.put(value, block, context);
@Override
public Object get(Value value, Class clazz, CoderContext context) {
- DuplicationGroup g = new DuplicationGroup((DuplicationGroup.Block) value.get());
+ DuplicationGroup g = new DuplicationGroup((Block) blockCoder.get(value, DuplicationGroup.Block.class, context));
int count = value.getInt();
ArrayList<DuplicationGroup.Block> blocks = new ArrayList<DuplicationGroup.Block>(count);
for (int i = 0; i < count; i++) {
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.index;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.sonar.api.database.model.MeasureMapper;
+import org.sonar.api.database.model.MeasureModel;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.PersistenceMode;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.batch.duplication.DuplicationCache;
+import org.sonar.batch.duplication.DuplicationGroup;
+import org.sonar.batch.index.Cache.Entry;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+
+import java.util.ArrayList;
+
+public final class DuplicationPersister implements ScanPersister {
+ private final MyBatis mybatis;
+ private final RuleFinder ruleFinder;
+ private final SnapshotCache snapshotCache;
+ private final ResourceCache resourceCache;
+ private final DuplicationCache duplicationCache;
+ private final org.sonar.api.measures.MetricFinder metricFinder;
+
+ public DuplicationPersister(MyBatis mybatis, RuleFinder ruleFinder,
+ SnapshotCache snapshotCache, ResourceCache resourceCache,
+ DuplicationCache duplicationCache, org.sonar.api.measures.MetricFinder metricFinder) {
+ this.mybatis = mybatis;
+ this.ruleFinder = ruleFinder;
+ this.snapshotCache = snapshotCache;
+ this.resourceCache = resourceCache;
+ this.duplicationCache = duplicationCache;
+ this.metricFinder = metricFinder;
+ }
+
+ @Override
+ public void persist() {
+ // Don't use batch insert for duplications since keeping all data in memory can produce OOM
+ DbSession session = mybatis.openSession(false);
+ try {
+ MeasureMapper mapper = session.getMapper(MeasureMapper.class);
+ org.sonar.api.measures.Metric duplicationMetricWithId = metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY);
+ for (Entry<ArrayList<DuplicationGroup>> entry : duplicationCache.entries()) {
+ String effectiveKey = entry.key()[0].toString();
+ Measure measure = new Measure(duplicationMetricWithId, toXml(entry.value())).setPersistenceMode(PersistenceMode.DATABASE);
+ Resource resource = resourceCache.get(effectiveKey);
+
+ if (MeasurePersister.shouldPersistMeasure(resource, measure)) {
+ Snapshot snapshot = snapshotCache.get(effectiveKey);
+ MeasureModel measureModel = MeasurePersister.model(measure, ruleFinder).setSnapshotId(snapshot.getId());
+ mapper.insert(measureModel);
+ }
+ }
+
+ session.commit();
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to save some measures", e);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ private static String toXml(Iterable<DuplicationGroup> duplications) {
+ StringBuilder xml = new StringBuilder();
+ xml.append("<duplications>");
+ for (DuplicationGroup duplication : duplications) {
+ xml.append("<g>");
+ toXml(xml, duplication.originBlock());
+ for (DuplicationGroup.Block part : duplication.duplicates()) {
+ toXml(xml, part);
+ }
+ xml.append("</g>");
+ }
+ xml.append("</duplications>");
+ return xml.toString();
+ }
+
+ private static void toXml(StringBuilder xml, DuplicationGroup.Block part) {
+ xml.append("<b s=\"").append(part.startLine())
+ .append("\" l=\"").append(part.length())
+ .append("\" r=\"").append(StringEscapeUtils.escapeXml(part.resourceKey()))
+ .append("\"/>");
+ }
+
+}
package org.sonar.batch.index;
import com.google.common.annotations.VisibleForTesting;
-import org.apache.commons.lang.StringEscapeUtils;
import org.sonar.api.database.model.MeasureMapper;
import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.PersistenceMode;
import org.sonar.api.measures.RuleMeasure;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.technicaldebt.batch.Characteristic;
-import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.duplication.DuplicationGroup;
import org.sonar.batch.index.Cache.Entry;
import org.sonar.batch.scan.measure.MeasureCache;
import org.sonar.core.persistence.DbSession;
import javax.annotation.Nullable;
-import java.util.ArrayList;
-
public final class MeasurePersister implements ScanPersister {
private final MyBatis mybatis;
private final RuleFinder ruleFinder;
private final MeasureCache measureCache;
private final SnapshotCache snapshotCache;
private final ResourceCache resourceCache;
- private final DuplicationCache duplicationCache;
- private final org.sonar.api.measures.MetricFinder metricFinder;
public MeasurePersister(MyBatis mybatis, RuleFinder ruleFinder,
- MeasureCache measureCache, SnapshotCache snapshotCache, ResourceCache resourceCache,
- DuplicationCache duplicationCache, org.sonar.api.measures.MetricFinder metricFinder) {
+ MeasureCache measureCache, SnapshotCache snapshotCache, ResourceCache resourceCache) {
this.mybatis = mybatis;
this.ruleFinder = ruleFinder;
this.measureCache = measureCache;
this.snapshotCache = snapshotCache;
this.resourceCache = resourceCache;
- this.duplicationCache = duplicationCache;
- this.metricFinder = metricFinder;
}
@Override
if (shouldPersistMeasure(resource, measure)) {
Snapshot snapshot = snapshotCache.get(effectiveKey);
- MeasureModel measureModel = model(measure).setSnapshotId(snapshot.getId());
- mapper.insert(measureModel);
- }
- }
-
- org.sonar.api.measures.Metric duplicationMetricWithId = metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY);
- for (Entry<ArrayList<DuplicationGroup>> entry : duplicationCache.entries()) {
- String effectiveKey = entry.key()[0].toString();
- Measure measure = new Measure(duplicationMetricWithId, toXml(entry.value())).setPersistenceMode(PersistenceMode.DATABASE);
- Resource resource = resourceCache.get(effectiveKey);
-
- if (shouldPersistMeasure(resource, measure)) {
- Snapshot snapshot = snapshotCache.get(effectiveKey);
- MeasureModel measureModel = model(measure).setSnapshotId(snapshot.getId());
+ MeasureModel measureModel = model(measure, ruleFinder).setSnapshotId(snapshot.getId());
mapper.insert(measureModel);
}
}
}
}
- private static String toXml(Iterable<DuplicationGroup> duplications) {
- StringBuilder xml = new StringBuilder();
- xml.append("<duplications>");
- for (DuplicationGroup duplication : duplications) {
- xml.append("<g>");
- toXml(xml, duplication.originBlock());
- for (DuplicationGroup.Block part : duplication.duplicates()) {
- toXml(xml, part);
- }
- xml.append("</g>");
- }
- xml.append("</duplications>");
- return xml.toString();
- }
-
- private static void toXml(StringBuilder xml, DuplicationGroup.Block part) {
- xml.append("<b s=\"").append(part.startLine())
- .append("\" l=\"").append(part.length())
- .append("\" r=\"").append(StringEscapeUtils.escapeXml(part.resourceKey()))
- .append("\"/>");
- }
-
@VisibleForTesting
static boolean shouldPersistMeasure(@Nullable Resource resource, @Nullable Measure measure) {
if (resource == null || measure == null) {
|| isNotEmpty;
}
- private MeasureModel model(Measure measure) {
+ static MeasureModel model(Measure measure, RuleFinder ruleFinder) {
MeasureModel model = new MeasureModel();
// we assume that the index has updated the metric
model.setMetricId(measure.getMetric().getId());
import org.sonar.batch.index.DefaultPersistenceManager;
import org.sonar.batch.index.DefaultResourcePersister;
import org.sonar.batch.index.DependencyPersister;
+import org.sonar.batch.index.DuplicationPersister;
import org.sonar.batch.index.EventPersister;
import org.sonar.batch.index.LinkPersister;
import org.sonar.batch.index.MeasurePersister;
EventPersister.class,
LinkPersister.class,
MeasurePersister.class,
+ DuplicationPersister.class,
DefaultResourcePersister.class,
SourcePersister.class,
DefaultNotificationManager.class,
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.index;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.resources.File;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.batch.duplication.DuplicationCache;
+import org.sonar.batch.duplication.DuplicationGroup;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DuplicationPersisterTest extends AbstractDaoTestCase {
+
+ @org.junit.Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ public static final int FILE_SNAPSHOT_ID = 3003;
+
+ DuplicationPersister duplicationPersister;
+ RuleFinder ruleFinder = mock(RuleFinder.class);
+ File aFile = new File("org/foo/Bar.java");
+ Snapshot fileSnapshot = snapshot(FILE_SNAPSHOT_ID);
+ SnapshotCache snapshotCache;
+
+ private DuplicationCache duplicationCache;
+
+ @Before
+ public void mockResourcePersister() {
+ duplicationCache = mock(DuplicationCache.class);
+
+ snapshotCache = mock(SnapshotCache.class);
+ ResourceCache resourceCache = mock(ResourceCache.class);
+ when(snapshotCache.get("foo:org/foo/Bar.java")).thenReturn(fileSnapshot);
+ when(resourceCache.get("foo:org/foo/Bar.java")).thenReturn(aFile);
+
+ MetricFinder metricFinder = mock(MetricFinder.class);
+ when(metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY)).thenReturn(CoreMetrics.DUPLICATIONS_DATA.setId(2));
+
+ duplicationPersister = new DuplicationPersister(getMyBatis(), ruleFinder, snapshotCache, resourceCache, duplicationCache, metricFinder);
+ }
+
+ @Test
+ public void should_insert_duplications() {
+ setupData("empty");
+
+ DuplicationGroup.Block originBlock = new DuplicationGroup.Block("foo:org/foo/Bar.java", 1, 4);
+
+ DuplicationGroup group = new DuplicationGroup(originBlock)
+ .addDuplicate(new DuplicationGroup.Block("foo:org/foo/Foo.java", 5, 9));
+
+ when(duplicationCache.entries()).thenReturn(
+ Arrays.<Cache.Entry<ArrayList<DuplicationGroup>>>asList(new Cache.Entry(new String[] {"foo:org/foo/Bar.java"}, Arrays.asList(group))));
+
+ duplicationPersister.persist();
+
+ checkTables("shouldInsertDuplication", "project_measures");
+ }
+
+ private static Snapshot snapshot(int id) {
+ Snapshot snapshot = mock(Snapshot.class);
+ when(snapshot.getId()).thenReturn(id);
+ return snapshot;
+ }
+
+}
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
import org.sonar.api.measures.PersistenceMode;
import org.sonar.api.measures.RuleMeasure;
import org.sonar.api.resources.Directory;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
-import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.duplication.DuplicationGroup;
import org.sonar.batch.scan.measure.MeasureCache;
import org.sonar.core.persistence.AbstractDaoTestCase;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
public void mockResourcePersister() {
snapshotCache = mock(SnapshotCache.class);
measureCache = mock(MeasureCache.class);
- DuplicationCache duplicationCache = mock(DuplicationCache.class);
- when(duplicationCache.entries()).thenReturn(Collections.<Cache.Entry<ArrayList<DuplicationGroup>>>emptyList());
ResourceCache resourceCache = mock(ResourceCache.class);
when(snapshotCache.get("foo")).thenReturn(projectSnapshot);
when(snapshotCache.get("foo:org/foo")).thenReturn(packageSnapshot);
when(resourceCache.get("foo:org/foo/Bar.java")).thenReturn(aFile);
when(resourceCache.get("foo:org/foo")).thenReturn(aDirectory);
- measurePersister = new MeasurePersister(getMyBatis(), ruleFinder, measureCache, snapshotCache, resourceCache, duplicationCache, mock(MetricFinder.class));
+ measurePersister = new MeasurePersister(getMyBatis(), ruleFinder, measureCache, snapshotCache, resourceCache);
}
@Test
--- /dev/null
+<dataset>
+</dataset>
--- /dev/null
+<dataset>
+
+ <project_measures id="1" VALUE="[null]" METRIC_ID="2" SNAPSHOT_ID="3003" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]"
+ text_value='<duplications><g><b s="1" l="4" r="foo:org/foo/Bar.java"/><b s="5" l="9" r="foo:org/foo/Foo.java"/></g></duplications>'
+ tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
+ person_id="[null]"
+ variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"
+ measure_data="[null]"/>
+
+</dataset>
+