/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: UMSException.java,v 1.5 2009/01/28 05:34:51 ww203982 Exp $
*
* Portions Copyrighted 2011-2015 ForgeRock AS.
*/
package com.iplanet.ums;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ResourceBundle;
import org.forgerock.opendj.ldap.LdapException;
/**
* <PRE>
*
* This class is the super-class for all UMS <B>checked</B> exceptions.
*
*
* Some Exception throwing guidelines: -------------------------------------
*
* <B> Checked exceptions </B> are sub-classes of java.lang.Exception; methods
* throwing this type of exception are forced to define a throws clause in the
* method signature and client programmers need to catch and handle the
* exception with a try/catch block or declare the throws clause in their
* methods. <B> Unchecked exceptions </B> are sub-classes of
* java.lang.RuntimeException. Client programmers don't have to deal with the
* exception using a try/catch block and the method throwing it does not have to
* define it in its signature.
* - If your method encounters an abnormal condition which causes it to be
* unable to fulfill its contract, or throw a checked or unchecked exception
* (either UMSException or RuntimeException).
* - If your method discovers that a client has breached its contract, for
* example, passing a null as a parameter where a non-null value is required,
* throw an unchecked exception (RuntimeException).
* - If your method is unable to fulfill its contract and you feel client
* programmers should consciously decide how to handle, throw checked exceptions
* (UMSException).
*
*
* Embedded/Nested Exceptions: --------------------------
*
* An exception of type UMSException can embed any exception of type Throwable.
* Embedded exceptions ensure traceability of errors in a multi-tiered
* application. For example, in a simple 3- Tier model - presentation/client
* tier, middle/domain tier and database/persistence tier - the real cause of
* error might be lost by the time control, which is passed back from the
* persistence tier to the client tier. To ensure tracking info, the constructor
* UMSException(message,Throwable) should be used while throwing the exception.
* Normally, the first object at each tier/module will have generic exceptions
* defined, for example, LDAPException, RelationalDBException,
* ConfigManagerException. Client programs can then invoke the #getRootCause()
* method to get the underlying cause.
*
* Exception hierarchy should be defined: -------------------------------------
* An exception for each abnormal cause should be created. For example,
* LDAPSearchException, LDAPArchiveException, etc. UMSException should probably
* be thrown only by external API's. Even these should have embedded exceptions
* from lower level tiers. For example, UMSException will have LDAPException
* embedded in it, LDAPException will have LDAPSearchException nested, and so
* on. Every package should define its own exception hierarchies specific to its
* context, for example, policy-related exceptions should be defined in the
* policy package.
*
* Localizing Error Messages ------------------------- The java resource bundle
* mechanism is used to implement localization. The ResourceSet and
* ResourceSetManager classes are used to implement localization.
*
* Steps for creating UMSException Sub-classes and messages
* ------------------------------------------------------
*
* 1. Identify the package this exception will belong to. A policy-related
* exception, PolicyNotFoundException, should be part of the policy package.
*
* 2. Each package should have its own properties file to store error messages.
* For example policy.properties in package policy #policy.properties #
* Resources for com.iplanet.ums.policy policy-nopolicyfound=Cannot find this
* Policy
*
* 3. Create a sub-class of UMSException and override the constructors.
*
* public class PolicyNotFoundException extends UMSException { public
* PolicyNotFoundException() { super(); } public PolicyNotFoundException(String
* msg) { super(msg); } public PolicyNotFoundExceptin(String msg, Throwable t) {
* super(msg,t); }
*
*
* Throwing/Catching Exception Examples: ------------------------------------
*
* 1. Throwing a non-nested Exception <B>(not recommended, use Ex. 3 below)</B>
* UMSException ux = new UMSException("Some weird error!..."); throw ux;
*
* 2. Throwing a nested Exception <B>(not recommended, use Ex. 3 below)</B>
* try { ....... ....... } catch (LDAPException le) { UMSException ux = new
* UMSException("Some weird error!...", le); throw ux; }
*
* 3. Throwing an Exception using the ResourceSetManager
*
* ...... ...... public static final String PKG =
* "com.iplanet.ums.policy.policy"; public static final String PREFIX =
* "policy"; public static final String NO_POLICY_DOMAIN = "nopolicydomain";
* public static final String POLICY_NOT_FOUND = "nopolicyfound"; ...... ......
* if( policyDomainName == null || policyDomainName.length() == 0) {
* String msg = ResourceSetManager.getString( PKG, PREFIX, NO_POLICY_DOMAIN );
* // RuntimeException
* throw new IllegalArgumentException( msg ); } ...... ......
* if (policy not found ) { String msg = ResourceSetManager.getString( PKG,
* PREFIX, POLICY_NOT_FOUND); // RuntimeException throw new
* InvalidPolicyException(msg); }
*
*
* The properties file (com/iplanet/ums/policy/policy.properties) looks like
* this: # Resources for com.iplanet.ums.policy policy-nopolicydomain=Policy
* Domain name cannot be null or blank policy-nopolicyfound=Cannot find this
* Policy
*
* - Logging/Dealing with an Exception, inclunding all nested exceptions try {
* ....... ....... } catch (UMSException ux) {
*
* if (ux.getRootCause() instanceof LDAPException) { PrintWriter pw = new
* PrintWriter(<some file stream>); ux.log(pw); } else {
* System.out.println(ux.getMessage()); }
* }
*
* </PRE>
*
* @see #UMSException(String, Throwable)
* @see #getRootCause()
* @see java.lang.Exception
* @see java.lang.RuntimeException
* @supported.api
*/
public class UMSException extends java.lang.Exception {
private static final long serialVersionUID = -7043204896844472780L;
static ResourceBundle xcptMsgs = null;
protected String xcptMessage;
protected Throwable rootCause;
/**
* Constructs a UMSException with a detailed message.
*
* @param message
* Detailed message for this exception.
* @supported.api
*/
public UMSException(String message) {
super(message);
xcptMessage = message;
}
/**
* Constructs a UMSException with a message and an embedded exception.
*
* @param message
* Detailed message for this exception.
* @param rootCause
* An embedded exception
* @supported.api
*/
public UMSException(String message, Throwable rootCause) {
super(message);
xcptMessage = message;
this.rootCause = rootCause;
}
/**
* Constructs a UMSException with no details.
*/
protected UMSException() {
super();
xcptMessage = null;
}
/**
* Returns the detail message of this exception and all embedded exceptions.
* @supported.api
*/
public String getMessage() {
// if there's no nested exception,
// return the main message
if (getRootCause() == null)
return xcptMessage;
StringBuilder theMsg = new StringBuilder();
// get the root cause message
String nestedMsg;
if (rootCause instanceof LdapException) {
nestedMsg = ((LdapException) rootCause).getResult().getDiagnosticMessage();
} else {
nestedMsg = rootCause.getMessage();
}
if (xcptMessage != null)
theMsg.append(xcptMessage).append("::").append(nestedMsg);
else
theMsg.append(nestedMsg);
return theMsg.toString();
}
/**
* Returns the embedded exception.
* @supported.api
*/
public Throwable getRootCause() {
return rootCause;
}
/**
* Format this UMSException to a PrintWriter.
*
* @param out
* PrintWriter to write exception to.
*
* @return The out parameter passed in.
* @see java.io.PrintWriter
* @supported.api
*/
public PrintWriter log(PrintWriter out) {
return log(this, out);
}
/**
* A utility method to format an Exception to a PrintWriter.
*
* @param xcpt
* Exception to log.
* @param out
* PrintWriter to write exception to.
*
* @return The out parameter passed in.
* @see java.io.PrintWriter
* @supported.api
*/
static public PrintWriter log(Throwable xcpt, PrintWriter out) {
out.println("-----------");
out.println(xcpt.toString());
out.println("Stack Trace:");
out.print(getStackTrace(xcpt));
out.println("-----------");
out.flush();
return out;
}
/**
* Formats a UMSException exception message; includes embedded exceptions.
* @supported.api
*/
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("--------------------------------------");
buf.append("Got UMS Exception\n");
String msg = getMessage();
if (msg != null && msg.length() > 0) {
buf.append("Message: ").append(getMessage());
}
// Invoke toString() of rootCause first
if (rootCause != null) {
buf.append("\nLower level exception: ");
buf.append(getRootCause());
}
return buf.toString();
}
/**
* Prints this exception's stack trace to <tt>System.err</tt>. If this
* exception has a root exception; the stack trace of the root exception is
* printed to <tt>System.err</tt> instead.
* @supported.api
*/
public void printStackTrace() {
printStackTrace(System.err);
}
/**
* Prints this exception's stack trace to a print stream. If this exception
* has a root exception, the stack trace of the root exception is printed to
* the print stream instead.
*
* @param ps
* The non-null print stream to which to print.
* @supported.api
*/
public void printStackTrace(java.io.PrintStream ps) {
if (rootCause != null) {
String superString = super.toString();
synchronized (ps) {
ps.print(superString + (superString.endsWith(".") ? "" : ".")
+ " Root exception is ");
rootCause.printStackTrace(ps);
}
} else {
super.printStackTrace(ps);
}
}
/**
* Prints this exception's stack trace to a print writer. If this exception
* has a root exception; the stack trace of the root exception is printed to
* the print writer instead.
*
* @param pw The non-null print writer to which to print.
* @supported.api
*/
public void printStackTrace(java.io.PrintWriter pw) {
if (rootCause != null) {
String superString = super.toString();
synchronized (pw) {
pw.print(superString + (superString.endsWith(".") ? "" : ".")
+ " Root exception is ");
rootCause.printStackTrace(pw);
}
} else {
super.printStackTrace(pw);
}
}
/**
* Get exception stack trace as a string.
*
* java.lang.Throwable java.lang.Exception UMSException <name of exception
* being thrown>
*/
static private String getStackTrace(Throwable xcpt) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
xcpt.printStackTrace(pw);
return sw.toString();
}
}