/**
* Copyright (C) 2010 Orbeon, Inc.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
*/
package org.orbeon.oxf.processor.generator;
import org.orbeon.errorified.Exceptions;
import org.orbeon.oxf.common.OXFException;
import org.orbeon.oxf.common.OrbeonLocationException;
import org.orbeon.oxf.common.ValidationException;
import org.orbeon.oxf.pipeline.api.PipelineContext;
import org.orbeon.oxf.xml.XMLReceiver;
import org.orbeon.oxf.processor.ProcessorImpl;
import org.orbeon.oxf.processor.ProcessorInputOutputInfo;
import org.orbeon.oxf.processor.ProcessorOutput;
import org.orbeon.oxf.webapp.ProcessorService;
import org.orbeon.oxf.xml.XMLReceiverHelper;
import org.orbeon.oxf.xml.dom4j.ExtendedLocationData;
import org.orbeon.oxf.xml.dom4j.LocationData;
import java.util.Iterator;
import java.util.List;
/**
* ExceptionGenerator produces a structured XML document containing information about the
* throwable stored into the PipelineContext.
*/
public class ExceptionGenerator extends ProcessorImpl {
public ExceptionGenerator() {
addOutputInfo(new ProcessorInputOutputInfo(OUTPUT_DATA));
}
@Override
public ProcessorOutput createOutput(String name) {
final ProcessorOutput output = new ProcessorOutputImpl(ExceptionGenerator.this, name) {
public void readImpl(PipelineContext context, XMLReceiver xmlReceiver) {
// Get top throwable
Throwable throwable = (Throwable) context.getAttribute(ProcessorService.Throwable());
final XMLReceiverHelper helper = new XMLReceiverHelper(xmlReceiver);
helper.startDocument();
helper.startElement("exceptions");
// Write out document
try {
while (throwable != null) {
addThrowable(helper, throwable, true);
throwable = Exceptions.getNestedThrowableOrNull(throwable);
}
} catch (Exception e) {
throw new OXFException(e);
}
helper.endElement();
helper.endDocument();
}
};
addOutput(name, output);
return output;
}
public static void addThrowable(XMLReceiverHelper helper, Throwable throwable, boolean stackTrace) {
helper.startElement("exception");
helper.element("type", throwable.getClass().getName());
helper.element("message", throwable instanceof ValidationException
? ((ValidationException) throwable).message()
: throwable.getMessage());
addLocationData(helper, OrbeonLocationException.jGetAllLocationData(throwable));
if (stackTrace) {
final StackTraceElement[] elements = throwable.getStackTrace();
// We were able to get a structured stack trace
helper.startElement("stack-trace-elements");
for (int i = 0; i < elements.length; i++) {
final StackTraceElement element = elements[i];
helper.startElement("element");
helper.element("class-name", element.getClassName());
helper.element("method-name", element.getMethodName());
helper.element("file-name", element.getFileName());
helper.element("line-number", element.getLineNumber());
helper.endElement();
}
helper.endElement();
}
helper.endElement();
}
public static void addLocationData(XMLReceiverHelper helper, List locationDataList) {
if (locationDataList != null) {
for (Iterator i = locationDataList.iterator(); i.hasNext();) {
final LocationData locationData = (LocationData) i.next();
helper.startElement("location");
helper.element("system-id", locationData.file());
helper.element("line", Integer.toString(locationData.line()));
helper.element("column", Integer.toString(locationData.col()));
if (locationData instanceof ExtendedLocationData) {
final ExtendedLocationData extendedLocationData = (ExtendedLocationData) locationData;
final String description = extendedLocationData.getDescription();
if (description != null)
helper.element("description", description);
String elementString = extendedLocationData.getElementString();
final String[] parameters = extendedLocationData.getParameters();
if (parameters.length > 0) {
helper.startElement("parameters");
for (int j = 0; j < parameters.length; j += 2) {
final String paramName = parameters[j];
final String paramValue = parameters[j + 1];
if (elementString == null && paramName.equals("element")) {
// Use "element" parameter as element string if present and not already set
elementString = paramValue;
} else {
// Just output the parameter
helper.startElement("parameter");
helper.element("name", paramName);
helper.element("value", paramValue);
helper.endElement();
}
}
helper.endElement();
}
// Output element string if set
if (elementString != null)
helper.element("element", elementString);
}
helper.endElement();
}
}
}
}