001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020 package org.sonar.batch.index;
021
022 import com.google.common.annotations.VisibleForTesting;
023 import org.sonar.api.database.model.MeasureMapper;
024 import org.sonar.api.database.model.MeasureModel;
025 import org.sonar.api.database.model.Snapshot;
026 import org.sonar.api.measures.Measure;
027 import org.sonar.api.measures.RuleMeasure;
028 import org.sonar.api.resources.Resource;
029 import org.sonar.api.resources.ResourceUtils;
030 import org.sonar.api.rule.RuleKey;
031 import org.sonar.api.rules.Rule;
032 import org.sonar.api.rules.RuleFinder;
033 import org.sonar.api.technicaldebt.batch.Characteristic;
034 import org.sonar.batch.index.Cache.Entry;
035 import org.sonar.batch.scan.measure.MeasureCache;
036 import org.sonar.core.persistence.DbSession;
037 import org.sonar.core.persistence.MyBatis;
038
039 import javax.annotation.Nullable;
040
041 public final class MeasurePersister implements ScanPersister {
042 private final MyBatis mybatis;
043 private final RuleFinder ruleFinder;
044 private final MeasureCache measureCache;
045 private final SnapshotCache snapshotCache;
046 private final ResourceCache resourceCache;
047
048 public MeasurePersister(MyBatis mybatis, RuleFinder ruleFinder,
049 MeasureCache measureCache, SnapshotCache snapshotCache, ResourceCache resourceCache) {
050 this.mybatis = mybatis;
051 this.ruleFinder = ruleFinder;
052 this.measureCache = measureCache;
053 this.snapshotCache = snapshotCache;
054 this.resourceCache = resourceCache;
055 }
056
057 @Override
058 public void persist() {
059 DbSession session = mybatis.openSession(true);
060 try {
061 MeasureMapper mapper = session.getMapper(MeasureMapper.class);
062
063 for (Entry<Measure> entry : measureCache.entries()) {
064 String effectiveKey = entry.key()[0].toString();
065 Measure measure = entry.value();
066 Resource resource = resourceCache.get(effectiveKey);
067
068 if (shouldPersistMeasure(resource, measure)) {
069 Snapshot snapshot = snapshotCache.get(effectiveKey);
070 MeasureModel measureModel = model(measure, ruleFinder).setSnapshotId(snapshot.getId());
071 mapper.insert(measureModel);
072 }
073 }
074
075 session.commit();
076 } catch (Exception e) {
077 throw new IllegalStateException("Unable to save some measures", e);
078 } finally {
079 MyBatis.closeQuietly(session);
080 }
081 }
082
083 @VisibleForTesting
084 static boolean shouldPersistMeasure(@Nullable Resource resource, @Nullable Measure measure) {
085 if (resource == null || measure == null) {
086 return false;
087 }
088 return measure.getPersistenceMode().useDatabase() &&
089 !(ResourceUtils.isEntity(resource) && measure.isBestValue()) && isMeasureNotEmpty(measure);
090 }
091
092 private static boolean isMeasureNotEmpty(Measure measure) {
093 boolean isNotEmpty = false;
094 for (int i = 1; i <= 5; i++) {
095 isNotEmpty = isNotEmpty || measure.getVariation(i) != null;
096 }
097 return measure.getValue() != null || measure.getData() != null
098 || isNotEmpty;
099 }
100
101 static MeasureModel model(Measure measure, RuleFinder ruleFinder) {
102 MeasureModel model = new MeasureModel();
103 // we assume that the index has updated the metric
104 model.setMetricId(measure.getMetric().getId());
105 model.setDescription(measure.getDescription());
106 model.setData(measure.getData());
107 model.setAlertStatus(measure.getAlertStatus());
108 model.setAlertText(measure.getAlertText());
109 model.setTendency(measure.getTendency());
110 model.setVariationValue1(measure.getVariation1());
111 model.setVariationValue2(measure.getVariation2());
112 model.setVariationValue3(measure.getVariation3());
113 model.setVariationValue4(measure.getVariation4());
114 model.setVariationValue5(measure.getVariation5());
115 model.setUrl(measure.getUrl());
116 Characteristic characteristic = measure.getCharacteristic();
117 if (characteristic != null) {
118 model.setCharacteristicId(characteristic.id());
119 }
120 model.setPersonId(measure.getPersonId());
121 model.setValue(measure.getValue());
122 if (measure instanceof RuleMeasure) {
123 RuleMeasure ruleMeasure = (RuleMeasure) measure;
124 model.setRulePriority(ruleMeasure.getSeverity());
125 RuleKey ruleKey = ruleMeasure.ruleKey();
126 if (ruleKey != null) {
127 Rule ruleWithId = ruleFinder.findByKey(ruleKey);
128 if (ruleWithId == null) {
129 throw new IllegalStateException("Can not save a measure with unknown rule " + ruleMeasure);
130 }
131 model.setRuleId(ruleWithId.getId());
132 }
133 }
134 return model;
135 }
136 }