1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.statcvs.model;
21
22 import java.util.Date;
23 import java.util.HashSet;
24 import java.util.Set;
25 import java.util.SortedSet;
26 import java.util.TreeSet;
27
28 /**
29 * Represents one versioned file in the {@link Repository Repository},
30 * including its name, {@link Directory} and {@link Revision} list.
31 * Revisions can be created using the <tt>addXXXRevision</tt> factory
32 * methods. Revisions can be created in any order.
33 *
34 * TODO: Rename class to something like VersionedFile, getCurrentLinesOfCode() to getCurrentLines(), maybe getFilenameXXX, isDead() to isDeleted()
35 *
36 * @author Manuel Schulze
37 * @author Richard Cyganiak <richard@cyganiak.de>
38 * @version $Id: VersionedFile.java,v 1.5 2009/08/31 19:16:35 benoitx Exp $
39 */
40 public class VersionedFile implements Comparable {
41 private final String filename;
42 private final SortedSet revisions = new TreeSet();
43 private final Directory directory;
44 private Module module;
45 private final Set authors = new HashSet();
46
47 /**
48 * Creates a VersionedFile object.
49 *
50 * @param name The full name of the file
51 * @param directory the directory where the file resides
52 */
53 public VersionedFile(final String name, final Directory directory) {
54 this.filename = name;
55 this.directory = directory;
56 if (directory != null) {
57 directory.addFile(this);
58 }
59 }
60
61 /**
62 * Returns a list of authors that have commited at least one revision of the file.
63 * @return a list of authors
64 */
65 public Set getAuthors() {
66 return authors;
67 }
68
69 /**
70 * Returns the full filename.
71 * @return the full filename
72 */
73 public String getFilenameWithPath() {
74 return filename;
75 }
76
77 /**
78 * Returns the filename without path.
79 * @return the filename without path
80 */
81 public String getFilename() {
82 final int lastDelim = this.filename.lastIndexOf("/");
83 return this.filename.substring(lastDelim + 1, this.filename.length());
84 }
85
86 /**
87 * Returns the file's <tt>Directory</tt>.
88 * @return the file's <tt>Directory</tt>
89 */
90 public Directory getDirectory() {
91 return directory;
92 }
93
94 /**
95 * Gets the latest revision of this file.
96 * @return the latest revision of this file
97 */
98 public Revision getLatestRevision() {
99 return (Revision) this.revisions.last();
100 }
101
102 /**
103 * Gets the earliest revision of this file.
104 * @return the earliest revision of this file
105 */
106 public Revision getInitialRevision() {
107 return (Revision) this.revisions.first();
108 }
109
110 /**
111 * Returns the list of {@link Revision}s of this file,
112 * sorted from earliest to most recent.
113 * @return a <tt>SortedSet</tt> of {@link Revision}s
114 */
115 public SortedSet getRevisions() {
116 return this.revisions;
117 }
118
119 /**
120 * Returns the current number of lines for this file. Binary files
121 * and deleted files are assumed to have 0 lines.
122 * @return the current number of lines for this file
123 */
124 public int getCurrentLinesOfCode() {
125 return getLatestRevision().getLines();
126 }
127
128 /**
129 * Returns <code>true</code> if the latest revision of this file was
130 * a deletion.
131 * @return <code>true</code> if this file is deleted
132 */
133 public boolean isDead() {
134 return getLatestRevision().isDead();
135 }
136
137 /**
138 * Returns true, if <code>author</code> worked on this file.
139 * @param author The <code>Author</code> to search for
140 * @return <code>true</code>, if the author is listed in one of
141 * this file's revisions
142 */
143 public boolean hasAuthor(final Author author) {
144 return authors.contains(author);
145 }
146
147 /**
148 * Returns the revision which was replaced by the revision given as
149 * argument. Returns <tt>null</tt> if the given revision is the initial
150 * revision of this file.
151 * @param revision a revision of this file
152 * @return this revision's predecessor
153 */
154 public Revision getPreviousRevision(final Revision revision) {
155 if (!revisions.contains(revision)) {
156 throw new IllegalArgumentException("revision not containted in file");
157 }
158 final SortedSet headSet = revisions.headSet(revision);
159 if (headSet.isEmpty()) {
160 return null;
161 }
162 return (Revision) headSet.last();
163 }
164
165 /**
166 * {@inheritDoc}
167 */
168 public String toString() {
169 return getFilenameWithPath() + " (" + revisions.size() + " revisions)";
170 }
171
172 /**
173 * Compares this file to another one, based on filename.
174 * @see java.lang.Comparable#compareTo(java.lang.Object)
175 */
176 public int compareTo(final Object other) {
177 return filename.compareTo(((VersionedFile) other).filename);
178 }
179
180 public boolean equals(final Object rhs) {
181 if (rhs == null) {
182 return false;
183 }
184 if (!(rhs instanceof VersionedFile)) {
185 return false;
186 }
187 final VersionedFile that = (VersionedFile) rhs;
188
189 final boolean eq = filename.equals(that.filename);
190
191 return eq;
192 }
193
194 public int hashCode() {
195 return filename.hashCode();
196 }
197
198 /**
199 * Adds an initial revision to the file. An initial revision is either
200 * the first revision of the file, or a re-add after the file was
201 * deleted.
202 * @param revisionNumber the revision number, for example "1.1"
203 * @param author the login from which the change was committed
204 * @param date the time when the change was committed
205 * @param comment the commit message
206 * @param lines the number of lines of the new file
207 */
208 public Revision addInitialRevision(final String revisionNumber, final Author author, final Date date, final String comment, final int lines,
209 final SortedSet symbolicNames) {
210 final Revision result = new Revision(this, revisionNumber, Revision.TYPE_CREATION, author, date, comment, lines, lines, 0, symbolicNames);
211 addRevision(result);
212 return result;
213 }
214
215 /**
216 * Adds a change revision to the file.
217 * @param revisionNumber the revision number, for example "1.1"
218 * @param author the login from which the change was committed
219 * @param date the time when the change was committed
220 * @param comment the commit message
221 * @param lines the number of lines in the file after the change
222 * @param linesDelta the change in the number of lines
223 * @param replacedLines number of lines that were removed and replaced by others
224 */
225 public Revision addChangeRevision(final String revisionNumber, final Author author, final Date date, final String comment, final int lines,
226 final int linesDelta, final int replacedLines, final SortedSet symbolicNames) {
227 final Revision result = new Revision(this, revisionNumber, Revision.TYPE_CHANGE, author, date, comment, lines, linesDelta, replacedLines, symbolicNames);
228 addRevision(result);
229 return result;
230 }
231
232 /**
233 * Adds a deletion revision to the file.
234 * @param revisionNumber the revision number, for example "1.1"
235 * @param author the login from which the change was committed
236 * @param date the time when the change was committed
237 * @param comment the commit message
238 * @param lines the number of lines in the file before it was deleted
239 */
240 public Revision addDeletionRevision(final String revisionNumber, final Author author, final Date date, final String comment, final int lines,
241 final SortedSet symbolicNames) {
242 final Revision result = new Revision(this, revisionNumber, Revision.TYPE_DELETION, author, date, comment, 0, -lines, 0, symbolicNames);
243 addRevision(result);
244 return result;
245 }
246
247 /**
248 * Adds a "begin of log" revision to the file. This kind of revision
249 * only marks the beginning of the log timespan if the file was
250 * already present in the repository at this time. It is not an actual
251 * revision committed by an author.
252 * @param date the begin of the log
253 * @param lines the number of lines in the file at that time
254 */
255 public Revision addBeginOfLogRevision(final Date date, final int lines, final SortedSet symbolicNames) {
256 final Revision result = new Revision(this, "0.0", Revision.TYPE_BEGIN_OF_LOG, null, date, null, lines, 0, 0, symbolicNames);
257 addRevision(result);
258 return result;
259 }
260
261 private void addRevision(final Revision revision) {
262 revisions.add(revision);
263 if (revision.getAuthor() != null) {
264 authors.add(revision.getAuthor());
265 }
266 }
267
268 public Module getModule() {
269 return module;
270 }
271
272 public void setModule(Module module) {
273 this.module = module;
274 }
275 }