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