1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /*
6  * Licensed to the Apache Software Foundation (ASF) under one or more
7  * contributor license agreements.  See the NOTICE file distributed with
8  * this work for additional information regarding copyright ownership.
9  * The ASF licenses this file to You under the Apache License, Version 2.0
10  * (the "License"); you may not use this file except in compliance with
11  * the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 package com.sun.org.apache.xerces.internal.impl.xs.traversers;
23 
24 import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOMParser;
25 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
26 import com.sun.org.apache.xerces.internal.util.SAXLocatorWrapper;
27 import com.sun.org.apache.xerces.internal.util.SymbolTable;
28 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
29 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
30 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
31 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
32 import com.sun.org.apache.xerces.internal.xni.QName;
33 import com.sun.org.apache.xerces.internal.xni.XMLString;
34 import com.sun.org.apache.xerces.internal.xni.XNIException;
35 import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
36 import org.w3c.dom.Document;
37 import org.xml.sax.Attributes;
38 import org.xml.sax.ContentHandler;
39 import org.xml.sax.Locator;
40 import org.xml.sax.SAXException;
41 import org.xml.sax.SAXParseException;
42 import org.xml.sax.helpers.LocatorImpl;
43 
44 /**
45  * <p>SchemaContentHandler converts SAX events into XNI
46  * and passes them directly to the SchemaDOMParser.</p>
47  *
48  * @xerces.internal
49  *
50  * @author Michael Glavassevich, IBM
51  * @author Jack Z. Wang, IBM
52  *
53  */
54 final class SchemaContentHandler implements ContentHandler {
55 
56     /** Symbol table **/
57     private SymbolTable fSymbolTable;
58 
59     /** SchemaDOMParser, events will be delegated to SchemaDOMParser to pass */
60     private SchemaDOMParser fSchemaDOMParser;
61 
62     /** XML Locator wrapper for SAX. **/
63     private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper();
64 
65     /** The namespace context of this document: stores namespaces in scope */
66     private NamespaceSupport fNamespaceContext = new NamespaceSupport();
67 
68     /** Indicate if push NamespaceContest is needed */
69     private boolean fNeedPushNSContext;
70 
71     /** Flag used to track whether namespace declarations are reported as attributes. */
72     private boolean fNamespacePrefixes = false;
73 
74     /** Flag used to track whether XML names and Namespace URIs have been internalized. */
75     private boolean fStringsInternalized = false;
76 
77     /** Fields for start element, end element and characters. */
78     private final QName fElementQName = new QName();
79     private final QName fAttributeQName = new QName();
80     private final XMLAttributesImpl fAttributes = new XMLAttributesImpl();
81     private final XMLString fTempString = new XMLString();
82     private final XMLStringBuffer fStringBuffer = new XMLStringBuffer();
83 
84     /**
85      * <p>Constructs an SchemaContentHandler.</p>
86      */
SchemaContentHandler()87     public SchemaContentHandler() {}
88 
89     /*
90      * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
91      */
getDocument()92     public Document getDocument() {
93         return fSchemaDOMParser.getDocument();
94     }
95 
96     /*
97      * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
98      */
setDocumentLocator(Locator locator)99     public void setDocumentLocator(Locator locator) {
100         fSAXLocatorWrapper.setLocator(locator);
101     }
102 
103     /*
104      * @see org.xml.sax.ContentHandler#startDocument()
105      */
startDocument()106     public void startDocument() throws SAXException {
107         fNeedPushNSContext = true;
108         fNamespaceContext.reset();
109         try {
110             fSchemaDOMParser.startDocument(fSAXLocatorWrapper, null, fNamespaceContext, null);
111         }
112         catch (XMLParseException e) {
113             convertToSAXParseException(e);
114         }
115         catch (XNIException e) {
116             convertToSAXException(e);
117         }
118     }
119 
120     /*
121      * @see org.xml.sax.ContentHandler#endDocument()
122      */
endDocument()123     public void endDocument() throws SAXException {
124         fSAXLocatorWrapper.setLocator(null);
125         try {
126             fSchemaDOMParser.endDocument(null);
127         }
128         catch (XMLParseException e) {
129             convertToSAXParseException(e);
130         }
131         catch (XNIException e) {
132             convertToSAXException(e);
133         }
134     }
135 
136     /*
137      * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
138      */
startPrefixMapping(String prefix, String uri)139     public void startPrefixMapping(String prefix, String uri) throws SAXException {
140         if (fNeedPushNSContext) {
141             fNeedPushNSContext = false;
142             fNamespaceContext.pushContext();
143         }
144         if (!fStringsInternalized) {
145             prefix = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING;
146             uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
147         }
148         else {
149             if (prefix == null) {
150                 prefix = XMLSymbols.EMPTY_STRING;
151             }
152             if (uri != null && uri.length() == 0) {
153                 uri = null;
154             }
155         }
156         fNamespaceContext.declarePrefix(prefix, uri);
157     }
158 
159     /*
160      * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
161      */
endPrefixMapping(String prefix)162     public void endPrefixMapping(String prefix) throws SAXException {
163         // do nothing
164     }
165 
166     /*
167      * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
168      */
startElement(String uri, String localName, String qName, Attributes atts)169     public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
170         if (fNeedPushNSContext) {
171             fNamespaceContext.pushContext();
172         }
173         fNeedPushNSContext = true;
174 
175         // Fill element QName and XMLAttributes
176         fillQName(fElementQName, uri, localName, qName);
177         fillXMLAttributes(atts);
178 
179         // Add namespace declarations if necessary
180         if (!fNamespacePrefixes) {
181             final int prefixCount = fNamespaceContext.getDeclaredPrefixCount();
182             if (prefixCount > 0) {
183                 addNamespaceDeclarations(prefixCount);
184             }
185         }
186 
187         try {
188             fSchemaDOMParser.startElement(fElementQName, fAttributes, null);
189         }
190         catch (XMLParseException e) {
191             convertToSAXParseException(e);
192         }
193         catch (XNIException e) {
194             convertToSAXException(e);
195         }
196     }
197 
198     /*
199      * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
200      */
endElement(String uri, String localName, String qName)201     public void endElement(String uri, String localName, String qName) throws SAXException {
202         fillQName(fElementQName, uri, localName, qName);
203         try {
204             fSchemaDOMParser.endElement(fElementQName, null);
205         }
206         catch (XMLParseException e) {
207             convertToSAXParseException(e);
208         }
209         catch (XNIException e) {
210             convertToSAXException(e);
211         }
212         finally {
213             fNamespaceContext.popContext();
214         }
215     }
216 
217     /*
218      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
219      */
characters(char[] ch, int start, int length)220     public void characters(char[] ch, int start, int length) throws SAXException {
221         try {
222             fTempString.setValues(ch, start, length);
223             fSchemaDOMParser.characters(fTempString, null);
224         }
225         catch (XMLParseException e) {
226             convertToSAXParseException(e);
227         }
228         catch (XNIException e) {
229             convertToSAXException(e);
230         }
231     }
232 
233     /*
234      * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
235      */
ignorableWhitespace(char[] ch, int start, int length)236     public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
237         try {
238             fTempString.setValues(ch, start, length);
239             fSchemaDOMParser.ignorableWhitespace(fTempString, null);
240         }
241         catch (XMLParseException e) {
242             convertToSAXParseException(e);
243         }
244         catch (XNIException e) {
245             convertToSAXException(e);
246         }
247     }
248 
249     /*
250      * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
251      */
processingInstruction(String target, String data)252     public void processingInstruction(String target, String data) throws SAXException {
253         try {
254             fTempString.setValues(data.toCharArray(), 0, data.length());
255             fSchemaDOMParser.processingInstruction(target, fTempString, null);
256         }
257         catch (XMLParseException e) {
258             convertToSAXParseException(e);
259         }
260         catch (XNIException e) {
261             convertToSAXException(e);
262         }
263     }
264 
265     /*
266      * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
267      */
skippedEntity(String arg)268     public void skippedEntity(String arg) throws SAXException {
269         // do-nothing
270     }
271 
272     /*
273      * Other methods
274      */
275 
fillQName(QName toFill, String uri, String localpart, String rawname)276     private void fillQName(QName toFill, String uri, String localpart, String rawname) {
277         if (!fStringsInternalized) {
278             uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
279             localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING;
280             rawname = (rawname != null) ? fSymbolTable.addSymbol(rawname) : XMLSymbols.EMPTY_STRING;
281         }
282         else {
283             if (uri != null && uri.length() == 0) {
284                 uri = null;
285             }
286             if (localpart == null) {
287                 localpart = XMLSymbols.EMPTY_STRING;
288             }
289             if (rawname == null) {
290                 rawname = XMLSymbols.EMPTY_STRING;
291             }
292         }
293         String prefix = XMLSymbols.EMPTY_STRING;
294         int prefixIdx = rawname.indexOf(':');
295         if (prefixIdx != -1) {
296             prefix = fSymbolTable.addSymbol(rawname.substring(0, prefixIdx));
297             // local part may be an empty string if this is a namespace declaration
298             if (localpart == XMLSymbols.EMPTY_STRING) {
299                 localpart = fSymbolTable.addSymbol(rawname.substring(prefixIdx + 1));
300             }
301         }
302         // local part may be an empty string if this is a namespace declaration
303         else if (localpart == XMLSymbols.EMPTY_STRING) {
304             localpart = rawname;
305         }
306         toFill.setValues(prefix, localpart, rawname, uri);
307     }
308 
fillXMLAttributes(Attributes atts)309     private void fillXMLAttributes(Attributes atts) {
310         fAttributes.removeAllAttributes();
311         final int attrCount = atts.getLength();
312         for (int i = 0; i < attrCount; ++i) {
313             fillQName(fAttributeQName, atts.getURI(i), atts.getLocalName(i), atts.getQName(i));
314             String type = atts.getType(i);
315             fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, atts.getValue(i));
316             fAttributes.setSpecified(i, true);
317         }
318     }
319 
addNamespaceDeclarations(final int prefixCount)320     private void addNamespaceDeclarations(final int prefixCount) {
321         String prefix = null;
322         String localpart = null;
323         String rawname = null;
324         String nsPrefix = null;
325         String nsURI = null;
326         for (int i = 0; i < prefixCount; ++i) {
327             nsPrefix = fNamespaceContext.getDeclaredPrefixAt(i);
328             nsURI = fNamespaceContext.getURI(nsPrefix);
329             if (nsPrefix.length() > 0) {
330                 prefix = XMLSymbols.PREFIX_XMLNS;
331                 localpart = nsPrefix;
332                 fStringBuffer.clear();
333                 fStringBuffer.append(prefix);
334                 fStringBuffer.append(':');
335                 fStringBuffer.append(localpart);
336                 rawname = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
337             }
338             else {
339                 prefix = XMLSymbols.EMPTY_STRING;
340                 localpart = XMLSymbols.PREFIX_XMLNS;
341                 rawname = XMLSymbols.PREFIX_XMLNS;
342             }
343             fAttributeQName.setValues(prefix, localpart, rawname, NamespaceContext.XMLNS_URI);
344             fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol,
345                     (nsURI != null) ? nsURI : XMLSymbols.EMPTY_STRING);
346         }
347     }
348 
reset(SchemaDOMParser schemaDOMParser, SymbolTable symbolTable, boolean namespacePrefixes, boolean stringsInternalized)349     public void reset(SchemaDOMParser schemaDOMParser, SymbolTable symbolTable,
350             boolean namespacePrefixes, boolean stringsInternalized) {
351         fSchemaDOMParser = schemaDOMParser;
352         fSymbolTable = symbolTable;
353         fNamespacePrefixes = namespacePrefixes;
354         fStringsInternalized = stringsInternalized;
355     }
356 
357     /*
358      * Static methods
359      */
360 
convertToSAXParseException(XMLParseException e)361     static void convertToSAXParseException(XMLParseException e) throws SAXException {
362         Exception ex = e.getException();
363         if (ex == null) {
364             // must be a parser exception; mine it for locator info and throw
365             // a SAXParseException
366             LocatorImpl locatorImpl = new LocatorImpl();
367             locatorImpl.setPublicId(e.getPublicId());
368             locatorImpl.setSystemId(e.getExpandedSystemId());
369             locatorImpl.setLineNumber(e.getLineNumber());
370             locatorImpl.setColumnNumber(e.getColumnNumber());
371             throw new SAXParseException(e.getMessage(), locatorImpl);
372         }
373         if (ex instanceof SAXException) {
374             // why did we create an XMLParseException?
375             throw (SAXException) ex;
376         }
377         throw new SAXException(ex);
378     }
379 
convertToSAXException(XNIException e)380     static void convertToSAXException(XNIException e) throws SAXException {
381         Exception ex = e.getException();
382         if (ex == null) {
383             throw new SAXException(e.getMessage());
384         }
385         if (ex instanceof SAXException) {
386             throw (SAXException) ex;
387         }
388         throw new SAXException(ex);
389     }
390 
391 } // SchemaContentHandler
392