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 */
020 package org.sonar.api.issue.internal;
021
022 import com.google.common.base.Splitter;
023 import com.google.common.base.Strings;
024 import com.google.common.collect.Maps;
025
026 import javax.annotation.CheckForNull;
027 import javax.annotation.Nullable;
028
029 import java.io.Serializable;
030 import java.util.Date;
031 import java.util.Map;
032
033 /**
034 * PLUGINS MUST NOT USE THIS CLASS, EXCEPT FOR UNIT TESTING.
035 *
036 * @since 3.6
037 */
038 public 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 }