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.scan2;
021
022 import org.sonar.api.batch.sensor.measure.Measure;
023 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder;
024
025 import com.google.common.base.Objects;
026 import com.google.common.base.Preconditions;
027 import com.google.common.collect.ImmutableMap;
028 import com.google.common.collect.Maps;
029 import org.sonar.api.batch.fs.InputFile;
030 import org.sonar.api.batch.measure.MetricFinder;
031 import org.sonar.api.measures.FileLinesContext;
032 import org.sonar.api.utils.KeyValueFormat;
033 import org.sonar.api.utils.KeyValueFormat.Converter;
034 import org.sonar.core.component.ComponentKeys;
035
036 import java.util.Map;
037
038 public class DefaultFileLinesContext implements FileLinesContext {
039
040 private final AnalyzerMeasureCache measureCache;
041 private final InputFile inputFile;
042
043 /**
044 * metric key -> line -> value
045 */
046 private final Map<String, Map<Integer, Object>> map = Maps.newHashMap();
047 private String projectKey;
048 private MetricFinder metricFinder;
049
050 public DefaultFileLinesContext(MetricFinder metricFinder, AnalyzerMeasureCache measureCache, String projectKey, InputFile inputFile) {
051 this.metricFinder = metricFinder;
052 this.projectKey = projectKey;
053 Preconditions.checkNotNull(measureCache);
054 this.measureCache = measureCache;
055 this.inputFile = inputFile;
056 }
057
058 public void setIntValue(String metricKey, int line, int value) {
059 Preconditions.checkNotNull(metricKey);
060 Preconditions.checkArgument(line > 0);
061
062 setValue(metricKey, line, value);
063 }
064
065 public Integer getIntValue(String metricKey, int line) {
066 Preconditions.checkNotNull(metricKey);
067 Preconditions.checkArgument(line > 0);
068
069 Map lines = map.get(metricKey);
070 if (lines == null) {
071 // not in memory, so load
072 lines = loadData(metricKey, KeyValueFormat.newIntegerConverter());
073 map.put(metricKey, lines);
074 }
075 return (Integer) lines.get(line);
076 }
077
078 public void setStringValue(String metricKey, int line, String value) {
079 Preconditions.checkNotNull(metricKey);
080 Preconditions.checkArgument(line > 0);
081 Preconditions.checkNotNull(value);
082
083 setValue(metricKey, line, value);
084 }
085
086 public String getStringValue(String metricKey, int line) {
087 Preconditions.checkNotNull(metricKey);
088 Preconditions.checkArgument(line > 0);
089
090 Map lines = map.get(metricKey);
091 if (lines == null) {
092 // not in memory, so load
093 lines = loadData(metricKey, KeyValueFormat.newStringConverter());
094 map.put(metricKey, lines);
095 }
096 return (String) lines.get(line);
097 }
098
099 private Map<Integer, Object> getOrCreateLines(String metricKey) {
100 Map<Integer, Object> lines = map.get(metricKey);
101 if (lines == null) {
102 lines = Maps.newHashMap();
103 map.put(metricKey, lines);
104 }
105 return lines;
106 }
107
108 private void setValue(String metricKey, int line, Object value) {
109 getOrCreateLines(metricKey).put(line, value);
110 }
111
112 public void save() {
113 for (Map.Entry<String, Map<Integer, Object>> entry : map.entrySet()) {
114 String metricKey = entry.getKey();
115 org.sonar.api.batch.measure.Metric<String> metric = metricFinder.findByKey(metricKey);
116 if (metric == null) {
117 throw new IllegalStateException("Unable to find metric with key: " + metricKey);
118 }
119 Map<Integer, Object> lines = entry.getValue();
120 if (shouldSave(lines)) {
121 String data = KeyValueFormat.format(lines);
122 measureCache.put(projectKey, ComponentKeys.createEffectiveKey(projectKey, inputFile), new DefaultMeasureBuilder<String>()
123 .forMetric(metric)
124 .onFile(inputFile)
125 .withValue(data)
126 .build());
127 entry.setValue(ImmutableMap.copyOf(lines));
128 }
129 }
130 }
131
132 private Map loadData(String metricKey, Converter converter) {
133 Measure measure = measureCache.byMetric(projectKey, ComponentKeys.createEffectiveKey(projectKey, inputFile), metricKey);
134 if (measure == null) {
135 // no such measure
136 return ImmutableMap.of();
137 }
138 return ImmutableMap.copyOf(KeyValueFormat.parse((String) measure.value(), KeyValueFormat.newIntegerConverter(), converter));
139 }
140
141 /**
142 * Checks that measure was not saved.
143 *
144 * @see #loadData(String, Converter)
145 * @see #save()
146 */
147 private boolean shouldSave(Map<Integer, Object> lines) {
148 return !(lines instanceof ImmutableMap);
149 }
150
151 @Override
152 public String toString() {
153 return Objects.toStringHelper(this)
154 .add("map", map)
155 .toString();
156 }
157
158 }