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.io.PrintWriter;
19 import java.io.StringWriter;
20 import java.text.MessageFormat;
21 import java.util.ArrayList;
22 import java.util.Enumeration;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.ResourceBundle;
26 import java.util.StringTokenizer;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.exolab.castor.mapping.FieldHandler;
31 import org.exolab.castor.mapping.MapItem;
32 import org.exolab.castor.xml.UnmarshalHandler.ArrayHandler;
33 import org.exolab.castor.xml.util.XMLFieldDescriptorImpl;
34 import org.xml.sax.ContentHandler;
35 import org.xml.sax.SAXException;
36
37
38
39
40
41
42
43
44
45 public class EndElementProcessor {
46
47
48
49
50 private static final Log LOG = LogFactory.getLog(EndElementProcessor.class);
51
52
53
54
55 protected static ResourceBundle resourceBundle;
56
57
58
59
60
61 private final UnmarshalHandler _unmarshalHandler;
62
63 static {
64 resourceBundle = ResourceBundle.getBundle("UnmarshalHandlerMessages",
65 Locale.getDefault());
66 }
67
68
69
70
71
72
73
74
75
76
77 public EndElementProcessor(final UnmarshalHandler unmarshalHandler) {
78 _unmarshalHandler = unmarshalHandler;
79 }
80
81 public void compute(String name) throws org.xml.sax.SAXException {
82 if (LOG.isTraceEnabled()) {
83 String trace = MessageFormat.format(resourceBundle
84 .getString("unmarshalHandler.log.trace.endElement"),
85 new Object[] { name });
86 LOG.trace(trace);
87 }
88
89
90
91
92 if (_unmarshalHandler.getStrictElementHandler().skipEndElement()) {
93 return;
94 }
95
96
97 if (_unmarshalHandler.getAnyNodeHandler().hasAnyUnmarshaller()) {
98 _unmarshalHandler.getAnyNodeHandler().endElement(name);
99
100 if (_unmarshalHandler.getAnyNodeHandler().isStartingNode()) {
101 _unmarshalHandler.setAnyNode(_unmarshalHandler
102 .getAnyNodeHandler().getStartingNode());
103 } else
104 return;
105 }
106
107 if (_unmarshalHandler.getStateStack().isEmpty()) {
108 String err = MessageFormat.format(resourceBundle
109 .getString("unmarshalHandler.error.missing.startElement"),
110 new Object[] { name });
111 throw new SAXException(err);
112 }
113
114
115
116
117 int idx = name.indexOf(':');
118 if (idx >= 0) {
119 name = name.substring(idx + 1);
120 }
121
122
123 UnmarshalState state = _unmarshalHandler.getStateStack()
124 .removeLastState();
125
126
127 XMLFieldDescriptor descriptor = state.getFieldDescriptor();
128
129 if (!state.getElementName().equals(name)) {
130
131
132 if (descriptor.isContainer()) {
133 _unmarshalHandler.getStateStack().pushState(state);
134
135
136
137 StringBuffer tmpBuffer = null;
138 if (state.getBuffer() != null) {
139 if (!UnmarshalHandler.isWhitespace(state.getBuffer())) {
140 if (state.getClassDescriptor().getContentDescriptor() == null) {
141 tmpBuffer = state.getBuffer();
142 state.setBuffer(null);
143 }
144 }
145 }
146
147 _unmarshalHandler.endElement(state.getElementName());
148
149 if (tmpBuffer != null) {
150 state = _unmarshalHandler.getStateStack().getLastState();
151 if (state.getBuffer() == null)
152 state.setBuffer(tmpBuffer);
153 else
154 state.getBuffer().append(tmpBuffer.toString());
155 }
156 _unmarshalHandler.endElement(name);
157 return;
158 }
159 String err = MessageFormat
160 .format(resourceBundle
161 .getString("unmarshalHandler.error.different.endElement.expected"),
162 new Object[] { state.getElementName(), name });
163 throw new SAXException(err);
164 }
165
166
167 Class<?> type = state.getType();
168
169 if (type == null) {
170 if (!state.isWrapper()) {
171
172
173
174 String info = MessageFormat
175 .format(resourceBundle
176 .getString("unmarshalHandler.log.info.no.Descriptor.found"),
177 new Object[] { state.getElementName() });
178 LOG.info(info);
179 }
180
181
182
183
184
185
186 StringBuffer tmpBuffer = null;
187 if (state.getBuffer() != null) {
188 if (!UnmarshalHandler.isWhitespace(state.getBuffer())) {
189 tmpBuffer = state.getBuffer();
190 state.setBuffer(null);
191 }
192 }
193 if (tmpBuffer != null) {
194 UnmarshalState targetState = state;
195 String locPath = targetState.getElementName();
196 while ((targetState = targetState.getParent()) != null) {
197 if ((targetState.isWrapper())
198 || (targetState.getClassDescriptor() == null)) {
199 locPath = targetState.getElementName() + "/" + locPath;
200 continue;
201 }
202
203 XMLFieldDescriptor tmpDesc = targetState.getClassDescriptor()
204 .getContentDescriptor();
205 if (tmpDesc != null
206 && locPath.equals(tmpDesc.getLocationPath())) {
207 if (targetState.getBuffer() == null)
208 targetState.setBuffer(tmpBuffer);
209 else
210 targetState.getBuffer().append(tmpBuffer.toString());
211 }
212 }
213 }
214
215
216 _unmarshalHandler.getNamespaceHandling()
217 .removeCurrentNamespaceInstance();
218 return;
219 }
220
221
222 boolean byteArray = false;
223 if (type.isArray()) {
224 byteArray = (type.getComponentType() == Byte.TYPE);
225 }
226
227
228
229 if ((state.getObject() == null) && (!state.isPrimitiveOrImmutable())) {
230
231 _unmarshalHandler.getNamespaceHandling()
232 .removeCurrentNamespaceInstance();
233 return;
234 }
235
236
237
238 if (state.isPrimitiveOrImmutable()) {
239
240 String str = null;
241
242 if (state.getBuffer() != null) {
243 str = state.getBuffer().toString();
244 state.getBuffer().setLength(0);
245 }
246
247 if (type == String.class
248 && !((XMLFieldDescriptorImpl) descriptor)
249 .isDerivedFromXSList()) {
250 if (str != null)
251 state.setObject(str);
252 else if (state.isNil()) {
253 state.setObject(null);
254 } else {
255 state.setObject("");
256 }
257 }
258
259 else if (byteArray && !descriptor.isDerivedFromXSList()) {
260 if (str == null)
261 state.setObject(new byte[0]);
262 else {
263 state.setObject(_unmarshalHandler.decodeBinaryData(
264 descriptor, str));
265 }
266 } else if (state.getConstructorArguments() != null) {
267 state.setObject(_unmarshalHandler.createInstance(state.getType(),
268 state.getConstructorArguments()));
269 } else if (descriptor.isMultivalued()
270 && descriptor.getSchemaType() != null
271 && descriptor.getSchemaType().equals("list")
272 && ((XMLFieldDescriptorImpl) descriptor)
273 .isDerivedFromXSList()) {
274 StringTokenizer attrValueTokenizer = new StringTokenizer(str);
275 List<Object> primitives = new ArrayList<Object>();
276 while (attrValueTokenizer.hasMoreTokens()) {
277 String tokenValue = attrValueTokenizer.nextToken();
278 if (MarshalFramework.isPrimitive(descriptor.getFieldType())) {
279 primitives.add(_unmarshalHandler.toPrimitiveObject(
280 type, tokenValue, state.getFieldDescriptor()));
281 } else {
282 Class<?> valueType = descriptor.getFieldType();
283
284 if (valueType.isArray()
285 && (valueType.getComponentType() == Byte.TYPE)) {
286 primitives.add(_unmarshalHandler.decodeBinaryData(
287 descriptor, tokenValue));
288 }
289 }
290
291 }
292 state.setObject(primitives);
293 } else {
294 if (state.isNil()) {
295 state.setObject(null);
296 } else {
297 state.setObject(_unmarshalHandler.toPrimitiveObject(type,
298 str, state.getFieldDescriptor()));
299 }
300 }
301 } else if (ArrayHandler.class.isAssignableFrom(state.getType())) {
302 state.setObject(((ArrayHandler) state.getObject()).getObject());
303 state.setType(state.getObject().getClass());
304
305 }
306
307
308 if ((state.getBuffer() != null) && (state.getBuffer().length() > 0)
309 && (state.getClassDescriptor() != null)) {
310 XMLFieldDescriptor cdesc = state.getClassDescriptor().getContentDescriptor();
311 if (cdesc != null) {
312 Object value = state.getBuffer().toString();
313 if (MarshalFramework.isPrimitive(cdesc.getFieldType()))
314 value = _unmarshalHandler.toPrimitiveObject(
315 cdesc.getFieldType(), (String) value,
316 state.getFieldDescriptor());
317 else {
318 Class<?> valueType = cdesc.getFieldType();
319
320 if (valueType.isArray()
321 && (valueType.getComponentType() == Byte.TYPE)) {
322 value = _unmarshalHandler.decodeBinaryData(descriptor,
323 (String) value);
324 }
325 }
326
327 try {
328 FieldHandler handler = cdesc.getHandler();
329 boolean addObject = true;
330 if (_unmarshalHandler.isReuseObjects()) {
331
332
333 Object tmp = handler.getValue(state.getObject());
334 if (tmp != null) {
335
336
337 addObject = (!tmp.equals(value));
338 }
339 }
340 if (addObject)
341 handler.setValue(state.getObject(), value);
342 } catch (java.lang.IllegalStateException ise) {
343 String err = MessageFormat
344 .format(resourceBundle
345 .getString("unmarshalHandler.error.unable.add.text"),
346 new Object[] { descriptor.getXMLName(),
347 ise.toString() });
348 throw new SAXException(err, ise);
349 }
350 }
351
352 else if (descriptor.isReference()) {
353 UnmarshalState pState = _unmarshalHandler.getStateStack()
354 .getLastState();
355 _unmarshalHandler.processIDREF(state.getBuffer().toString(),
356 descriptor, pState.getObject());
357 _unmarshalHandler.getNamespaceHandling()
358 .removeCurrentNamespaceInstance();
359 return;
360 } else {
361
362 if (!UnmarshalHandler.isWhitespace(state.getBuffer())) {
363 String err = MessageFormat.format(resourceBundle
364 .getString("unmarshalHandler.error.illegal.text"),
365 new Object[] { name, state.getBuffer() });
366 throw new SAXException(err);
367 }
368 }
369 }
370
371
372
373 Object stateObject = state.getObject();
374 Object parentObject = (state.getParent() == null) ? null
375 : state.getParent().getObject();
376 _unmarshalHandler.getDelegateUnmarshalListener().unmarshalled(
377 stateObject, parentObject);
378
379
380 if (_unmarshalHandler.getStateStack().isEmpty()) {
381 if (_unmarshalHandler.isValidating()) {
382 ValidationException first = null;
383 ValidationException last = null;
384
385
386 if (_unmarshalHandler.getResolveTable() != null
387 && !_unmarshalHandler.getInternalContext()
388 .getLenientIdValidation()) {
389 Enumeration enumeration = _unmarshalHandler
390 .getResolveTable().keys();
391 while (enumeration.hasMoreElements()) {
392 Object ref = enumeration.nextElement();
393
394
395
396 String msg = "unable to resolve reference: " + ref;
397 if (first == null) {
398 first = new ValidationException(msg);
399 last = first;
400 } else {
401 last.setNext(new ValidationException(msg));
402 last = last.getNext();
403 }
404 }
405 }
406 try {
407 Validator validator = new Validator();
408 ValidationContext context = new ValidationContext();
409 context.setInternalContext(_unmarshalHandler
410 .getInternalContext());
411 validator.validate(state.getObject(), context);
412 if (!_unmarshalHandler.getInternalContext()
413 .getLenientIdValidation()) {
414 validator.checkUnresolvedIdrefs(context);
415 }
416 context.cleanup();
417 } catch (ValidationException vEx) {
418 if (first == null)
419 first = vEx;
420 else
421 last.setNext(vEx);
422 }
423 if (first != null) {
424 throw new SAXException(first);
425 }
426 }
427 return;
428 }
429
430
431
432 if (descriptor.isIncremental()) {
433
434 _unmarshalHandler.getNamespaceHandling()
435 .removeCurrentNamespaceInstance();
436 return;
437 }
438
439 Object val = state.getObject();
440
441
442 if (_unmarshalHandler.getAnyNode() != null) {
443 val = _unmarshalHandler.getAnyNode();
444 _unmarshalHandler.setAnyNode(null);
445 }
446
447
448 UnmarshalState fieldState = state;
449
450
451 boolean firstOccurance = false;
452
453
454 state = _unmarshalHandler.getStateStack().getLastState();
455 if (state.isWrapper()) {
456 state = fieldState.getTargetState();
457 }
458
459
460
461
462
463 if (!descriptor.isMultivalued()) {
464
465 if (state.isUsed(descriptor)) {
466
467 String location = name;
468 while (!_unmarshalHandler.getStateStack().isEmpty()) {
469 UnmarshalState tmpState = _unmarshalHandler.getStateStack()
470 .removeLastState();
471 if (!tmpState.isWrapper()) {
472 if (tmpState.getFieldDescriptor().isContainer())
473 continue;
474 }
475 location = state.getElementName() + "/" + location;
476 }
477
478 String err = MessageFormat
479 .format(resourceBundle
480 .getString("unmarshalHandler.error.element.occurs.more.than.once"),
481 new Object[] { name, state.getType().getName(),
482 location });
483
484 ValidationException vx = new ValidationException(err);
485
486 throw new SAXException(vx);
487 }
488 state.markAsUsed(descriptor);
489
490 if (state.getClassDescriptor().getIdentity() == descriptor) {
491 state.setKey(val);
492 }
493 } else {
494
495 if (!state.isUsed(descriptor)) {
496 firstOccurance = true;
497 }
498
499
500 state.markAsUsed(descriptor);
501 }
502
503 try {
504 FieldHandler handler = descriptor.getHandler();
505
506
507 String valueType = descriptor.getSchemaType();
508 if ((valueType != null)
509 && (valueType.equals(MarshalFramework.QNAME_NAME))) {
510 val = _unmarshalHandler.getNamespaceHandling()
511 .resolveNamespace(val);
512 }
513
514 boolean addObject = true;
515 if (_unmarshalHandler.isReuseObjects()
516 && fieldState.isPrimitiveOrImmutable()) {
517
518
519 Object tmp = handler.getValue(state.getObject());
520 if (tmp != null) {
521
522
523 addObject = (!tmp.equals(val));
524 }
525 }
526
527
528 if (descriptor.isMapped()) {
529 if (!(val instanceof MapItem)) {
530 MapItem mapItem = new MapItem(fieldState.getKey(), val);
531 val = mapItem;
532 } else {
533
534 MapItem mapItem = (MapItem) val;
535 if (mapItem.getValue() == null) {
536
537 addObject = false;
538 _unmarshalHandler.addReference(mapItem.toString(),
539 state.getObject(), descriptor);
540 }
541 }
542 }
543
544 if (addObject) {
545
546 if (firstOccurance && _unmarshalHandler.isClearCollections()) {
547 handler.resetValue(state.getObject());
548 }
549
550 if (descriptor.isMultivalued()
551 && descriptor.getSchemaType() != null
552 && descriptor.getSchemaType().equals("list")
553 && ((XMLFieldDescriptorImpl) descriptor)
554 .isDerivedFromXSList()) {
555 List<Object> values = (List<Object>) val;
556 for (Object value : values) {
557
558 handler.setValue(state.getObject(), value);
559
560
561
562 _unmarshalHandler.getDelegateUnmarshalListener()
563 .fieldAdded(descriptor.getFieldName(),
564 state.getObject(), fieldState.getObject());
565 }
566 } else {
567
568
569 handler.setValue(state.getObject(), val);
570
571
572
573 _unmarshalHandler.getDelegateUnmarshalListener()
574 .fieldAdded(descriptor.getFieldName(),
575 state.getObject(), fieldState.getObject());
576 }
577 }
578
579 }
580
581
582
583
584
585
586
587
588
589
590
591 catch (Exception ex) {
592 StringWriter sw = new StringWriter();
593 PrintWriter pw = new PrintWriter(sw);
594 ex.printStackTrace(pw);
595 pw.flush();
596 String err = MessageFormat
597 .format(resourceBundle
598 .getString("unmarshalHandler.error.unable.add.element"),
599 new Object[] { name, state.getFieldDescriptor().getXMLName(),
600 sw.toString() });
601 throw new SAXException(err, ex);
602 }
603
604
605 _unmarshalHandler.getNamespaceHandling()
606 .removeCurrentNamespaceInstance();
607
608
609
610 if (state.getFieldDescriptor().isContainer() && state.getClassDescriptor().isChoice()
611 && !state.getFieldDescriptor().isMultivalued()) {
612 _unmarshalHandler.endElement(state.getElementName());
613 }
614
615 }
616 }