1
2
3
4
5
6
7
8 package org.codehaus.metaclass.io;
9
10 import java.util.ArrayList;
11 import java.util.Properties;
12 import org.codehaus.metaclass.model.Attribute;
13 import org.codehaus.metaclass.model.ClassDescriptor;
14 import org.codehaus.metaclass.model.FieldDescriptor;
15 import org.codehaus.metaclass.model.MethodDescriptor;
16 import org.codehaus.metaclass.model.ParameterDescriptor;
17 import org.w3c.dom.Element;
18 import org.w3c.dom.Node;
19 import org.w3c.dom.NodeList;
20 import org.w3c.dom.Attr;
21 import org.w3c.dom.Document;
22
23 /***
24 * Utility class to build a ClassDescriptor from a DOM
25 * representation Element.
26 *
27 * @author Peter Donald
28 * @version $Revision: 1.13 $ $Date: 2003/11/27 08:09:53 $
29 */
30 public final class DOMMetaClassDeserializer
31 {
32 /***
33 * Build a ClassDescriptor from a Document.
34 *
35 * @param document the document
36 * @return the ClassDescriptor
37 * @throws Exception if document malformed
38 */
39 public ClassDescriptor buildClassDescriptor( final Document document )
40 throws Exception
41 {
42 return buildClassDescriptor( document.getDocumentElement() );
43 }
44
45 /***
46 * Build a ClassDescriptor from element.
47 *
48 * @param element the element
49 * @return the ClassDescriptor
50 * @throws Exception if element malformed
51 */
52 public ClassDescriptor buildClassDescriptor( final Element element )
53 throws Exception
54 {
55 expectElement( element, MetaClassIOXml.CLASS_ELEMENT );
56 final String type =
57 expectAttribute( element, MetaClassIOXml.TYPE_ATTRIBUTE );
58 Attribute[] attributes = Attribute.EMPTY_SET;
59 MethodDescriptor[] methods = MethodDescriptor.EMPTY_SET;
60 FieldDescriptor[] fields = FieldDescriptor.EMPTY_SET;
61 final NodeList nodes = element.getChildNodes();
62 final int length = nodes.getLength();
63 for( int i = 0; i < length; i++ )
64 {
65 final Node node = nodes.item( i );
66 final short nodeType = node.getNodeType();
67 if( nodeType == Node.ELEMENT_NODE )
68 {
69 final Element child = (Element)node;
70 final String childName = child.getNodeName();
71 if( childName.equals( MetaClassIOXml.METHODS_ELEMENT ) )
72 {
73 methods = buildMethods( child );
74 }
75 else if( childName.equals( MetaClassIOXml.FIELDS_ELEMENT ) )
76 {
77 fields = buildFields( child );
78 }
79 else
80 {
81 attributes = buildAttributes( child );
82 }
83 }
84 }
85 return new ClassDescriptor( type,
86 attributes,
87 attributes,
88 fields,
89 methods );
90 }
91
92 /***
93 * Build a set of methods from element.
94 *
95 * @param element the element
96 * @return the methods
97 * @throws Exception if element malformed
98 */
99 MethodDescriptor[] buildMethods( final Element element )
100 throws Exception
101 {
102 expectElement( element, MetaClassIOXml.METHODS_ELEMENT );
103
104 final ArrayList methods = new ArrayList();
105 final NodeList nodes = element.getChildNodes();
106 final int length = nodes.getLength();
107 for( int i = 0; i < length; i++ )
108 {
109 final Node node = nodes.item( i );
110 final short nodeType = node.getNodeType();
111 if( nodeType == Node.ELEMENT_NODE )
112 {
113 final MethodDescriptor field = buildMethod( (Element)node );
114 methods.add( field );
115 }
116 }
117
118 return (MethodDescriptor[])methods.
119 toArray( new MethodDescriptor[ methods.size() ] );
120 }
121
122 /***
123 * Build a method from element.
124 *
125 * @param element the element
126 * @return the method
127 * @throws Exception if element malformed
128 */
129 MethodDescriptor buildMethod( final Element element )
130 throws Exception
131 {
132 expectElement( element, MetaClassIOXml.METHOD_ELEMENT );
133 final String name =
134 expectAttribute( element, MetaClassIOXml.NAME_ATTRIBUTE );
135 final String type =
136 expectAttribute( element, MetaClassIOXml.TYPE_ATTRIBUTE );
137 Attribute[] attributes = Attribute.EMPTY_SET;
138 ParameterDescriptor[] parameters = ParameterDescriptor.EMPTY_SET;
139 final NodeList nodes = element.getChildNodes();
140 final int length = nodes.getLength();
141 for( int i = 0; i < length; i++ )
142 {
143 final Node node = nodes.item( i );
144 final short nodeType = node.getNodeType();
145 if( nodeType == Node.ELEMENT_NODE )
146 {
147 final Element child = (Element)node;
148 final String childName = child.getNodeName();
149 if( childName.equals( MetaClassIOXml.PARAMETERS_ELEMENT ) )
150 {
151 parameters = buildParameters( child );
152 }
153 else
154 {
155 attributes = buildAttributes( child );
156 }
157 }
158 }
159 return new MethodDescriptor( name, type, parameters, attributes, attributes );
160 }
161
162 /***
163 * Build a set of method parameters from element.
164 *
165 * @param element the element
166 * @return the method parameters
167 * @throws Exception if element malformed
168 */
169 ParameterDescriptor[] buildParameters( final Element element )
170 throws Exception
171 {
172 expectElement( element, MetaClassIOXml.PARAMETERS_ELEMENT );
173
174 final ArrayList parameters = new ArrayList();
175 final NodeList nodes = element.getChildNodes();
176 final int length = nodes.getLength();
177 for( int i = 0; i < length; i++ )
178 {
179 final Node node = nodes.item( i );
180 final short nodeType = node.getNodeType();
181 if( nodeType == Node.ELEMENT_NODE )
182 {
183 final ParameterDescriptor parameter =
184 buildParameter( (Element)node );
185 parameters.add( parameter );
186 }
187 }
188
189 return (ParameterDescriptor[])parameters.
190 toArray( new ParameterDescriptor[ parameters.size() ] );
191 }
192
193 /***
194 * Build a method parameter from element.
195 *
196 * @param element the element
197 * @return the method parameter
198 * @throws Exception if element malformed
199 */
200 ParameterDescriptor buildParameter( final Element element )
201 throws Exception
202 {
203 expectElement( element, MetaClassIOXml.PARAMETER_ELEMENT );
204 final String name =
205 expectAttribute( element, MetaClassIOXml.NAME_ATTRIBUTE );
206 final String type =
207 expectAttribute( element, MetaClassIOXml.TYPE_ATTRIBUTE );
208
209 return new ParameterDescriptor( name, type );
210 }
211
212 /***
213 * Build a set of fields from element.
214 *
215 * @param element the element
216 * @return the fields
217 * @throws Exception if element malformed
218 */
219 FieldDescriptor[] buildFields( final Element element )
220 throws Exception
221 {
222 expectElement( element, MetaClassIOXml.FIELDS_ELEMENT );
223
224 final ArrayList fields = new ArrayList();
225 final NodeList nodes = element.getChildNodes();
226 final int length = nodes.getLength();
227 for( int i = 0; i < length; i++ )
228 {
229 final Node node = nodes.item( i );
230 final short nodeType = node.getNodeType();
231 if( nodeType == Node.ELEMENT_NODE )
232 {
233 final FieldDescriptor field = buildField( (Element)node );
234 fields.add( field );
235 }
236 }
237
238 return (FieldDescriptor[])fields.
239 toArray( new FieldDescriptor[ fields.size() ] );
240 }
241
242 /***
243 * Build a field from element.
244 *
245 * @param element the element
246 * @return the field
247 * @throws Exception if element malformed
248 */
249 FieldDescriptor buildField( final Element element )
250 throws Exception
251 {
252 expectElement( element, MetaClassIOXml.FIELD_ELEMENT );
253 final String name =
254 expectAttribute( element, MetaClassIOXml.NAME_ATTRIBUTE );
255 final String type =
256 expectAttribute( element, MetaClassIOXml.TYPE_ATTRIBUTE );
257 Attribute[] attributes = Attribute.EMPTY_SET;
258 final NodeList nodes = element.getChildNodes();
259 final int length = nodes.getLength();
260 for( int i = 0; i < length; i++ )
261 {
262 final Node node = nodes.item( i );
263 final short nodeType = node.getNodeType();
264 if( nodeType == Node.ELEMENT_NODE )
265 {
266 attributes = buildAttributes( (Element)node );
267 }
268 }
269 return new FieldDescriptor( name, type, attributes, attributes );
270 }
271
272 /***
273 * Build a set of attributes from element.
274 *
275 * @param element the element
276 * @return the attributes
277 * @throws Exception if element malformed
278 */
279 Attribute[] buildAttributes( final Element element )
280 throws Exception
281 {
282 expectElement( element, MetaClassIOXml.ATTRIBUTES_ELEMENT );
283
284 final ArrayList attributes = new ArrayList();
285 final NodeList nodes = element.getChildNodes();
286 final int length = nodes.getLength();
287 for( int i = 0; i < length; i++ )
288 {
289 final Node node = nodes.item( i );
290 final short nodeType = node.getNodeType();
291 if( nodeType == Node.ELEMENT_NODE )
292 {
293 final Attribute attribute = buildAttribute( (Element)node );
294 attributes.add( attribute );
295 }
296 }
297
298 return (Attribute[])attributes.
299 toArray( new Attribute[ attributes.size() ] );
300 }
301
302 /***
303 * Build attribute from specified element.
304 *
305 * @param element the element
306 * @return the attribute
307 * @throws Exception if element malformed
308 */
309 Attribute buildAttribute( final Element element )
310 throws Exception
311 {
312 expectElement( element, MetaClassIOXml.ATTRIBUTE_ELEMENT );
313 final String name =
314 expectAttribute( element, MetaClassIOXml.NAME_ATTRIBUTE );
315
316 final StringBuffer sb = new StringBuffer();
317 final Properties parameters = new Properties();
318 final NodeList nodes = element.getChildNodes();
319 final int length = nodes.getLength();
320 for( int i = 0; i < length; i++ )
321 {
322 final Node node = nodes.item( i );
323 final short nodeType = node.getNodeType();
324 if( nodeType == Node.ELEMENT_NODE )
325 {
326 buildParam( (Element)node, parameters );
327 }
328 else if( nodeType == Node.TEXT_NODE ||
329 nodeType == Node.CDATA_SECTION_NODE )
330 {
331 final String value = node.getNodeValue();
332 sb.append( value );
333 }
334 }
335
336 final String value = sb.toString().trim();
337 if( 0 != value.length() &&
338 0 < parameters.size() )
339 {
340 final String message =
341 "Attribute named " + name +
342 " specified both a value (" + value + ") " +
343 "and parameters (" + parameters + ").";
344 throw new Exception( message );
345 }
346 if( 0 == value.length() )
347 {
348 return new Attribute( name, parameters );
349 }
350 else
351 {
352 return new Attribute( name, value );
353 }
354 }
355
356 /***
357 * Build a parameter from element and add to specified parameters.
358 *
359 * @param element the element
360 * @param parameters the parameters
361 * @throws Exception if element malformed
362 */
363 void buildParam( final Element element,
364 final Properties parameters )
365 throws Exception
366 {
367 expectElement( element, MetaClassIOXml.PARAM_ELEMENT );
368 final String name =
369 expectAttribute( element, MetaClassIOXml.NAME_ATTRIBUTE );
370 final String value =
371 expectAttribute( element, MetaClassIOXml.VALUE_ATTRIBUTE );
372 parameters.setProperty( name, value );
373 }
374
375 /***
376 * Expect that specified element has specified name else
377 * throw an exception.
378 *
379 * @param element the element
380 * @param name the name
381 * @throws Exception if element does not have name
382 */
383 void expectElement( final Element element,
384 final String name )
385 throws Exception
386 {
387 final String actual = element.getTagName();
388 if( !actual.equals( name ) )
389 {
390 final String message = "Unexpected element. " +
391 "Expected: " + name + ". Actual: " + actual +
392 " @ " + getPathDescription( element ) + ".";
393 throw new Exception( message );
394 }
395 }
396
397 /***
398 * Expect that specified element has attribute with specified
399 * name and return value. If attribute can not be located then
400 * throw an exception.
401 *
402 * @param element the element
403 * @param name the attributes name
404 * @return the attributes value
405 * @throws Exception if unable to locate attribute
406 */
407 String expectAttribute( final Element element,
408 final String name )
409 throws Exception
410 {
411 final Attr actual = element.getAttributeNode( name );
412 if( null == actual )
413 {
414 final String message =
415 "Element named " + element.getTagName() +
416 " missing attribute named " + name +
417 " @ " + getPathDescription( element ) + ".";
418 throw new Exception( message );
419 }
420 return actual.getValue();
421 }
422
423 /***
424 * Return a description of path to specified element.
425 * The path is separate by "/" and starts with root
426 * element descending to specified element.
427 *
428 * @param cause the element
429 * @return the path description
430 */
431 String getPathDescription( final Element cause )
432 {
433 final StringBuffer sb = new StringBuffer();
434
435 Element element = cause;
436 while( true )
437 {
438 if( sb.length() > 0 )
439 {
440 sb.insert( 0, "/" );
441 }
442 sb.insert( 0, element.getNodeName() );
443 final Node parentNode = element.getParentNode();
444 if( parentNode instanceof Element )
445 {
446 element = (Element)parentNode;
447 }
448 else
449 {
450 break;
451 }
452 }
453
454 return sb.toString();
455 }
456 }