ohair@286: /* aefimov@650: * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.xml.internal.bind.v2.runtime.unmarshaller; ohair@286: mkos@397: import com.sun.xml.internal.bind.Util; ohair@286: import javax.xml.bind.JAXBException; ohair@286: import javax.xml.bind.UnmarshallerHandler; ohair@286: ohair@286: import com.sun.xml.internal.bind.WhiteSpaceProcessor; ohair@286: import com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl; mkos@397: import java.util.logging.Level; mkos@397: import java.util.logging.Logger; ohair@286: ohair@286: import org.xml.sax.Attributes; ohair@286: import org.xml.sax.Locator; ohair@286: import org.xml.sax.SAXException; ohair@286: ohair@286: /** ohair@286: * Receives SAX events and convert them to our internal events. ohair@286: * ohair@286: * @author Kohsuke Kawaguchi ohair@286: */ ohair@286: public final class SAXConnector implements UnmarshallerHandler { ohair@286: ohair@286: private LocatorEx loc; ohair@286: mkos@397: private static final Logger logger = Util.getClassLogger(); mkos@397: ohair@286: /** ohair@286: * SAX may fire consecutive characters event, but we don't allow it. ohair@286: * so use this buffer to perform buffering. ohair@286: */ ohair@286: private final StringBuilder buffer = new StringBuilder(); ohair@286: ohair@286: private final XmlVisitor next; ohair@286: private final UnmarshallingContext context; ohair@286: private final XmlVisitor.TextPredictor predictor; ohair@286: ohair@286: private static final class TagNameImpl extends TagName { ohair@286: String qname; mkos@397: @Override ohair@286: public String getQname() { ohair@286: return qname; ohair@286: } ohair@286: } ohair@286: ohair@286: private final TagNameImpl tagName = new TagNameImpl(); ohair@286: ohair@286: /** ohair@286: * @param externalLocator ohair@286: * If the caller is producing SAX events from sources other than Unicode and angle brackets, ohair@286: * the caller can override the default SAX {@link Locator} object by this object ohair@286: * to provide better location information. ohair@286: */ ohair@286: public SAXConnector(XmlVisitor next, LocatorEx externalLocator ) { ohair@286: this.next = next; ohair@286: this.context = next.getContext(); ohair@286: this.predictor = next.getPredictor(); ohair@286: this.loc = externalLocator; ohair@286: } ohair@286: mkos@397: @Override ohair@286: public Object getResult() throws JAXBException, IllegalStateException { ohair@286: return context.getResult(); ohair@286: } ohair@286: ohair@286: public UnmarshallingContext getContext() { ohair@286: return context; ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void setDocumentLocator(final Locator locator) { ohair@286: if(loc!=null) ohair@286: return; // we already have an external locator. ignore. ohair@286: ohair@286: this.loc = new LocatorExWrapper(locator); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void startDocument() throws SAXException { mkos@397: if (logger.isLoggable(Level.FINER)) { mkos@397: logger.log(Level.FINER, "SAXConnector.startDocument"); mkos@397: } ohair@286: next.startDocument(loc,null); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void endDocument() throws SAXException { mkos@397: if (logger.isLoggable(Level.FINER)) { mkos@397: logger.log(Level.FINER, "SAXConnector.endDocument"); mkos@397: } ohair@286: next.endDocument(); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void startPrefixMapping(String prefix, String uri) throws SAXException { mkos@397: if (logger.isLoggable(Level.FINER)) { mkos@397: logger.log(Level.FINER, "SAXConnector.startPrefixMapping: {0}:{1}", new Object[]{prefix, uri}); mkos@397: } ohair@286: next.startPrefixMapping(prefix,uri); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void endPrefixMapping(String prefix) throws SAXException { mkos@397: if (logger.isLoggable(Level.FINER)) { mkos@397: logger.log(Level.FINER, "SAXConnector.endPrefixMapping: {0}", new Object[]{prefix}); mkos@397: } ohair@286: next.endPrefixMapping(prefix); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void startElement(String uri, String local, String qname, Attributes atts) throws SAXException { mkos@397: if (logger.isLoggable(Level.FINER)) { mkos@397: logger.log(Level.FINER, "SAXConnector.startElement: {0}:{1}:{2}, attrs: {3}", new Object[]{uri, local, qname, atts}); mkos@397: } ohair@286: // work gracefully with misconfigured parsers that don't support namespaces ohair@286: if( uri==null || uri.length()==0 ) ohair@286: uri=""; ohair@286: if( local==null || local.length()==0 ) ohair@286: local=qname; ohair@286: if( qname==null || qname.length()==0 ) ohair@286: qname=local; ohair@286: aefimov@650: processText(!context.getCurrentState().isMixed()); ohair@286: ohair@286: tagName.uri = uri; ohair@286: tagName.local = local; ohair@286: tagName.qname = qname; ohair@286: tagName.atts = atts; ohair@286: next.startElement(tagName); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void endElement(String uri, String localName, String qName) throws SAXException { mkos@397: if (logger.isLoggable(Level.FINER)) { mkos@397: logger.log(Level.FINER, "SAXConnector.startElement: {0}:{1}:{2}", new Object[]{uri, localName, qName}); mkos@397: } ohair@286: processText(false); ohair@286: tagName.uri = uri; ohair@286: tagName.local = localName; ohair@286: tagName.qname = qName; ohair@286: next.endElement(tagName); ohair@286: } ohair@286: ohair@286: mkos@397: @Override ohair@286: public final void characters( char[] buf, int start, int len ) { mkos@397: if (logger.isLoggable(Level.FINEST)) { mkos@397: logger.log(Level.FINEST, "SAXConnector.characters: {0}", buf); mkos@397: } ohair@286: if( predictor.expectText() ) ohair@286: buffer.append(buf,start,len); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public final void ignorableWhitespace( char[] buf, int start, int len ) { mkos@397: if (logger.isLoggable(Level.FINEST)) { mkos@397: logger.log(Level.FINEST, "SAXConnector.characters{0}", buf); mkos@397: } ohair@286: characters(buf,start,len); ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void processingInstruction(String target, String data) { ohair@286: // nop ohair@286: } ohair@286: mkos@397: @Override ohair@286: public void skippedEntity(String name) { ohair@286: // nop ohair@286: } ohair@286: ohair@286: private void processText( boolean ignorable ) throws SAXException { aefimov@650: if (predictor.expectText() && (!ignorable || !WhiteSpaceProcessor.isWhiteSpace(buffer))) ohair@286: next.text(buffer); ohair@286: buffer.setLength(0); ohair@286: } ohair@286: ohair@286: }