View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999-2002 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  
46  package org.exolab.castor.xml.schema.reader;
47  
48  import org.exolab.castor.xml.AttributeSet;
49  import org.exolab.castor.xml.NamespacesStack;
50  import org.exolab.castor.xml.XMLException;
51  import org.exolab.castor.xml.util.AttributeSetImpl;
52  import org.xml.sax.AttributeList;
53  import org.xml.sax.DocumentHandler;
54  import org.xml.sax.Locator;
55  import org.xml.sax.SAXException;
56  import org.xml.sax.SAXParseException;
57  
58  /**
59   * A SAX adapter class for the ComponentReader.
60   * 
61   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
62   * @version $Revision$ $Date: 2006-04-14 04:14:43 -0600 (Fri, 14 Apr
63   *          2006) $
64   **/
65  @SuppressWarnings("deprecation")
66  public final class Sax2ComponentReader implements DocumentHandler, org.xml.sax.ErrorHandler {
67  
68     private static final String XMLNS = "xmlns";
69     private static final String XMLNS_PREFIX = XMLNS + ":";
70     private static final String XML_PREFIX = "xml";
71  
72     private ComponentReader componentReader = null;
73  
74     /**
75      * Represents the namespaces stack.
76      */
77     private NamespacesStack namespacesStack = null;
78  
79     public Sax2ComponentReader(ComponentReader compReader) {
80        super();
81        componentReader = compReader;
82        namespacesStack = new NamespacesStack();
83     }
84  
85     /**
86      * Processes the attributes and namespace declarations found in the given SAX
87      * AttributeList. The global AttributeSet is cleared and updated with the
88      * attributes. Namespace declarations are added to the set of namespaces in
89      * scope.
90      * 
91      * @param atts
92      *           the AttributeList to process.
93      **/
94     private AttributeSet processAttributeList(AttributeList atts) throws SAXException {
95  
96        if (atts == null)
97           return new AttributeSetImpl(0);
98  
99        // -- process all namespaces first
100       int attCount = 0;
101       boolean[] validAtts = new boolean[atts.getLength()];
102       for (int i = 0; i < validAtts.length; i++) {
103          String attName = atts.getName(i);
104          if (attName.equals(XMLNS)) {
105             namespacesStack.addNamespace("", atts.getValue(i));
106          } else if (attName.startsWith(XMLNS_PREFIX)) {
107             String prefix = attName.substring(XMLNS_PREFIX.length());
108             namespacesStack.addNamespace(prefix, atts.getValue(i));
109          } else {
110             validAtts[i] = true;
111             ++attCount;
112          }
113       }
114       // -- process validAtts...if any exist
115       AttributeSetImpl attSet = null;
116       if (attCount > 0) {
117          attSet = new AttributeSetImpl(attCount);
118          for (int i = 0; i < validAtts.length; i++) {
119             if (!validAtts[i])
120                continue;
121             String namespace = null;
122             String attName = atts.getName(i);
123             int idx = attName.indexOf(':');
124             if (idx > 0) {
125                String prefix = attName.substring(0, idx);
126                if (!prefix.equals(XML_PREFIX)) {
127                   attName = attName.substring(idx + 1);
128                   namespace = namespacesStack.getNamespaceURI(prefix);
129                   if (namespace == null) {
130                      String error = "The namespace associated with " + "the prefix '" + prefix
131                            + "' could not be resolved.";
132                      throw new SAXException(error);
133 
134                   }
135                }
136             }
137             attSet.setAttribute(attName, atts.getValue(i), namespace);
138          }
139       } else
140          attSet = new AttributeSetImpl(0);
141 
142       return attSet;
143 
144    }
145 
146    public void characters(char[] ch, int start, int length) throws org.xml.sax.SAXException {
147       try {
148          componentReader.characters(ch, start, length);
149       } catch (XMLException ex) {
150          throw new SAXException(ex);
151       }
152 
153    }
154 
155    public void endDocument() throws org.xml.sax.SAXException {
156       // -- do nothing
157    }
158 
159    public void endElement(String name) throws org.xml.sax.SAXException {
160       String namespace = null;
161       int idx = name.indexOf(':');
162       if (idx >= 0) {
163          String prefix = name.substring(0, idx);
164          name = name.substring(idx + 1);
165          namespace = namespacesStack.getNamespaceURI(prefix);
166       } else
167          namespace = namespacesStack.getDefaultNamespaceURI();
168 
169       // remove namespaces
170       namespacesStack.removeNamespaceScope();
171 
172       try {
173          componentReader.endElement(name, namespace);
174       } catch (XMLException ex) {
175          throw new SAXException(ex);
176       }
177    }
178 
179    public void ignorableWhitespace(char[] ch, int start, int length) throws org.xml.sax.SAXException {
180       // -- do nothing
181    }
182 
183    public void processingInstruction(String target, String data) throws org.xml.sax.SAXException {
184       // -- do nothing
185    }
186 
187    public void setDocumentLocator(Locator locator) {
188       componentReader.setDocumentLocator(locator);
189    }
190 
191    public void startDocument() throws org.xml.sax.SAXException {
192       // -- do nothing
193    }
194 
195    public void startElement(String name, AttributeList atts) throws org.xml.sax.SAXException {
196       // -- create new Namespace scope
197       namespacesStack.addNewNamespaceScope();
198 
199       // -- handle namespaces
200       AttributeSet attSet = processAttributeList(atts);
201 
202       String namespace = null;
203       int idx = name.indexOf(':');
204       if (idx >= 0) {
205          String prefix = name.substring(0, idx);
206          name = name.substring(idx + 1);
207          namespace = namespacesStack.getNamespaceURI(prefix);
208       } else {
209          namespace = namespacesStack.getNamespaceURI("");
210       }
211 
212       try {
213          componentReader.startElement(name, namespace, attSet, namespacesStack.getCurrentNamespaceScope());
214       } catch (XMLException ex) {
215          throw new SAXException(ex);
216       }
217    }
218 
219    public void error(SAXParseException exception) throws org.xml.sax.SAXException {
220       String systemId = exception.getSystemId();
221       String err = "Parsing Error : " + exception.getMessage() + '\n' + "Line : " + exception.getLineNumber() + '\n'
222             + "Column : " + exception.getColumnNumber() + '\n';
223       if (systemId != null) {
224          err = "In document: '" + systemId + "'\n" + err;
225       }
226 
227       throw new SAXException(err);
228    }
229 
230    public void fatalError(SAXParseException exception) throws org.xml.sax.SAXException {
231       String systemId = exception.getSystemId();
232       String err = "Parsing Error : " + exception.getMessage() + '\n' + "Line : " + exception.getLineNumber() + '\n'
233             + "Column : " + exception.getColumnNumber() + '\n';
234       if (systemId != null) {
235          err = "In document: '" + systemId + "'\n" + err;
236       }
237       throw new SAXException(err);
238    }
239 
240    public void warning(SAXParseException exception) throws org.xml.sax.SAXException {
241       String systemId = exception.getSystemId();
242       String err = "Parsing Error : " + exception.getMessage() + '\n' + "Line : " + exception.getLineNumber() + '\n'
243             + "Column : " + exception.getColumnNumber() + '\n';
244       if (systemId != null) {
245          err = "In document: '" + systemId + "'\n" + err;
246       }
247       throw new SAXException(err);
248    }
249 
250 }