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 }