src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallingContext.java

changeset 397
b99d7e355d4b
parent 286
f50545b5e2f1
child 637
9c07ef4934dd
child 650
121e938cb9c3
equal deleted inserted replaced
393:6cdc6ed98780 397:b99d7e355d4b
1 /* 1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this 7 * published by the Free Software Foundation. Oracle designates this
33 import java.util.HashMap; 33 import java.util.HashMap;
34 import java.util.Iterator; 34 import java.util.Iterator;
35 import java.util.List; 35 import java.util.List;
36 import java.util.Map; 36 import java.util.Map;
37 import java.util.concurrent.Callable; 37 import java.util.concurrent.Callable;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
38 40
39 import javax.xml.XMLConstants; 41 import javax.xml.XMLConstants;
40 import javax.xml.bind.JAXBElement; 42 import javax.xml.bind.JAXBElement;
41 import javax.xml.bind.UnmarshalException; 43 import javax.xml.bind.UnmarshalException;
42 import javax.xml.bind.Unmarshaller; 44 import javax.xml.bind.Unmarshaller;
49 51
50 import com.sun.istack.internal.NotNull; 52 import com.sun.istack.internal.NotNull;
51 import com.sun.istack.internal.Nullable; 53 import com.sun.istack.internal.Nullable;
52 import com.sun.istack.internal.SAXParseException2; 54 import com.sun.istack.internal.SAXParseException2;
53 import com.sun.xml.internal.bind.IDResolver; 55 import com.sun.xml.internal.bind.IDResolver;
56 import com.sun.xml.internal.bind.Util;
54 import com.sun.xml.internal.bind.api.AccessorException; 57 import com.sun.xml.internal.bind.api.AccessorException;
55 import com.sun.xml.internal.bind.api.ClassResolver; 58 import com.sun.xml.internal.bind.api.ClassResolver;
56 import com.sun.xml.internal.bind.unmarshaller.InfosetScanner; 59 import com.sun.xml.internal.bind.unmarshaller.InfosetScanner;
57 import com.sun.xml.internal.bind.v2.ClassFactory; 60 import com.sun.xml.internal.bind.v2.ClassFactory;
58 import com.sun.xml.internal.bind.v2.runtime.AssociationMap; 61 import com.sun.xml.internal.bind.v2.runtime.AssociationMap;
59 import com.sun.xml.internal.bind.v2.runtime.Coordinator; 62 import com.sun.xml.internal.bind.v2.runtime.Coordinator;
60 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; 63 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
61 import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo; 64 import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo;
65 import java.util.logging.Level;
66 import java.util.logging.Logger;
62 67
63 import org.xml.sax.ErrorHandler; 68 import org.xml.sax.ErrorHandler;
64 import org.xml.sax.SAXException; 69 import org.xml.sax.SAXException;
65 import org.xml.sax.helpers.LocatorImpl; 70 import org.xml.sax.helpers.LocatorImpl;
66 71
74 * @author Kohsuke Kawaguchi 79 * @author Kohsuke Kawaguchi
75 */ 80 */
76 public final class UnmarshallingContext extends Coordinator 81 public final class UnmarshallingContext extends Coordinator
77 implements NamespaceContext, ValidationEventHandler, ErrorHandler, XmlVisitor, XmlVisitor.TextPredictor { 82 implements NamespaceContext, ValidationEventHandler, ErrorHandler, XmlVisitor, XmlVisitor.TextPredictor {
78 83
84 private static final Logger logger = Logger.getLogger(UnmarshallingContext.class.getName());
85
79 /** 86 /**
80 * Root state. 87 * Root state.
81 */ 88 */
82 private final State root; 89 private final State root;
83 90
173 /** 180 /**
174 * User-supplied {@link ClassLoader} for converting name to {@link Class}. 181 * User-supplied {@link ClassLoader} for converting name to {@link Class}.
175 * For backward compatibility, when null, use thread context classloader. 182 * For backward compatibility, when null, use thread context classloader.
176 */ 183 */
177 public @Nullable ClassLoader classLoader; 184 public @Nullable ClassLoader classLoader;
185
186 /**
187 * The variable introduced to avoid reporting n^10 similar errors.
188 * After error is reported counter is decremented. When it became 0 - errors should not be reported any more.
189 *
190 * volatile is required to ensure that concurrent threads will see changed value
191 */
192 private static volatile int errorsCounter = 10;
178 193
179 /** 194 /**
180 * State information for each element. 195 * State information for each element.
181 */ 196 */
182 public final class State { 197 public final class State {
258 */ 273 */
259 public UnmarshallingContext getContext() { 274 public UnmarshallingContext getContext() {
260 return UnmarshallingContext.this; 275 return UnmarshallingContext.this;
261 } 276 }
262 277
278 @SuppressWarnings("LeakingThisInConstructor")
263 private State(State prev) { 279 private State(State prev) {
264 this.prev = prev; 280 this.prev = prev;
265 if(prev!=null) 281 if (prev!=null) {
266 prev.next = this; 282 prev.next = this;
283 }
267 } 284 }
268 285
269 private void push() { 286 private void push() {
270 if(next==null) 287 if (logger.isLoggable(Level.FINEST)) {
288 logger.log(Level.FINEST, "State.push");
289 }
290 if (next==null) {
291 assert current == this;
271 allocateMoreStates(); 292 allocateMoreStates();
293 }
294 nil = false;
272 State n = next; 295 State n = next;
273 n.numNsDecl = nsLen; 296 n.numNsDecl = nsLen;
274 current = n; 297 current = n;
275 } 298 }
276 299
277 private void pop() { 300 private void pop() {
301 if (logger.isLoggable(Level.FINEST)) {
302 logger.log(Level.FINEST, "State.pop");
303 }
278 assert prev!=null; 304 assert prev!=null;
279 loader = null; 305 loader = null;
280 nil = false; 306 nil = false;
281 receiver = null; 307 receiver = null;
282 intercepter = null; 308 intercepter = null;
379 private void allocateMoreStates() { 405 private void allocateMoreStates() {
380 // this method should be used only when we run out of a state. 406 // this method should be used only when we run out of a state.
381 assert current.next==null; 407 assert current.next==null;
382 408
383 State s = current; 409 State s = current;
384 for( int i=0; i<8; i++ ) 410 for (int i=0; i<8; i++) {
385 s = new State(s); 411 s = new State(s);
412 }
386 } 413 }
387 414
388 public void clearStates() { 415 public void clearStates() {
389 State last = current; 416 State last = current;
390 while (last.next != null) last = last.next; 417 while (last.next != null) last = last.next;
434 461
435 factories.put(type,new Factory(factory,m)); 462 factories.put(type,new Factory(factory,m));
436 } 463 }
437 } 464 }
438 465
466 @Override
439 public void startDocument(LocatorEx locator, NamespaceContext nsContext) throws SAXException { 467 public void startDocument(LocatorEx locator, NamespaceContext nsContext) throws SAXException {
440 if(locator!=null) 468 if(locator!=null)
441 this.locator = locator; 469 this.locator = locator;
442 this.environmentNamespaceContext = nsContext; 470 this.environmentNamespaceContext = nsContext;
443 // reset the object 471 // reset the object
447 patchersLen=0; 475 patchersLen=0;
448 aborted = false; 476 aborted = false;
449 isUnmarshalInProgress = true; 477 isUnmarshalInProgress = true;
450 nsLen=0; 478 nsLen=0;
451 479
452 setThreadAffinity();
453
454 if(expectedType!=null) 480 if(expectedType!=null)
455 root.loader = EXPECTED_TYPE_ROOT_LOADER; 481 root.loader = EXPECTED_TYPE_ROOT_LOADER;
456 else 482 else
457 root.loader = DEFAULT_ROOT_LOADER; 483 root.loader = DEFAULT_ROOT_LOADER;
458 484
459 idResolver.startDocument(this); 485 idResolver.startDocument(this);
460 } 486 }
461 487
488 @Override
462 public void startElement(TagName tagName) throws SAXException { 489 public void startElement(TagName tagName) throws SAXException {
463 pushCoordinator(); 490 pushCoordinator();
464 try { 491 try {
465 _startElement(tagName); 492 _startElement(tagName);
466 } finally { 493 } finally {
484 assert current.loader!=null; // the childElement should register this 511 assert current.loader!=null; // the childElement should register this
485 // and tell the new child that you are activated 512 // and tell the new child that you are activated
486 current.loader.startElement(current,tagName); 513 current.loader.startElement(current,tagName);
487 } 514 }
488 515
516 @Override
489 public void text(CharSequence pcdata) throws SAXException { 517 public void text(CharSequence pcdata) throws SAXException {
490 State cur = current; 518 State cur = current;
491 pushCoordinator(); 519 pushCoordinator();
492 try { 520 try {
493 if(cur.elementDefaultValue!=null) { 521 if(cur.elementDefaultValue!=null) {
500 } finally { 528 } finally {
501 popCoordinator(); 529 popCoordinator();
502 } 530 }
503 } 531 }
504 532
533 @Override
505 public final void endElement(TagName tagName) throws SAXException { 534 public final void endElement(TagName tagName) throws SAXException {
506 pushCoordinator(); 535 pushCoordinator();
507 try { 536 try {
508 State child = current; 537 State child = current;
509 538
524 } finally { 553 } finally {
525 popCoordinator(); 554 popCoordinator();
526 } 555 }
527 } 556 }
528 557
558 @Override
529 public void endDocument() throws SAXException { 559 public void endDocument() throws SAXException {
530 runPatchers(); 560 runPatchers();
531 idResolver.endDocument(); 561 idResolver.endDocument();
532 562
533 isUnmarshalInProgress = false; 563 isUnmarshalInProgress = false;
535 locator = DUMMY_INSTANCE; 565 locator = DUMMY_INSTANCE;
536 environmentNamespaceContext = null; 566 environmentNamespaceContext = null;
537 567
538 // at the successful completion, scope must be all closed 568 // at the successful completion, scope must be all closed
539 assert root==current; 569 assert root==current;
540
541 resetThreadAffinity();
542 } 570 }
543 571
544 /** 572 /**
545 * You should be always calling this through {@link TextPredictor}. 573 * You should be always calling this through {@link TextPredictor}.
546 */ 574 */
547 @Deprecated 575 @Deprecated
576 @Override
548 public boolean expectText() { 577 public boolean expectText() {
549 return current.loader.expectText; 578 return current.loader.expectText;
550 } 579 }
551 580
552 /** 581 /**
553 * You should be always getting {@link TextPredictor} from {@link XmlVisitor}. 582 * You should be always getting {@link TextPredictor} from {@link XmlVisitor}.
554 */ 583 */
555 @Deprecated 584 @Deprecated
585 @Override
556 public TextPredictor getPredictor() { 586 public TextPredictor getPredictor() {
557 return this; 587 return this;
558 } 588 }
559 589
590 @Override
560 public UnmarshallingContext getContext() { 591 public UnmarshallingContext getContext() {
561 return this; 592 return this;
562 } 593 }
563 594
564 /** 595 /**
648 new UnmarshalException( 679 new UnmarshalException(
649 event.getMessage(), 680 event.getMessage(),
650 event.getLinkedException() ) ); 681 event.getLinkedException() ) );
651 } 682 }
652 683
684 @Override
653 public boolean handleEvent(ValidationEvent event) { 685 public boolean handleEvent(ValidationEvent event) {
654 try { 686 try {
655 // if the handler says "abort", we will not return the object. 687 // if the handler says "abort", we will not return the object.
656 boolean recover = parent.getEventHandler().handleEvent(event); 688 boolean recover = parent.getEventHandler().handleEvent(event);
657 if(!recover) aborted = true; 689 if(!recover) aborted = true;
678 710
679 public void handleError(String msg) { 711 public void handleError(String msg) {
680 handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,msg,locator.getLocation())); 712 handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,msg,locator.getLocation()));
681 } 713 }
682 714
715 @Override
683 protected ValidationEventLocator getLocation() { 716 protected ValidationEventLocator getLocation() {
684 return locator.getLocation(); 717 return locator.getLocation();
685 } 718 }
686 719
687 /** 720 /**
799 // 832 //
800 // 833 //
801 private String[] nsBind = new String[16]; 834 private String[] nsBind = new String[16];
802 private int nsLen=0; 835 private int nsLen=0;
803 836
837 @Override
804 public void startPrefixMapping( String prefix, String uri ) { 838 public void startPrefixMapping( String prefix, String uri ) {
805 if(nsBind.length==nsLen) { 839 if(nsBind.length==nsLen) {
806 // expand the buffer 840 // expand the buffer
807 String[] n = new String[nsLen*2]; 841 String[] n = new String[nsLen*2];
808 System.arraycopy(nsBind,0,n,0,nsLen); 842 System.arraycopy(nsBind,0,n,0,nsLen);
809 nsBind=n; 843 nsBind=n;
810 } 844 }
811 nsBind[nsLen++] = prefix; 845 nsBind[nsLen++] = prefix;
812 nsBind[nsLen++] = uri; 846 nsBind[nsLen++] = uri;
813 } 847 }
848 @Override
814 public void endPrefixMapping( String prefix ) { 849 public void endPrefixMapping( String prefix ) {
815 nsLen-=2; 850 nsLen-=2;
816 } 851 }
817 private String resolveNamespacePrefix( String prefix ) { 852 private String resolveNamespacePrefix( String prefix ) {
818 if(prefix.equals("xml")) 853 if(prefix.equals("xml"))
866 return r; 901 return r;
867 } 902 }
868 903
869 // NamespaceContext2 implementation 904 // NamespaceContext2 implementation
870 // 905 //
906 @Override
871 public Iterator<String> getPrefixes(String uri) { 907 public Iterator<String> getPrefixes(String uri) {
872 // TODO: could be implemented much faster 908 // TODO: could be implemented much faster
873 // wrap it into unmodifiable list so that the remove method 909 // wrap it into unmodifiable list so that the remove method
874 // will throw UnsupportedOperationException. 910 // will throw UnsupportedOperationException.
875 return Collections.unmodifiableList( 911 return Collections.unmodifiableList(
897 a.add(nsBind[i]); 933 a.add(nsBind[i]);
898 934
899 return a; 935 return a;
900 } 936 }
901 937
938 @Override
902 public String getPrefix(String uri) { 939 public String getPrefix(String uri) {
903 if( uri==null ) 940 if( uri==null )
904 throw new IllegalArgumentException(); 941 throw new IllegalArgumentException();
905 if( uri.equals(XMLConstants.XML_NS_URI) ) 942 if( uri.equals(XMLConstants.XML_NS_URI) )
906 return XMLConstants.XML_NS_PREFIX; 943 return XMLConstants.XML_NS_PREFIX;
917 return environmentNamespaceContext.getPrefix(uri); 954 return environmentNamespaceContext.getPrefix(uri);
918 955
919 return null; 956 return null;
920 } 957 }
921 958
959 @Override
922 public String getNamespaceURI(String prefix) { 960 public String getNamespaceURI(String prefix) {
923 if (prefix == null) 961 if (prefix == null)
924 throw new IllegalArgumentException(); 962 throw new IllegalArgumentException();
925 if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) 963 if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE))
926 return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; 964 return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
1057 @Override 1095 @Override
1058 public Collection<QName> getExpectedChildElements() { 1096 public Collection<QName> getExpectedChildElements() {
1059 return getInstance().getJAXBContext().getValidRootNames(); 1097 return getInstance().getJAXBContext().getValidRootNames();
1060 } 1098 }
1061 1099
1100 @Override
1062 public void receive(State state, Object o) { 1101 public void receive(State state, Object o) {
1063 if(state.backup!=null) { 1102 if(state.backup!=null) {
1064 ((JAXBElement<Object>)state.backup).setValue(o); 1103 ((JAXBElement<Object>)state.backup).setValue(o);
1065 o = state.backup; 1104 o = state.backup;
1066 } 1105 }
1093 // which adds the resident memory footprint. Since XsiNilLoader is small, 1132 // which adds the resident memory footprint. Since XsiNilLoader is small,
1094 // I intentionally allocate a new instance freshly. 1133 // I intentionally allocate a new instance freshly.
1095 state.loader = new XsiNilLoader(context.expectedType.getLoader(null,true)); 1134 state.loader = new XsiNilLoader(context.expectedType.getLoader(null,true));
1096 } 1135 }
1097 1136
1137 @Override
1098 public void receive(State state, Object o) { 1138 public void receive(State state, Object o) {
1099 JAXBElement e = (JAXBElement)state.target; 1139 JAXBElement e = (JAXBElement)state.target;
1100 e.setValue(o); 1140 e.setValue(o);
1101 state.getContext().recordOuterPeer(e); 1141 state.getContext().recordOuterPeer(e);
1102 state.getContext().result = e; 1142 state.getContext().result = e;
1231 return (StructureLoader)current.loader; 1271 return (StructureLoader)current.loader;
1232 1272
1233 return null; 1273 return null;
1234 } 1274 }
1235 1275
1276 /**
1277 * Based on current {@link Logger} {@link Level} and errorCounter value determines if error should be reported.
1278 *
1279 * If the method called and return true it is expected that error will be reported. And that's why
1280 * errorCounter is automatically decremented during the check.
1281 *
1282 * NOT THREAD SAFE!!! In case of heave concurrency access several additional errors could be reported. It's not expected to be the
1283 * problem. Otherwise add synchronization here.
1284 *
1285 * @return true in case if {@link Level#FINEST} is set OR we haven't exceed errors reporting limit.
1286 */
1287 public boolean shouldErrorBeReported() throws SAXException {
1288 if (logger.isLoggable(Level.FINEST))
1289 return true;
1290
1291 if (errorsCounter >= 0) {
1292 --errorsCounter;
1293 if (errorsCounter == 0) // it's possible to miss this because of concurrency. If required add synchronization here
1294 handleEvent(new ValidationEventImpl(ValidationEvent.WARNING, Messages.ERRORS_LIMIT_EXCEEDED.format(),
1295 getLocator().getLocation(), null), true);
1296 }
1297 return errorsCounter >= 0;
1298 }
1236 } 1299 }

mercurial