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