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