View Javadoc
1   /*
2    * Copyright (C) 2005, Intalio Inc.
3    *
4    * The program(s) herein may be used and/or copied only with the
5    * written permission of Intalio Inc. or in accordance with the terms
6    * and conditions stipulated in the agreement/contract under which the
7    * program(s) have been supplied.
8    *
9    * $Id$
10   * 
11   * Created on Jan 12, 2005 by kvisco
12   *
13   */
14  package org.exolab.castor.util;
15  
16  import java.io.BufferedReader;
17  import java.io.File;
18  import java.io.FileNotFoundException;
19  import java.io.FileReader;
20  import java.io.FileWriter;
21  import java.io.IOException;
22  import java.text.ParseException;
23  import java.util.ArrayList;
24  
25  import org.castor.xml.InternalContext;
26  import org.castor.xml.XMLProperties;
27  import org.exolab.castor.xml.Marshaller;
28  import org.exolab.castor.xml.XMLContext;
29  
30  /**
31   * A simple command line utility that parses Castor's change log file and outputs the
32   * file in an XML format, a Castor mapping file may be used to change the XML format
33   * that is output. Actually I haven't enabled any command line options yet, so the
34   * mapping file can't be specified at the moment. 
35   * 
36   * @author <a href="mailto:kvisco@intalio.com">kvisco</a>
37   * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
38   */
39  public class ChangeLog2XML {
40  
41      /**
42       * The default filename for the CHANGELOG file
43       */
44      private static final String DEFAULT_FILE = "CHANGELOG";
45      
46      private static final String DEFAULT_OUTPUT = "changelog.xml";
47      
48      
49      private static final String L_PAREN             = "(";
50      private static final String R_PAREN             = ")";
51      private static final String DETAILS_TOKEN       = "Details:";
52      private static final String VERSION_SEPARATOR   = "---";
53      private static final String VERSION_TOKEN       = "Version";
54      
55      /**
56       * The {@link AbstractInternalContext} holding global state and configuration
57       * information.
58       */
59      private InternalContext _internalContext;
60  
61      /**
62       * Creates a new instance of ChangeLog2XML
63       *
64       */
65      public ChangeLog2XML() {
66          super();
67      }
68      
69      /**
70       * To set the {@link AbstractInternalContext} into the ChangeLog2XML instance.
71       * @param internalContext the context to set
72       */
73      public void setInternalContext(final InternalContext internalContext) {
74          _internalContext = internalContext;
75      }
76      
77      /**
78       * The method which does the parsing of the CHANGELOG file
79       * 
80       * @param file
81       * @return
82       * @throws FileNotFoundException
83       * @throws IOException
84       * @throws ParseException
85       */
86      private Changelog parse(File file)     
87          throws FileNotFoundException, IOException, ParseException
88      {
89      	if (!file.exists()) {
90      		throw new IllegalArgumentException("The argument 'file' must not be null!");
91          }
92          
93          
94          FileReader fileReader = new FileReader(file);
95          BufferedReader reader = new BufferedReader(fileReader);
96          String line = null;
97          boolean checkForVersion = false;
98          boolean inEntry = false;
99          String prevLine = null;
100         StringBuffer buffer = null;
101         String details = null;
102         Changelog changelog = new Changelog();
103         Release release = null;
104         
105         while ((line = reader.readLine()) != null)  {
106             
107             //-- check for version separator?
108             if (checkForVersion) {
109                 checkForVersion = false;
110             	if (line.startsWith(VERSION_SEPARATOR)) {
111                    release = new Release();
112                    String version = prevLine;
113                    //-- strip off 'Version'
114                    version = version.substring(VERSION_TOKEN.length()).trim();
115                    release.setVersion(version);
116                    changelog.addRelease(release);
117                    continue;
118                 }
119               inEntry = true;
120               buffer = new StringBuffer();
121               buffer.append(prevLine.trim());
122             }
123             
124             //-- empty line is either end of entry or ignorable
125             //-- whitespace
126             if (line.length() == 0) {
127                 if (inEntry) {
128                 	Entry entry = new Entry();
129                     String value = buffer.toString();
130                     
131                     /* cleanup of entry values*/
132                     
133                     //-- strip off old entry designator "-";
134                     if (value.startsWith("-")) {
135                         value = value.substring(1);
136                     }
137                     int idx = value.indexOf(':');
138                     //-- Strip off component type (ie XML, JDO, ALL, etc);
139                     if ((idx >= 0) && (idx < 10)) {
140                     	String component = value.substring(0, idx);
141                         entry.setComponent(component);
142                         value = value.substring(idx+1);
143                     }
144                     
145                     
146                     if (details != null) {
147                     	entry.setDetails(details);
148                     }
149                     
150                     //-- check for committer and date
151                     int lastLength = prevLine.length();
152                     if (prevLine.startsWith(L_PAREN) && prevLine.endsWith(R_PAREN)) {
153                     	prevLine = prevLine.substring(1, lastLength-1);
154                         idx = prevLine.indexOf('-');
155                         if (idx >= 0) {
156                         	entry.setCommitter(prevLine.substring(0, idx).trim());
157                             entry.setDate(prevLine.substring(idx+1).trim());
158                             //-- cleanup value
159                             value = value.substring(0, value.length()-lastLength);
160                         }
161                     }
162                     
163                     entry.setValue(value.trim());
164                     
165                     release.addEntry(entry);
166                     inEntry = false;
167                     details = null;
168                 }
169                 continue;
170             }
171             
172             if (!inEntry) {
173                 if (line.startsWith(VERSION_TOKEN)) {
174                     checkForVersion = true;
175                     prevLine = line;
176                     continue;
177                 }
178                 inEntry = true;
179                 buffer = new StringBuffer();
180                 buffer.append(line.trim());
181             }
182             else {
183                 
184                 line = line.trim();
185                 
186                 if (line.startsWith(DETAILS_TOKEN)) {
187                 	details = line.substring(DETAILS_TOKEN.length() + 1);
188                 }
189                 else {
190                     if (buffer.length() > 0) {
191                     	buffer.append(' ');
192                     }
193                 	buffer.append(line);
194                 }
195                 prevLine = line;
196             }
197             
198             //-- if we make it here we have valid text
199             
200         }
201         
202         fileReader.close();
203         
204         
205         return changelog;
206         
207     }
208     
209     public static void main(String[] args) {
210         //TODO: add CommandLineOptions
211         // options needed
212         // 1. filename/path of CHANGELOG
213         // 2. mapping file for customization
214         // 3. output file name
215         
216         XMLContext xmlContext = new XMLContext();
217         ChangeLog2XML parser = xmlContext.createChangeLog2XML();
218         
219         try {
220             File file = new File(DEFAULT_FILE);
221         	Changelog changelog = parser.parse(file);
222             
223             file = new File(DEFAULT_OUTPUT);
224             FileWriter writer = new FileWriter(file);
225 
226             xmlContext.setProperty(XMLProperties.USE_INDENTATION, true);
227             Marshaller marshaller = xmlContext.createMarshaller();
228             marshaller.setWriter(writer);
229             
230             marshaller.setRootElement("changelog");
231             marshaller.setSuppressXSIType(true);
232             marshaller.marshal(changelog);
233             
234         }
235         catch(Exception ex) {
236         	ex.printStackTrace();
237         }
238     }
239     
240     /* 
241        Inner JavaBean classes, these classes must follow the basic JavaBean
242        guidelines so that the Castor Introspector will introspect them
243        properly  
244        
245      */
246     
247     public static class Changelog {
248         
249         private ArrayList _releases = new ArrayList();
250         
251         public Changelog() {
252         	super();
253         }
254         
255         public void addRelease(Release release) {
256             if (release != null) {
257             	_releases.add(release);
258             }
259         }
260         
261         public Release[] getRelease() {
262             Release[] relArray = new Release[_releases.size()];
263             _releases.toArray(relArray);
264             return relArray;
265         }
266     }
267     
268     public static class Release {
269         private String _version = null;
270         private ArrayList _entries = new ArrayList();
271         
272         public Release() {
273         	super();
274         }
275         
276         public void addEntry(Entry entry) {
277         	if (entry != null) {
278                _entries.add(entry);      
279             }
280         }
281         
282         public Entry[] getEntry() {
283         	Entry[] entryArray = new Entry[_entries.size()];
284             _entries.toArray(entryArray);
285             return entryArray;
286         }
287         public String getVersion() {
288         	return _version;
289         }
290         
291         public void setVersion(String version) {
292         	_version = version;
293         }
294     }
295     
296     public static class Entry {
297         
298         private String _component = null;
299         private String _details   = null;
300         private String _value     = null;
301         private String _committer = null;
302         private String _date      = null;
303         
304         public Entry() {
305         	super();
306         }
307         
308         public String getCommitter() {
309             return _committer;
310         }
311         
312         public String getComponent() {
313         	return _component;
314         }
315         
316         public String getDate() {
317         	return _date;
318         }
319         
320         public String getDetails() {
321             return _details;
322         }
323         
324         public String getValue() {
325            return _value;
326         }
327         
328         public void setCommitter(String committer) {
329         	_committer = committer;
330         }
331         
332         public void setComponent(String component) {
333         	_component = component;
334         }
335         
336         public void setDate(String date) {
337         	_date = date;
338         }
339         
340         public void setDetails(String details) {
341         	_details = details;
342         }
343         
344         public void setValue(String value) {
345         	_value = value;
346         }
347     }
348 }