All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.spardat.enterprise.exc.BaseException Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/*******************************************************************************
 * Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     s IT Solutions AT Spardat GmbH - initial API and implementation
 *******************************************************************************/

// @(#) $Id: BaseException.java 2618 2008-07-09 09:49:15Z gub $
package at.spardat.enterprise.exc;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Locale;

/**
 * This class supports the notification of application or system level exceptions. Since this
 * class works much the same as class {@link Notification}, please have a look there
 * for the description of the API. 

* * What makes this class different from Notification is the fact that * you can throw an instance of subclasses of BaseException. Furthermore you may * set a detail Throwable at construction time, which should indicate * a more detailed (often technical) reason why you are creating and throwing * an BaseException.

* * This class must be sublassed outside the framework. * * @author YSD, 21.05.2003 19:29:23 */ public abstract class BaseException extends RuntimeException implements INotification, java.io.Serializable { /** * Increase this if u make non compatible changes */ private static final long serialVersionUID = 1L; /** * The wrapped notification object */ protected Notification notification_; /** * The stack trace of this */ private StackTrace thisStack_; /** * A detail exception converted to a StackTrace */ private StackTrace detailStack_; /** * The detail exception */ private Throwable detail_; /** * Indicates if this exception may be shown to the end user or not. This is just * a hint for the presentation layer to decide if it should wrap this in * another exception. */ protected boolean showToEndUser_; /** * For internal use only. */ protected BaseException () { } /** * Constructs and sets the message from a format string as * defined in java.text.MessageFormat. The required parameters * must be contained in the params array. * * @param detail detail exception. * @param message string that either is a java.text.MessageFormat * or not, depending on params. * @param l a java.util.Locale to format locale * dependent data types or null if the * params do not contain local specifics. * @param params the parameters of the message. If not null, message * is expected to be a string compliant to MessageFormat. */ public BaseException (Throwable detail, String message, Locale l, Object[] params) { notification_ = new Notification (message, l, params); // store the stacktrace thisStack_ = new StackTrace(StackTrace.splitLines(getSuperStackTrace())); // set detail if (detail != null) setDetail (detail); } /** * Returns the code. The code should be used to discrimitate among * different kinds of exceptions/notifications. */ public int getCode () { return notification_.getCode(); } /** * Returns true if this or any recursively nested detail BaseExceptions * code equals code. * * @param code the code to be checked for equality with the code of this or * any contained BaseException. */ public boolean containsCode (int code) { if (getCode() == code) return true; if (detail_ != null && detail_ instanceof BaseException) return ((BaseException)detail_).containsCode(code); return false; } /** * @see at.spardat.enterprise.exc.INotification#getType() */ public int getType() { return notification_.getType(); } /** * @see at.spardat.enterprise.exc.INotification#getReaction() */ public int getReaction() { return notification_.getReaction(); } /** * @see at.spardat.enterprise.exc.INotification#getShortMessage() */ public String getShortMessage() { return notification_.getShortMessage(); } /** * @see at.spardat.enterprise.exc.INotification#getMessage() */ public String getMessage() { return notification_.getMessage(); } /** * This method takes into account that BaseExceptions might be nested and * the outermost exceptions might have empty messages. It searches * the detail list down until it finds a non-empty message and * returns it. * * @param withClassNamePraefix indicates, if the message should be praefixed * by the classname and a colon. * * @return the first non-empty message in the BaseException-detail-list * or the empty-string if all messages are empty. */ public String getFirstNonEmptyMessage (boolean withClassNamePraefix) { String message = getMessage(); if (message.trim().length() > 0) return getMessage (withClassNamePraefix); if (detail_ == null) return getMessage (withClassNamePraefix); // recurse down if detail is BaseException if (detail_ instanceof BaseException) return ((BaseException)detail_).getFirstNonEmptyMessage(withClassNamePraefix); message = withClassNamePraefix ? detail_.toString() : detail_.getMessage(); return message == null ? "" : message; } /** * Returns the message of this, optionally praefixed by classname and a colon. * * @param withClassNamePraefix indicates that a classname praefix is required. * @return non-null String */ public String getMessage (boolean withClassNamePraefix) { if (withClassNamePraefix) { return getClass().getName() + ": " + getMessage(); } else { return getMessage(); } } /** * Sets the detail exception. This usually is the technical exception that * is the root cause of this exception. * * @param detail the root cause technical exception. */ private void setDetail (Throwable detail) { detail_ = detail; detailStack_ = null; } /** * Returns the detail throwable. The returned value is null if * no detail has been set or this has been migrated and * the detail is not an BaseException. * * @see #prepareMigration */ public Throwable getDetail () { return detail_; } /** * Initializes the cause of this throwable to the specified value. *

* This method can be called at most once. If a detail exception has * been passed to the constructor, it can't even be called once. * @throws IllegalStateException if a detail exception is allread defined. */ public synchronized Throwable initCause(Throwable cause) { if (detail_ != null) throw new IllegalStateException("Can't overwrite cause"); if (cause == this) throw new IllegalArgumentException("Self-causation not permitted"); detail_ = cause; detailStack_ = null; return this; } /** * Returns the cause of this throwable. The returned value is null if * no detail has been set or this has been migrated and * the detail is not an BaseException. * This method returns exactly the same as {@link #getDetail()}. * * @see #prepareMigration */ public Throwable getCause() { return detail_; } /** * Indicates if this exception may be directly displayed to the end user. */ public boolean showToEndUser () { return showToEndUser_; } /** * This method should be called if this is about to leave the JVM * and therefore must be serialized. We expect that the recipient * JVM is able to deserialize an BaseException, but not * necessarely any other contained detail exception. Therefore, if the * detail-throwable is not an BaseException, it is converted * to a String[] and stored as String[]. {@link #getDetail} will return * null afterwards.

* * This method does nothing if there is no detail-throwable. If * the detail itself is an BaseException, the method is * called recursively.

* * The end effect of calling this method is, to summarize the words above, * that any contained exception, directly or indirectly, is morphed * to a String[] if it is not an BaseException. */ public void prepareMigration () { if (detail_ != null) { if (detail_ instanceof BaseException) { ((BaseException)detail_).prepareMigration(); } else { detailStack_ = new StackTrace(detail_); detail_ = null; } } } /** * Returns a String which contains the class name, message and code * of this exception/notification. * * @see java.lang.Object#toString() */ public String toString () { StringBuffer result = new StringBuffer(); result.append(getClass().getName()); if (notification_.getCode() != 0) { result.append (" ["); result.append (notification_.getCode()); result.append ("]"); } result.append(": "); result.append(getMessage()); return result.toString(); } /** * Prints this to System.err. * * @see java.lang.Throwable#printStackTrace() */ public void printStackTrace() { printStackTrace (System.err); } /** * Prints this to the provided PrintStream including the stacktrace * and the information of all contained exceptions. * * @see java.lang.Throwable#printStackTrace(java.io.PrintStream) */ public void printStackTrace (PrintStream s) { printStackTraceRec (s, null); } private void printStackTraceRec (PrintStream s, StackTrace enclosing) { synchronized (s) { StackTrace thisStack = getStackOfThis(); thisStack.printStackTrace (s, enclosing); if (detailStack_ != null) { s.print ("Caused by: "); detailStack_.printStackTrace (s, thisStack); } if (detail_ != null) { s.print ("Caused by: "); if (detail_ instanceof BaseException) ((BaseException)detail_).printStackTraceRec (s, thisStack); else { StackTrace detailStack = new StackTrace(detail_); detailStack.printStackTrace (s, thisStack); } } } } /** * Prints this to the provided PrintWriter including the stacktrace * and the information of all contained exceptions. * * @see java.lang.Throwable#printStackTrace(java.io.PrintWriter) */ public void printStackTrace (PrintWriter s) { printStackTraceRec (s, null); } private void printStackTraceRec (PrintWriter s, StackTrace enclosing) { synchronized (s) { StackTrace thisStack = getStackOfThis(); thisStack.printStackTrace (s, enclosing); if (detailStack_ != null) { s.print ("Caused by: "); detailStack_.printStackTrace (s, thisStack); } if (detail_ != null) { s.print ("Caused by: "); if (detail_ instanceof BaseException) ((BaseException)detail_).printStackTraceRec (s, thisStack); else { StackTrace detailStack = new StackTrace(detail_); detailStack.printStackTrace (s, thisStack); } } } } /** * Returns the result of calling printStackTrace on super. */ private String getSuperStackTrace() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); super.printStackTrace(pw); pw.close(); return sw.toString(); } /** * Returns the stacktrace of this exception ignoring the detail exception. */ public String getOwnStackTrace() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); StackTrace thisStack = getStackOfThis(); thisStack.printStackTrace (pw, null); pw.close(); return sw.toString(); } /** * Returns the stack trace of this with a corrected header. The header * may have changed since we have saved the stack in the constructor. */ public StackTrace getStackOfThis () { if (thisStack_.isWellFormed()) { // normally, this is well formed String newHeader = toString(); String [] headerLines = StackTrace.splitLines(newHeader); thisStack_.replaceHeaderLines(headerLines); } return thisStack_; } /** * Sets the instance variables in this from ex. ex is made unusable * with this method.

* * Although this method is public, it may not be called from outside the framework. */ private void stealFrom (BaseException ex) { notification_ = ex.notification_; thisStack_ = ex.thisStack_; detailStack_ = ex.detailStack_; detail_ = ex.detail_; showToEndUser_ = ex.showToEndUser_; ex.notification_ = null; ex.thisStack_ = null; ex.detailStack_ = null; ex.detail_ = null; } /** * Creates a AppException or SysException from this that has * the property that this and all contained BaseExceptions are instances * of AppException or SysException, but not subclasses of them.

* * This (the target object) is destroyed and must not be used anymore!!! This * method must not be called from outside the framework!!! */ public BaseException truncateSubclasses () { /** * Morph this down to AppException or SysException */ BaseException toReturn = null; if (this instanceof AppException) { toReturn = new AppException(""); toReturn.stealFrom (this); } else if (this instanceof SysException) { toReturn = new SysException(""); toReturn.stealFrom (this); } else { throw new RuntimeException ("BaseException subclassing is not allowed"); } if (toReturn.detail_ != null && toReturn.detail_ instanceof BaseException) { /** * Recursively on detail_ */ toReturn.detail_ = ((BaseException)toReturn.detail_).truncateSubclasses(); } return toReturn; } /** * Sets the message of this from a one * parameter java.text.MessageFormat compatible string. * * @param messageFmt format string as defined in java.text.MessageFormat. * @param param1 message parameter * @param param2 message parameter * @return this */ public BaseException setMessage (String messageFmt, Object param1, Object param2) { notification_.setMessage (messageFmt, param1, param2); return this; } /** * Sets the message of this from a one * parameter java.text.MessageFormat compatible string. * * @param messageFmt format string as defined in java.text.MessageFormat. * @param param1 message parameter * @return this */ public BaseException setMessage (String messageFmt, Object param1) { notification_.setMessage (messageFmt, param1); return this; } /** * Constructs and sets the message to the provided value. * * @param message text to set * @return this */ public BaseException setMessage (String message) { notification_.setMessage (message); return this; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy