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