--- old/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallingContext.java 2013-08-13 18:16:55.293040625 +0200 +++ new/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallingContext.java 2013-08-13 18:16:55.233037969 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.xml.XMLConstants; import javax.xml.bind.JAXBElement; @@ -51,6 +53,7 @@ import com.sun.istack.internal.Nullable; import com.sun.istack.internal.SAXParseException2; import com.sun.xml.internal.bind.IDResolver; +import com.sun.xml.internal.bind.Util; import com.sun.xml.internal.bind.api.AccessorException; import com.sun.xml.internal.bind.api.ClassResolver; import com.sun.xml.internal.bind.unmarshaller.InfosetScanner; @@ -59,6 +62,8 @@ import com.sun.xml.internal.bind.v2.runtime.Coordinator; import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo; +import java.util.logging.Level; +import java.util.logging.Logger; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; @@ -76,6 +81,8 @@ public final class UnmarshallingContext extends Coordinator implements NamespaceContext, ValidationEventHandler, ErrorHandler, XmlVisitor, XmlVisitor.TextPredictor { + private static final Logger logger = Logger.getLogger(UnmarshallingContext.class.getName()); + /** * Root state. */ @@ -177,6 +184,14 @@ public @Nullable ClassLoader classLoader; /** + * The variable introduced to avoid reporting n^10 similar errors. + * After error is reported counter is decremented. When it became 0 - errors should not be reported any more. + * + * volatile is required to ensure that concurrent threads will see changed value + */ + private static volatile int errorsCounter = 10; + + /** * State information for each element. */ public final class State { @@ -260,21 +275,32 @@ return UnmarshallingContext.this; } + @SuppressWarnings("LeakingThisInConstructor") private State(State prev) { this.prev = prev; - if(prev!=null) + if (prev!=null) { prev.next = this; + } } private void push() { - if(next==null) + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "State.push"); + } + if (next==null) { + assert current == this; allocateMoreStates(); + } + nil = false; State n = next; n.numNsDecl = nsLen; current = n; } private void pop() { + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "State.pop"); + } assert prev!=null; loader = null; nil = false; @@ -381,8 +407,9 @@ assert current.next==null; State s = current; - for( int i=0; i<8; i++ ) + for (int i=0; i<8; i++) { s = new State(s); + } } public void clearStates() { @@ -436,6 +463,7 @@ } } + @Override public void startDocument(LocatorEx locator, NamespaceContext nsContext) throws SAXException { if(locator!=null) this.locator = locator; @@ -449,8 +477,6 @@ isUnmarshalInProgress = true; nsLen=0; - setThreadAffinity(); - if(expectedType!=null) root.loader = EXPECTED_TYPE_ROOT_LOADER; else @@ -459,6 +485,7 @@ idResolver.startDocument(this); } + @Override public void startElement(TagName tagName) throws SAXException { pushCoordinator(); try { @@ -486,6 +513,7 @@ current.loader.startElement(current,tagName); } + @Override public void text(CharSequence pcdata) throws SAXException { State cur = current; pushCoordinator(); @@ -502,6 +530,7 @@ } } + @Override public final void endElement(TagName tagName) throws SAXException { pushCoordinator(); try { @@ -526,6 +555,7 @@ } } + @Override public void endDocument() throws SAXException { runPatchers(); idResolver.endDocument(); @@ -537,14 +567,13 @@ // at the successful completion, scope must be all closed assert root==current; - - resetThreadAffinity(); } /** * You should be always calling this through {@link TextPredictor}. */ @Deprecated + @Override public boolean expectText() { return current.loader.expectText; } @@ -553,10 +582,12 @@ * You should be always getting {@link TextPredictor} from {@link XmlVisitor}. */ @Deprecated + @Override public TextPredictor getPredictor() { return this; } + @Override public UnmarshallingContext getContext() { return this; } @@ -650,6 +681,7 @@ event.getLinkedException() ) ); } + @Override public boolean handleEvent(ValidationEvent event) { try { // if the handler says "abort", we will not return the object. @@ -680,6 +712,7 @@ handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,msg,locator.getLocation())); } + @Override protected ValidationEventLocator getLocation() { return locator.getLocation(); } @@ -801,6 +834,7 @@ private String[] nsBind = new String[16]; private int nsLen=0; + @Override public void startPrefixMapping( String prefix, String uri ) { if(nsBind.length==nsLen) { // expand the buffer @@ -811,6 +845,7 @@ nsBind[nsLen++] = prefix; nsBind[nsLen++] = uri; } + @Override public void endPrefixMapping( String prefix ) { nsLen-=2; } @@ -868,6 +903,7 @@ // NamespaceContext2 implementation // + @Override public Iterator getPrefixes(String uri) { // TODO: could be implemented much faster // wrap it into unmodifiable list so that the remove method @@ -899,6 +935,7 @@ return a; } + @Override public String getPrefix(String uri) { if( uri==null ) throw new IllegalArgumentException(); @@ -919,6 +956,7 @@ return null; } + @Override public String getNamespaceURI(String prefix) { if (prefix == null) throw new IllegalArgumentException(); @@ -1059,6 +1097,7 @@ return getInstance().getJAXBContext().getValidRootNames(); } + @Override public void receive(State state, Object o) { if(state.backup!=null) { ((JAXBElement)state.backup).setValue(o); @@ -1095,6 +1134,7 @@ state.loader = new XsiNilLoader(context.expectedType.getLoader(null,true)); } + @Override public void receive(State state, Object o) { JAXBElement e = (JAXBElement)state.target; e.setValue(o); @@ -1233,4 +1273,27 @@ return null; } + /** + * Based on current {@link Logger} {@link Level} and errorCounter value determines if error should be reported. + * + * If the method called and return true it is expected that error will be reported. And that's why + * errorCounter is automatically decremented during the check. + * + * NOT THREAD SAFE!!! In case of heave concurrency access several additional errors could be reported. It's not expected to be the + * problem. Otherwise add synchronization here. + * + * @return true in case if {@link Level#FINEST} is set OR we haven't exceed errors reporting limit. + */ + public boolean shouldErrorBeReported() throws SAXException { + if (logger.isLoggable(Level.FINEST)) + return true; + + if (errorsCounter >= 0) { + --errorsCounter; + if (errorsCounter == 0) // it's possible to miss this because of concurrency. If required add synchronization here + handleEvent(new ValidationEventImpl(ValidationEvent.WARNING, Messages.ERRORS_LIMIT_EXCEEDED.format(), + getLocator().getLocation(), null), true); + } + return errorsCounter >= 0; + } }