1 /*
   2  * Copyright (c) 1997, 2010, 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.tools.internal.ws.wsdl.parser;
  27 
  28 import com.sun.xml.internal.bind.unmarshaller.DOMScanner;
  29 import org.w3c.dom.Document;
  30 import org.w3c.dom.Element;
  31 import org.w3c.dom.Node;
  32 import org.xml.sax.Attributes;
  33 import org.xml.sax.ContentHandler;
  34 import org.xml.sax.Locator;
  35 import org.xml.sax.SAXException;
  36 import org.xml.sax.helpers.XMLFilterImpl;
  37 
  38 /**
  39  * Produces a complete series of SAX events from any DOM node
  40  * in the DOMForest.
  41  *
  42  * <p>
  43  * This class hides a logic of re-associating {@link org.xml.sax.Locator}
  44  * to the generated SAX event stream.
  45  *
  46  * @author
  47  *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
  48  */
  49 public class DOMForestScanner {
  50 
  51     private final DOMForest forest;
  52 
  53     /**
  54      * Scans DOM nodes of the given forest.
  55      *
  56      * DOM node parameters to the scan method must be a part of
  57      * this forest.
  58      */
  59     public DOMForestScanner( DOMForest _forest ) {
  60         this.forest = _forest;
  61     }
  62 
  63     /**
  64      * Generates the whole set of SAX events by treating
  65      * element e as if it's a root element.
  66      */
  67     public void scan( Element e, ContentHandler contentHandler ) throws SAXException {
  68         DOMScanner scanner = new DOMScanner();
  69 
  70         // insert the location resolver into the pipe line
  71         LocationResolver resolver = new LocationResolver(scanner);
  72         resolver.setContentHandler(contentHandler);
  73 
  74         // parse this DOM.
  75         scanner.setContentHandler(resolver);
  76         scanner.scan(e);
  77     }
  78 
  79     /**
  80      * Generates the whole set of SAX events from the given Document
  81      * in the DOMForest.
  82      */
  83     public void scan( Document d, ContentHandler contentHandler ) throws SAXException {
  84         scan( d.getDocumentElement(), contentHandler );
  85     }
  86 
  87     /**
  88      * Intercepts the invocation of the setDocumentLocator method
  89      * and passes itself as the locator.
  90      *
  91      * If the client calls one of the methods on the Locator interface,
  92      * use the LocatorTable to resolve the source location.
  93      */
  94     private class LocationResolver extends XMLFilterImpl implements Locator {
  95         LocationResolver( DOMScanner _parent ) {
  96             this.parent = _parent;
  97         }
  98 
  99         private final DOMScanner parent;
 100 
 101         /**
 102          * Flag that tells us whether we are processing a start element event
 103          * or an end element event.
 104          *
 105          * DOMScanner's getCurrentLocation method doesn't tell us which, but
 106          * this information is necessary to return the correct source line information.
 107          *
 108          * Thus we set this flag appropriately before we pass an event to
 109          * the next ContentHandler, thereby making it possible to figure
 110          * out which location to return.
 111          */
 112         private boolean inStart = false;
 113 
 114         public void setDocumentLocator(Locator locator) {
 115             // ignore one set by the parent.
 116 
 117             super.setDocumentLocator(this);
 118         }
 119 
 120         public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
 121             inStart = false;
 122             super.endElement(namespaceURI, localName, qName);
 123         }
 124 
 125         public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
 126             throws SAXException {
 127             inStart = true;
 128             super.startElement(namespaceURI, localName, qName, atts);
 129         }
 130 
 131 
 132 
 133 
 134         private Locator findLocator() {
 135             Node n = parent.getCurrentLocation();
 136             if( n instanceof Element ) {
 137                 Element e = (Element)n;
 138                 if( inStart )
 139                     return forest.locatorTable.getStartLocation( e );
 140                 else
 141                     return forest.locatorTable.getEndLocation( e );
 142             }
 143             return null;
 144         }
 145 
 146         //
 147         //
 148         // Locator methods
 149         //
 150         //
 151         public int getColumnNumber() {
 152             Locator l = findLocator();
 153             if(l!=null)     return l.getColumnNumber();
 154             return          -1;
 155         }
 156 
 157         public int getLineNumber() {
 158             Locator l = findLocator();
 159             if(l!=null)     return l.getLineNumber();
 160             return          -1;
 161         }
 162 
 163         public String getPublicId() {
 164             Locator l = findLocator();
 165             if(l!=null)     return l.getPublicId();
 166             return          null;
 167         }
 168 
 169         public String getSystemId() {
 170             Locator l = findLocator();
 171             if(l!=null)     return l.getSystemId();
 172             return          null;
 173         }
 174 
 175     }
 176 }