1 package net.sf.statsvn.input;
2
3 import javax.xml.parsers.ParserConfigurationException;
4
5 import org.xml.sax.Attributes;
6 import org.xml.sax.SAXException;
7 import org.xml.sax.SAXParseException;
8 import org.xml.sax.helpers.DefaultHandler;
9
10 /**
11 * This is the SAX parser for the our line count persistence mechanism. It feeds information to (@link net.sf.statsvn.input.LineCountsBuilder).
12 *
13 * @author Gunter Mussbacher <gunterm@site.uottawa.ca>
14 *
15 * @version $Id: SvnXmlCacheFileHandler.java 351 2008-03-28 18:46:26Z benoitx $
16 */
17 public class SvnXmlCacheFileHandler extends DefaultHandler {
18 private static final String FATAL_ERROR_MESSAGE = "Invalid StatSVN cache file.";
19
20 private String lastElement = "";
21
22 private final CacheBuilder cacheBuilder;
23
24 /**
25 * Default constructor
26 *
27 * @param cacheBuilder
28 * the cacheBuilder to which to send back line count information.
29 */
30 public SvnXmlCacheFileHandler(final CacheBuilder cacheBuilder) {
31 this.cacheBuilder = cacheBuilder;
32 }
33
34 /**
35 * Makes sure the last element received is appropriate.
36 *
37 * @param last
38 * the expected last element.
39 * @throws SAXException
40 * unexpected event.
41 */
42 private void checkLastElement(final String last) throws SAXException {
43 if (!lastElement.equals(last)) {
44 fatalError(FATAL_ERROR_MESSAGE);
45 }
46 }
47
48 /**
49 * Handles the end of an xml element and redirects to the appropriate end* method.
50 *
51 * @throws SAXException
52 * unexpected event.
53 */
54 public void endElement(final String uri, final String localName, final String qName) throws SAXException {
55 super.endElement(uri, localName, qName);
56 String eName = localName;
57 if ("".equals(eName)) {
58 eName = qName;
59 }
60
61 if (eName.equals(CacheConfiguration.CACHE)) {
62 endCache();
63 } else if (eName.equals(CacheConfiguration.PATH)) {
64 endPath();
65 } else if (eName.equals(CacheConfiguration.REVISION)) {
66 endRevision();
67 } else {
68 fatalError(FATAL_ERROR_MESSAGE);
69 }
70 }
71
72 /**
73 * End of line counts element.
74 *
75 * @throws SAXException
76 * unexpected event.
77 */
78 private void endCache() throws SAXException {
79 checkLastElement(CacheConfiguration.CACHE);
80 lastElement = "";
81 }
82
83 /**
84 * End of path element.
85 *
86 * @throws SAXException
87 * unexpected event.
88 */
89 private void endPath() throws SAXException {
90 checkLastElement(CacheConfiguration.PATH);
91 lastElement = CacheConfiguration.CACHE;
92 }
93
94 /**
95 * End of revision element.
96 *
97 * @throws SAXException
98 * unexpected event.
99 */
100 private void endRevision() throws SAXException {
101 checkLastElement(CacheConfiguration.PATH);
102 }
103
104 /**
105 * Throws a fatal error with the specified message.
106 *
107 * @param message
108 * the reason for the error
109 * @throws SAXException
110 * the error
111 */
112 private void fatalError(final String message) throws SAXException {
113 fatalError(new SAXParseException(message, null));
114 }
115
116 /**
117 * Handles the start of an xml element and redirects to the appropriate start* method.
118 *
119 * @throws SAXException
120 * unexpected event.
121 */
122 public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
123 super.startElement(uri, localName, qName, attributes);
124
125 String eName = localName;
126 if ("".equals(eName)) {
127 eName = qName;
128 }
129
130 if (eName.equals(CacheConfiguration.CACHE)) {
131 startCache();
132 } else if (eName.equals(CacheConfiguration.PATH)) {
133 startPath(attributes);
134 } else if (eName.equals(CacheConfiguration.REVISION)) {
135 startRevision(attributes);
136 } else {
137 fatalError(FATAL_ERROR_MESSAGE);
138 }
139 }
140
141 /**
142 * Handles the start of the document. Initializes the line count builder.
143 *
144 * @throws SAXException
145 * unable to build the root.
146 */
147 private void startCache() throws SAXException {
148 checkLastElement("");
149 lastElement = CacheConfiguration.CACHE;
150 try {
151 cacheBuilder.buildRoot();
152 } catch (final ParserConfigurationException e) {
153 fatalError(FATAL_ERROR_MESSAGE);
154 }
155 }
156
157 /**
158 * Handles start of a path. Initializes line count builder for use with this filename.
159 *
160 * @param attributes
161 * element's xml attributes.
162 * @throws SAXException
163 * missing some data.
164 */
165 private void startPath(final Attributes attributes) throws SAXException {
166 checkLastElement(CacheConfiguration.CACHE);
167 lastElement = CacheConfiguration.PATH;
168 if (attributes != null && attributes.getValue(CacheConfiguration.NAME) != null) {
169 final String name = attributes.getValue(CacheConfiguration.NAME);
170 String revision = "0";
171 if (attributes.getValue(CacheConfiguration.LATEST_REVISION) != null) {
172 revision = attributes.getValue(CacheConfiguration.LATEST_REVISION);
173 }
174 String binaryStatus = CacheConfiguration.UNKNOWN;
175 if (attributes.getValue(CacheConfiguration.BINARY_STATUS) != null) {
176 binaryStatus = attributes.getValue(CacheConfiguration.BINARY_STATUS);
177 }
178 cacheBuilder.buildPath(name, revision, binaryStatus);
179 } else {
180 fatalError(FATAL_ERROR_MESSAGE);
181 }
182 }
183
184 /**
185 * Handles start of a revision. Gives information back to the line count builder.
186 *
187 * @param attributes
188 * element's xml attributes.
189 * @throws SAXException
190 * missing some data.
191 */
192 private void startRevision(final Attributes attributes) throws SAXException {
193 checkLastElement(CacheConfiguration.PATH);
194 if (attributes != null && attributes.getValue(CacheConfiguration.NUMBER) != null && attributes.getValue(CacheConfiguration.ADDED) != null
195 && attributes.getValue(CacheConfiguration.REMOVED) != null) {
196 final String number = attributes.getValue(CacheConfiguration.NUMBER);
197 final String added = attributes.getValue(CacheConfiguration.ADDED);
198 final String removed = attributes.getValue(CacheConfiguration.REMOVED);
199 String binaryStatus = CacheConfiguration.UNKNOWN;
200 if (attributes.getValue(CacheConfiguration.BINARY_STATUS) != null) {
201 binaryStatus = attributes.getValue(CacheConfiguration.BINARY_STATUS);
202 }
203 cacheBuilder.buildRevision(number, added, removed, binaryStatus);
204 } else {
205 fatalError(FATAL_ERROR_MESSAGE);
206 }
207 }
208 }