View Javadoc

1   /*
2       StatCvs - CVS statistics generation 
3       Copyright (C) 2002  Lukasz Pekacki <lukasz@pekacki.de>
4       http://statcvs.sf.net/
5       
6       This library is free software; you can redistribute it and/or
7       modify it under the terms of the GNU Lesser General Public
8       License as published by the Free Software Foundation; either
9       version 2.1 of the License, or (at your option) any later version.
10  
11      This library is distributed in the hope that it will be useful,
12      but WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      Lesser General Public License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public
17      License along with this library; if not, write to the Free Software
18      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19      
20  	$RCSfile: Revision.java,v $ 
21  	Created on $Date: 2009/08/20 17:44:05 $ 
22  */
23  package net.sf.statcvs.model;
24  
25  import java.util.Date;
26  import java.util.Iterator;
27  import java.util.SortedSet;
28  
29  /**
30   * One revision of a {@link VersionedFile}. That can be an initial revision
31   * (checkin), a change, a deletion, or a re-add. Revisions are created
32   * using the methods {@link VersionedFile#addInitialRevision},
33   * {@link VersionedFile#addChangeRevision} and
34   * {@link VersionedFile#addDeletionRevision}.
35   *
36   * TODO: Replace type code with hierarchy
37   * TODO: Rename class to Revision, getAuthor() to getLogin(), isDead() to isDeletion()
38   * 
39   * @author Manuel Schulze
40   * @author Richard Cyganiak <richard@cyganiak.de>
41   * @version $Id: Revision.java,v 1.3 2009/08/20 17:44:05 benoitx Exp $
42   */
43  public class Revision implements Comparable {
44  
45      /**
46       * Marks a revision that creates a new file. The file did not exist
47       * in the current branch before this revision, and it does exist
48       * afterwards. Possibly the file existed before, that is, it was
49       * deleted and restored. 
50       */
51      public static final int TYPE_CREATION = 1;
52  
53      /**
54       * Marks a revision that changes the file. It does neither create nor
55       * delete the file.
56       */
57      public static final int TYPE_CHANGE = 2;
58  
59      /**
60       * Marks a revision that deletes the file. The file existed before, but
61       * does not exist afterwards in the current branch.
62       */
63      public static final int TYPE_DELETION = 3;
64  
65      /**
66       * Marks a revision at the very beginning of the log timespan. This is
67       * only a container for the number of code lines at the beginning of
68       * the log. It is not a real revision committed by an author.
69       */
70      public static final int TYPE_BEGIN_OF_LOG = 5;
71  
72      private final VersionedFile file;
73      private final String revisionNumber;
74      private final int type;
75      private final Author author;
76      private final Date date;
77      private final String comment;
78      private final int lines;
79      private final int linesReplaced;
80      private final int linesDelta;
81  
82      private final SortedSet symbolicNames;
83  
84      /**
85       * Creates a new revision of a file with the
86       * specified revision number. Should not be called directly. Instead,
87       * {@link VersionedFile#addInitialRevision} and its sister methods should
88       * be used.
89       * @param file VersionedFile that belongs to this revision
90       * @param revisionNumber revision number, for example "1.1"
91       * @param type a <tt>TYPE_XXX</tt> constant
92       * @param author the author of the revision
93       * @param date the date of the revision
94       * @param comment the author's comment
95       * @param lines number of lines; 0 for deletions
96       * @param linesDelta by how much did the number of lines change, compared to the previous revision?
97       * @param linesReplaced How many lines were removed and replaced by other lines, without the delta changing?
98       * @param symbolicNames list of symbolic names for this revision or null if this revision has no symbolic names	 
99       */
100     public Revision(final VersionedFile file, final String revisionNumber, final int type, final Author author, final Date date, final String comment,
101             final int lines, final int linesDelta, final int linesReplaced, final SortedSet symbolicNames) {
102         this.file = file;
103         this.revisionNumber = revisionNumber;
104         this.type = type;
105         this.author = author;
106         this.date = date;
107         this.comment = comment;
108         this.lines = lines;
109         this.linesDelta = linesDelta;
110         this.linesReplaced = linesReplaced;
111         this.symbolicNames = symbolicNames;
112 
113         if (author != null) {
114             author.addRevision(this);
115         }
116 
117         if (symbolicNames != null) {
118             final Iterator it = symbolicNames.iterator();
119             while (it.hasNext()) {
120                 ((SymbolicName) it.next()).addRevision(this);
121             }
122         }
123     }
124 
125     /**
126      * Returns the revision number.
127      * @return the revision number
128      */
129     public String getRevisionNumber() {
130         return revisionNumber;
131     }
132 
133     /**
134      * Returns the author of this revision.
135      * @return the author
136      */
137     public Author getAuthor() {
138         return author;
139     }
140 
141     /**
142      * Returns the comment for this revision.
143      * @return the comment
144      */
145     public String getComment() {
146         return comment;
147     }
148 
149     /**
150      * Returns the date of this revision.
151      * @return the date
152      */
153     public Date getDate() {
154         return date;
155     }
156 
157     /**
158      * Returns the number of lines for this revision. This is 0 for
159      * dead revisions.
160      * 
161      * @return the number of lines
162      */
163     public int getLines() {
164         return lines;
165     }
166 
167     /**
168      * Returns by how many lines the line count changed with this
169      * revision. Deletions return <code>-getLines()</code>,
170      * re-adds and initial revisions return <code>getLines()</code>.
171      * 
172      * @return the line count change of this revision
173      */
174     public int getLinesDelta() {
175         return linesDelta;
176     }
177 
178     /**
179      * Returns the number of lines that were removed and replaced
180      * by other lines in this revision. For example, if 5 lines were
181      * added and 2 lines removed, this would be 3. If 1 line was added
182      * and 1 was removed, it would be 1. If it was an initial revision
183      * or a deletion, it would be 0.
184      * 
185      * @return the number of lines that were replaced by other lines.
186      */
187     public int getReplacedLines() {
188         return linesReplaced;
189     }
190 
191     /**
192      * Returns the number of "new" lines in this revision. This is the
193      * sum of added and changed lines. In other words, all the "original"
194      * lines the author of this revision came up with.
195      * @return lines changed or added
196      */
197     public int getNewLines() {
198         if (getLinesDelta() > 0) {
199             return getLinesDelta() + getReplacedLines();
200         }
201         return getReplacedLines();
202     }
203 
204     /**
205      * Returns the change of the file count caused by this revision.
206      * This is 1 for initial revisions and re-adds, -1 for deletions,
207      * and 0 for normal revisions.
208      * @return the file count change of this revision
209      */
210     public int getFileCountDelta() {
211         if (isInitialRevision()) {
212             return 1;
213         } else if (isDead()) {
214             return -1;
215         } else {
216             return 0;
217         }
218     }
219 
220     /**
221      * Returns <code>true</code> if the file did not exist before this
222      * revision and does exist afterwards. Possibly the file was deleted
223      * before, or it never existed before.
224      * 
225      * @return <code>true</code> if the file did not exist before
226      */
227     public boolean isInitialRevision() {
228         return type == TYPE_CREATION;
229     }
230 
231     /**
232      * Returns <tt>true</tt> if the file is deleted in this revision.
233      * @return <code>true</code> if the file is deleted in this revision
234      */
235     public boolean isDead() {
236         return type == TYPE_DELETION;
237     }
238 
239     /**
240      * Returns <tt>true</tt> if this is a revision
241      * at the very beginning of the log timespan which is
242      * only a container for the number of code lines at the beginning
243      * of the log and not a real revision committed by an author.
244      * @return <code>true</code> if this revision exists
245      * only for StatCvs bookkeeping purposes
246      */
247     public boolean isBeginOfLog() {
248         return type == TYPE_BEGIN_OF_LOG;
249     }
250 
251     /**
252      * {@inheritDoc}
253      */
254     public String toString() {
255         return this.author.getName() + " - " + this.revisionNumber;
256     }
257 
258     /**
259      * Returns the file which was changed by this revision.
260      * @return the file
261      */
262     public VersionedFile getFile() {
263         return file;
264     }
265 
266     /**
267      * Returns the predecessor of this revision or <tt>null</tt> if it
268      * is the first revision for the file.
269      * @return the predecessor of this revision
270      */
271     public Revision getPreviousRevision() {
272         return file.getPreviousRevision(this);
273     }
274 
275     /**
276      * Returns a list of {@link SymbolicName}s of this revision or null if
277      * the revision has no symbolic names. The list is ordered from 
278      * latest to oldest.
279      *
280      * @return list of symbolic names 
281      */
282     public SortedSet getSymbolicNames() {
283         return symbolicNames;
284     }
285 
286     /**
287      * Compares this revision to another revision. A revision is considered
288      * smaller if its date is smaller. If the dates are identical, the filename,
289      * author name, revision number and comment will be used to break the tie.
290      */
291     public int compareTo(final Object other) {
292         if (this == other) {
293             return 0;
294         }
295         final Revision otherRevision = (Revision) other;
296         int result = date.compareTo(otherRevision.getDate());
297         if (result != 0) {
298             return result;
299         }
300         result = file.getFilenameWithPath().compareTo(otherRevision.getFile().getFilenameWithPath());
301         if (result != 0) {
302             return result;
303         }
304         result = revisionNumber.compareTo(otherRevision.getRevisionNumber());
305         if (result != 0) {
306             return result;
307         }
308         if (author != null && otherRevision.getAuthor() != null) {
309             result = author.compareTo(otherRevision.getAuthor());
310             if (result != 0) {
311                 return result;
312             }
313         }
314         if (comment != null && otherRevision.getComment() != null) {
315             return comment.compareTo(otherRevision.getComment());
316         }
317         return 1;
318     }
319 
320     public boolean equals(final Object rhs) {
321         if (rhs == null) {
322             return false;
323         }
324         if (!(rhs instanceof Revision)) {
325             return false;
326         }
327         final Revision that = (Revision) rhs;
328 
329         boolean eq = getDate().equals(that.getDate());
330 
331         if (eq) {
332             eq = file.getFilenameWithPath().equals(that.file.getFilenameWithPath());
333         }
334         if (eq) {
335             eq = revisionNumber.equals(that.getRevisionNumber());
336         }
337         if (eq) {
338             eq = author != null && author.equals(that.getAuthor());
339         }
340         return eq;
341     }
342 
343     public int hashCode() {
344         return getDate().hashCode() + file.hashCode() + revisionNumber.hashCode();
345     }
346 
347     //TODO: remove all deprecated methods when they are no longer used by StatCvs-XML
348 
349     /**
350      * @deprecated Use {@link #getLinesDelta()} and {@link #getReplacedLines()} instead.
351      */
352     public int getLinesAdded() {
353         if (isInitialRevision() && getPreviousRevision() != null) {
354             return 0;
355         }
356         return getNewLines();
357     }
358 
359     /**
360      * @deprecated Use {@link #getLinesDelta()} and {@link #getReplacedLines()} instead.
361      */
362     public int getLinesRemoved() {
363         if (isDead()) {
364             return 0;
365         }
366         if (getLinesDelta() < 0) {
367             return -getLinesDelta() + getReplacedLines();
368         }
369         return getReplacedLines();
370     }
371 
372     /**
373      * @deprecated Use {@link #getLines()} instead.
374      */
375     public int getLinesOfCode() {
376         if (isDead() && getPreviousRevision() != null) {
377             return getPreviousRevision().getLines();
378         }
379         return getLines();
380     }
381 
382     /**
383      * @deprecated Use {@link #getLines()} instead.
384      */
385     public int getEffectiveLinesOfCode() {
386         return getLines();
387     }
388 
389     /**
390      * @deprecated Use {@link #getLinesDelta()} instead.
391      */
392     public int getLinesOfCodeChange() {
393         return getLinesDelta();
394     }
395 
396     /**
397      * @deprecated Use {@link #getNewLines()} instead.
398      */
399     public int getLineValue() {
400         return getNewLines();
401     }
402 
403     /**
404      * @deprecated Use {@link #getReplacedLines()} and {@link #getLinesDelta} instead.
405      */
406     public int getRemovingValue() {
407         if (getLinesDelta() > 0) {
408             return getReplacedLines();
409         }
410         return -getLinesDelta() + getReplacedLines();
411     }
412 
413     /**
414      * @deprecated Use {@link #getFileCountDelta()} instead.
415      */
416     public int getFileCountChange() {
417         return getFileCountDelta();
418     }
419 
420     /**
421      * @deprecated Use {@link #getRevisionNumber()} instead.
422      */
423     public String getRevision() {
424         return getRevisionNumber();
425     }
426 }