1 package net.sf.statsvn.input;
2
3 import java.text.ParseException;
4 import java.util.ArrayList;
5 import java.util.Date;
6 import java.util.HashMap;
7
8 import net.sf.statsvn.output.SvnConfigurationOptions;
9 import net.sf.statsvn.util.XMLUtil;
10
11 import org.xml.sax.Attributes;
12 import org.xml.sax.SAXException;
13 import org.xml.sax.SAXParseException;
14 import org.xml.sax.helpers.DefaultHandler;
15
16
17
18
19
20
21
22
23
24
25 public class SvnXmlLogFileHandler extends DefaultHandler {
26
27 private static final String INVALID_SVN_LOG_FILE = "Invalid SVN log file.";
28
29 private static final String AUTHOR = "author";
30
31 private static final String DATE = "date";
32
33 private static final String FATAL_ERROR_MESSAGE = INVALID_SVN_LOG_FILE;
34
35 private static final String LOG = "log";
36
37 private static final String LOGENTRY = "logentry";
38
39 private static final String MSG = "msg";
40
41 private static final String PATH = "path";
42
43 private static final String PATHS = "paths";
44
45 private final SvnLogBuilder builder;
46
47 private ArrayList currentFilenames;
48
49 private RevisionData currentRevisionData;
50
51 private ArrayList currentRevisions;
52
53 private String lastElement = "";
54
55 private String pathAction = "";
56
57 private String stringData = "";
58
59 private String copyfromRev = "";
60
61 private String copyfromPath = "";
62
63 private final RepositoryFileManager repositoryFileManager;
64
65 private final HashMap tagsMap = new HashMap();
66
67 private final HashMap tagsDateMap = new HashMap();
68
69
70
71
72
73
74
75
76
77 public SvnXmlLogFileHandler(final SvnLogBuilder builder, final RepositoryFileManager repositoryFileManager) {
78 this.builder = builder;
79 this.repositoryFileManager = repositoryFileManager;
80 }
81
82
83
84
85
86 public void characters(final char[] ch, final int start, final int length) throws SAXException {
87 super.characters(ch, start, length);
88 stringData += new String(ch, start, length);
89 }
90
91
92
93
94
95
96
97
98
99 private void checkLastElement(final String last) throws SAXException {
100 if (!lastElement.equals(last)) {
101 fatalError(FATAL_ERROR_MESSAGE);
102 }
103 }
104
105
106
107
108
109
110
111 private void endAuthor() throws SAXException {
112 checkLastElement(LOGENTRY);
113 currentRevisionData.setLoginName(stringData);
114 }
115
116
117
118
119
120
121
122
123
124
125 private void endDate() throws SAXException {
126 checkLastElement(LOGENTRY);
127 Date dt;
128 try {
129 dt = XMLUtil.parseXsdDateTime(stringData);
130 currentRevisionData.setDate(dt);
131 } catch (final ParseException e) {
132 warning("Invalid date specified.");
133 }
134 }
135
136
137
138
139
140
141
142
143 public void endElement(final String uri, final String localName, final String qName) throws SAXException {
144 super.endElement(uri, localName, qName);
145 String eName = localName;
146 if ("".equals(eName)) {
147 eName = qName;
148 }
149 if (eName.equals(LOG)) {
150 endLog();
151 } else if (eName.equals(LOGENTRY)) {
152 endLogEntry();
153 } else if (eName.equals(AUTHOR)) {
154 endAuthor();
155 } else if (eName.equals(DATE)) {
156 endDate();
157 } else if (eName.equals(MSG)) {
158 endMsg();
159 } else if (eName.equals(PATHS)) {
160 endPaths();
161 } else if (eName.equals(PATH)) {
162 endPath();
163 } else {
164 fatalError(INVALID_SVN_LOG_FILE);
165 }
166 }
167
168
169
170
171
172
173
174 private void endLog() throws SAXException {
175 checkLastElement(LOG);
176 lastElement = "";
177 }
178
179
180
181
182
183
184
185
186 private void endLogEntry() throws SAXException {
187 checkLastElement(LOGENTRY);
188 lastElement = LOG;
189
190 for (int i = 0; i < currentFilenames.size(); i++) {
191 if (currentFilenames.get(i) == null) {
192 continue;
193 }
194 final RevisionData revisionData = (RevisionData) currentRevisions.get(i);
195 revisionData.setComment(currentRevisionData.getComment());
196 revisionData.setDate(currentRevisionData.getDate());
197 revisionData.setLoginName(currentRevisionData.getLoginName());
198 final String currentFilename = currentFilenames.get(i).toString();
199
200 final boolean isBinary = repositoryFileManager.isBinary(currentFilename);
201 builder.buildFile(currentFilename, isBinary, revisionData.isDeletion(), tagsMap, tagsDateMap);
202 builder.buildRevision(revisionData);
203 }
204 }
205
206
207
208
209
210
211
212 private void endMsg() throws SAXException {
213 checkLastElement(LOGENTRY);
214 currentRevisionData.setComment(stringData);
215 }
216
217
218
219
220
221
222
223
224 private void endPath() throws SAXException {
225 checkLastElement(PATHS);
226
227
228
229 final String filename = repositoryFileManager.absoluteToRelativePath(stringData);
230 final RevisionData data = currentRevisionData.createCopy();
231 if (!pathAction.equals("D")) {
232 data.setStateExp(true);
233 if (pathAction.equals("A") || pathAction.equals("R")) {
234 data.setStateAdded(true);
235 }
236 } else {
237 data.setStateDead(true);
238 }
239
240 final String tagsStr = SvnConfigurationOptions.getTagsDirectory();
241 if (copyfromRev != null && filename == null && stringData != null && stringData.indexOf(tagsStr) >= 0) {
242 String tag = stringData.substring(stringData.indexOf(tagsStr) + tagsStr.length());
243 if (tag.indexOf("/") >= 0) {
244 tag = tag.substring(0, tag.indexOf("/"));
245 }
246
247 if (!tagsMap.containsKey(tag) && builder.matchesTagPatterns(tag)) {
248 SvnConfigurationOptions.getTaskLogger().info("= TAG " + tag + " rev:" + copyfromRev + " stringData [" + stringData + "]");
249 tagsMap.put(tag, copyfromRev);
250 tagsDateMap.put(tag, currentRevisionData.getDate());
251 }
252 }
253
254 data.setCopyfromPath(copyfromPath);
255 data.setCopyfromRevision(copyfromRev);
256
257 currentRevisions.add(data);
258 currentFilenames.add(filename);
259 }
260
261
262
263
264
265
266
267 private void endPaths() throws SAXException {
268 checkLastElement(PATHS);
269 lastElement = LOGENTRY;
270 }
271
272
273
274
275
276
277
278
279
280 private void fatalError(final String message) throws SAXException {
281 fatalError(new SAXParseException(message, null));
282 }
283
284
285
286
287
288
289
290 private void startAuthorDateMsg() throws SAXException {
291 checkLastElement(LOGENTRY);
292 }
293
294
295
296
297
298
299
300
301 public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
302 super.startElement(uri, localName, qName, attributes);
303 stringData = "";
304 String eName = localName;
305 if ("".equals(eName)) {
306 eName = qName;
307 }
308 if (eName.equals(LOG)) {
309 startLog();
310 } else if (eName.equals(LOGENTRY)) {
311 startLogEntry(attributes);
312 } else if (eName.equals(AUTHOR) || eName.equals(DATE) || eName.equals(MSG)) {
313 startAuthorDateMsg();
314 } else if (eName.equals(PATHS)) {
315 startPaths();
316 } else if (eName.equals(PATH)) {
317 startPath(attributes);
318 } else {
319 fatalError(INVALID_SVN_LOG_FILE);
320 }
321 }
322
323
324
325
326
327
328
329 private void startLog() throws SAXException {
330 checkLastElement("");
331 lastElement = LOG;
332
333 try {
334 repositoryFileManager.loadInfo();
335 builder.buildModule(repositoryFileManager.getModuleName());
336 } catch (final Exception e) {
337 throw new SAXException(e);
338 }
339
340 }
341
342
343
344
345
346
347
348
349 private void startLogEntry(final Attributes attributes) throws SAXException {
350 checkLastElement(LOG);
351 lastElement = LOGENTRY;
352 currentRevisionData = new RevisionData();
353 currentRevisions = new ArrayList();
354 currentFilenames = new ArrayList();
355 if (attributes != null && attributes.getValue("revision") != null) {
356 currentRevisionData.setRevisionNumber(attributes.getValue("revision"));
357 } else {
358 fatalError(INVALID_SVN_LOG_FILE);
359 }
360 }
361
362
363
364
365
366
367
368 private void startPath(final Attributes attributes) throws SAXException {
369 checkLastElement(PATHS);
370 if (attributes != null && attributes.getValue("action") != null) {
371 pathAction = attributes.getValue("action");
372 } else {
373 fatalError(INVALID_SVN_LOG_FILE);
374 }
375
376 copyfromPath = attributes.getValue("copyfrom-path");
377 copyfromRev = attributes.getValue("copyfrom-rev");
378
379 }
380
381
382
383
384
385
386
387 private void startPaths() throws SAXException {
388 checkLastElement(LOGENTRY);
389 lastElement = PATHS;
390 }
391
392
393
394
395
396
397
398
399
400 private void warning(final String message) throws SAXException {
401 SvnConfigurationOptions.getTaskLogger().info(message);
402 }
403 }