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