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