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.utils;
021    
022    import com.google.common.collect.Multiset;
023    import org.apache.commons.collections.Bag;
024    import org.apache.commons.lang.StringUtils;
025    import org.apache.commons.lang.math.NumberUtils;
026    
027    import java.util.HashMap;
028    import java.util.Map;
029    
030    /**
031     * Util class to format key/value data. Output is a string representation ready to be
032     * injected into the database
033     *
034     * @since 1.10
035     */
036    public final class KeyValueFormat {
037    
038      private KeyValueFormat() {
039      }
040    
041      public static <KEY, VALUE> Map<KEY, VALUE> parse(String data, Transformer<KEY, VALUE> transformer) {
042        Map<String, String> rawData = parse(data);
043        Map<KEY, VALUE> map = new HashMap<KEY, VALUE>();
044        for (Map.Entry<String, String> entry : rawData.entrySet()) {
045          KeyValue<KEY, VALUE> keyVal = transformer.transform(entry.getKey(), entry.getValue());
046          if (keyVal != null) {
047            map.put(keyVal.getKey(), keyVal.getValue());
048          }
049        }
050        return map;
051      }
052    
053      public static Map<String, String> parse(String data) {
054        Map<String, String> map = new HashMap<String, String>();
055        String[] pairs = StringUtils.split(data, ";");
056        for (String pair : pairs) {
057          String[] keyValue = StringUtils.split(pair, "=");
058          String key = keyValue[0];
059          String value = (keyValue.length == 2 ? keyValue[1] : "");
060          map.put(key, value);
061        }
062        return map;
063      }
064    
065      public static <KEY, VALUE> String format(Map<KEY, VALUE> map) {
066        StringBuilder sb = new StringBuilder();
067        boolean first = true;
068        for (Map.Entry<?, ?> entry : map.entrySet()) {
069          if (!first) {
070            sb.append(";");
071          }
072          sb.append(entry.getKey().toString());
073          sb.append("=");
074          if (entry.getValue() != null) {
075            sb.append(entry.getValue());
076          }
077          first = false;
078        }
079    
080        return sb.toString();
081      }
082    
083      /**
084       * Please use Multiset from google collections instead of commons-collections bags.
085       */
086      public static String format(Bag bag) {
087        return format(bag, 0);
088      }
089    
090      /**
091       * Please use Multiset from google collections instead of commons-collections bags.
092       */
093      public static String format(Bag bag, int var) {
094        StringBuilder sb = new StringBuilder();
095        boolean first = true;
096        for (Object obj : bag.uniqueSet()) {
097          if (!first) {
098            sb.append(";");
099          }
100          sb.append(obj.toString());
101          sb.append("=");
102          sb.append(bag.getCount(obj) + var);
103          first = false;
104        }
105    
106        return sb.toString();
107      }
108    
109      public static String format(Multiset<?> set) {
110        StringBuilder sb = new StringBuilder();
111        boolean first = true;
112        for (Multiset.Entry<?> entry : set.entrySet()) {
113          if (!first) {
114            sb.append(";");
115          }
116          sb.append(entry.getElement().toString());
117          sb.append("=");
118          sb.append(entry.getCount());
119          first = false;
120        }
121        return sb.toString();
122      }
123    
124      public static String format(Object... objects) {
125        StringBuilder sb = new StringBuilder();
126        boolean first = true;
127        if (objects != null) {
128          for (int i = 0; i < objects.length; i++) {
129            if (!first) {
130              sb.append(";");
131            }
132            sb.append(objects[i++].toString());
133            sb.append("=");
134            sb.append(objects[i]);
135            first = false;
136          }
137        }
138        return sb.toString();
139      }
140    
141      public interface Transformer<KEY, VALUE> {
142    
143        public KeyValue<KEY, VALUE> transform(String key, String value);
144      }
145    
146      public static class StringNumberPairTransformer implements Transformer<String, Double> {
147    
148        public KeyValue<String, Double> transform(String key, String value) {
149          return new KeyValue<String, Double>(key, toDouble(value));
150        }
151      }
152    
153      public static class DoubleNumbersPairTransformer implements Transformer<Double, Double> {
154    
155        public KeyValue<Double, Double> transform(String key, String value) {
156          return new KeyValue<Double, Double>(toDouble(key), toDouble(value));
157        }
158      }
159    
160      public static class IntegerNumbersPairTransformer implements Transformer<Integer, Integer> {
161    
162        public KeyValue<Integer, Integer> transform(String key, String value) {
163          return new KeyValue<Integer, Integer>(toInteger(key), toInteger(value));
164        }
165      }
166    
167      private static Double toDouble(String value) {
168        return StringUtils.isBlank(value) ? null : NumberUtils.toDouble(value);
169      }
170    
171      private static Integer toInteger(String value) {
172        return StringUtils.isBlank(value) ? null : NumberUtils.toInt(value);
173      }
174    }