1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: XPathException.java 468655 2006-10-28 07:12:06Z minchau $
20 */
21package org.apache.xpath;
22
23import javax.xml.transform.TransformerException;
24
25import org.w3c.dom.Node;
26
27/**
28 * This class implements an exception object that all
29 * XPath classes will throw in case of an error.  This class
30 * extends TransformerException, and may hold other exceptions. In the
31 * case of nested exceptions, printStackTrace will dump
32 * all the traces of the nested exceptions, not just the trace
33 * of this object.
34 * @xsl.usage general
35 */
36public class XPathException extends TransformerException
37{
38    static final long serialVersionUID = 4263549717619045963L;
39
40  /** The home of the expression that caused the error.
41   *  @serial  */
42  Object m_styleNode = null;
43
44  /**
45   * Get the stylesheet node from where this error originated.
46   * @return The stylesheet node from where this error originated, or null.
47   */
48  public Object getStylesheetNode()
49  {
50    return m_styleNode;
51  }
52
53  /**
54   * Set the stylesheet node from where this error originated.
55   * @param styleNode The stylesheet node from where this error originated, or null.
56   */
57  public void setStylesheetNode(Object styleNode)
58  {
59    m_styleNode = styleNode;
60  }
61
62
63  /** A nested exception.
64   *  @serial   */
65  protected Exception m_exception;
66
67  /**
68   * Create an XPathException object that holds
69   * an error message.
70   * @param message The error message.
71   */
72  public XPathException(String message, ExpressionNode ex)
73  {
74    super(message);
75    this.setLocator(ex);
76    setStylesheetNode(getStylesheetNode(ex));
77  }
78
79  /**
80   * Create an XPathException object that holds
81   * an error message.
82   * @param message The error message.
83   */
84  public XPathException(String message)
85  {
86    super(message);
87  }
88
89
90  /**
91   * Get the XSLT ElemVariable that this sub-expression references.  In order for
92   * this to work, the SourceLocator must be the owning ElemTemplateElement.
93   * @return The dereference to the ElemVariable, or null if not found.
94   */
95  public org.w3c.dom.Node getStylesheetNode(ExpressionNode ex)
96  {
97
98    ExpressionNode owner = getExpressionOwner(ex);
99
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", (Class<?>) 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}
329