001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2013 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 createdAt, updatedAt;
045      private final Map<String, Diff> diffs = Maps.newLinkedHashMap();
046    
047      public Map<String, Diff> diffs() {
048        return diffs;
049      }
050    
051      public Diff get(String field) {
052        return diffs.get(field);
053      }
054    
055      @CheckForNull
056      public String userLogin() {
057        return userLogin;
058      }
059    
060      public FieldDiffs setUserLogin(@Nullable String s) {
061        this.userLogin = s;
062        return this;
063      }
064    
065      public Date createdAt() {
066        return createdAt;
067      }
068    
069      public FieldDiffs setCreatedAt(Date d) {
070        this.createdAt = d;
071        return this;
072      }
073    
074      public Date updatedAt() {
075        return updatedAt;
076      }
077    
078      public FieldDiffs setUpdatedAt(Date d) {
079        this.updatedAt = d;
080        return this;
081      }
082    
083      public String issueKey() {
084        return issueKey;
085      }
086    
087      public FieldDiffs setIssueKey(String issueKey) {
088        this.issueKey = issueKey;
089        return this;
090      }
091    
092      @SuppressWarnings("unchecked")
093      public FieldDiffs setDiff(String field, @Nullable Serializable oldValue, @Nullable Serializable newValue) {
094        Diff diff = diffs.get(field);
095        if (diff == null) {
096          diff = new Diff(oldValue, newValue);
097          diffs.put(field, diff);
098        } else {
099          diff.setNewValue(newValue);
100        }
101        return this;
102      }
103    
104      @Override
105      public String toString() {
106        StringBuilder sb = new StringBuilder();
107        boolean notFirst = false;
108        for (Map.Entry<String, Diff> entry : diffs.entrySet()) {
109          if (notFirst) {
110            sb.append(',');
111          } else {
112            notFirst = true;
113          }
114          sb.append(entry.getKey());
115          sb.append('=');
116          sb.append(entry.getValue().toString());
117        }
118        return sb.toString();
119      }
120    
121      public static FieldDiffs parse(@Nullable String s) {
122        FieldDiffs diffs = new FieldDiffs();
123        if (!Strings.isNullOrEmpty(s)) {
124          Iterable<String> fields = FIELDS_SPLITTER.split(s);
125          for (String field : fields) {
126            String[] keyValues = field.split("=");
127            if (keyValues.length == 2) {
128              String[] values = keyValues[1].split("\\|");
129              String oldValue = "";
130              String newValue = "";
131              if(values.length == 1) {
132                newValue = Strings.nullToEmpty(values[0]);
133              } else if(values.length == 2) {
134                oldValue = Strings.nullToEmpty(values[0]);
135                newValue = Strings.nullToEmpty(values[1]);
136              }
137              diffs.setDiff(keyValues[0], oldValue, newValue);
138            } else {
139              diffs.setDiff(keyValues[0], "", "");
140            }
141          }
142        }
143        return diffs;
144      }
145    
146      public static class Diff<T extends Serializable> implements Serializable {
147        private T oldValue, newValue;
148    
149        public Diff(@Nullable T oldValue, @Nullable T newValue) {
150          this.oldValue = oldValue;
151          this.newValue = newValue;
152        }
153    
154        @CheckForNull
155        public T oldValue() {
156          return oldValue;
157        }
158    
159        @CheckForNull
160        public Long oldValueLong() {
161          return toLong(oldValue);
162        }
163    
164        @CheckForNull
165        public T newValue() {
166          return newValue;
167        }
168    
169        @CheckForNull
170        public Long newValueLong() {
171          return toLong(newValue);
172        }
173    
174        void setNewValue(T t) {
175          this.newValue = t;
176        }
177    
178        @CheckForNull
179        private Long toLong(Serializable value) {
180          if (value != null && !"".equals(value)) {
181            try {
182              return Long.valueOf((String) value);
183            } catch (ClassCastException e) {
184              return (Long) value;
185            }
186          }
187          return null;
188        }
189    
190        @Override
191        public String toString() {
192          //TODO escape , and | characters
193          StringBuilder sb = new StringBuilder();
194          if(newValue != null) {
195            if(oldValue != null) {
196              sb.append(oldValue.toString());
197              sb.append('|');
198            }
199            sb.append(newValue.toString());
200          }
201          return sb.toString();
202        }
203      }
204    }