001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.generation;
018:
019: import java.io.IOException;
020: import java.util.List;
021: import java.util.Map;
022:
023: import org.apache.avalon.framework.parameters.Parameters;
024: import org.apache.cocoon.ProcessingException;
025: import org.apache.cocoon.environment.ObjectModelHelper;
026: import org.apache.cocoon.environment.SourceResolver;
027: import org.apache.cocoon.util.location.LocatableException;
028: import org.apache.cocoon.util.location.Location;
029: import org.apache.cocoon.util.location.LocationUtils;
030: import org.apache.cocoon.util.location.MultiLocatable;
031: import org.apache.cocoon.xml.AttributesImpl;
032: import org.apache.commons.lang.SystemUtils;
033: import org.apache.commons.lang.exception.ExceptionUtils;
034: import org.xml.sax.Attributes;
035: import org.xml.sax.ContentHandler;
036: import org.xml.sax.SAXException;
037:
038: /**
039: * A generator that dumps an XML representation of the exception raised during a pipeline execution.
040: * <p>
041: * The Cocoon stack trace is produced, reflecting all locations the original exception went through,
042: * along with the root exception stacktrace and the full exception stacktrace.
043: *
044: * @since 2.1.8
045: * @version $Id: ExceptionGenerator.java 433543 2006-08-22 06:22:54Z crossley $
046: */
047: public class ExceptionGenerator extends AbstractGenerator {
048:
049: private Throwable thr;
050:
051: public static final String EXCEPTION_NS = "http://apache.org/cocoon/exception/1.0";
052:
053: public void setup(SourceResolver resolver, Map objectModel,
054: String src, Parameters par) throws ProcessingException,
055: SAXException, IOException {
056: super .setup(resolver, objectModel, src, par);
057: thr = (Throwable) objectModel
058: .get(ObjectModelHelper.THROWABLE_OBJECT);
059: if (thr == null) {
060: throw new ProcessingException(
061: "ExceptionGenerator should be used in <map:handle-errors>");
062: }
063: }
064:
065: public void generate() throws IOException, SAXException,
066: ProcessingException {
067: this .contentHandler.startDocument();
068: toSAX(thr, this .contentHandler);
069: this .contentHandler.endDocument();
070: }
071:
072: public static void toSAX(Throwable thr, ContentHandler handler)
073: throws SAXException {
074: Throwable root = ExceptionUtils.getRootCause(thr);
075: if (root == null)
076: root = thr;
077:
078: AttributesImpl attr = new AttributesImpl();
079: handler.startPrefixMapping("ex", EXCEPTION_NS);
080: attr.addCDATAAttribute("class", root.getClass().getName());
081: handler.startElement(EXCEPTION_NS, "exception-report",
082: "ex:exception-report", attr);
083:
084: // Root exception location
085: Location loc = LocationUtils.getLocation(root);
086: if (LocationUtils.isKnown(loc)) {
087: attr.clear();
088: dumpLocation(loc, attr, handler);
089: }
090:
091: // Root exception message
092: attr.clear();
093: String message = root instanceof LocatableException ? ((LocatableException) root)
094: .getRawMessage()
095: : root.getMessage();
096: simpleElement("message", attr, message, handler);
097:
098: // Cocoon stacktrace: dump all located exceptions in the exception stack
099: handler.startElement(EXCEPTION_NS, "cocoon-stacktrace",
100: "ex:cocoon-stacktrace", attr);
101: Throwable current = thr;
102: while (current != null) {
103: loc = LocationUtils.getLocation(current);
104: if (LocationUtils.isKnown(loc)) {
105: // One or more locations: dump it
106: handler.startElement(EXCEPTION_NS, "exception",
107: "ex:exception", attr);
108:
109: message = current instanceof LocatableException ? ((LocatableException) current)
110: .getRawMessage()
111: : current.getMessage();
112: simpleElement("message", attr, message, handler);
113:
114: attr.clear();
115: handler.startElement(EXCEPTION_NS, "locations",
116: "ex:locations", attr);
117: dumpLocation(loc, attr, handler);
118:
119: if (current instanceof MultiLocatable) {
120: List locations = ((MultiLocatable) current)
121: .getLocations();
122: for (int i = 1; i < locations.size(); i++) { // start at 1 because we already dumped the first one
123: attr.clear();
124: dumpLocation((Location) locations.get(i), attr,
125: handler);
126: }
127: }
128: handler.endElement(EXCEPTION_NS, "locations",
129: "ex:locations");
130: handler.endElement(EXCEPTION_NS, "exception",
131: "ex:exception");
132: }
133:
134: // Dump parent location
135: current = ExceptionUtils.getCause(current);
136: }
137:
138: handler.endElement(EXCEPTION_NS, "cocoon-stacktrace",
139: "ex:cocoon-stacktrace");
140:
141: // Root exception stacktrace
142: attr.clear();
143: simpleElement("stacktrace", attr, ExceptionUtils
144: .getStackTrace(root), handler);
145:
146: // Full stack trace (if exception is chained)
147: if (thr != root) {
148: String trace = SystemUtils.isJavaVersionAtLeast(140) ? ExceptionUtils
149: .getStackTrace(thr)
150: : ExceptionUtils.getFullStackTrace(thr);
151:
152: simpleElement("full-stacktrace", attr, trace, handler);
153: }
154:
155: handler.endElement(EXCEPTION_NS, "exception-report",
156: "ex:exception-report");
157: handler.endPrefixMapping("ex");
158: }
159:
160: private static void dumpLocation(Location loc, AttributesImpl attr,
161: ContentHandler handler) throws SAXException {
162: attr.addCDATAAttribute("uri", loc.getURI());
163: attr.addCDATAAttribute("line", Integer.toString(loc
164: .getLineNumber()));
165: attr.addCDATAAttribute("column", Integer.toString(loc
166: .getColumnNumber()));
167: simpleElement("location", attr, loc.getDescription(), handler);
168: }
169:
170: private static void simpleElement(String name, Attributes attr,
171: String value, ContentHandler handler) throws SAXException {
172: handler.startElement(EXCEPTION_NS, name, "ex:" + name, attr);
173: if (value != null && value.length() > 0) {
174: handler.characters(value.toCharArray(), 0, value.length());
175: }
176: handler.endElement(EXCEPTION_NS, name, "ex:" + name);
177: }
178: }
|