001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
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.api.measures;
021    
022    import org.apache.commons.collections.SortedBag;
023    import org.apache.commons.collections.bag.TreeBag;
024    import org.apache.commons.lang.StringUtils;
025    import org.apache.commons.lang.math.NumberUtils;
026    import org.sonar.api.utils.KeyValueFormat;
027    import org.sonar.api.utils.SonarException;
028    
029    import java.util.Map;
030    
031    /**
032     * @since 1.10
033     */
034    public class CountDistributionBuilder implements MeasureBuilder {
035    
036      private Metric metric;
037      private SortedBag countBag;
038    
039      public CountDistributionBuilder(Metric metric) {
040        setMetric(metric);
041        this.countBag = new TreeBag();
042      }
043    
044      public CountDistributionBuilder add(Object object, int count) {
045        if (count == 0) {
046          addZero(object);
047    
048        } else {
049          if (this.countBag.add(object, count)) {
050            this.countBag.add(object, 1);//hack
051          }
052        }
053        return this;
054      }
055    
056      public CountDistributionBuilder add(Object object) {
057        return add(object, 1);
058      }
059    
060      public CountDistributionBuilder addZero(Object object) {
061        if (!countBag.contains(object)) {
062          countBag.add(object, 1);
063        }
064        return this;
065      }
066    
067      public CountDistributionBuilder add(Measure measure) {
068        if (measure != null && measure.getData() != null) {
069          Map<String, String> map = KeyValueFormat.parse(measure.getData());
070          for (Map.Entry<String, String> entry : map.entrySet()) {
071            String key = entry.getKey();
072            int value = (StringUtils.isBlank(entry.getValue()) ? 0 : Integer.parseInt(entry.getValue()));
073            if (NumberUtils.isNumber(key)) {
074              add(NumberUtils.toInt(key), value);
075            } else {
076              add(key, value);
077            }
078          }
079        }
080        return this;
081      }
082    
083      public boolean isEmpty() {
084        return countBag.isEmpty();
085      }
086    
087      public CountDistributionBuilder clear() {
088        countBag.clear();
089        return this;
090      }
091    
092      public Measure build() {
093        return build(true);
094      }
095    
096      public Measure build(boolean allowEmptyData) {
097        if (!isEmpty() || allowEmptyData) {
098          return new Measure(metric, KeyValueFormat.format(countBag, -1)); //-1 is a hack to include zero values
099        }
100        return null;
101      }
102    
103      private void setMetric(Metric metric) {
104        if (metric == null || !metric.isDataType()) {
105          throw new SonarException("Metric is null or has unvalid type");
106        }
107        this.metric = metric;
108      }
109    }