001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program 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 * This program 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 */ 020package org.sonar.api.measures; 021 022import com.google.common.collect.Multiset; 023import com.google.common.collect.TreeMultiset; 024import java.util.Map; 025import javax.annotation.Nullable; 026import org.apache.commons.lang.StringUtils; 027import org.apache.commons.lang.math.NumberUtils; 028import org.sonar.api.utils.KeyValueFormat; 029import org.sonar.api.utils.SonarException; 030 031/** 032 * Utility to build a distribution based on discrete values 033 * 034 * <p>An example of usage : you wish to record the number of violations for each level of rules priority 035 * 036 * @since 1.10 037 * @deprecated since 5.6. Scanner side is not responsible to aggregate measures since 5.2. 038 */ 039@Deprecated 040public class CountDistributionBuilder implements MeasureBuilder { 041 042 private final Metric metric; 043 private final Multiset countBag = TreeMultiset.create(); 044 045 /** 046 * Creates an empty CountDistributionBuilder for a specified metric 047 * 048 * @param metric the metric 049 */ 050 public CountDistributionBuilder(Metric metric) { 051 if (metric == null || !metric.isDataType()) { 052 throw new SonarException("Metric is null or has invalid type"); 053 } 054 this.metric = metric; 055 } 056 057 /** 058 * Increments an entry 059 * 060 * @param value the value that should be incremented 061 * @param count the number by which to increment 062 * @return the current object 063 */ 064 public CountDistributionBuilder add(Object value, int count) { 065 if (count == 0) { 066 addZero(value); 067 068 } else { 069 if (this.countBag.add(value, count) == 0) { 070 // hack 071 this.countBag.add(value, 1); 072 } 073 } 074 return this; 075 } 076 077 /** 078 * Increments an entry by one 079 * 080 * @param value the value that should be incremented 081 * @return the current object 082 */ 083 public CountDistributionBuilder add(Object value) { 084 return add(value, 1); 085 } 086 087 /** 088 * Adds an entry without a zero count if it does not exist 089 * 090 * @param value the entry to be added 091 * @return the current object 092 */ 093 public CountDistributionBuilder addZero(Object value) { 094 if (!countBag.contains(value)) { 095 countBag.add(value, 1); 096 } 097 return this; 098 } 099 100 /** 101 * Adds an existing Distribution to the current one. 102 * It will create the entries if they don't exist. 103 * Can be used to add the values of children resources for example 104 * 105 * @param measure the measure to add to the current one 106 * @return the current object 107 */ 108 public CountDistributionBuilder add(@Nullable Measure measure) { 109 if (measure != null && measure.getData() != null) { 110 Map<String, String> map = KeyValueFormat.parse(measure.getData()); 111 for (Map.Entry<String, String> entry : map.entrySet()) { 112 String key = entry.getKey(); 113 int value = StringUtils.isBlank(entry.getValue()) ? 0 : Integer.parseInt(entry.getValue()); 114 if (NumberUtils.isNumber(key)) { 115 add(NumberUtils.toInt(key), value); 116 } else { 117 add(key, value); 118 } 119 } 120 } 121 return this; 122 } 123 124 /** 125 * @return whether the current object is empty or not 126 */ 127 public boolean isEmpty() { 128 return countBag.isEmpty(); 129 } 130 131 /** 132 * Resets all entries to zero 133 * 134 * @return the current object 135 */ 136 public CountDistributionBuilder clear() { 137 countBag.clear(); 138 return this; 139 } 140 141 /** 142 * Shortcut for <code>build(true)</code> 143 * 144 * @return the built measure 145 */ 146 @Override 147 public Measure build() { 148 return build(true); 149 } 150 151 /** 152 * Used to build a measure from the current object 153 * 154 * @param allowEmptyData should be built if current object is empty 155 * @return the built measure 156 */ 157 public Measure build(boolean allowEmptyData) { 158 if (!isEmpty() || allowEmptyData) { 159 return new Measure(metric, MultisetDistributionFormat.format(countBag)); 160 } 161 return null; 162 } 163}