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.components.notification;
018:
019: import org.apache.avalon.framework.component.Component;
020:
021: import org.apache.commons.lang.SystemUtils;
022: import org.apache.commons.lang.exception.ExceptionUtils;
023: import org.xml.sax.SAXParseException;
024:
025: import javax.xml.transform.SourceLocator;
026: import javax.xml.transform.TransformerException;
027: import java.io.PrintWriter;
028: import java.io.StringWriter;
029: import java.io.Writer;
030: import java.util.Map;
031:
032: /**
033: * Generates an Notifying representation of widely used objects.
034: *
035: * @author <a href="mailto:nicolaken@apache.org">Nicola Ken Barozzi</a>
036: * @author Marc Liyanage (futureLAB AG)
037: * @version CVS $Id: DefaultNotifyingBuilder.java 433543 2006-08-22 06:22:54Z crossley $
038: */
039: public class DefaultNotifyingBuilder implements NotifyingBuilder,
040: Component {
041:
042: /**
043: * Builds a Notifying object (SimpleNotifyingBean in this case)
044: * that tries to explain what the Object o can reveal.
045: *
046: * @param sender who sent this Object.
047: * @param o the object to use when building the SimpleNotifyingBean
048: * @return the Notifying Object that was build
049: * @see org.apache.cocoon.components.notification.Notifying
050: */
051: public Notifying build(Object sender, Object o) {
052: if (o instanceof Notifying) {
053: return (Notifying) o;
054: } else if (o instanceof Throwable) {
055: Throwable t = (Throwable) o;
056: SimpleNotifyingBean n = new SimpleNotifyingBean(sender);
057: n.setType(Notifying.ERROR_NOTIFICATION);
058: n.setTitle("An Error Occurred");
059:
060: if (t != null) {
061: Throwable rootCause = getRootCause(t);
062:
063: n.setSource(t.getClass().getName());
064:
065: // NullPointerException usually does not have a message
066: if (rootCause.getMessage() != null) {
067: n.setMessage(rootCause.getMessage());
068: } else {
069: n.setMessage(t.getMessage());
070: }
071:
072: n.setDescription(t.toString());
073: n.addExtraDescription(Notifying.EXTRA_CAUSE, rootCause
074: .toString());
075:
076: if (rootCause instanceof SAXParseException) {
077: SAXParseException saxParseException = (SAXParseException) rootCause;
078:
079: n.addExtraDescription(Notifying.EXTRA_LOCATION,
080: String.valueOf(saxParseException
081: .getSystemId()));
082: n
083: .addExtraDescription(Notifying.EXTRA_LINE,
084: String.valueOf(saxParseException
085: .getLineNumber()));
086: n.addExtraDescription(Notifying.EXTRA_COLUMN,
087: String.valueOf(saxParseException
088: .getColumnNumber()));
089: } else if (rootCause instanceof TransformerException) {
090: TransformerException transformerException = (TransformerException) rootCause;
091: SourceLocator sourceLocator = transformerException
092: .getLocator();
093:
094: if (null != sourceLocator) {
095: n.addExtraDescription(Notifying.EXTRA_LOCATION,
096: String.valueOf(sourceLocator
097: .getSystemId()));
098: n.addExtraDescription(Notifying.EXTRA_LINE,
099: String.valueOf(sourceLocator
100: .getLineNumber()));
101: n.addExtraDescription(Notifying.EXTRA_COLUMN,
102: String.valueOf(sourceLocator
103: .getColumnNumber()));
104: }
105: }
106:
107: // Add root cause exception stacktrace
108: StringWriter sw = new StringWriter();
109: rootCause.printStackTrace(new PrintWriter(sw));
110: n.addExtraDescription(Notifying.EXTRA_STACKTRACE, sw
111: .toString());
112:
113: // Add full exception chain
114: sw = new StringWriter();
115: appendTraceChain(sw, t);
116: n.addExtraDescription(Notifying.EXTRA_FULLTRACE, sw
117: .toString());
118: }
119:
120: return n;
121: } else {
122: SimpleNotifyingBean n = new SimpleNotifyingBean(sender);
123: n.setType(Notifying.UNKNOWN_NOTIFICATION);
124: n.setTitle("Object Notification");
125: n.setMessage(String.valueOf(o));
126: n.setDescription("No details available.");
127: return n;
128: }
129: }
130:
131: /**
132: * Builds a Notifying object (SimpleNotifyingBean in this case)
133: * that explains a notification.
134: *
135: * @param sender who sent this Object.
136: * @param o the object to use when building the SimpleNotifyingBean
137: * @param type see the Notifying apidocs
138: * @param title see the Notifying apidocs
139: * @param source see the Notifying apidocs
140: * @param message see the Notifying apidocs
141: * @param description see the Notifying apidocs
142: * @param extra see the Notifying apidocs
143: * @return the Notifying Object that was build
144: * @see org.apache.cocoon.components.notification.Notifying
145: */
146: public Notifying build(Object sender, Object o, String type,
147: String title, String source, String message,
148: String description, Map extra) {
149: // NKB Cast here is secure, the method is of this class
150: SimpleNotifyingBean n = (SimpleNotifyingBean) build(sender, o);
151:
152: if (type != null)
153: n.setType(type);
154: if (title != null)
155: n.setTitle(title);
156: if (source != null)
157: n.setSource(source);
158: if (message != null)
159: n.setMessage(message);
160: if (description != null)
161: n.setDescription(description);
162: if (extra != null)
163: n.addExtraDescriptions(extra);
164:
165: return n;
166: }
167:
168: /**
169: * Print stacktrace of the Throwable and stacktraces of its all nested causes into a Writer.
170: */
171: private static void appendTraceChain(Writer out, Throwable t) {
172: PrintWriter pw = new PrintWriter(out);
173: if (SystemUtils.isJavaVersionAtLeast(140)) {
174: t.printStackTrace(pw);
175: } else {
176: for (Throwable cause = t; cause != null; cause = ExceptionUtils
177: .getCause(cause)) {
178: if (cause != t) {
179: pw.println();
180: }
181: cause.printStackTrace(pw);
182: }
183: }
184: }
185:
186: /**
187: * Get root cause Throwable.
188: */
189: public static Throwable getRootCause(Throwable t) {
190: Throwable rootCause = ExceptionUtils.getRootCause(t);
191: return rootCause != null ? rootCause : t;
192: }
193: }
|