001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2011 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar 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 * Sonar 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
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
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.batch.index.DefaultIndex;
035
036 import javax.persistence.Query;
037 import java.util.*;
038
039 public class DefaultTimeMachine implements TimeMachine {
040
041 private DatabaseSession session;
042 private DefaultIndex index;
043 private MetricFinder metricFinder;
044
045 public DefaultTimeMachine(DatabaseSession session, DefaultIndex index, MetricFinder metricFinder) {
046 this.session = session;
047 this.index = index;
048 this.metricFinder = metricFinder;
049 }
050
051 public List<Measure> getMeasures(TimeMachineQuery query) {
052 Map<Integer, Metric> metricById = getMetricsById(query);
053
054 List<Object[]> objects = execute(query, true, metricById.keySet());
055 List<Measure> result = Lists.newArrayList();
056
057 for (Object[] object : objects) {
058 MeasureModel model = (MeasureModel) object[0];
059 Measure measure = toMeasure(model, metricById.get(model.getMetricId()));
060 measure.setDate((Date) object[1]);
061 result.add(measure);
062 }
063 return result;
064 }
065
066 public List<Object[]> getMeasuresFields(TimeMachineQuery query) {
067 Map<Integer, Metric> metricById = getMetricsById(query);
068 List<Object[]> rows = execute(query, false, metricById.keySet());
069 for (Object[] fields : rows) {
070 fields[1] = metricById.get(fields[1]);
071 }
072 return rows;
073 }
074
075 protected List execute(TimeMachineQuery query, boolean selectAllFields, Set<Integer> metricIds) {
076 Resource resource = query.getResource();
077 if (resource != null && resource.getId() == null) {
078 resource = index.getResource(query.getResource());
079 }
080 if (resource == null) {
081 return Collections.emptyList();
082 }
083
084 StringBuilder sb = new StringBuilder();
085 Map<String, Object> params = Maps.newHashMap();
086
087 if (selectAllFields) {
088 sb.append("SELECT m, s.createdAt ");
089 } else {
090 sb.append("SELECT s.createdAt, m.metricId, m.value ");
091 }
092 sb.append(" FROM ")
093 .append(MeasureModel.class.getSimpleName())
094 .append(" m, ")
095 .append(Snapshot.class.getSimpleName())
096 .append(" s WHERE m.snapshotId=s.id AND s.resourceId=:resourceId AND s.status=:status AND m.characteristic IS NULL AND s.qualifier<>:lib");
097 params.put("resourceId", resource.getId());
098 params.put("status", Snapshot.STATUS_PROCESSED);
099 params.put("lib", Qualifiers.LIBRARY);
100
101 sb.append(" AND m.ruleId IS NULL AND m.rulePriority IS NULL ");
102 if (!metricIds.isEmpty()) {
103 sb.append(" AND m.metricId IN (:metricIds) ");
104 params.put("metricIds", metricIds);
105 }
106 if (query.isFromCurrentAnalysis()) {
107 sb.append(" AND s.createdAt>=:from ");
108 params.put("from", index.getProject().getAnalysisDate());
109
110 } else if (query.getFrom() != null) {
111 sb.append(" AND s.createdAt>=:from ");
112 params.put("from", query.getFrom());
113 }
114 if (query.isToCurrentAnalysis()) {
115 sb.append(" AND s.createdAt<=:to ");
116 params.put("to", index.getProject().getAnalysisDate());
117
118 } else if (query.getTo() != null) {
119 sb.append(" AND s.createdAt<=:to ");
120 params.put("to", query.getTo());
121 }
122 if (query.isOnlyLastAnalysis()) {
123 sb.append(" AND s.last=:last ");
124 params.put("last", Boolean.TRUE);
125 }
126 sb.append(" ORDER BY s.createdAt ");
127
128 Query jpaQuery = session.createQuery(sb.toString());
129
130 for (Map.Entry<String, Object> entry : params.entrySet()) {
131 jpaQuery.setParameter(entry.getKey(), entry.getValue());
132 }
133 return jpaQuery.getResultList();
134 }
135
136 public Map<Integer, Metric> getMetricsById(TimeMachineQuery query) {
137 Collection<Metric> metrics = metricFinder.findAll(query.getMetricKeys());
138 Map<Integer, Metric> result = Maps.newHashMap();
139 for (Metric metric : metrics) {
140 result.put(metric.getId(), metric);
141 }
142 return result;
143 }
144
145 static Measure toMeasure(MeasureModel model, Metric metric) {
146 // NOTE: measures on rule are not supported
147 Measure measure = new Measure(metric);
148 measure.setId(model.getId());
149 measure.setDescription(model.getDescription());
150 measure.setValue(model.getValue());
151 measure.setData(model.getData(metric));
152 measure.setAlertStatus(model.getAlertStatus());
153 measure.setAlertText(model.getAlertText());
154 measure.setTendency(model.getTendency());
155 measure.setVariation1(model.getVariationValue1());
156 measure.setVariation2(model.getVariationValue2());
157 measure.setVariation3(model.getVariationValue3());
158 measure.setVariation4(model.getVariationValue4());
159 measure.setVariation5(model.getVariationValue5());
160 measure.setUrl(model.getUrl());
161 measure.setCharacteristic(model.getCharacteristic());
162 return measure;
163 }
164 }