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