1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.exolab.castor.xml;
17
18 import java.text.MessageFormat;
19 import java.util.Locale;
20 import java.util.ResourceBundle;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.castor.xml.XMLProperties;
26 import org.exolab.castor.mapping.ExtendedFieldHandler;
27 import org.exolab.castor.mapping.FieldHandler;
28 import org.exolab.castor.mapping.loader.FieldHandlerImpl;
29 import org.exolab.castor.xml.MarshalFramework.InheritanceMatch;
30 import org.exolab.castor.xml.MarshalFramework.InternalXMLClassDescriptor;
31 import org.exolab.castor.xml.UnmarshalHandler.Arguments;
32 import org.exolab.castor.xml.UnmarshalHandler.ArrayHandler;
33 import org.exolab.castor.xml.util.ContainerElement;
34 import org.exolab.castor.xml.util.XMLClassDescriptorImpl;
35 import org.xml.sax.ContentHandler;
36 import org.xml.sax.SAXException;
37
38
39
40
41
42
43
44
45
46 public class StartElementProcessor {
47
48
49
50
51 private static final Log LOG = LogFactory
52 .getLog(StartElementProcessor.class);
53
54
55
56
57 protected static ResourceBundle resourceBundle;
58
59
60
61
62
63 private final UnmarshalHandler _unmarshalHandler;
64
65 static {
66 resourceBundle = ResourceBundle.getBundle("UnmarshalHandlerMessages",
67 Locale.getDefault());
68 }
69
70
71
72
73
74
75
76
77
78
79 public StartElementProcessor(final UnmarshalHandler unmarshalHandler) {
80 super();
81 _unmarshalHandler = unmarshalHandler;
82 }
83
84 public void compute(String name, String namespace, AttributeSet atts)
85 throws SAXException {
86
87 UnmarshalState state = null;
88 String xmlSpace = null;
89
90
91 if (atts != null) {
92
93 xmlSpace = atts.getValue(UnmarshalHandler.XML_SPACE,
94 Namespaces.XML_NAMESPACE);
95 if (xmlSpace == null) {
96 xmlSpace = atts.getValue(
97 UnmarshalHandler.XML_SPACE_WITH_PREFIX, "");
98 }
99 }
100
101 if (_unmarshalHandler.getStateStack().isEmpty()) {
102
103 _unmarshalHandler.processFirstElement(name, namespace, atts,
104 xmlSpace);
105 return;
106 }
107
108
109 UnmarshalState parentState = _unmarshalHandler.getStateStack()
110 .getLastState();
111
112
113
114
115
116
117 boolean canAccept = false;
118 while ((parentState.getFieldDescriptor() != null)
119 && (parentState.getFieldDescriptor().isContainer() && !canAccept)) {
120 XMLClassDescriptor tempClassDesc = parentState.getClassDescriptor();
121
122
123 if (tempClassDesc == null) {
124 tempClassDesc = (XMLClassDescriptor) parentState.getFieldDescriptor()
125 .getClassDescriptor();
126 if (tempClassDesc == null)
127 tempClassDesc = _unmarshalHandler
128 .getClassDescriptor(parentState.getObject().getClass());
129 }
130
131 canAccept = tempClassDesc.canAccept(name, namespace,
132 parentState.getObject());
133
134 if (!canAccept) {
135
136 if (tempClassDesc.getFieldDescriptor(name, namespace,
137 NodeType.Element) != null) {
138 if (!parentState.getFieldDescriptor().isMultivalued()) {
139 String error = MessageFormat
140 .format(resourceBundle
141 .getString("unmarshalHandler.error.container.full"),
142 new Object[] {
143 tempClassDesc.getJavaClass()
144 .getName(), name });
145 ValidationException vx = new ValidationException(error);
146 throw new SAXException(vx);
147 }
148 }
149 _unmarshalHandler.endElement(parentState.getElementName());
150 parentState = _unmarshalHandler.getStateStack().getLastState();
151 }
152 tempClassDesc = null;
153 }
154
155
156 state = new UnmarshalState();
157 state.setElementName(name);
158 state.setParent(parentState);
159
160 if (xmlSpace != null) {
161 state.setWhitespacePreserving(UnmarshalHandler.PRESERVE.equals(xmlSpace));
162 } else {
163 state.setWhitespacePreserving(parentState.isWhitespacePreserving());
164 }
165
166 _unmarshalHandler.getStateStack().pushState(state);
167
168
169 if (parentState.getObject() == null) {
170 if (!parentState.isWrapper()) {
171 return;
172 }
173 }
174
175 Class cls = null;
176
177
178 XMLClassDescriptor classDesc = parentState.getClassDescriptor();
179 if (classDesc == null) {
180 classDesc = (XMLClassDescriptor) parentState.getFieldDescriptor().getClassDescriptor();
181 if (classDesc == null)
182 classDesc = _unmarshalHandler.getClassDescriptor(parentState.getObject().getClass());
183 } else {
184
185 }
186
187
188
189
190
191
192
193 XMLFieldDescriptor descriptor = null;
194
195
196
197 XMLClassDescriptor cdInherited = null;
198
199
200
201 UnmarshalState targetState = parentState;
202 String path = "";
203 StringBuffer pathBuf = null;
204 int count = 0;
205 boolean isWrapper = false;
206 XMLClassDescriptor oldClassDesc = classDesc;
207 while (descriptor == null) {
208
209
210
211
212
213 if (path.length() > 0) {
214 String tmpName = path + "/" + name;
215 descriptor = classDesc.getFieldDescriptor(tmpName, namespace,
216 NodeType.Element);
217 }
218
219
220 if (descriptor == null) {
221 descriptor = classDesc.getFieldDescriptor(name, namespace,
222 NodeType.Element);
223 }
224
225
226
227 if ((descriptor != null) && (!descriptor.isContainer())) {
228 if (StringUtils.isNotEmpty(namespace)) {
229 if (!MarshalFramework.namespaceEquals(namespace,
230 descriptor.getNameSpaceURI())) {
231
232
233
234
235 if ((descriptor.getNameSpaceURI() != null)
236 || (!descriptor.matches("*"))) {
237 descriptor = null;
238 }
239
240 }
241 }
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255 if ((descriptor == null) && (!targetState.isWrapper())) {
256 MarshalFramework.InheritanceMatch[] matches = null;
257 try {
258 matches = _unmarshalHandler.searchInheritance(name,
259 namespace, classDesc);
260
261 } catch (MarshalException rx) {
262
263 }
264 if (matches.length != 0) {
265 InheritanceMatch match = null;
266
267
268
269
270 for (int i = 0; i < matches.length; i++) {
271 if (parentState.getElementName()
272 .equals(matches[i].parentFieldDesc
273 .getLocationPath())) {
274 match = matches[i];
275 break;
276 }
277 }
278 if (match == null)
279 match = matches[0];
280 descriptor = match.parentFieldDesc;
281 cdInherited = match.inheritedClassDesc;
282 break;
283 }
284
285
286
287
288
289
290 StringBuffer tmpLocation = new StringBuffer();
291 if (count > 0) {
292 tmpLocation.append(path + "/" + name);
293 } else {
294 tmpLocation.append(name);
295 }
296 isWrapper = (isWrapper || MarshalFramework.hasFieldsAtLocation(
297 tmpLocation.toString(), classDesc));
298 } else if (descriptor != null) {
299 String tmpPath = descriptor.getLocationPath();
300 if (path.equals(StringUtils.defaultString(tmpPath)))
301 break;
302 descriptor = null;
303 } else {
304 if (pathBuf == null)
305 pathBuf = new StringBuffer();
306 else
307 pathBuf.setLength(0);
308 pathBuf.append(path);
309 pathBuf.append('/');
310 pathBuf.append(name);
311 isWrapper = (isWrapper || MarshalFramework.hasFieldsAtLocation(
312 pathBuf.toString(), classDesc));
313 }
314
315
316
317
318 if (targetState == _unmarshalHandler.getTopState())
319 break;
320
321
322 if (count == 0)
323 path = targetState.getElementName();
324 else {
325 if (pathBuf == null)
326 pathBuf = new StringBuffer();
327 else
328 pathBuf.setLength(0);
329 pathBuf.append(targetState.getElementName());
330 pathBuf.append('/');
331 pathBuf.append(path);
332 path = pathBuf.toString();
333 }
334
335
336
337
338 targetState = targetState.getParent();
339 classDesc = targetState.getClassDescriptor();
340 count++;
341 }
342
343 if (descriptor != null
344 && _unmarshalHandler.isValidating()
345 && !_unmarshalHandler.getInternalContext()
346 .getLenientSequenceOrder()) {
347 try {
348 classDesc.checkDescriptorForCorrectOrderWithinSequence(
349 descriptor, parentState, name);
350 } catch (ValidationException e) {
351 throw new SAXException(e);
352 }
353 }
354
355
356 if (descriptor == null) {
357
358
359 classDesc = oldClassDesc;
360
361
362 if (isWrapper) {
363 state.setClassDescriptor(new XMLClassDescriptorImpl(
364 ContainerElement.class, name));
365 state.setWrapper(true);
366 if (LOG.isDebugEnabled()) {
367 LOG.debug("wrapper-element: " + name);
368 }
369
370 _unmarshalHandler.processWrapperAttributes(atts);
371 return;
372 }
373
374 String error = MessageFormat.format(resourceBundle
375 .getString("unmarshalHandler.error.find.field.descriptor"),
376 new Object[] { name, classDesc.getXMLName() });
377
378
379
380 if (classDesc instanceof InternalXMLClassDescriptor) {
381 classDesc = ((InternalXMLClassDescriptor) classDesc)
382 .getClassDescriptor();
383 }
384
385
386
387
388
389 boolean lenientElementStrictnessForIntrospection = _unmarshalHandler
390 .getInternalContext()
391 .getBooleanProperty(
392 XMLProperties.LENIENT_INTROSPECTED_ELEMENT_STRICTNESS)
393 .booleanValue();
394
395 if (_unmarshalHandler.getStrictElementHandler().skipStartElementIgnoringDepth()) {
396
397 _unmarshalHandler.getStateStack().removeLastState();
398
399 _unmarshalHandler.getNamespaceHandling()
400 .removeCurrentNamespaceInstance();
401 if (LOG.isDebugEnabled()) {
402 String debug = MessageFormat.format(resourceBundle
403 .getString("unmarshalHandler.log.debug.ignore.extra.element"),
404 new Object[] { error });
405 LOG.debug(debug);
406 }
407 return;
408 }
409
410
411
412 else if (lenientElementStrictnessForIntrospection
413 && Introspector.introspected(classDesc)) {
414 LOG.warn(error);
415 return;
416 }
417
418
419 else {
420 throw new SAXException(error);
421 }
422 }
423
424
425
426
427 if (targetState != parentState) {
428 state.setTargetState(targetState);
429 parentState = targetState;
430 }
431
432 Object object = parentState.getObject();
433
434 if (descriptor.isContainer()) {
435
436
437
438 if (LOG.isDebugEnabled()) {
439 LOG.debug("#container: " + descriptor.getFieldName());
440 }
441
442
443 state.clear();
444
445 state.setWhitespacePreserving(parentState.isWhitespacePreserving());
446 state.setParent(parentState);
447
448
449 state.setElementName(descriptor.getFieldName());
450 state.setFieldDescriptor(descriptor);
451 state.setClassDescriptor((XMLClassDescriptor) descriptor
452 .getClassDescriptor());
453 Object containerObject = null;
454
455
456 if (!descriptor.isMultivalued()) {
457
458 FieldHandler handler = descriptor.getHandler();
459 containerObject = handler.getValue(object);
460 if (containerObject != null) {
461 if (state.getClassDescriptor() != null) {
462 if (state.getClassDescriptor().canAccept(name, namespace,
463 containerObject)) {
464
465 parentState.markAsNotUsed(descriptor);
466 }
467 } else {
468
469 parentState.markAsNotUsed(descriptor);
470 }
471 } else {
472 containerObject = handler.newInstance(object);
473 }
474
475 }
476
477 else {
478 Class containerClass = descriptor.getFieldType();
479 try {
480 containerObject = containerClass.newInstance();
481 } catch (Exception ex) {
482 throw new SAXException(ex);
483 }
484 }
485 state.setObject(containerObject);
486 state.setType(containerObject.getClass());
487
488
489
490
491 _unmarshalHandler.getNamespaceHandling().createNamespace();
492 _unmarshalHandler.startElementProcessing(name, namespace, atts);
493 return;
494 }
495
496
497
498 state.setFieldDescriptor(descriptor);
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514 classDesc = null;
515 if (cdInherited != null)
516 classDesc = cdInherited;
517 else if (!name.equals(descriptor.getXMLName()))
518 classDesc = _unmarshalHandler.resolveByXMLName(name, namespace,
519 null);
520
521 if (classDesc == null)
522 classDesc = (XMLClassDescriptor) descriptor.getClassDescriptor();
523 FieldHandler handler = descriptor.getHandler();
524 boolean useHandler = true;
525
526 try {
527
528
529
530
531 if (classDesc != null) {
532 cls = classDesc.getJavaClass();
533
534
535
536
537 if (descriptor.getFieldType() != cls) {
538 state.setDerived(true);
539 }
540 } else {
541 cls = descriptor.getFieldType();
542 }
543
544
545
546
547
548 if (cls == null) {
549 cls = java.lang.Object.class;
550 }
551
552
553 String currentPackage = _unmarshalHandler
554 .getJavaPackage(parentState.getType());
555 String instanceType = _unmarshalHandler.getInstanceType(atts,
556 currentPackage);
557 if (instanceType != null) {
558
559 Class instanceClass = null;
560 try {
561
562 XMLClassDescriptor instanceDesc = _unmarshalHandler
563 .getClassDescriptor(instanceType,
564 _unmarshalHandler.getClassLoader());
565
566 boolean loadClass = true;
567
568 if (instanceDesc != null) {
569 instanceClass = instanceDesc.getJavaClass();
570 classDesc = instanceDesc;
571 if (instanceClass != null) {
572 loadClass = (!instanceClass.getName().equals(
573 instanceType));
574 }
575 }
576
577 if (loadClass) {
578 instanceClass = _unmarshalHandler.loadClass(
579 instanceType, null);
580
581
582 FieldHandler tempHandler = descriptor.getHandler();
583
584 boolean collection = false;
585 if (tempHandler instanceof FieldHandlerImpl) {
586 collection = ((FieldHandlerImpl) tempHandler)
587 .isCollection();
588 } else {
589 collection = Introspector
590 .isCollection(instanceClass);
591 }
592
593 if ((!collection)
594 && !cls.isAssignableFrom(instanceClass)) {
595 if (!MarshalFramework.isPrimitive(cls)) {
596 String err = MessageFormat
597 .format(resourceBundle
598 .getString("unmarshalHandler.error.not.subclass"),
599 new Object[] {
600 instanceClass.getName(),
601 cls.getName() });
602 throw new SAXException(err);
603 }
604 }
605 }
606 cls = instanceClass;
607 useHandler = false;
608 } catch (Exception ex) {
609 String err = MessageFormat
610 .format(resourceBundle
611 .getString("unmarshalHandler.error.unable.instantiate.exception"),
612 new Object[] { instanceType,
613 ex.getMessage() });
614 throw new SAXException(err, ex);
615 }
616
617 }
618
619
620 if (cls == Object.class) {
621 if (parentState.getObject() instanceof ArrayHandler)
622 cls = ((ArrayHandler) parentState.getObject()).componentType();
623 }
624
625
626
627 if (cls == Object.class) {
628 Class pClass = parentState.getType();
629 ClassLoader loader = pClass.getClassLoader();
630
631
632 classDesc = _unmarshalHandler.resolveByXMLName(name, namespace,
633 loader);
634
635 String cname = null;
636 if (classDesc == null) {
637
638 cname = _unmarshalHandler.getJavaNaming().toJavaClassName(
639 name);
640 classDesc = _unmarshalHandler.getClassDescriptor(cname,
641 loader);
642 }
643
644 if (classDesc == null) {
645
646 String pkg = pClass.getName();
647 int idx = pkg.lastIndexOf('.');
648 if (idx > 0) {
649 pkg = pkg.substring(0, idx + 1);
650 cname = pkg + cname;
651 classDesc = _unmarshalHandler.getClassDescriptor(cname,
652 loader);
653 }
654 }
655
656 if (classDesc != null) {
657 cls = classDesc.getJavaClass();
658 useHandler = false;
659 } else {
660
661 state.setObject(_unmarshalHandler.getAnyNodeHandler()
662 .commonStartElement(name, namespace,
663 state.isWhitespacePreserving()));
664 state.setType(cls);
665 return;
666 }
667 }
668
669 boolean byteArray = false;
670 if (cls.isArray())
671 byteArray = (cls.getComponentType() == Byte.TYPE);
672
673
674 if (MarshalFramework.isPrimitive(cls) || descriptor.isImmutable()
675 || byteArray) {
676 state.setObject(null);
677 state.setPrimitiveOrImmutable(true);
678
679 if (descriptor.isImmutable()) {
680 if (classDesc == null)
681 classDesc = _unmarshalHandler.getClassDescriptor(cls);
682 state.setClassDescriptor(classDesc);
683 Arguments args = _unmarshalHandler.processConstructorArgs(
684 atts, classDesc);
685 if ((args != null) && (args.size() > 0)) {
686 state.setConstructorArguments(args);
687 }
688 }
689 } else {
690 if (classDesc == null)
691 classDesc = _unmarshalHandler.getClassDescriptor(cls);
692
693
694
695 if ((!state.isDerived()) && useHandler) {
696
697 boolean create = true;
698 if (_unmarshalHandler.isReuseObjects()) {
699 state.setObject(handler.getValue(parentState.getObject()));
700 create = (state.getObject() == null);
701 }
702 if (create) {
703 Arguments args = _unmarshalHandler
704 .processConstructorArgs(atts, classDesc);
705 if ((args.getValues() != null) && (args.getValues().length > 0)) {
706 if (handler instanceof ExtendedFieldHandler) {
707 ExtendedFieldHandler efh = (ExtendedFieldHandler) handler;
708 state.setObject(efh.newInstance(
709 parentState.getObject(), args.getValues()));
710 } else {
711 String err = resourceBundle
712 .getString("unmarshalHandler.error.constructor.arguments");
713 throw new SAXException(err);
714 }
715 } else {
716 state.setObject(handler
717 .newInstance(parentState.getObject()));
718 }
719 }
720 }
721
722
723
724
725 if (state.getObject() != null) {
726 cls = state.getObject().getClass();
727 if (classDesc != null) {
728 if (classDesc.getJavaClass() != cls) {
729 classDesc = null;
730 }
731 }
732 } else {
733 try {
734 if (cls.isArray()) {
735 state.setObject(new ArrayHandler(
736 cls.getComponentType()));
737 cls = ArrayHandler.class;
738 } else {
739 Arguments args = _unmarshalHandler
740 .processConstructorArgs(atts, classDesc);
741 state.setObject(_unmarshalHandler.createInstance(
742 cls, args));
743
744 }
745 } catch (java.lang.Exception ex) {
746 String err = MessageFormat
747 .format(resourceBundle
748 .getString("unmarshalHandler.error.unable.instantiate.exception"),
749 new Object[] {
750 _unmarshalHandler
751 .className(cls),
752 ex.getMessage() });
753 throw new SAXException(err, ex);
754 }
755 }
756 }
757 state.setType(cls);
758 } catch (java.lang.IllegalStateException ise) {
759 LOG.error(ise.toString());
760 throw new SAXException(ise);
761 }
762
763
764
765
766 if (classDesc == null) {
767 classDesc = _unmarshalHandler.getClassDescriptor(cls);
768 }
769 state.setClassDescriptor(classDesc);
770
771 if ((state.getObject() == null) && (!state.isPrimitiveOrImmutable())) {
772 String err = MessageFormat.format(resourceBundle
773 .getString("unmarshalHandler.error.unable.unmarshal"),
774 new Object[] { name, _unmarshalHandler.className(cls) });
775 throw new SAXException(err);
776 }
777
778
779
780 if (descriptor.isIncremental()) {
781 if (LOG.isDebugEnabled()) {
782 String debug = MessageFormat.format(resourceBundle
783 .getString("unmarshalHandler.log.debug.process.incrementally"),
784 new Object[] { name });
785 LOG.debug(debug);
786 }
787 try {
788 handler.setValue(parentState.getObject(), state.getObject());
789 } catch (java.lang.IllegalStateException ise) {
790 String err = MessageFormat
791 .format(resourceBundle
792 .getString("unmarshalHandler.error.unable.add.element"),
793 new Object[] { name,
794 parentState.getFieldDescriptor().getXMLName(),
795 ise.getMessage() });
796 throw new SAXException(err, ise);
797 }
798 }
799
800 if (state.getObject() != null) {
801
802
803 Object stateObject = state.getObject();
804 Object parentObject = (state.getParent() == null) ? null
805 : state.getParent().getObject();
806 _unmarshalHandler.getDelegateUnmarshalListener().initialized(
807 stateObject, parentObject);
808 _unmarshalHandler.processAttributes(atts, classDesc);
809 _unmarshalHandler.getDelegateUnmarshalListener().attributesProcessed(
810 stateObject, parentObject);
811 _unmarshalHandler.getNamespaceHandling().processNamespaces(classDesc,
812 _unmarshalHandler.getStateStack().getLastState().getObject());
813 } else if ((state.getType() != null) && (!state.isPrimitiveOrImmutable())) {
814 if (atts != null) {
815 _unmarshalHandler.processWrapperAttributes(atts);
816 String warn = MessageFormat.format(resourceBundle
817 .getString("unmarshalHandler.log.warn.process.attribute.as.location"),
818 new Object[] { name });
819 LOG.warn(warn);
820 }
821 } else {
822
823 if (atts != null) {
824 String nil = atts.getValue(MarshalFramework.NIL_ATTR,
825 MarshalFramework.XSI_NAMESPACE);
826 state.setNil("true".equals(nil));
827 _unmarshalHandler.processWrapperAttributes(atts);
828 }
829 }
830 }
831
832 }