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: XPathException.java 468655 2006-10-28 07:12:06Z minchau $
020 */
021 package org.apache.xpath;
022
023 import javax.xml.transform.TransformerException;
024
025 import org.w3c.dom.Node;
026
027 /**
028 * This class implements an exception object that all
029 * XPath classes will throw in case of an error. This class
030 * extends TransformerException, and may hold other exceptions. In the
031 * case of nested exceptions, printStackTrace will dump
032 * all the traces of the nested exceptions, not just the trace
033 * of this object.
034 * @xsl.usage general
035 */
036 public class XPathException extends TransformerException
037 {
038 static final long serialVersionUID = 4263549717619045963L;
039
040 /** The home of the expression that caused the error.
041 * @serial */
042 Object m_styleNode = null;
043
044 /**
045 * Get the stylesheet node from where this error originated.
046 * @return The stylesheet node from where this error originated, or null.
047 */
048 public Object getStylesheetNode()
049 {
050 return m_styleNode;
051 }
052
053 /**
054 * Set the stylesheet node from where this error originated.
055 * @param styleNode The stylesheet node from where this error originated, or null.
056 */
057 public void setStylesheetNode(Object styleNode)
058 {
059 m_styleNode = styleNode;
060 }
061
062
063 /** A nested exception.
064 * @serial */
065 protected Exception m_exception;
066
067 /**
068 * Create an XPathException object that holds
069 * an error message.
070 * @param message The error message.
071 */
072 public XPathException(String message, ExpressionNode ex)
073 {
074 super(message);
075 this.setLocator(ex);
076 setStylesheetNode(getStylesheetNode(ex));
077 }
078
079 /**
080 * Create an XPathException object that holds
081 * an error message.
082 * @param message The error message.
083 */
084 public XPathException(String message)
085 {
086 super(message);
087 }
088
089
090 /**
091 * Get the XSLT ElemVariable that this sub-expression references. In order for
092 * this to work, the SourceLocator must be the owning ElemTemplateElement.
093 * @return The dereference to the ElemVariable, or null if not found.
094 */
095 public org.w3c.dom.Node getStylesheetNode(ExpressionNode ex)
096 {
097
098 ExpressionNode owner = getExpressionOwner(ex);
099
100 if (null != owner && owner instanceof org.w3c.dom.Node)
101 {
102 return ((org.w3c.dom.Node)owner);
103 }
104 return null;
105
106 }
107
108 /**
109 * Get the first non-Expression parent of this node.
110 * @return null or first ancestor that is not an Expression.
111 */
112 protected ExpressionNode getExpressionOwner(ExpressionNode ex)
113 {
114 ExpressionNode parent = ex.exprGetParent();
115 while((null != parent) && (parent instanceof Expression))
116 parent = parent.exprGetParent();
117 return parent;
118 }
119
120
121
122 /**
123 * Create an XPathException object that holds
124 * an error message and the stylesheet node that
125 * the error originated from.
126 * @param message The error message.
127 * @param styleNode The stylesheet node that the error originated from.
128 */
129 public XPathException(String message, Object styleNode)
130 {
131
132 super(message);
133
134 m_styleNode = styleNode;
135 }
136
137 /**
138 * Create an XPathException object that holds
139 * an error message, the stylesheet node that
140 * the error originated from, and another exception
141 * that caused this exception.
142 * @param message The error message.
143 * @param styleNode The stylesheet node that the error originated from.
144 * @param e The exception that caused this exception.
145 */
146 public XPathException(String message, Node styleNode, Exception e)
147 {
148
149 super(message);
150
151 m_styleNode = styleNode;
152 this.m_exception = e;
153 }
154
155 /**
156 * Create an XPathException object that holds
157 * an error message, and another exception
158 * that caused this exception.
159 * @param message The error message.
160 * @param e The exception that caused this exception.
161 */
162 public XPathException(String message, Exception e)
163 {
164
165 super(message);
166
167 this.m_exception = e;
168 }
169
170 /**
171 * Print the the trace of methods from where the error
172 * originated. This will trace all nested exception
173 * objects, as well as this object.
174 * @param s The stream where the dump will be sent to.
175 */
176 public void printStackTrace(java.io.PrintStream s)
177 {
178
179 if (s == null)
180 s = System.err;
181
182 try
183 {
184 super.printStackTrace(s);
185 }
186 catch (Exception e){}
187
188 Throwable exception = m_exception;
189
190 for (int i = 0; (i < 10) && (null != exception); i++)
191 {
192 s.println("---------");
193 exception.printStackTrace(s);
194
195 if (exception instanceof TransformerException)
196 {
197 TransformerException se = (TransformerException) exception;
198 Throwable prev = exception;
199
200 exception = se.getException();
201
202 if (prev == exception)
203 break;
204 }
205 else
206 {
207 exception = null;
208 }
209 }
210 }
211
212 /**
213 * Find the most contained message.
214 *
215 * @return The error message of the originating exception.
216 */
217 public String getMessage()
218 {
219
220 String lastMessage = super.getMessage();
221 Throwable exception = m_exception;
222
223 while (null != exception)
224 {
225 String nextMessage = exception.getMessage();
226
227 if (null != nextMessage)
228 lastMessage = nextMessage;
229
230 if (exception instanceof TransformerException)
231 {
232 TransformerException se = (TransformerException) exception;
233 Throwable prev = exception;
234
235 exception = se.getException();
236
237 if (prev == exception)
238 break;
239 }
240 else
241 {
242 exception = null;
243 }
244 }
245
246 return (null != lastMessage) ? lastMessage : "";
247 }
248
249 /**
250 * Print the the trace of methods from where the error
251 * originated. This will trace all nested exception
252 * objects, as well as this object.
253 * @param s The writer where the dump will be sent to.
254 */
255 public void printStackTrace(java.io.PrintWriter s)
256 {
257
258 if (s == null)
259 s = new java.io.PrintWriter(System.err);
260
261 try
262 {
263 super.printStackTrace(s);
264 }
265 catch (Exception e){}
266
267
268 boolean isJdk14OrHigher = false;
269 try {
270 Throwable.class.getMethod("getCause",null);
271 isJdk14OrHigher = true;
272 } catch (NoSuchMethodException nsme) {
273 // do nothing
274 }
275
276 // The printStackTrace method of the Throwable class in jdk 1.4
277 // and higher will include the cause when printing the backtrace.
278 // The following code is only required when using jdk 1.3 or lower
279 if (!isJdk14OrHigher) {
280
281 Throwable exception = m_exception;
282
283 for (int i = 0; (i < 10) && (null != exception); i++)
284 {
285 s.println("---------");
286
287 try
288 {
289 exception.printStackTrace(s);
290 }
291 catch (Exception e)
292 {
293 s.println("Could not print stack trace...");
294 }
295
296 if (exception instanceof TransformerException)
297 {
298 TransformerException se = (TransformerException) exception;
299 Throwable prev = exception;
300
301 exception = se.getException();
302
303 if (prev == exception)
304 {
305 exception = null;
306
307 break;
308 }
309 }
310 else
311 {
312 exception = null;
313 }
314 }
315 }
316 }
317
318 /**
319 * Return the embedded exception, if any.
320 * Overrides javax.xml.transform.TransformerException.getException().
321 *
322 * @return The embedded exception, or null if there is none.
323 */
324 public Throwable getException()
325 {
326 return m_exception;
327 }
328 }