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;
021
022 import com.google.common.collect.Lists;
023 import com.google.common.collect.Maps;
024 import org.sonar.api.batch.TimeMachine;
025 import org.sonar.api.batch.TimeMachineQuery;
026 import org.sonar.api.database.DatabaseSession;
027 import org.sonar.api.database.model.MeasureModel;
028 import org.sonar.api.database.model.Snapshot;
029 import org.sonar.api.measures.Measure;
030 import org.sonar.api.measures.Metric;
031 import org.sonar.api.measures.MetricFinder;
032 import org.sonar.api.resources.Qualifiers;
033 import org.sonar.api.resources.Resource;
034 import org.sonar.api.technicaldebt.batch.Characteristic;
035 import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
036 import org.sonar.batch.index.DefaultIndex;
037
038 import javax.annotation.Nullable;
039 import javax.persistence.Query;
040
041 import java.util.Collection;
042 import java.util.Collections;
043 import java.util.Date;
044 import java.util.List;
045 import java.util.Map;
046 import java.util.Set;
047
048 public class DefaultTimeMachine implements TimeMachine {
049
050 private DatabaseSession session;
051 private DefaultIndex index;
052 private MetricFinder metricFinder;
053 private TechnicalDebtModel techDebtModel;
054
055 public DefaultTimeMachine(DatabaseSession session, DefaultIndex index, MetricFinder metricFinder, TechnicalDebtModel techDebtModel) {
056 this.session = session;
057 this.index = index;
058 this.metricFinder = metricFinder;
059 this.techDebtModel = techDebtModel;
060 }
061
062 public List<Measure> getMeasures(TimeMachineQuery query) {
063 Map<Integer, Metric> metricById = getMetricsById(query);
064
065 List<Object[]> objects = execute(query, true, metricById.keySet());
066 List<Measure> result = Lists.newArrayList();
067
068 for (Object[] object : objects) {
069 MeasureModel model = (MeasureModel) object[0];
070 Integer characteristicId = model.getCharacteristicId();
071 Characteristic characteristic = techDebtModel.characteristicById(characteristicId);
072 Measure measure = toMeasure(model, metricById.get(model.getMetricId()), characteristic);
073 measure.setDate((Date) object[1]);
074 result.add(measure);
075 }
076 return result;
077 }
078
079 public List<Object[]> getMeasuresFields(TimeMachineQuery query) {
080 Map<Integer, Metric> metricById = getMetricsById(query);
081 List<Object[]> rows = execute(query, false, metricById.keySet());
082 for (Object[] fields : rows) {
083 fields[1] = metricById.get(fields[1]);
084 }
085 return rows;
086 }
087
088 protected List<Object[]> execute(TimeMachineQuery query, boolean selectAllFields, Set<Integer> metricIds) {
089 Resource resource = query.getResource();
090 if (resource != null && resource.getId() == null) {
091 resource = index.getResource(query.getResource());
092 }
093 if (resource == null) {
094 return Collections.emptyList();
095 }
096
097 StringBuilder sb = new StringBuilder();
098 Map<String, Object> params = Maps.newHashMap();
099
100 if (selectAllFields) {
101 sb.append("SELECT m, s.createdAt ");
102 } else {
103 sb.append("SELECT s.createdAt, m.metricId, m.value ");
104 }
105 sb.append(" FROM ")
106 .append(MeasureModel.class.getSimpleName())
107 .append(" m, ")
108 .append(Snapshot.class.getSimpleName())
109 .append(" s WHERE m.snapshotId=s.id AND s.resourceId=:resourceId AND s.status=:status AND s.qualifier<>:lib");
110 params.put("resourceId", resource.getId());
111 params.put("status", Snapshot.STATUS_PROCESSED);
112 params.put("lib", Qualifiers.LIBRARY);
113
114 sb.append(" AND m.characteristicId IS NULL");
115 sb.append(" AND m.personId IS NULL");
116 sb.append(" AND m.ruleId IS NULL AND m.rulePriority IS NULL");
117 if (!metricIds.isEmpty()) {
118 sb.append(" AND m.metricId IN (:metricIds) ");
119 params.put("metricIds", metricIds);
120 }
121 if (query.isFromCurrentAnalysis()) {
122 sb.append(" AND s.createdAt>=:from ");
123 params.put("from", index.getProject().getAnalysisDate());
124
125 } else if (query.getFrom() != null) {
126 sb.append(" AND s.createdAt>=:from ");
127 params.put("from", query.getFrom());
128 }
129 if (query.isToCurrentAnalysis()) {
130 sb.append(" AND s.createdAt<=:to ");
131 params.put("to", index.getProject().getAnalysisDate());
132
133 } else if (query.getTo() != null) {
134 sb.append(" AND s.createdAt<=:to ");
135 params.put("to", query.getTo());
136 }
137 if (query.isOnlyLastAnalysis()) {
138 sb.append(" AND s.last=:last ");
139 params.put("last", Boolean.TRUE);
140 }
141 sb.append(" ORDER BY s.createdAt ");
142
143 Query jpaQuery = session.createQuery(sb.toString());
144
145 for (Map.Entry<String, Object> entry : params.entrySet()) {
146 jpaQuery.setParameter(entry.getKey(), entry.getValue());
147 }
148 return jpaQuery.getResultList();
149 }
150
151 public Map<Integer, Metric> getMetricsById(TimeMachineQuery query) {
152 Collection<Metric> metrics = metricFinder.findAll(query.getMetricKeys());
153 Map<Integer, Metric> result = Maps.newHashMap();
154 for (Metric metric : metrics) {
155 result.put(metric.getId(), metric);
156 }
157 return result;
158 }
159
160 static Measure toMeasure(MeasureModel model, Metric metric, @Nullable Characteristic characteristic) {
161 // NOTE: measures on rule are not supported
162 Measure measure = new Measure(metric);
163 measure.setDescription(model.getDescription());
164 measure.setValue(model.getValue());
165 measure.setData(model.getData(metric));
166 measure.setAlertStatus(model.getAlertStatus());
167 measure.setAlertText(model.getAlertText());
168 measure.setTendency(model.getTendency());
169 measure.setVariation1(model.getVariationValue1());
170 measure.setVariation2(model.getVariationValue2());
171 measure.setVariation3(model.getVariationValue3());
172 measure.setVariation4(model.getVariationValue4());
173 measure.setVariation5(model.getVariationValue5());
174 measure.setUrl(model.getUrl());
175 measure.setCharacteristic(characteristic);
176 measure.setPersonId(model.getPersonId());
177 return measure;
178 }
179 }