1 /*
   2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   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
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.bind.v2.runtime.unmarshaller;
  27 
  28 import javax.xml.bind.JAXBException;
  29 import javax.xml.bind.UnmarshallerHandler;
  30 
  31 import com.sun.xml.internal.bind.WhiteSpaceProcessor;
  32 import com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl;
  33 
  34 import org.xml.sax.Attributes;
  35 import org.xml.sax.Locator;
  36 import org.xml.sax.SAXException;
  37 
  38 /**
  39  * Receives SAX events and convert them to our internal events.
  40  *
  41  * @author Kohsuke Kawaguchi
  42  */
  43 public final class SAXConnector implements UnmarshallerHandler {
  44 
  45     private LocatorEx loc;
  46 
  47     /**
  48      * SAX may fire consecutive characters event, but we don't allow it.
  49      * so use this buffer to perform buffering.
  50      */
  51     private final StringBuilder buffer = new StringBuilder();
  52 
  53     private final XmlVisitor next;
  54     private final UnmarshallingContext context;
  55     private final XmlVisitor.TextPredictor predictor;
  56 
  57     private static final class TagNameImpl extends TagName {
  58         String qname;
  59         public String getQname() {
  60             return qname;
  61         }
  62     }
  63 
  64     private final TagNameImpl tagName = new TagNameImpl();
  65 
  66     /**
  67      * @param externalLocator
  68      *      If the caller is producing SAX events from sources other than Unicode and angle brackets,
  69      *      the caller can override the default SAX {@link Locator} object by this object
  70      *      to provide better location information.
  71      */
  72     public SAXConnector(XmlVisitor next, LocatorEx externalLocator ) {
  73         this.next = next;
  74         this.context = next.getContext();
  75         this.predictor = next.getPredictor();
  76         this.loc = externalLocator;
  77     }
  78 
  79     public Object getResult() throws JAXBException, IllegalStateException {
  80         return context.getResult();
  81     }
  82 
  83     public UnmarshallingContext getContext() {
  84         return context;
  85     }
  86 
  87     public void setDocumentLocator(final Locator locator) {
  88         if(loc!=null)
  89             return; // we already have an external locator. ignore.
  90 
  91         this.loc = new LocatorExWrapper(locator);
  92     }
  93 
  94     public void startDocument() throws SAXException {
  95         next.startDocument(loc,null);
  96     }
  97 
  98     public void endDocument() throws SAXException {
  99         next.endDocument();
 100     }
 101 
 102     public void startPrefixMapping(String prefix, String uri) throws SAXException {
 103         next.startPrefixMapping(prefix,uri);
 104     }
 105 
 106     public void endPrefixMapping(String prefix) throws SAXException {
 107         next.endPrefixMapping(prefix);
 108     }
 109 
 110     public void startElement(String uri, String local, String qname, Attributes atts) throws SAXException {
 111         // work gracefully with misconfigured parsers that don't support namespaces
 112         if( uri==null || uri.length()==0 )
 113             uri="";
 114         if( local==null || local.length()==0 )
 115             local=qname;
 116         if( qname==null || qname.length()==0 )
 117             qname=local;
 118 
 119 
 120         boolean ignorable = true;
 121         StructureLoader sl;
 122 
 123         // not null only if element content is processed (StructureLoader is used)
 124         // ugly
 125         if((sl = this.context.getStructureLoader()) != null) {
 126             ignorable = ((ClassBeanInfoImpl)sl.getBeanInfo()).hasElementOnlyContentModel();
 127         }
 128 
 129         processText(ignorable);
 130 
 131         tagName.uri = uri;
 132         tagName.local = local;
 133         tagName.qname = qname;
 134         tagName.atts = atts;
 135         next.startElement(tagName);
 136     }
 137 
 138     public void endElement(String uri, String localName, String qName) throws SAXException {
 139         processText(false);
 140         tagName.uri = uri;
 141         tagName.local = localName;
 142         tagName.qname = qName;
 143         next.endElement(tagName);
 144     }
 145 
 146 
 147     public final void characters( char[] buf, int start, int len ) {
 148         if( predictor.expectText() )
 149             buffer.append(buf,start,len);
 150     }
 151 
 152     public final void ignorableWhitespace( char[] buf, int start, int len ) {
 153         characters(buf,start,len);
 154     }
 155 
 156     public void processingInstruction(String target, String data) {
 157         // nop
 158     }
 159 
 160     public void skippedEntity(String name) {
 161         // nop
 162     }
 163 
 164     private void processText( boolean ignorable ) throws SAXException {
 165         if( predictor.expectText() && (!ignorable || !WhiteSpaceProcessor.isWhiteSpace(buffer)))
 166             next.text(buffer);
 167         buffer.setLength(0);
 168     }
 169 
 170 }