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