1 /*
2 * Copyright (C) The JContainer Group. All rights reserved.
3 *
4 * This software is published under the terms of the JContainer
5 * Software License version 1.1, a copy of which has been included
6 * with this distribution in the LICENSE.txt file.
7 */
8 package org.jcontainer.dna.impl;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import org.jcontainer.dna.Configuration;
13 import org.xml.sax.Attributes;
14 import org.xml.sax.Locator;
15 import org.xml.sax.SAXException;
16 import org.xml.sax.SAXParseException;
17 import org.xml.sax.helpers.DefaultHandler;
18
19 /***
20 * The SAXConfigurationHandler builds a Configuration tree
21 * from SAX events.
22 *
23 * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
24 * @version $Revision: 1.21 $ $Date: 2003/10/05 09:04:55 $
25 */
26 public class SAXConfigurationHandler
27 extends DefaultHandler
28 {
29 /***
30 * Empty string used for padding out contents array.
31 */
32 private static final String EMPTY_STRING = "";
33
34 /***
35 * Constant to indicate location of
36 * element when parser does not support Locator
37 * interface.
38 */
39 private static final String UNKNOWN = "";
40
41 /***
42 * Stack of configuration elements currently being
43 * constructed.
44 */
45 private final List m_elements = new ArrayList();
46
47 /***
48 * Stakc of content text for elements currently being
49 * constructed.
50 */
51 private final ArrayList m_values = new ArrayList();
52
53 /***
54 * The configuration element created.
55 */
56 private Configuration m_configuration;
57
58 /***
59 * The Locator specified by XML parser.
60 */
61 private Locator m_locator;
62
63 /***
64 * Let the XML parser specify locator for when
65 * events arrive at handler.
66 *
67 * @param locator the locator
68 */
69 public void setDocumentLocator( final Locator locator )
70 {
71 m_locator = locator;
72 }
73
74 /***
75 * Reset internal state of handler in preapration for reuse.
76 */
77 public void clear()
78 {
79 m_elements.clear();
80 m_values.clear();
81 m_locator = null;
82 }
83
84 /***
85 * Return the configuration created by handler.
86 *
87 * @return the configuration created by handler.
88 */
89 public Configuration getConfiguration()
90 {
91 return m_configuration;
92 }
93
94 /***
95 * Start an element and thus a Configuration object.
96 *
97 * @param uri the uri (ignored)
98 * @param localName the localName (ignored)
99 * @param qName the qualified name (used for name of configuration)
100 * @param attributes the attributes of XML element
101 * @throws SAXException if unable to parse element
102 */
103 public void startElement( final String uri,
104 final String localName,
105 final String qName,
106 final Attributes attributes )
107 throws SAXException
108 {
109 DefaultConfiguration parent = null;
110 String path = ConfigurationUtil.ROOT_PATH;
111 if( m_elements.size() > 0 )
112 {
113 final int index = m_elements.size() - 1;
114 parent =
115 (DefaultConfiguration)m_elements.get( index );
116 path = ConfigurationUtil.
117 generatePathName( parent.getPath(),
118 parent.getName() );
119 }
120 final DefaultConfiguration configuration =
121 new DefaultConfiguration( qName, getLocationDescription(), path );
122 if( null != parent )
123 {
124 parent.addChild( configuration );
125 }
126 final int length = attributes.getLength();
127 for( int i = 0; i < length; i++ )
128 {
129 final String key = attributes.getQName( i );
130 final String value = attributes.getValue( i );
131 final String newValue =
132 processAttributeText( configuration, key, value );
133 configuration.setAttribute( key, newValue );
134 }
135
136 m_elements.add( configuration );
137 }
138
139 /***
140 * End an element and thus a Configuration object.
141 * Will pop of configuration and value of object from
142 * stack. If the handler detects that element has both
143 * child elements and a text value then it will throw
144 * a SAXException.
145 *
146 * @param uri the uri (ignored)
147 * @param localName the localName (ignored)
148 * @param qName the qualified name (used for name of configuration)
149 * @throws SAXException if element had mixed content
150 */
151 public void endElement( final String uri,
152 final String localName,
153 final String qName )
154 throws SAXException
155 {
156 final int index = m_elements.size() - 1;
157 final DefaultConfiguration configuration =
158 (DefaultConfiguration)m_elements.remove( index );
159 if( index < m_values.size() )
160 {
161 final String value = m_values.remove( index ).toString();
162 if( 0 != value.trim().length() )
163 {
164 if( 0 == configuration.getChildren().length )
165 {
166 final String newValue =
167 processValueText( configuration, value );
168 configuration.setValue( newValue );
169 }
170 else
171 {
172 final String message =
173 "Mixed content (" + value.trim() + ") " +
174 "not supported @ " + getLocationDescription();
175 throw new SAXException( message );
176 }
177 }
178 }
179 m_configuration = configuration;
180 }
181
182 /***
183 * Receive text data for current element.
184 *
185 * @param ch the char array
186 * @param start the start index
187 * @param length the length of data
188 * @throws SAXException if unable ot parse data
189 */
190 public void characters( final char[] ch,
191 final int start,
192 final int length )
193 throws SAXException
194 {
195 final int index = m_elements.size() - 1;
196 StringBuffer sb = null;
197 if( index < m_values.size() )
198 {
199 sb = (StringBuffer)m_values.get( index );
200 }
201 if( null == sb )
202 {
203 sb = new StringBuffer();
204 final int minCapacity = index + 1;
205 m_values.ensureCapacity( minCapacity );
206 final int size = m_values.size();
207 for( int i = size; i < minCapacity; i++ )
208 {
209 m_values.add( EMPTY_STRING );
210 }
211 m_values.set( index, sb );
212 }
213 sb.append( ch, start, length );
214 }
215
216 /***
217 * Rethrow exception and dont attempt to do
218 * any error handling.
219 *
220 * @param spe the input exception
221 * @throws SAXException always thrown
222 */
223 public void warning( final SAXParseException spe )
224 throws SAXException
225 {
226 throw spe;
227 }
228
229 /***
230 * Rethrow exception and dont attempt to do
231 * any error handling.
232 *
233 * @param spe the input exception
234 * @throws SAXException always thrown
235 */
236 public void error( final SAXParseException spe )
237 throws SAXException
238 {
239 throw spe;
240 }
241
242 /***
243 * Rethrow exception and dont attempt to do
244 * any error handling.
245 *
246 * @param spe the input exception
247 * @throws SAXException always thrown
248 */
249 public void fatalError( final SAXParseException spe )
250 throws SAXException
251 {
252 throw spe;
253 }
254
255 /***
256 * Utility method to derive current location of
257 * XML parser. Attempts to build up a string containing
258 * systemID:lineNumber:columnNumber such as
259 * "file.xml:20:3" if parser supports all fields.
260 *
261 * @return the location description
262 */
263 protected final String getLocationDescription()
264 {
265 if( null == m_locator ||
266 null == m_locator.getSystemId() )
267 {
268 return UNKNOWN;
269 }
270 else if( -1 == m_locator.getLineNumber() )
271 {
272 return m_locator.getSystemId();
273 }
274 else if( -1 == m_locator.getColumnNumber() )
275 {
276 return m_locator.getSystemId() + ":" +
277 m_locator.getLineNumber();
278 }
279 else
280 {
281 return m_locator.getSystemId() + ':' +
282 m_locator.getLineNumber() + ':' +
283 m_locator.getColumnNumber();
284 }
285 }
286
287 /***
288 * Users may subclass this method to process attribute
289 * prior to it being set.
290 *
291 * @param configuration the associated configuration
292 * @param name the attribute name
293 * @param value the attribute value
294 * @return the attribute value
295 */
296 protected String processAttributeText( final Configuration configuration,
297 final String name,
298 final String value )
299 {
300 return value;
301 }
302
303 /***
304 * Users may subclass this method to process content
305 * prior to it being set.
306 *
307 * @param configuration the associated configuration
308 * @param value the value
309 * @return the value
310 */
311 protected String processValueText( final Configuration configuration,
312 final String value )
313 {
314 return value;
315 }
316 }
This page was automatically generated by Maven