View Javadoc

1   package org.apache.maven.clearcaselib;
2   
3   /* ====================================================================
4    *   Licensed to the Apache Software Foundation (ASF) under one or more
5    *   contributor license agreements.  See the NOTICE file distributed with
6    *   this work for additional information regarding copyright ownership.
7    *   The ASF licenses this file to You under the Apache License, Version 2.0
8    *   (the "License"); you may not use this file except in compliance with
9    *   the License.  You may obtain a copy of the License at
10   *
11   *       http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *   Unless required by applicable law or agreed to in writing, software
14   *   distributed under the License is distributed on an "AS IS" BASIS,
15   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *   See the License for the specific language governing permissions and
17   *   limitations under the License.
18   * ====================================================================
19   */
20  
21  import java.io.BufferedReader;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.InputStreamReader;
25  
26  import java.text.ParseException;
27  import java.text.SimpleDateFormat;
28  
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.Map;
32  import java.util.TreeMap;
33  
34  // commons imports
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.maven.changelog.ChangeLog;
38  import org.apache.maven.changelog.ChangeLogEntry;
39  import org.apache.maven.changelog.ChangeLogFile;
40  import org.apache.maven.changelog.ChangeLogParser;
41  
42  
43  /**
44   * Clearcase specific implementation of ChangeLogParser interface.
45   *
46   * @author <a href="mailto:aldarion@virgilio.it">Simone Zorzetti</a>
47   */
48  public class ClearcaseChangeLogParser implements ChangeLogParser
49  {
50      /** Log */
51      private static final Log LOG =
52          LogFactory.getLog( ClearcaseChangeLogParser.class );
53  
54      /**
55       * Formatter used to parse Clearcase date/timestamp.
56       */
57      private static final SimpleDateFormat CLEARCASE_TIMESTAMP_FORMAT =
58          new SimpleDateFormat( "yyyyMMdd.HHmmss" );
59      private static final String NAME_TAG = "NAME:";
60      private static final String USER_TAG = "USER:";
61      private static final String DATE_TAG = "DATE:";
62      private static final String COMMENT_TAG = "COMM:";
63  
64      /**
65       * Custom date/time formatter.  Rounds ChangeLogEntry times to the nearest
66       * minute.
67       */
68      private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
69          new SimpleDateFormat( "yyyyMMddHHmm" );
70  
71      /**
72       * Custom date/time formatter.  Rounds ChangeLogEntry to date
73       */
74      private static final SimpleDateFormat GROUPED_ENTRY_KEY_TIMESTAMP_FORMAT =
75          new SimpleDateFormat( "yyyyMMdd" );
76  
77      // state machine constants for reading clearcase lshistory command output
78  
79      /** expecting file information */
80      private static final int GET_FILE = 1;
81  
82      /** expecting date */
83      private static final int GET_DATE = 2;
84  
85      /** expecting comments */
86      private static final int GET_COMMENT = 3;
87  
88      /**
89       * rcs entries, in reverse (date, time, author, comment) order
90       */
91      private Map entries = new TreeMap( Collections.reverseOrder() );
92  
93      /** current status of the parser */
94      private int status = GET_FILE;
95  
96      /** the current log entry being processed by the parser*/
97      private ChangeLogEntry currentLogEntry = null;
98  
99      /** the current file being processed by the parser */
100     private ChangeLogFile currentFile = null;
101 
102     /**
103      * Create a new ChangeLogParser.
104      */
105     public ClearcaseChangeLogParser()
106     {
107     }
108 
109     /**
110      * initialize the parser from the change log
111      * @param changeLog the controlling task
112      * @see ChangeLogParser#init(ChangeLog)
113      */
114     public void init( ChangeLog changeLog )
115     {
116     }
117 
118     /**
119      * Clean up any parser resources
120      * @see ChangeLogParser#cleanup()
121      */
122     public void cleanup()
123     {
124     }
125 
126     /**
127      * Parse the input stream into a collection.
128      * @param anInputStream an input stream containing clearcase log output
129      * @return a collection of ChangeLogEntry's
130      * @throws IOException when there are errors reading the provided stream
131      */
132     public Collection parse( InputStream anInputStream )
133         throws IOException
134     {
135         BufferedReader stream =
136             new BufferedReader( new InputStreamReader( anInputStream ) );
137 
138         // Read the tags in the order they are produced by the command setup
139         // by ClearcaseChangeLogGenerator
140         //      File name
141         //      Date                
142         //      Comment
143         //      User Name (author)        
144         String line = null;
145 
146         while ( ( line = stream.readLine() ) != null )
147         {
148             switch ( getStatus() )
149             {
150             case GET_FILE :
151                 processGetFile( line );
152 
153                 break;
154 
155             case GET_DATE :
156                 processGetDate( line );
157 
158                 break;
159 
160             case GET_COMMENT :
161                 processGetCommentAndUser( line );
162 
163                 break;
164 
165             default :
166                 throw new IllegalStateException( "Unknown state: " + status );
167             }
168         }
169 
170         return entries.values();
171     }
172 
173     /**
174      * Add a change log entry to the list (if it's not already there)
175      * with the given file.
176      * @param entry a {@link ChangeLogEntry} to be added to the list if another
177      *      with the same key doesn't exist already. If the entry's author
178      *      is null, the entry wont be added
179      * @param file a {@link ChangeLogFile} to be added to the entry
180      */
181     private void addEntry( ChangeLogEntry entry, ChangeLogFile file )
182     {
183         // do not add if entry is not populated
184         if ( entry.getAuthor() == null )
185         {
186             return;
187         }
188 
189         // do not add if the operation is not checkin
190         if ( entry.getComment().indexOf( "checkin " ) == -1 )
191         {
192             return;
193         }
194 
195         String key =
196             ENTRY_KEY_TIMESTAMP_FORMAT.format( entry.getDate() )
197             + entry.getAuthor() + entry.getComment();
198 
199         file.setRevision( "" );
200 
201         if ( !entries.containsKey( key ) )
202         {
203             entry.addFile( file );
204             entries.put( key, entry );
205         }
206         else
207         {
208             ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get( key );
209 
210             existingEntry.addFile( file );
211         }
212     }
213 
214     /**
215      * Process the current input line in the Get File state.
216      * @param line a line of text from the clearcase log output
217      */
218     private void processGetFile( String line )
219     {
220         if ( line.startsWith( NAME_TAG ) )
221         {
222             setCurrentLogEntry( new ChangeLogEntry() );
223             setCurrentFile( new ChangeLogFile( line.substring( 
224                         NAME_TAG.length(), line.length() ) ) );
225             setStatus( GET_DATE );
226         }
227     }
228 
229     /**
230      * Process the current input line in the Get Date state.
231      * @param line a line of text from the clearcase log output
232      */
233     private void processGetDate( String line )
234     {
235         if ( line.startsWith( DATE_TAG ) )
236         {
237             try
238             {
239                 getCurrentLogEntry().setDate( CLEARCASE_TIMESTAMP_FORMAT
240                     .parse( line.substring( DATE_TAG.length() ) ) );
241             }
242             catch ( ParseException e )
243             {
244                 // TODO Auto-generated catch block
245                 e.printStackTrace();
246             }
247 
248             setStatus( GET_COMMENT );
249         }
250     }
251 
252     /**
253      * Process the current input line in the Get Comment state.
254      * @param line a line of text from the clearcase log output
255      */
256     private void processGetCommentAndUser( String line )
257     {
258         if ( line.startsWith( COMMENT_TAG ) )
259         {
260             String comm = line.substring( COMMENT_TAG.length() );
261 
262             getCurrentLogEntry().setComment( getCurrentLogEntry()
263                                                    .getComment() + comm
264                 + "\n" );
265         }
266         else if ( line.startsWith( USER_TAG ) )
267         {
268             getCurrentLogEntry().setAuthor( line.substring( 
269                     USER_TAG.length() ).trim() );
270 
271             // add entry, and set state to get file
272             addEntry( getCurrentLogEntry(), getCurrentFile() );
273             setStatus( GET_FILE );
274         }
275         else
276         {
277             // keep gathering comments
278             getCurrentLogEntry().setComment( getCurrentLogEntry()
279                                                    .getComment() + line
280                 + "\n" );
281         }
282     }
283 
284     /**
285      * Getter for property currentFile.
286      * @return Value of property currentFile.
287      */
288     private ChangeLogFile getCurrentFile()
289     {
290         return currentFile;
291     }
292 
293     /**
294      * Setter for property currentFile.
295      * @param currentFile New value of property currentFile.
296      */
297     private void setCurrentFile( ChangeLogFile currentFile )
298     {
299         this.currentFile = currentFile;
300     }
301 
302     /**
303      * Getter for property currentLogEntry.
304      * @return Value of property currentLogEntry.
305      */
306     private ChangeLogEntry getCurrentLogEntry()
307     {
308         return currentLogEntry;
309     }
310 
311     /**
312      * Setter for property currentLogEntry.
313      * @param currentLogEntry New value of property currentLogEntry.
314      */
315     private void setCurrentLogEntry( ChangeLogEntry currentLogEntry )
316     {
317         this.currentLogEntry = currentLogEntry;
318     }
319 
320     /**
321      * Getter for property status.
322      * @return Value of property status.
323      */
324     private int getStatus()
325     {
326         return status;
327     }
328 
329     /**
330      * Setter for property status.
331      * @param status New value of property status.
332      */
333     private void setStatus( int status )
334     {
335         this.status = status;
336     }
337 
338     public void setDateFormatInFile( String dateFormat )
339     {
340     }
341 }