001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: DefaultErrorHandler.java 524806 2007-04-02 15:51:39Z zongaro $
020 */
021 package org.apache.xml.utils;
022
023 import java.io.PrintStream;
024 import java.io.PrintWriter;
025
026 import javax.xml.transform.ErrorListener;
027 import javax.xml.transform.SourceLocator;
028 import javax.xml.transform.TransformerException;
029
030 import org.apache.xml.res.XMLErrorResources;
031 import org.apache.xml.res.XMLMessages;
032
033 import org.xml.sax.ErrorHandler;
034 import org.xml.sax.SAXException;
035 import org.xml.sax.SAXParseException;
036
037
038 /**
039 * Implement SAX error handler for default reporting.
040 * @xsl.usage general
041 */
042 public class DefaultErrorHandler implements ErrorHandler, ErrorListener
043 {
044 PrintWriter m_pw;
045
046 /**
047 * if this flag is set to true, we will rethrow the exception on
048 * the error() and fatalError() methods. If it is false, the errors
049 * are reported to System.err.
050 */
051 boolean m_throwExceptionOnError = true;
052
053 /**
054 * Constructor DefaultErrorHandler
055 */
056 public DefaultErrorHandler(PrintWriter pw)
057 {
058 m_pw = pw;
059 }
060
061 /**
062 * Constructor DefaultErrorHandler
063 */
064 public DefaultErrorHandler(PrintStream pw)
065 {
066 m_pw = new PrintWriter(pw, true);
067 }
068
069 /**
070 * Constructor DefaultErrorHandler
071 */
072 public DefaultErrorHandler()
073 {
074 this(true);
075 }
076
077 /**
078 * Constructor DefaultErrorHandler
079 */
080 public DefaultErrorHandler(boolean throwExceptionOnError)
081 {
082 // Defer creation of a PrintWriter until it's actually needed
083 m_throwExceptionOnError = throwExceptionOnError;
084 }
085
086 /**
087 * Retrieve <code>java.io.PrintWriter</code> to which errors are being
088 * directed.
089 * @return The <code>PrintWriter</code> installed via the constructor
090 * or the default <code>PrintWriter</code>
091 */
092 public PrintWriter getErrorWriter() {
093 // Defer creating the java.io.PrintWriter until an error needs to be
094 // reported.
095 if (m_pw == null) {
096 m_pw = new PrintWriter(System.err, true);
097 }
098 return m_pw;
099 }
100
101 /**
102 * Receive notification of a warning.
103 *
104 * <p>SAX parsers will use this method to report conditions that
105 * are not errors or fatal errors as defined by the XML 1.0
106 * recommendation. The default behaviour is to take no action.</p>
107 *
108 * <p>The SAX parser must continue to provide normal parsing events
109 * after invoking this method: it should still be possible for the
110 * application to process the document through to the end.</p>
111 *
112 * @param exception The warning information encapsulated in a
113 * SAX parse exception.
114 * @throws SAXException Any SAX exception, possibly
115 * wrapping another exception.
116 */
117 public void warning(SAXParseException exception) throws SAXException
118 {
119 PrintWriter pw = getErrorWriter();
120
121 printLocation(pw, exception);
122 pw.println("Parser warning: " + exception.getMessage());
123 }
124
125 /**
126 * Receive notification of a recoverable error.
127 *
128 * <p>This corresponds to the definition of "error" in section 1.2
129 * of the W3C XML 1.0 Recommendation. For example, a validating
130 * parser would use this callback to report the violation of a
131 * validity constraint. The default behaviour is to take no
132 * action.</p>
133 *
134 * <p>The SAX parser must continue to provide normal parsing events
135 * after invoking this method: it should still be possible for the
136 * application to process the document through to the end. If the
137 * application cannot do so, then the parser should report a fatal
138 * error even if the XML 1.0 recommendation does not require it to
139 * do so.</p>
140 *
141 * @param exception The error information encapsulated in a
142 * SAX parse exception.
143 * @throws SAXException Any SAX exception, possibly
144 * wrapping another exception.
145 */
146 public void error(SAXParseException exception) throws SAXException
147 {
148 //printLocation(exception);
149 // getErrorWriter().println(exception.getMessage());
150
151 throw exception;
152 }
153
154 /**
155 * Receive notification of a non-recoverable error.
156 *
157 * <p>This corresponds to the definition of "fatal error" in
158 * section 1.2 of the W3C XML 1.0 Recommendation. For example, a
159 * parser would use this callback to report the violation of a
160 * well-formedness constraint.</p>
161 *
162 * <p>The application must assume that the document is unusable
163 * after the parser has invoked this method, and should continue
164 * (if at all) only for the sake of collecting addition error
165 * messages: in fact, SAX parsers are free to stop reporting any
166 * other events once this method has been invoked.</p>
167 *
168 * @param exception The error information encapsulated in a
169 * SAX parse exception.
170 * @throws SAXException Any SAX exception, possibly
171 * wrapping another exception.
172 */
173 public void fatalError(SAXParseException exception) throws SAXException
174 {
175 // printLocation(exception);
176 // getErrorWriter().println(exception.getMessage());
177
178 throw exception;
179 }
180
181 /**
182 * Receive notification of a warning.
183 *
184 * <p>SAX parsers will use this method to report conditions that
185 * are not errors or fatal errors as defined by the XML 1.0
186 * recommendation. The default behaviour is to take no action.</p>
187 *
188 * <p>The SAX parser must continue to provide normal parsing events
189 * after invoking this method: it should still be possible for the
190 * application to process the document through to the end.</p>
191 *
192 * @param exception The warning information encapsulated in a
193 * SAX parse exception.
194 * @throws javax.xml.transform.TransformerException Any SAX exception, possibly
195 * wrapping another exception.
196 * @see javax.xml.transform.TransformerException
197 */
198 public void warning(TransformerException exception) throws TransformerException
199 {
200 PrintWriter pw = getErrorWriter();
201
202 printLocation(pw, exception);
203 pw.println(exception.getMessage());
204 }
205
206 /**
207 * Receive notification of a recoverable error.
208 *
209 * <p>This corresponds to the definition of "error" in section 1.2
210 * of the W3C XML 1.0 Recommendation. For example, a validating
211 * parser would use this callback to report the violation of a
212 * validity constraint. The default behaviour is to take no
213 * action.</p>
214 *
215 * <p>The SAX parser must continue to provide normal parsing events
216 * after invoking this method: it should still be possible for the
217 * application to process the document through to the end. If the
218 * application cannot do so, then the parser should report a fatal
219 * error even if the XML 1.0 recommendation does not require it to
220 * do so.</p>
221 *
222 * @param exception The error information encapsulated in a
223 * SAX parse exception.
224 * @throws javax.xml.transform.TransformerException Any SAX exception, possibly
225 * wrapping another exception.
226 * @see javax.xml.transform.TransformerException
227 */
228 public void error(TransformerException exception) throws TransformerException
229 {
230 // If the m_throwExceptionOnError flag is true, rethrow the exception.
231 // Otherwise report the error to System.err.
232 if (m_throwExceptionOnError)
233 throw exception;
234 else
235 {
236 PrintWriter pw = getErrorWriter();
237
238 printLocation(pw, exception);
239 pw.println(exception.getMessage());
240 }
241 }
242
243 /**
244 * Receive notification of a non-recoverable error.
245 *
246 * <p>This corresponds to the definition of "fatal error" in
247 * section 1.2 of the W3C XML 1.0 Recommendation. For example, a
248 * parser would use this callback to report the violation of a
249 * well-formedness constraint.</p>
250 *
251 * <p>The application must assume that the document is unusable
252 * after the parser has invoked this method, and should continue
253 * (if at all) only for the sake of collecting addition error
254 * messages: in fact, SAX parsers are free to stop reporting any
255 * other events once this method has been invoked.</p>
256 *
257 * @param exception The error information encapsulated in a
258 * SAX parse exception.
259 * @throws javax.xml.transform.TransformerException Any SAX exception, possibly
260 * wrapping another exception.
261 * @see javax.xml.transform.TransformerException
262 */
263 public void fatalError(TransformerException exception) throws TransformerException
264 {
265 // If the m_throwExceptionOnError flag is true, rethrow the exception.
266 // Otherwise report the error to System.err.
267 if (m_throwExceptionOnError)
268 throw exception;
269 else
270 {
271 PrintWriter pw = getErrorWriter();
272
273 printLocation(pw, exception);
274 pw.println(exception.getMessage());
275 }
276 }
277
278 public static void ensureLocationSet(TransformerException exception)
279 {
280 // SourceLocator locator = exception.getLocator();
281 SourceLocator locator = null;
282 Throwable cause = exception;
283
284 // Try to find the locator closest to the cause.
285 do
286 {
287 if(cause instanceof SAXParseException)
288 {
289 locator = new SAXSourceLocator((SAXParseException)cause);
290 }
291 else if (cause instanceof TransformerException)
292 {
293 SourceLocator causeLocator = ((TransformerException)cause).getLocator();
294 if(null != causeLocator)
295 locator = causeLocator;
296 }
297
298 if(cause instanceof TransformerException)
299 cause = ((TransformerException)cause).getCause();
300 else if(cause instanceof SAXException)
301 cause = ((SAXException)cause).getException();
302 else
303 cause = null;
304 }
305 while(null != cause);
306
307 exception.setLocator(locator);
308 }
309
310 public static void printLocation(PrintStream pw, TransformerException exception)
311 {
312 printLocation(new PrintWriter(pw), exception);
313 }
314
315 public static void printLocation(java.io.PrintStream pw, org.xml.sax.SAXParseException exception)
316 {
317 printLocation(new PrintWriter(pw), exception);
318 }
319
320 public static void printLocation(PrintWriter pw, Throwable exception)
321 {
322 SourceLocator locator = null;
323 Throwable cause = exception;
324
325 // Try to find the locator closest to the cause.
326 do
327 {
328 if(cause instanceof SAXParseException)
329 {
330 locator = new SAXSourceLocator((SAXParseException)cause);
331 }
332 else if (cause instanceof TransformerException)
333 {
334 SourceLocator causeLocator = ((TransformerException)cause).getLocator();
335 if(null != causeLocator)
336 locator = causeLocator;
337 }
338 if(cause instanceof TransformerException)
339 cause = ((TransformerException)cause).getCause();
340 else if(cause instanceof WrappedRuntimeException)
341 cause = ((WrappedRuntimeException)cause).getException();
342 else if(cause instanceof SAXException)
343 cause = ((SAXException)cause).getException();
344 else
345 cause = null;
346 }
347 while(null != cause);
348
349 if(null != locator)
350 {
351 // getErrorWriter().println("Parser fatal error: "+exception.getMessage());
352 String id = (null != locator.getPublicId() )
353 ? locator.getPublicId()
354 : (null != locator.getSystemId())
355 ? locator.getSystemId() : XMLMessages.createXMLMessage(XMLErrorResources.ER_SYSTEMID_UNKNOWN, null); //"SystemId Unknown";
356
357 pw.print(id + "; " +XMLMessages.createXMLMessage("line", null) + locator.getLineNumber()
358 + "; " +XMLMessages.createXMLMessage("column", null) + locator.getColumnNumber()+"; ");
359 }
360 else
361 pw.print("("+XMLMessages.createXMLMessage(XMLErrorResources.ER_LOCATION_UNKNOWN, null)+")");
362 }
363 }