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 */
020package org.sonar.api.issue.internal;
021
022import com.google.common.base.Splitter;
023import com.google.common.base.Strings;
024import com.google.common.collect.Maps;
025
026import javax.annotation.CheckForNull;
027import javax.annotation.Nullable;
028
029import java.io.Serializable;
030import java.util.Date;
031import java.util.Map;
032
033/**
034 * PLUGINS MUST NOT USE THIS CLASS, EXCEPT FOR UNIT TESTING.
035 *
036 * @since 3.6
037 */
038public class FieldDiffs implements Serializable {
039
040  public static final Splitter FIELDS_SPLITTER = Splitter.on(',').omitEmptyStrings();
041
042  private String issueKey;
043  private String userLogin;
044  private Date creationDate;
045
046  private final Map<String, Diff> diffs = Maps.newLinkedHashMap();
047
048  public Map<String, Diff> diffs() {
049    return diffs;
050  }
051
052  public Diff get(String field) {
053    return diffs.get(field);
054  }
055
056  @CheckForNull
057  public String userLogin() {
058    return userLogin;
059  }
060
061  public FieldDiffs setUserLogin(@Nullable String s) {
062    this.userLogin = s;
063    return this;
064  }
065
066  public Date creationDate() {
067    return creationDate;
068  }
069
070  public FieldDiffs setCreationDate(Date creationDate) {
071    this.creationDate = creationDate;
072    return this;
073  }
074
075  public String issueKey() {
076    return issueKey;
077  }
078
079  public FieldDiffs setIssueKey(String issueKey) {
080    this.issueKey = issueKey;
081    return this;
082  }
083
084  @SuppressWarnings("unchecked")
085  public FieldDiffs setDiff(String field, @Nullable Serializable oldValue, @Nullable Serializable newValue) {
086    Diff diff = diffs.get(field);
087    if (diff == null) {
088      diff = new Diff(oldValue, newValue);
089      diffs.put(field, diff);
090    } else {
091      diff.setNewValue(newValue);
092    }
093    return this;
094  }
095
096  @Override
097  public String toString() {
098    StringBuilder sb = new StringBuilder();
099    boolean notFirst = false;
100    for (Map.Entry<String, Diff> entry : diffs.entrySet()) {
101      if (notFirst) {
102        sb.append(',');
103      } else {
104        notFirst = true;
105      }
106      sb.append(entry.getKey());
107      sb.append('=');
108      sb.append(entry.getValue().toString());
109    }
110    return sb.toString();
111  }
112
113  public static FieldDiffs parse(@Nullable String s) {
114    FieldDiffs diffs = new FieldDiffs();
115    if (!Strings.isNullOrEmpty(s)) {
116      Iterable<String> fields = FIELDS_SPLITTER.split(s);
117      for (String field : fields) {
118        String[] keyValues = field.split("=");
119        if (keyValues.length == 2) {
120          String[] values = keyValues[1].split("\\|");
121          String oldValue = "";
122          String newValue = "";
123          if(values.length == 1) {
124            newValue = Strings.nullToEmpty(values[0]);
125          } else if(values.length == 2) {
126            oldValue = Strings.nullToEmpty(values[0]);
127            newValue = Strings.nullToEmpty(values[1]);
128          }
129          diffs.setDiff(keyValues[0], oldValue, newValue);
130        } else {
131          diffs.setDiff(keyValues[0], "", "");
132        }
133      }
134    }
135    return diffs;
136  }
137
138  public static class Diff<T extends Serializable> implements Serializable {
139    private T oldValue, newValue;
140
141    public Diff(@Nullable T oldValue, @Nullable T newValue) {
142      this.oldValue = oldValue;
143      this.newValue = newValue;
144    }
145
146    @CheckForNull
147    public T oldValue() {
148      return oldValue;
149    }
150
151    @CheckForNull
152    public Long oldValueLong() {
153      return toLong(oldValue);
154    }
155
156    @CheckForNull
157    public T newValue() {
158      return newValue;
159    }
160
161    @CheckForNull
162    public Long newValueLong() {
163      return toLong(newValue);
164    }
165
166    void setNewValue(T t) {
167      this.newValue = t;
168    }
169
170    @CheckForNull
171    private Long toLong(Serializable value) {
172      if (value != null && !"".equals(value)) {
173        try {
174          return Long.valueOf((String) value);
175        } catch (ClassCastException e) {
176          return (Long) value;
177        }
178      }
179      return null;
180    }
181
182    @Override
183    public String toString() {
184      //TODO escape , and | characters
185      StringBuilder sb = new StringBuilder();
186      if(newValue != null) {
187        if(oldValue != null) {
188          sb.append(oldValue.toString());
189          sb.append('|');
190        }
191        sb.append(newValue.toString());
192      }
193      return sb.toString();
194    }
195  }
196}