KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > cvsclient > admin > Entry


1 /*****************************************************************************
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is the CVS Client Library.
16  * The Initial Developer of the Original Software is Robert Greig.
17  * Portions created by Robert Greig are Copyright (C) 2000.
18  * All Rights Reserved.
19  *
20  * Contributor(s): Robert Greig.
21  *****************************************************************************/

22 package org.netbeans.lib.cvsclient.admin;
23
24 import java.text.*;
25 import java.util.*;
26
27 /**
28  * The class abstracts the CVS concept of an <i>entry line</i>. The entry
29  * line is textually of the form:<p>
30  * / name / version / conflict / options / tag_or_date
31  * <p>These are explained in section 5.1 of the CVS protocol 1.10 document.
32  * @author Robert Greig
33  */

34 public final class Entry {
35     /**
36      * The dummy timestamp set the conflict information for added or removed
37      * files.
38      */

39     public static final String JavaDoc DUMMY_TIMESTAMP = "dummy timestamp"; //NOI18N
40
public static final String JavaDoc DUMMY_TIMESTAMP_NEW_ENTRY = "dummy timestamp from new-entry"; //NOI18N
41

42     public static final String JavaDoc MERGE_TIMESTAMP = "Result of merge"; //NOI18N
43

44     /**
45      * Indicates a sticky tag.
46      */

47     private static final String JavaDoc TAG = "T"; //NOI18N
48

49     /**
50      * Indicates a sticky date.
51      */

52     private static final String JavaDoc DATE = "D"; //NOI18N
53

54     /**
55      * The instance of the date formatter for sticky dates.
56      */

57     private static SimpleDateFormat stickyDateFormatter;
58
59     /**
60      * Returns the instance of the date formatter for sticky dates.
61      */

62     private static SimpleDateFormat getStickyDateFormatter() {
63         if (stickyDateFormatter == null) {
64             stickyDateFormatter = new SimpleDateFormat("yyyy.MM.dd.hh.mm.ss"); //NOI18N
65
}
66         return stickyDateFormatter;
67     }
68
69     /**
70      * Indicates a binary file.
71      */

72     private static final String JavaDoc BINARY_FILE = "-kb"; //NOI18N
73

74     /**
75      * Indicates that no user file is meant by the version details
76      */

77     private static final String JavaDoc NO_USER_FILE = ""; //NOI18N
78

79     /**
80      * Indicates that a new user file is meant by the version details
81      */

82     private static final String JavaDoc NEW_USER_FILE = "0"; //NOI18N
83

84     /**
85      * Indicates that the file is to be removed, in the version details
86      */

87     private static final String JavaDoc REMOVE_USER_FILE = "-"; //NOI18N
88

89     /**
90      * The date formatter to be used for noting the Last Modified date in a
91      * file.
92      */

93     private static SimpleDateFormat lastModifiedDateFormatter;
94
95     /**
96      * Returns the instance of the Last-Modified-Date-Formatter.
97      */

98     public static SimpleDateFormat getLastModifiedDateFormatter() {
99         if (lastModifiedDateFormatter == null) {
100             lastModifiedDateFormatter =
101                     new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", Locale.US); //NOI18N
102
lastModifiedDateFormatter.setTimeZone(getTimeZone());
103         }
104         return lastModifiedDateFormatter;
105     }
106
107     /**
108      * All entries times are by defaulf in Zulu/GMT0
109      */

110     public static TimeZone getTimeZone() {
111         return TimeZone.getTimeZone("GMT"); //NOI18N
112
}
113     
114     /**
115      * Indicates that the file had conflicts.
116      */

117     public static final char HAD_CONFLICTS = '+';
118
119     /**
120      * Indicates that the timestamp matches the file.
121      */

122     public static final char TIMESTAMP_MATCHES_FILE = '=';
123
124     /**
125      * Indicates that the file had conflicts and timestamp matches.
126      * It likely means unresolved conflict.
127      */

128     public static final String JavaDoc HAD_CONFLICTS_AND_TIMESTAMP_MATCHES_FILE = "+=";
129
130     /**
131      * Initial letter that indicates a directory entry.
132      */

133     private static final String JavaDoc DIRECTORY_PREFIX = "D/";
134
135     /**
136      * The name of the file.
137      */

138     private String JavaDoc name;
139
140     /**
141      * The revision. There are constants defined for no user file, new user
142      * file and user file has to be removed.
143      */

144     private String JavaDoc revision;
145
146     /**
147      * The conflict information. There are constants defined for indicating
148      * that conflicts occurred and that the timestamp matches the file
149      */

150     private String JavaDoc conflict;
151
152     /**
153      * The last modified date of the file.
154      */

155     private Date lastModified;
156
157     /**
158      * The options for signifying keyword expansion.
159      */

160     private String JavaDoc options;
161
162     /**
163      * The tag. May be present in place of the date information.
164      */

165     private String JavaDoc tag;
166
167     /**
168      * The date. May be present in place of the tag information.
169      */

170     private Date date;
171
172     /**
173      * Indicates whether the entry is for a directory.
174      */

175     private boolean directory;
176
177     /**
178      * Construct a new Entry from a given entry line.
179      */

180     public Entry(String JavaDoc entryLine) {
181         init(entryLine);
182     }
183
184     /**
185      * Construct a new blank Entry.
186      */

187     public Entry() {
188     }
189
190     /**
191      * Initialise the Entry by parsing an entry line.
192      * @param entryLine the entry line in standard CVS format
193      */

194     protected void init(String JavaDoc entryLine) {
195         //System.err.println("Constructing an entry line from: " + entryLine);
196
// try to parse the entry line, if we get stuck just
197
// throw an illegal argument exception
198

199         if (entryLine.startsWith(DIRECTORY_PREFIX)) {
200             directory = true;
201             entryLine = entryLine.substring(1);
202         }
203
204         // first character is a slash, so name is read from position 1
205
// up to the next slash
206
final int[] slashPositions = new int[5];
207
208         try {
209             slashPositions[0] = 0;
210             for (int i = 1; i < 5; i++) {
211                 slashPositions[i] = entryLine.indexOf('/',
212                                                       slashPositions[i - 1] + 1);
213             }
214
215             // Test if this is a D on its own, a special case indicating that
216
// directories are understood and there are no subdirectories
217
// in the current folder
218
if (slashPositions[1] > 0) {
219                 // note that the parameters to substring are treated as follows:
220
// (inclusive, exclusive)
221
name = entryLine.substring(slashPositions[0] + 1,
222                                            slashPositions[1]);
223                 revision = entryLine.substring(slashPositions[1] + 1,
224                                                slashPositions[2]);
225                 if ((slashPositions[3] - slashPositions[2]) > 1) {
226                     String JavaDoc conflict = entryLine.substring(slashPositions[2] + 1,
227                                                           slashPositions[3]);
228                     setConflict(conflict);
229                 }
230                 if ((slashPositions[4] - slashPositions[3]) > 1) {
231                     options = entryLine.substring(slashPositions[3] + 1,
232                                                   slashPositions[4]);
233                 }
234                 if (slashPositions[4] != (entryLine.length() - 1)) {
235                     String JavaDoc tagOrDate = entryLine.substring(slashPositions[4]
236                                                            + 1);
237                     if (tagOrDate.startsWith(TAG)) {
238                         setTag(tagOrDate.substring(1));
239                     }
240                     else if (tagOrDate.startsWith(DATE)) {
241                         //TODO process date into something useful
242
// MK - I didn't notice any time conversions (according to timezone)
243
// So I just convert it from String to Date and back.
244
try {
245                             String JavaDoc dateString = tagOrDate.substring(DATE.length());
246                             Date stickyDate = getStickyDateFormatter().
247                                     parse(dateString);
248                             setDate(stickyDate);
249                         }
250                         catch (ParseException exc) {
251                             System.err.println("We got another inconsistency in the library's date formatting."); //NOI18N
252
}
253                     }
254                 }
255             }
256         }
257         catch (Exception JavaDoc e) {
258             System.err.println("Error parsing entry line: " + e); //NOI18N
259
e.printStackTrace();
260             throw new IllegalArgumentException JavaDoc("Invalid entry line: " + //NOI18N
261
entryLine);
262         }
263     }
264
265     /**
266      * Get the name of the associated file.
267      * @return the file name
268      */

269     public String JavaDoc getName() {
270         return name;
271     }
272
273     /**
274      * Set the name.
275      * @param theName the filename to set
276      */

277     public void setName(String JavaDoc name) {
278         this.name = name;
279     }
280
281     /**
282      * Get the revision.
283      * @return the revision
284      */

285     public String JavaDoc getRevision() {
286         return revision;
287     }
288
289     /**
290      * Set the revision.
291      * @param theVersion the revision to set
292      */

293     public void setRevision(String JavaDoc revision) {
294         this.revision = revision;
295     }
296
297     /**
298      * Get the last modification time.
299      *
300      * @return date.getTime() compatible with File.lastModified()
301      */

302     public Date getLastModified() {
303         return lastModified;
304     }
305
306     /**
307      * Get the conflict information.
308      * @return the conflict String
309      */

310     public String JavaDoc getConflict() {
311         return conflict;
312     }
313
314     /**
315      * Set the conflict information.
316      * @param theConflict the conflict information
317      */

318     public void setConflict(String JavaDoc conflict) {
319         this.conflict = conflict;
320         this.lastModified = null;
321
322         if (conflict == null
323                 || conflict.equals(DUMMY_TIMESTAMP)
324                 || conflict.equals(MERGE_TIMESTAMP)
325                 || conflict.equals(DUMMY_TIMESTAMP_NEW_ENTRY)) {
326             return;
327         }
328
329         String JavaDoc dateString = conflict;
330
331         // Look for the position of + which indicates a conflict
332
int conflictIndex = dateString.indexOf(HAD_CONFLICTS);
333         if (conflictIndex >= 0) {
334             // if the timestamp matches the file, there will be an = following
335
// the +
336
int timeMatchIndex = dateString.indexOf(TIMESTAMP_MATCHES_FILE);
337             conflictIndex = Math.max(conflictIndex, timeMatchIndex);
338         }
339
340         // At this point the conflict index tells us where the real conflict
341
// string starts
342
if (conflictIndex >= 0) {
343             dateString = dateString.substring(conflictIndex + 1);
344         }
345
346         // if we have nothing after the = then don't try to parse it
347
if (dateString.length() == 0) {
348             return;
349         }
350
351         try {
352             this.lastModified = getLastModifiedDateFormatter().parse(dateString);
353         }
354         catch (Exception JavaDoc ex) {
355             lastModified = null;
356 // System.err.println("[Entry] can't parse " + dateString); //NOI18N
357
}
358     }
359
360     /**
361      * Get the options information.
362      * @return the options details
363      */

364     public String JavaDoc getOptions() {
365         return options;
366     }
367
368     /**
369      * Set the options information.
370      * @param theOptions the options
371      */

372     public void setOptions(String JavaDoc options) {
373         this.options = options;
374     }
375
376     /**
377      * Get the sticky information.
378      * It's either a tag, a date or null.
379      */

380     public String JavaDoc getStickyInformation() {
381         if (tag != null) {
382             return tag;
383         }
384         return getDateFormatted();
385     }
386
387     /**
388      * Get the sticky tag information.
389      * May return null if no tag information was present. If so, you should
390      * check for date information. Note that tag and date information cannot
391      * both be present.
392      * @return the tag, or null if none is present
393      */

394     public String JavaDoc getTag() {
395         return tag;
396     }
397
398     /**
399      * Set the sticky tag information.
400      * Setting this will remove any date information that is set.
401      * @param theTag the tag information
402      */

403     public void setTag(String JavaDoc tag) {
404         this.tag = tag;
405         date = null;
406     }
407
408     /**
409      * Get sticky date information.
410      * May return null if no date information is available. If so, you should
411      * check for tag informaton. Note that tag and date information cannot both
412      * be present.
413      * @return the date, or null if none is present
414      */

415     public Date getDate() {
416         return date;
417     }
418
419     /**
420      * Gets the sticky date information as a string in the appropriate format.
421      * Returns null if there ain't a sticky date assigned.
422      */

423     public String JavaDoc getDateFormatted() {
424         if (getDate() == null) {
425             return null;
426         }
427         SimpleDateFormat format = getStickyDateFormatter();
428         String JavaDoc dateFormatted = format.format(getDate());
429         return dateFormatted;
430     }
431
432     /**
433      * Set the sticky date information.
434      * Note that setting this will remove any tag information that is currently set.
435      * @param theDate the date to use.
436      */

437     public void setDate(Date date) {
438         this.date = date;
439         tag = null;
440     }
441
442     /**
443      * Determines whether the entry has a date (as opposed to a tag).
444      * @return true if the entry has a date, false otherwise
445      */

446     public boolean hasDate() {
447         return (date != null);
448     }
449
450     /**
451      * Determines whether the entry has a tag (as opposed to a date).
452      * @return true if the entry has a tag, false otherwise
453      */

454     public boolean hasTag() {
455         return (tag != null);
456     }
457
458     /**
459      * Determines whether the file is a binary file.
460      */

461     public boolean isBinary() {
462         return options != null
463                 && options.equals(BINARY_FILE);
464     }
465
466     /**
467      * Determine whether there is no user file of that name.
468      * @return true if there is no user file of that name
469      */

470     public boolean isNoUserFile() {
471         return revision == null
472                 || revision.equals(NO_USER_FILE);
473     }
474
475     /**
476      * Determine whether there is a new user file of that name.
477      * @return true if there is a new user file with that name
478      */

479     public boolean isNewUserFile() {
480         return revision != null
481                 && revision.startsWith(NEW_USER_FILE);
482     }
483
484     /**
485      * Determine whether the user file of that name is to be removed.
486      * @return true if the user file with this name is to be removed
487      */

488     public boolean isUserFileToBeRemoved() {
489         return revision != null
490                 && revision.startsWith(REMOVE_USER_FILE);
491     }
492
493     /**
494      * Determines whether the entry is valid.
495      * A valid entry has at least a name.
496      */

497     public boolean isValid() {
498         return getName() != null &&
499                 getName().length() > 0;
500     }
501
502     /**
503      * Determine whether the entry refers to a directory.
504      */

505     public boolean isDirectory() {
506         return directory;
507     }
508
509     /**
510      * Set whether the entry refers to a directory.
511      */

512     public void setDirectory(boolean directory) {
513         this.directory = directory;
514     }
515
516     /**
517      * Determine whether there were any conflicts.
518      * @return true if there were conflicts, false otherwise
519      */

520     public boolean hadConflicts() {
521         if (conflict != null) {
522             return conflict.indexOf(HAD_CONFLICTS) >= 0;
523         }
524         else {
525             return false;
526         }
527     }
528
529     /**
530      * Determine whether the timestamp matches the file.
531      * @return true if the timpestamp does match the file, false otherwise
532      */

533     public boolean timestampMatchesFile() {
534         return (conflict.charAt(1) == TIMESTAMP_MATCHES_FILE);
535     }
536
537     /**
538      * Create a string representation of the entry line.
539      * Create the standard CVS 1.10 entry line format.
540      * <p>
541      * Th eline format is suitable for writing into <tt>CVS/Entries</tt> file.
542      * Conflict one must be transformed before sending to wire
543      * {@link org.netbeans.lib.cvsclient.command.BasicCommand#sendEntryAndModifiedRequests}.
544      */

545     public String JavaDoc toString() {
546         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
547         if (directory) {
548             buf.append(DIRECTORY_PREFIX);
549         }
550         else {
551             buf.append('/');
552         }
553         // if name is null, then this is a totally empty entry, so append
554
// nothing further
555
if (name != null) {
556             buf.append(name);
557             buf.append('/');
558             if (revision != null) {
559                 buf.append(revision);
560             }
561             buf.append('/');
562             if (conflict != null) {
563                 buf.append(conflict);
564             }
565             buf.append('/');
566             if (options != null) {
567                 buf.append(options);
568             }
569             buf.append('/');
570             // TODO: put in tag_or_date section!!!
571
// MK - Added. Based on assumption "There can be only one"
572
if (tag != null && date == null) {
573                 if ("HEAD".equals(tag) == false) {
574                     buf.append(TAG);
575                     buf.append(getTag());
576                 }
577             }
578             else if (tag == null && date != null) {
579                 String JavaDoc dateString = getDateFormatted();
580                 buf.append(DATE);
581                 buf.append(dateString);
582             }
583         }
584         return buf.toString();
585     }
586 }
587
Popular Tags