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