View Javadoc

1   /*
2    * Copyright 2006 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.xml.stream;
18  
19  import javax.xml.stream.Location;
20  import javax.xml.stream.XMLStreamException;
21  
22  import org.xml.sax.ContentHandler;
23  import org.xml.sax.InputSource;
24  import org.xml.sax.Locator;
25  import org.xml.sax.SAXException;
26  import org.xml.sax.SAXNotRecognizedException;
27  import org.xml.sax.SAXNotSupportedException;
28  import org.xml.sax.SAXParseException;
29  
30  import org.springframework.xml.sax.AbstractXmlReader;
31  
32  /**
33   * Abstract base class for SAX <code>XMLReader</code> implementations that use StAX as a basis.
34   *
35   * @author Arjen Poutsma
36   * @see #setContentHandler(org.xml.sax.ContentHandler)
37   * @see #setDTDHandler(org.xml.sax.DTDHandler)
38   * @see #setEntityResolver(org.xml.sax.EntityResolver)
39   * @see #setErrorHandler(org.xml.sax.ErrorHandler)
40   * @since 1.0.0
41   */
42  public abstract class AbstractStaxXmlReader extends AbstractXmlReader {
43  
44      private static final String NAMESPACES_FEATURE_NAME = "http://xml.org/sax/features/namespaces";
45  
46      private static final String NAMESPACE_PREFIXES_FEATURE_NAME = "http://xml.org/sax/features/namespace-prefixes";
47  
48      private static final String IS_STANDALONE_FEATURE_NAME = "http://xml.org/sax/features/is-standalone";
49  
50      private boolean namespacesFeature = true;
51  
52      private boolean namespacePrefixesFeature = false;
53  
54      private Boolean isStandalone;
55  
56      public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
57          if (NAMESPACES_FEATURE_NAME.equals(name)) {
58              return namespacesFeature;
59          }
60          else if (NAMESPACE_PREFIXES_FEATURE_NAME.equals(name)) {
61              return namespacePrefixesFeature;
62          }
63          else if (IS_STANDALONE_FEATURE_NAME.equals(name)) {
64              if (isStandalone != null) {
65                  return isStandalone.booleanValue();
66              }
67              else {
68                  throw new SAXNotSupportedException("startDocument() callback not completed yet");
69              }
70          }
71          else {
72              return super.getFeature(name);
73          }
74      }
75  
76      public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
77          if (NAMESPACES_FEATURE_NAME.equals(name)) {
78              this.namespacesFeature = value;
79          }
80          else if (NAMESPACE_PREFIXES_FEATURE_NAME.equals(name)) {
81              this.namespacePrefixesFeature = value;
82          }
83          else {
84              super.setFeature(name, value);
85          }
86      }
87  
88      /** Indicates whether the SAX feature <code>http://xml.org/sax/features/namespaces</code>" target="alexandria_uri">http://xml.org/sax/features/namespaces</code> is turned on. */
89      protected boolean hasNamespacesFeature() {
90          return namespacesFeature;
91      }
92  
93      /** Indicates whether the SAX feature <code>http://xml.org/sax/features/namespaces-prefixes</code>" target="alexandria_uri">http://xml.org/sax/features/namespaces-prefixes</code> is turned on. */
94      protected boolean hasNamespacePrefixesFeature() {
95          return namespacePrefixesFeature;
96      }
97  
98      protected void setStandalone(boolean standalone) {
99          isStandalone = (standalone) ? Boolean.TRUE : Boolean.FALSE;
100     }
101 
102     /**
103      * Parses the StAX XML reader passed at construction-time.
104      * <p/>
105      * <strong>Note</strong> that the given <code>InputSource</code> is not read, but ignored.
106      *
107      * @param ignored is ignored
108      * @throws SAXException A SAX exception, possibly wrapping a <code>XMLStreamException</code>
109      */
110     public final void parse(InputSource ignored) throws SAXException {
111         parse();
112     }
113 
114     /**
115      * Parses the StAX XML reader passed at construction-time.
116      * <p/>
117      * <strong>Note</strong> that the given system identifier is not read, but ignored.
118      *
119      * @param ignored is ignored
120      * @throws SAXException A SAX exception, possibly wrapping a <code>XMLStreamException</code>
121      */
122     public final void parse(String ignored) throws SAXException {
123         parse();
124     }
125 
126     private void parse() throws SAXException {
127         try {
128             parseInternal();
129         }
130         catch (XMLStreamException ex) {
131             Locator locator = null;
132             if (ex.getLocation() != null) {
133                 locator = new StaxLocator(ex.getLocation());
134             }
135             SAXParseException saxException = new SAXParseException(ex.getMessage(), locator, ex);
136             if (getErrorHandler() != null) {
137                 getErrorHandler().fatalError(saxException);
138             }
139             else {
140                 throw saxException;
141             }
142         }
143     }
144 
145     /**
146      * Sets the SAX <code>Locator</code> based on the given StAX <code>Location</code>.
147      *
148      * @param location the location
149      * @see ContentHandler#setDocumentLocator(org.xml.sax.Locator)
150      */
151     protected void setLocator(Location location) {
152         if (getContentHandler() != null) {
153             getContentHandler().setDocumentLocator(new StaxLocator(location));
154         }
155     }
156 
157     /** Template-method that parses the StAX reader passed at construction-time. */
158     protected abstract void parseInternal() throws SAXException, XMLStreamException;
159 
160     /**
161      * Implementation of the <code>Locator</code> interface that is based on a StAX <code>Location</code>.
162      *
163      * @see Locator
164      * @see Location
165      */
166     private static class StaxLocator implements Locator {
167 
168         private Location location;
169 
170         protected StaxLocator(Location location) {
171             this.location = location;
172         }
173 
174         public String getPublicId() {
175             return location.getPublicId();
176         }
177 
178         public String getSystemId() {
179             return location.getSystemId();
180         }
181 
182         public int getLineNumber() {
183             return location.getLineNumber();
184         }
185 
186         public int getColumnNumber() {
187             return location.getColumnNumber();
188         }
189     }
190 }