View Javadoc

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; // element name
57  		if ("".equals(eName)) {
58  			eName = qName; // namespaceAware = false
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; // element name
126 		if ("".equals(eName)) {
127 			eName = qName; // namespaceAware = false
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 }