1 package org.codehaus.modello.plugin.dom4j;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import javax.inject.Named;
26
27 import java.io.IOException;
28 import java.util.List;
29 import java.util.Properties;
30
31 import org.codehaus.modello.ModelloException;
32 import org.codehaus.modello.model.Model;
33 import org.codehaus.modello.model.ModelAssociation;
34 import org.codehaus.modello.model.ModelClass;
35 import org.codehaus.modello.model.ModelDefault;
36 import org.codehaus.modello.model.ModelField;
37 import org.codehaus.modello.plugin.java.javasource.JClass;
38 import org.codehaus.modello.plugin.java.javasource.JMethod;
39 import org.codehaus.modello.plugin.java.javasource.JParameter;
40 import org.codehaus.modello.plugin.java.javasource.JSourceCode;
41 import org.codehaus.modello.plugin.java.javasource.JSourceWriter;
42 import org.codehaus.modello.plugin.java.metadata.JavaFieldMetadata;
43 import org.codehaus.modello.plugin.model.ModelClassMetadata;
44 import org.codehaus.modello.plugins.xml.AbstractXmlJavaGenerator;
45 import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
46 import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
47 import org.codehaus.modello.plugins.xml.metadata.XmlModelMetadata;
48
49
50
51
52
53
54
55
56
57 @Named("dom4j-writer")
58 public class Dom4jWriterGenerator extends AbstractXmlJavaGenerator {
59
60 private boolean requiresDomSupport;
61
62 public void generate(Model model, Properties parameters) throws ModelloException {
63 initialize(model, parameters);
64
65 requiresDomSupport = false;
66
67 try {
68 generateDom4jWriter();
69 } catch (IOException ex) {
70 throw new ModelloException("Exception while generating Dom4j Writer.", ex);
71 }
72 }
73
74 private void generateDom4jWriter() throws ModelloException, IOException {
75 Model objectModel = getModel();
76
77 String packageName =
78 objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.dom4j";
79
80 String marshallerName = getFileName("Dom4jWriter");
81
82 JSourceWriter sourceWriter = newJSourceWriter(packageName, marshallerName);
83
84 JClass jClass = new JClass(packageName + '.' + marshallerName);
85 initHeader(jClass);
86 suppressAllWarnings(objectModel, jClass);
87
88 jClass.addImport("java.io.OutputStream");
89 jClass.addImport("java.io.Writer");
90 jClass.addImport("java.util.Arrays");
91 jClass.addImport("java.util.Iterator");
92 jClass.addImport("java.util.Locale");
93 jClass.addImport("java.text.DateFormat");
94 jClass.addImport("org.dom4j.Document");
95 jClass.addImport("org.dom4j.DocumentException");
96 jClass.addImport("org.dom4j.DocumentFactory");
97 jClass.addImport("org.dom4j.Element");
98 jClass.addImport("org.dom4j.io.OutputFormat");
99 jClass.addImport("org.dom4j.io.XMLWriter");
100
101 addModelImports(jClass, null);
102
103 String root = objectModel.getRoot(getGeneratedVersion());
104
105 ModelClass rootClass = objectModel.getClass(root, getGeneratedVersion());
106
107 String rootElement = resolveTagName(rootClass);
108 String variableName = uncapitalise(root);
109
110
111
112
113
114 JMethod marshall = new JMethod("write");
115
116 marshall.addParameter(new JParameter(new JClass("Writer"), "writer"));
117 marshall.addParameter(new JParameter(new JClass(root), variableName));
118
119 marshall.addException(new JClass("java.io.IOException"));
120
121 JSourceCode sc = marshall.getSourceCode();
122
123 sc.add("Document document = new DocumentFactory().createDocument();");
124
125 sc.add("write" + root + "( " + variableName + ", \"" + rootElement + "\", document );");
126
127
128 sc.add("OutputFormat format = OutputFormat.createPrettyPrint();");
129 sc.add("format.setLineSeparator( System.getProperty( \"line.separator\" ) );");
130 sc.add("XMLWriter serializer = new XMLWriter( writer, format );");
131
132 sc.add("serializer.write( document );");
133
134 jClass.addMethod(marshall);
135
136
137
138
139
140 marshall = new JMethod("write");
141
142 marshall.addParameter(new JParameter(new JClass("OutputStream"), "stream"));
143 marshall.addParameter(new JParameter(new JClass(root), variableName));
144
145 marshall.addException(new JClass("java.io.IOException"));
146
147 sc = marshall.getSourceCode();
148
149 sc.add("Document document = new DocumentFactory().createDocument();");
150
151 sc.add("write" + root + "( " + variableName + ", \"" + rootElement + "\", document );");
152
153
154 sc.add("OutputFormat format = OutputFormat.createPrettyPrint();");
155 sc.add("format.setLineSeparator( System.getProperty( \"line.separator\" ) );");
156 sc.add("format.setEncoding( " + variableName + ".getModelEncoding() );");
157 sc.add("XMLWriter serializer = new XMLWriter( stream, format );");
158
159 sc.add("serializer.write( document );");
160
161 jClass.addMethod(marshall);
162
163 writeAllClasses(objectModel, jClass);
164
165 if (requiresDomSupport) {
166 jClass.addImport("org.codehaus.plexus.util.xml.Xpp3Dom");
167 writeDomHelpers(jClass);
168 }
169
170 jClass.print(sourceWriter);
171
172 sourceWriter.close();
173 }
174
175 private void writeAllClasses(Model objectModel, JClass jClass) throws ModelloException {
176 for (ModelClass clazz : getClasses(objectModel)) {
177 writeClass(clazz, jClass);
178 }
179 }
180
181 private void writeClass(ModelClass modelClass, JClass jClass) throws ModelloException {
182 String className = modelClass.getName();
183
184 String uncapClassName = uncapitalise(className);
185
186 JMethod marshall = new JMethod("write" + className);
187 marshall.getModifiers().makePrivate();
188
189 marshall.addParameter(new JParameter(new JClass(className), uncapClassName));
190 marshall.addParameter(new JParameter(new JClass("String"), "tagName"));
191
192 ModelClassMetadata classMetadata = (ModelClassMetadata) modelClass.getMetadata(ModelClassMetadata.ID);
193
194 marshall.addParameter(new JParameter(new JClass("org.dom4j.Branch"), "parentElement"));
195
196 marshall.addException(new JClass("java.io.IOException"));
197
198 JSourceCode sc = marshall.getSourceCode();
199
200 sc.add("if ( " + uncapClassName + " != null )");
201
202 sc.add("{");
203 sc.indent();
204
205 XmlModelMetadata xmlModelMetadata =
206 (XmlModelMetadata) modelClass.getModel().getMetadata(XmlModelMetadata.ID);
207
208
209 if (classMetadata.isRootElement() && (xmlModelMetadata.getNamespace() != null)) {
210 String namespace = xmlModelMetadata.getNamespace(getGeneratedVersion());
211 sc.add("Element element = parentElement.addElement( tagName, \"" + namespace + "\" );");
212
213 if (xmlModelMetadata.getSchemaLocation() != null) {
214 String url = xmlModelMetadata.getSchemaLocation(getGeneratedVersion());
215
216 sc.add("element.addAttribute( \"xmlns:xsi\", \"http://www.w3.org/2001/XMLSchema-instance\" );");
217 sc.add("element.addAttribute( \"xsi:schemaLocation\", \"" + namespace + " " + url + "\" );");
218 }
219 } else {
220 sc.add("Element element = parentElement.addElement( tagName );");
221 }
222
223 ModelField contentField = null;
224
225 String contentValue = null;
226
227 List<ModelField> modelFields = getFieldsForXml(modelClass, getGeneratedVersion());
228
229
230 for (ModelField field : modelFields) {
231 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
232
233 JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
234
235 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
236
237 String type = field.getType();
238
239 String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
240
241 if (xmlFieldMetadata.isContent()) {
242 contentField = field;
243 contentValue = value;
244 continue;
245 }
246
247 if (xmlFieldMetadata.isAttribute()) {
248 sc.add(getValueChecker(type, value, field));
249
250 sc.add("{");
251 sc.addIndented("element.addAttribute( \"" + fieldTagName + "\", "
252 + getValue(field.getType(), value, xmlFieldMetadata) + " );");
253 sc.add("}");
254 }
255 }
256
257 if (contentField != null) {
258 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) contentField.getMetadata(XmlFieldMetadata.ID);
259 sc.add("element.setText( " + getValue(contentField.getType(), contentValue, xmlFieldMetadata) + " );");
260 }
261
262
263 for (ModelField field : modelFields) {
264 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
265
266 if (xmlFieldMetadata.isContent()) {
267
268 continue;
269 }
270
271 if (!xmlFieldMetadata.isAttribute()) {
272 processField(field, xmlFieldMetadata, uncapClassName, sc, modelClass, jClass);
273 }
274 }
275
276 sc.unindent();
277 sc.add("}");
278
279 jClass.addMethod(marshall);
280 }
281
282 private void processField(
283 ModelField field,
284 XmlFieldMetadata xmlFieldMetadata,
285 String uncapClassName,
286 JSourceCode sc,
287 ModelClass modelClass,
288 JClass jClass)
289 throws ModelloException {
290 JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
291
292 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
293
294 String type = field.getType();
295
296 String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
297
298 if (field instanceof ModelAssociation) {
299 ModelAssociation association = (ModelAssociation) field;
300
301 String associationName = association.getName();
302
303 if (association.isOneMultiplicity()) {
304 sc.add(getValueChecker(type, value, association));
305
306 sc.add("{");
307 sc.addIndented("write" + association.getTo() + "( " + value + ", \"" + fieldTagName + "\", element );");
308 sc.add("}");
309 } else {
310
311
312 XmlAssociationMetadata xmlAssociationMetadata =
313 (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
314
315 String valuesTagName = resolveTagName(fieldTagName, xmlAssociationMetadata);
316
317 type = association.getType();
318 String toType = association.getTo();
319
320 boolean wrappedItems = xmlAssociationMetadata.isWrappedItems();
321
322 if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
323 sc.add(getValueChecker(type, value, association));
324
325 sc.add("{");
326 sc.indent();
327
328 sc.add("Element listElement = element;");
329
330 if (wrappedItems) {
331 sc.add("listElement = element.addElement( \"" + fieldTagName + "\" );");
332 }
333
334 sc.add("for ( Iterator iter = " + value + ".iterator(); iter.hasNext(); )");
335
336 sc.add("{");
337 sc.indent();
338
339 if (isClassInModel(association.getTo(), modelClass.getModel())) {
340 sc.add(toType + " o = (" + toType + ") iter.next();");
341
342 sc.add("write" + toType + "( o, \"" + valuesTagName + "\", listElement );");
343 } else {
344 sc.add(toType + " " + singular(uncapitalise(field.getName())) + " = (" + toType
345 + ") iter.next();");
346
347 sc.add("listElement.addElement( \"" + valuesTagName + "\" ).setText( "
348 + singular(uncapitalise(field.getName())) + " );");
349 }
350
351 sc.unindent();
352 sc.add("}");
353
354 sc.unindent();
355 sc.add("}");
356 } else {
357
358
359 sc.add(getValueChecker(type, value, field));
360
361 sc.add("{");
362 sc.indent();
363
364 sc.add("Element listElement = element;");
365
366 if (wrappedItems) {
367 sc.add("listElement = element.addElement( \"" + fieldTagName + "\" );");
368 }
369
370 sc.add("for ( Iterator iter = " + value + ".keySet().iterator(); iter.hasNext(); )");
371
372 sc.add("{");
373 sc.indent();
374
375 sc.add("String key = (String) iter.next();");
376
377 sc.add("String value = (String) " + value + ".get( key );");
378
379 if (xmlAssociationMetadata.isMapExplode()) {
380 sc.add("Element assocElement = listElement.addElement( \"" + singular(associationName)
381 + "\" );");
382 sc.add("assocElement.addElement( \"key\" ).setText( key );");
383 sc.add("assocElement.addElement( \"value\" ).setText( value );");
384 } else {
385 sc.add("listElement.addElement( key ).setText( value );");
386 }
387
388 sc.unindent();
389 sc.add("}");
390
391 sc.unindent();
392 sc.add("}");
393 }
394 }
395 } else {
396 sc.add(getValueChecker(type, value, field));
397
398 sc.add("{");
399 sc.indent();
400
401 if ("DOM".equals(field.getType())) {
402 sc.add("writeXpp3DomToElement( (Xpp3Dom) " + value + ", element );");
403
404 requiresDomSupport = true;
405 } else {
406 sc.add("element.addElement( \"" + fieldTagName + "\" ).setText( "
407 + getValue(field.getType(), value, xmlFieldMetadata) + " );");
408 }
409
410 sc.unindent();
411 sc.add("}");
412 }
413 }
414
415 private void writeDomHelpers(JClass jClass) {
416 JMethod method = new JMethod("writeXpp3DomToElement");
417 method.getModifiers().makePrivate();
418
419 method.addParameter(new JParameter(new JClass("Xpp3Dom"), "xpp3Dom"));
420 method.addParameter(new JParameter(new JClass("Element"), "parentElement"));
421
422 JSourceCode sc = method.getSourceCode();
423
424 sc.add("Element element = parentElement.addElement( xpp3Dom.getName() );");
425
426 sc.add("if ( xpp3Dom.getValue() != null )");
427 sc.add("{");
428 sc.addIndented("element.setText( xpp3Dom.getValue() );");
429 sc.add("}");
430
431 sc.add("for ( Iterator i = Arrays.asList( xpp3Dom.getAttributeNames() ).iterator(); i.hasNext(); )");
432 sc.add("{");
433 sc.indent();
434
435 sc.add("String name = (String) i.next();");
436 sc.add("element.addAttribute( name, xpp3Dom.getAttribute( name ) );");
437
438 sc.unindent();
439 sc.add("}");
440
441 sc.add("for ( Iterator i = Arrays.asList( xpp3Dom.getChildren() ).iterator(); i.hasNext(); )");
442 sc.add("{");
443 sc.indent();
444
445 sc.add("Xpp3Dom child = (Xpp3Dom) i.next();");
446 sc.add("writeXpp3DomToElement( child, element );");
447
448 sc.unindent();
449 sc.add("}");
450
451 jClass.addMethod(method);
452 }
453 }