1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 package org.exolab.castor.builder.descriptors;
51
52 import java.util.Iterator;
53 import java.util.List;
54
55 import org.exolab.castor.builder.BuilderConfiguration;
56 import org.exolab.castor.builder.SGTypes;
57 import org.exolab.castor.builder.factory.XMLFieldHandlerFactory;
58 import org.exolab.castor.builder.info.ClassInfo;
59 import org.exolab.castor.builder.info.CollectionInfo;
60 import org.exolab.castor.builder.info.FieldInfo;
61 import org.exolab.castor.builder.info.XMLInfo;
62 import org.exolab.castor.builder.info.NodeType;
63 import org.exolab.castor.builder.info.nature.XMLInfoNature;
64 import org.exolab.castor.builder.types.XSList;
65 import org.exolab.castor.builder.types.XSListType;
66 import org.exolab.castor.builder.types.XSType;
67 import org.exolab.castor.mapping.FieldDescriptor;
68 import org.exolab.castor.xml.Validator;
69 import org.exolab.castor.xml.XMLConstants;
70 import org.exolab.castor.xml.XMLFieldDescriptor;
71 import org.exolab.javasource.JClass;
72 import org.exolab.javasource.JConstant;
73 import org.exolab.javasource.JConstructor;
74 import org.exolab.javasource.JField;
75 import org.exolab.javasource.JMember;
76 import org.exolab.javasource.JModifiers;
77 import org.exolab.javasource.JNaming;
78 import org.exolab.javasource.JPrimitiveType;
79 import org.exolab.javasource.JSourceCode;
80 import org.exolab.javasource.JType;
81
82
83
84
85
86
87
88 public final class DescriptorSourceFactory {
89
90 private static final JClass GENERALIZED_FIELD_HANDLER_CLASS =
91 new JClass("org.exolab.castor.mapping.GeneralizedFieldHandler");
92
93 private static final String FIELD_VALIDATOR_NAME = "fieldValidator";
94
95
96 private final BuilderConfiguration _config;
97
98
99 private XMLFieldHandlerFactory _xmlFieldHandlerFactory;
100
101
102
103
104
105
106 public DescriptorSourceFactory(final BuilderConfiguration config) {
107 if (config == null) {
108 String err = "The argument 'config' must not be null.";
109 throw new IllegalArgumentException(err);
110 }
111 _config = config;
112 _xmlFieldHandlerFactory = new XMLFieldHandlerFactory(config);
113 }
114
115
116
117
118
119
120
121
122 public JClass createSource(final ClassInfo classInfo) {
123 JClass jClass = classInfo.getJClass();
124 String localClassName = jClass.getLocalName();
125
126 String descriptorClassName = getQualifiedDescriptorClassName(jClass.getName());
127 DescriptorJClass classDesc = new DescriptorJClass(_config, descriptorClassName, jClass);
128
129
130 JConstructor cons = classDesc.getConstructor(0);
131 JSourceCode jsc = cons.getSourceCode();
132 XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
133
134
135 String nsPrefix = xmlNature.getNamespacePrefix();
136 if ((nsPrefix != null) && (nsPrefix.length() > 0)) {
137 jsc.add("_nsPrefix = \"");
138 jsc.append(nsPrefix);
139 jsc.append("\";");
140 }
141
142
143 String nsURI = xmlNature.getNamespaceURI();
144 if ((nsURI != null) && (nsURI.length() > 0)) {
145 jsc.add("_nsURI = \"");
146 jsc.append(nsURI);
147 jsc.append("\";");
148 }
149
150
151 String xmlName = xmlNature.getNodeName();
152 if (xmlName != null) {
153 jsc.add("_xmlName = \"");
154 jsc.append(xmlName);
155 jsc.append("\";");
156 }
157
158
159 boolean elementDefinition = xmlNature.isElementDefinition();
160 jsc.add("_elementDefinition = ");
161 jsc.append(new Boolean(elementDefinition).toString());
162 jsc.append(";");
163
164
165 if (xmlNature.isChoice()) {
166 jsc.add("");
167 jsc.add("//-- set grouping compositor");
168 jsc.add("setCompositorAsChoice();");
169 } else if (xmlNature.isSequence()) {
170 jsc.add("");
171 jsc.add("//-- set grouping compositor");
172 jsc.add("setCompositorAsSequence();");
173 }
174
175
176 List<String> substitutionGroups = xmlNature.getSubstitutionGroups();
177 if (!substitutionGroups.isEmpty()) {
178 jsc.add("java.util.List substitutionGroups = new java.util.ArrayList();");
179 Iterator<String> substitutionGroupIter = substitutionGroups.iterator();
180 while (substitutionGroupIter.hasNext()) {
181 String substitutionGroup = substitutionGroupIter.next();
182 jsc.add("substitutionGroups.add(\"");
183 jsc.append(substitutionGroup);
184 jsc.append("\");");
185 }
186 jsc.add("setSubstitutes(substitutionGroups);");
187 }
188
189
190
191 if (classInfo.getFieldCount() == 0) {
192 return classDesc;
193 }
194
195
196 jsc.add("org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;");
197 jsc.add("org.exolab.castor.mapping.FieldHandler handler = null;");
198 jsc.add("org.exolab.castor.xml.FieldValidator fieldValidator = null;");
199
200
201 if (classInfo.allowContent()) {
202 createDescriptor(classDesc, classInfo.getTextField(), localClassName, null, jsc);
203 }
204
205 ClassInfo base = classInfo.getBaseClass();
206 FieldInfo[] atts = classInfo.getAttributeFields();
207
208
209
210
211
212 jsc.add("//-- initialize attribute descriptors");
213 jsc.add("");
214
215 for (int i = 0; i < atts.length; i++) {
216 FieldInfo member = atts[i];
217
218 if (member.isTransient()) {
219 continue;
220 }
221
222 if (base != null) {
223 String baseNodeName = new XMLInfoNature(member).getNodeName();
224 if (baseNodeName.equals(XMLInfo.CHOICE_NODE_NAME_ERROR_INDICATION)) {
225 createDescriptor(classDesc, member, localClassName, nsURI, jsc);
226 } else {
227 if (base.getAttributeField(baseNodeName) != null) {
228 createRestrictedDescriptor(member, jsc);
229 } else {
230 createDescriptor(classDesc, member, localClassName,
231 nsURI, jsc);
232 }
233 }
234 } else {
235 createDescriptor(classDesc, member, localClassName, nsURI, jsc);
236 }
237 }
238
239
240
241
242 FieldInfo[] elements = classInfo.getElementFields();
243
244 jsc.add("//-- initialize element descriptors");
245 jsc.add("");
246
247 for (int i = 0; i < elements.length; i++) {
248 FieldInfo member = elements[i];
249 XMLInfoNature fieldNature = new XMLInfoNature(member);
250
251
252 if (member.isTransient()) {
253 continue;
254 }
255
256 if (base != null) {
257 String baseNodeName = fieldNature.getNodeName();
258 if (baseNodeName == null) {
259 createDescriptor(classDesc, member, localClassName, nsURI, jsc);
260 } else if (baseNodeName.equals(XMLInfo.CHOICE_NODE_NAME_ERROR_INDICATION)) {
261 createDescriptor(classDesc, member, localClassName, nsURI, jsc);
262 } else {
263 if (base.getElementField(baseNodeName) != null) {
264 createRestrictedDescriptor(member, jsc);
265 } else {
266 createDescriptor(classDesc, member, localClassName,
267 nsURI, jsc);
268 }
269 }
270 } else {
271 createDescriptor(classDesc, member, localClassName, nsURI, jsc);
272 }
273 }
274
275 return classDesc;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291 private String getQualifiedDescriptorClassName(final String name) {
292 String descPackage = JNaming.getPackageFromClassName(name);
293 String descClassName = JNaming.getLocalNameFromClassName(name);
294
295 if (descPackage != null && descPackage.length() > 0) {
296 descPackage = descPackage + "." + XMLConstants.DESCRIPTOR_PACKAGE + ".";
297 } else {
298 descPackage = "";
299 }
300 return descPackage + descClassName + XMLConstants.DESCRIPTOR_SUFFIX;
301 }
302
303
304
305
306
307
308
309
310
311
312
313 private static void createRestrictedDescriptor(final FieldInfo member, final JSourceCode jsc) {
314 jsc.add("desc = (org.exolab.castor.xml.util.XMLFieldDescriptorImpl) getFieldDescriptor(\"");
315 XMLInfoNature xmlNature = new XMLInfoNature(member);
316 jsc.append(xmlNature.getNodeName());
317 jsc.append("\"");
318 jsc.append(", _nsURI");
319 NodeType nodeType = xmlNature.getNodeType();
320 if (nodeType == NodeType.ELEMENT) {
321 jsc.append(", org.exolab.castor.xml.NodeType.Element);");
322 } else if (nodeType == NodeType.ATTRIBUTE) {
323 jsc.append(", org.exolab.castor.xml.NodeType.Attribute);");
324 } else {
325 jsc.append("org.exolab.castor.xml.NodeType.Text);");
326 }
327
328
329 if (xmlNature.isRequired()) {
330 jsc.add("desc.setRequired(true);");
331 }
332
333
334 addValidationCode(member, jsc);
335 }
336
337
338
339
340
341
342
343
344
345
346
347 private void createDescriptor(final DescriptorJClass classDesc, final FieldInfo member,
348 final String localClassName, final String nsURI,
349 final JSourceCode jsc) {
350
351 XMLInfoNature xmlNature = new XMLInfoNature(member);
352
353 XSType xsType = xmlNature.getSchemaType();
354 XSType xsCollectionType = null;
355
356 boolean any = false;
357 NodeType nodeType = xmlNature.getNodeType();
358 boolean isElement = (nodeType == NodeType.ELEMENT);
359 boolean isAttribute = (nodeType == NodeType.ATTRIBUTE);
360 boolean isText = (nodeType == NodeType.TEXT);
361
362 jsc.add("//-- ");
363 jsc.append(member.getName());
364
365
366 if (member.getName().equals("_anyObject")) {
367 any = true;
368 }
369
370 if (xsType.isCollection()) {
371
372 xsCollectionType = xsType;
373 xsType = new XMLInfoNature(((CollectionInfo) member).getContent()).getSchemaType();
374 }
375
376
377 String nodeName = xmlNature.getNodeName();
378 String nodeNameParam = null;
379 if ((nodeName != null) && (!isText)) {
380
381 nodeNameParam = "\"" + nodeName + "\"";
382 if (_config.classDescFieldNames()) {
383
384 nodeNameParam = nodeName.toUpperCase();
385
386 JConstant constant = new JConstant(SGTypes.STRING, nodeNameParam);
387 constant.setInitString("\"" + nodeName + "\"");
388 classDesc.addMember(constant);
389 }
390 }
391
392
393 jsc.add("desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(");
394 jsc.append(classType(xsType.getJType()));
395 jsc.append(", \"");
396 jsc.append(member.getName());
397 jsc.append("\", ");
398 if (nodeNameParam != null) {
399 jsc.append(nodeNameParam);
400 } else if (isText) {
401 jsc.append("\"PCDATA\"");
402 } else {
403 jsc.append("(java.lang.String) null");
404 }
405
406 if (isElement) {
407 jsc.append(", org.exolab.castor.xml.NodeType.Element);");
408 } else if (isAttribute) {
409 jsc.append(", org.exolab.castor.xml.NodeType.Attribute);");
410 } else if (isText) {
411 jsc.append(", org.exolab.castor.xml.NodeType.Text);");
412 }
413
414 switch (xsType.getType()) {
415 case XSType.STRING_TYPE :
416 jsc.add("desc.setImmutable(true);");
417 break;
418
419 case XSType.IDREF_TYPE :
420 jsc.add("desc.setReference(true);");
421 break;
422 case XSType.ID_TYPE :
423 jsc.add("this._identity = desc;");
424 break;
425 case XSType.QNAME_TYPE :
426 jsc.add("desc.setSchemaType(\"QName\");");
427 break;
428 default :
429 break;
430 }
431
432
433 if (member.getXMLFieldHandler() != null) {
434 String handler = member.getXMLFieldHandler();
435 jsc.add("handler = new " + handler + "();");
436 jsc.add("//-- test for generalized field handler");
437 jsc.add("if (handler instanceof ");
438 jsc.append(GENERALIZED_FIELD_HANDLER_CLASS.getName());
439 jsc.append(")");
440 jsc.add("{");
441 jsc.indent();
442 jsc.add("//-- save reference to user-specified handler");
443 jsc.add(GENERALIZED_FIELD_HANDLER_CLASS.getName());
444 jsc.append(" gfh = (");
445 jsc.append(GENERALIZED_FIELD_HANDLER_CLASS.getName());
446 jsc.append(") handler;");
447 _xmlFieldHandlerFactory.createXMLFieldHandler(
448 member, xsType, localClassName, jsc, true);
449 jsc.add("gfh.setFieldHandler(handler);");
450 jsc.add("handler = gfh;");
451 jsc.unindent();
452 jsc.add("}");
453 } else {
454 _xmlFieldHandlerFactory.createXMLFieldHandler(
455 member, xsType, localClassName, jsc, false);
456 addSpecialHandlerLogic(member, xsType, jsc);
457 }
458
459
460 if (xsCollectionType == null) {
461 jsc.add("desc.setSchemaType(\"" + xsType.getName() + "\");");
462 } else {
463 jsc.add("desc.setSchemaType(\"list\");");
464 jsc.add("desc.setComponentType(\"" + xsType.getName() + "\");");
465 if (xsCollectionType instanceof XSList && ((XSList) xsCollectionType).isDerivedFromXSList()) {
466 jsc.add("desc.setDerivedFromXSList(true);");
467 }
468 }
469 jsc.add("desc.setHandler(handler);");
470
471
472 if (member.isContainer()) {
473 jsc.add("desc.setContainer(true);");
474 String className = xsType.getName();
475
476
477 if (className.equals(localClassName)) {
478 jsc.add("desc.setClassDescriptor(this);");
479 } else {
480 String descriptorClassName = getQualifiedDescriptorClassName(className);
481 jsc.add("desc.setClassDescriptor(new " + descriptorClassName + "());");
482 }
483 }
484
485
486
487 if (xmlNature.getNamespaceURI() != null) {
488 jsc.add("desc.setNameSpaceURI(\"");
489 jsc.append(xmlNature.getNamespaceURI());
490 jsc.append("\");");
491 }
492
493
494 if (xmlNature.isRequired()) {
495 jsc.add("desc.setRequired(true);");
496 }
497
498
499 if (member.isNillable()) {
500 jsc.add("desc.setNillable(true);");
501 }
502
503
504 if (any) {
505 jsc.add("desc.setMatches(\"*\");");
506 }
507
508
509 if (isElement || isAttribute) {
510 jsc.add("desc.setMultivalued(" + xmlNature.isMultivalued());
511 jsc.append(");");
512 }
513
514 jsc.add("addFieldDescriptor(desc);");
515 if (isElement) {
516 jsc.add("addSequenceElement(desc);");
517 }
518 jsc.add("");
519
520 if (isElement) {
521
522 addSubstitutionGroups(member, jsc);
523 }
524
525
526 addValidationCode(member, jsc);
527 }
528
529
530
531
532
533
534 private void addSubstitutionGroups(final FieldInfo member, final JSourceCode jsc) {
535 List<String> substitutionGroupMembers = member.getSubstitutionGroupMembers();
536 if (!substitutionGroupMembers.isEmpty()) {
537 jsc.add("// set possible substitutes for member " + member.getName());
538 jsc.add("java.util.List substitutionGroups" + member.getName()
539 + " = new java.util.ArrayList();");
540 Iterator<String> substitutionGroupIter = substitutionGroupMembers.iterator();
541 while (substitutionGroupIter.hasNext()) {
542 String substitutionGroup = substitutionGroupIter.next();
543 jsc.add("substitutionGroups" + member.getName() + ".add(\"");
544 jsc.append(substitutionGroup);
545 jsc.append("\");");
546 }
547 jsc.add("desc.setSubstitutes(substitutionGroups" + member.getName() + ");");
548 }
549 }
550
551
552
553
554
555
556
557
558
559 private void addSpecialHandlerLogic(final FieldInfo member, final XSType xsType,
560 final JSourceCode jsc) {
561 XMLInfoNature xmlNature = new XMLInfoNature(member);
562
563 if (xsType.isEnumerated()) {
564 jsc.add("handler = new org.exolab.castor.xml.handlers.EnumFieldHandler(");
565 jsc.append(classType(xsType.getJType()));
566 jsc.append(", handler);");
567 jsc.add("desc.setImmutable(true);");
568 } else if (xsType.getType() == XSType.DATETIME_TYPE) {
569 jsc.add("handler = new org.exolab.castor.xml.handlers.DateFieldHandler(");
570 jsc.append("handler);");
571 jsc.add("desc.setImmutable(true);");
572 } else if (xsType.getType() == XSType.DECIMAL_TYPE) {
573 jsc.add("desc.setImmutable(true);");
574 } else if (xmlNature.getSchemaType().isCollection()) {
575
576 switch (xsType.getType()) {
577 case XSType.NMTOKEN_TYPE:
578 case XSType.NMTOKENS_TYPE:
579
580 jsc.add("handler = new org.exolab.castor.xml.handlers.CollectionFieldHandler(");
581 jsc.append("handler, new org.exolab.castor.xml.validators.NameValidator(");
582 jsc.append("org.exolab.castor.xml.XMLConstants.NAME_TYPE_NMTOKEN));");
583 break;
584 case XSType.QNAME_TYPE:
585
586 jsc.add("handler = new org.exolab.castor.xml.handlers.CollectionFieldHandler(");
587 jsc.append("handler, null);");
588 break;
589 case XSType.IDREF_TYPE:
590 case XSType.IDREFS_TYPE:
591
592
593 jsc.add("desc.setMultivalued(");
594 jsc.append("" + xmlNature.isMultivalued());
595 jsc.append(");");
596 break;
597 default:
598 break;
599 }
600 }
601 }
602
603
604
605
606
607
608
609
610 private static void addValidationCode(final FieldInfo member, final JSourceCode jsc) {
611 if (member == null || jsc == null) {
612 return;
613 }
614
615 jsc.add("//-- validation code for: ");
616 jsc.append(member.getName());
617 String validator = member.getValidator();
618 if (validator != null && validator.length() > 0) {
619 jsc.add("fieldValidator = new " + validator + "();");
620 } else {
621 jsc.add("fieldValidator = new org.exolab.castor.xml.FieldValidator();");
622
623
624 if (member.getName().equals("_anyObject")) {
625 jsc.add("desc.setValidator(fieldValidator);");
626 return;
627 }
628
629 XMLInfoNature xmlNature = new XMLInfoNature(member);
630 XSType xsType = xmlNature.getSchemaType();
631
632 if (xsType.isCollection()) {
633 XSListType xsList = (XSListType) xsType;
634
635 jsc.add("fieldValidator.setMinOccurs(");
636 jsc.append(Integer.toString(xsList.getMinimumSize()));
637 jsc.append(");");
638 if (xsList.getMaximumSize() > 0) {
639 jsc.add("fieldValidator.setMaxOccurs(");
640 jsc.append(Integer.toString(xsList.getMaximumSize()));
641 jsc.append(");");
642 }
643 } else if (xmlNature.isRequired()) {
644 jsc.add("fieldValidator.setMinOccurs(1);");
645 }
646
647 jsc.add("{ //-- local scope");
648 jsc.indent();
649 xsType.validationCode(jsc, member.getFixedValue(), FIELD_VALIDATOR_NAME);
650 jsc.unindent();
651 jsc.add("}");
652 }
653 jsc.add("desc.setValidator(fieldValidator);");
654 }
655
656
657
658
659
660
661 private static String classType(final JType jType) {
662 if (jType.isPrimitive()) {
663 JPrimitiveType primitive = (JPrimitiveType) jType;
664 return primitive.getWrapperName() + ".TYPE";
665 }
666 return jType.toString() + ".class";
667 }
668
669 }