001/* 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: UMSException.java,v 1.5 2009/01/28 05:34:51 ww203982 Exp $ 026 * 027 * Portions Copyrighted 2011-2015 ForgeRock AS. 028 */ 029 030package com.iplanet.ums; 031 032import java.io.PrintWriter; 033import java.io.StringWriter; 034import java.util.ResourceBundle; 035import org.forgerock.opendj.ldap.LdapException; 036 037/** 038 * <PRE> 039 * 040 * This class is the super-class for all UMS <B>checked</B> exceptions. 041 * 042 * 043 * Some Exception throwing guidelines: ------------------------------------- 044 * 045 * <B> Checked exceptions </B> are sub-classes of java.lang.Exception; methods 046 * throwing this type of exception are forced to define a throws clause in the 047 * method signature and client programmers need to catch and handle the 048 * exception with a try/catch block or declare the throws clause in their 049 * methods. <B> Unchecked exceptions </B> are sub-classes of 050 * java.lang.RuntimeException. Client programmers don't have to deal with the 051 * exception using a try/catch block and the method throwing it does not have to 052 * define it in its signature. 053 * - If your method encounters an abnormal condition which causes it to be 054 * unable to fulfill its contract, or throw a checked or unchecked exception 055 * (either UMSException or RuntimeException). 056 * - If your method discovers that a client has breached its contract, for 057 * example, passing a null as a parameter where a non-null value is required, 058 * throw an unchecked exception (RuntimeException). 059 * - If your method is unable to fulfill its contract and you feel client 060 * programmers should consciously decide how to handle, throw checked exceptions 061 * (UMSException). 062 * 063 * 064 * Embedded/Nested Exceptions: -------------------------- 065 * 066 * An exception of type UMSException can embed any exception of type Throwable. 067 * Embedded exceptions ensure traceability of errors in a multi-tiered 068 * application. For example, in a simple 3- Tier model - presentation/client 069 * tier, middle/domain tier and database/persistence tier - the real cause of 070 * error might be lost by the time control, which is passed back from the 071 * persistence tier to the client tier. To ensure tracking info, the constructor 072 * UMSException(message,Throwable) should be used while throwing the exception. 073 * Normally, the first object at each tier/module will have generic exceptions 074 * defined, for example, LDAPException, RelationalDBException, 075 * ConfigManagerException. Client programs can then invoke the #getRootCause() 076 * method to get the underlying cause. 077 * 078 * Exception hierarchy should be defined: ------------------------------------- 079 * An exception for each abnormal cause should be created. For example, 080 * LDAPSearchException, LDAPArchiveException, etc. UMSException should probably 081 * be thrown only by external API's. Even these should have embedded exceptions 082 * from lower level tiers. For example, UMSException will have LDAPException 083 * embedded in it, LDAPException will have LDAPSearchException nested, and so 084 * on. Every package should define its own exception hierarchies specific to its 085 * context, for example, policy-related exceptions should be defined in the 086 * policy package. 087 * 088 * Localizing Error Messages ------------------------- The java resource bundle 089 * mechanism is used to implement localization. The ResourceSet and 090 * ResourceSetManager classes are used to implement localization. 091 * 092 * Steps for creating UMSException Sub-classes and messages 093 * ------------------------------------------------------ 094 * 095 * 1. Identify the package this exception will belong to. A policy-related 096 * exception, PolicyNotFoundException, should be part of the policy package. 097 * 098 * 2. Each package should have its own properties file to store error messages. 099 * For example policy.properties in package policy #policy.properties # 100 * Resources for com.iplanet.ums.policy policy-nopolicyfound=Cannot find this 101 * Policy 102 * 103 * 3. Create a sub-class of UMSException and override the constructors. 104 * 105 * public class PolicyNotFoundException extends UMSException { public 106 * PolicyNotFoundException() { super(); } public PolicyNotFoundException(String 107 * msg) { super(msg); } public PolicyNotFoundExceptin(String msg, Throwable t) { 108 * super(msg,t); } 109 * 110 * 111 * Throwing/Catching Exception Examples: ------------------------------------ 112 * 113 * 1. Throwing a non-nested Exception <B>(not recommended, use Ex. 3 below)</B> 114 * UMSException ux = new UMSException("Some weird error!..."); throw ux; 115 * 116 * 2. Throwing a nested Exception <B>(not recommended, use Ex. 3 below)</B> 117 * try { ....... ....... } catch (LDAPException le) { UMSException ux = new 118 * UMSException("Some weird error!...", le); throw ux; } 119 * 120 * 3. Throwing an Exception using the ResourceSetManager 121 * 122 * ...... ...... public static final String PKG = 123 * "com.iplanet.ums.policy.policy"; public static final String PREFIX = 124 * "policy"; public static final String NO_POLICY_DOMAIN = "nopolicydomain"; 125 * public static final String POLICY_NOT_FOUND = "nopolicyfound"; ...... ...... 126 * if( policyDomainName == null || policyDomainName.length() == 0) { 127 * String msg = ResourceSetManager.getString( PKG, PREFIX, NO_POLICY_DOMAIN ); 128 * // RuntimeException 129 * throw new IllegalArgumentException( msg ); } ...... ...... 130 * if (policy not found ) { String msg = ResourceSetManager.getString( PKG, 131 * PREFIX, POLICY_NOT_FOUND); // RuntimeException throw new 132 * InvalidPolicyException(msg); } 133 * 134 * 135 * The properties file (com/iplanet/ums/policy/policy.properties) looks like 136 * this: # Resources for com.iplanet.ums.policy policy-nopolicydomain=Policy 137 * Domain name cannot be null or blank policy-nopolicyfound=Cannot find this 138 * Policy 139 * 140 * - Logging/Dealing with an Exception, inclunding all nested exceptions try { 141 * ....... ....... } catch (UMSException ux) { 142 * 143 * if (ux.getRootCause() instanceof LDAPException) { PrintWriter pw = new 144 * PrintWriter(<some file stream>); ux.log(pw); } else { 145 * System.out.println(ux.getMessage()); } 146 * } 147 * 148 * </PRE> 149 * 150 * @see #UMSException(String, Throwable) 151 * @see #getRootCause() 152 * @see java.lang.Exception 153 * @see java.lang.RuntimeException 154 * @supported.api 155 */ 156public class UMSException extends java.lang.Exception { 157 158 private static final long serialVersionUID = -7043204896844472780L; 159 160 static ResourceBundle xcptMsgs = null; 161 162 protected String xcptMessage; 163 164 protected Throwable rootCause; 165 166 /** 167 * Constructs a UMSException with a detailed message. 168 * 169 * @param message 170 * Detailed message for this exception. 171 * @supported.api 172 */ 173 public UMSException(String message) { 174 super(message); 175 xcptMessage = message; 176 } 177 178 /** 179 * Constructs a UMSException with a message and an embedded exception. 180 * 181 * @param message 182 * Detailed message for this exception. 183 * @param rootCause 184 * An embedded exception 185 * @supported.api 186 */ 187 public UMSException(String message, Throwable rootCause) { 188 super(message); 189 xcptMessage = message; 190 this.rootCause = rootCause; 191 } 192 193 /** 194 * Constructs a UMSException with no details. 195 */ 196 protected UMSException() { 197 super(); 198 xcptMessage = null; 199 } 200 201 /** 202 * Returns the detail message of this exception and all embedded exceptions. 203 * @supported.api 204 */ 205 public String getMessage() { 206 207 // if there's no nested exception, 208 // return the main message 209 if (getRootCause() == null) 210 return xcptMessage; 211 212 StringBuilder theMsg = new StringBuilder(); 213 214 // get the root cause message 215 String nestedMsg; 216 if (rootCause instanceof LdapException) { 217 nestedMsg = ((LdapException) rootCause).getResult().getDiagnosticMessage(); 218 } else { 219 nestedMsg = rootCause.getMessage(); 220 } 221 222 if (xcptMessage != null) 223 theMsg.append(xcptMessage).append("::").append(nestedMsg); 224 else 225 theMsg.append(nestedMsg); 226 227 return theMsg.toString(); 228 } 229 230 /** 231 * Returns the embedded exception. 232 * @supported.api 233 */ 234 public Throwable getRootCause() { 235 return rootCause; 236 } 237 238 /** 239 * Format this UMSException to a PrintWriter. 240 * 241 * @param out 242 * PrintWriter to write exception to. 243 * 244 * @return The out parameter passed in. 245 * @see java.io.PrintWriter 246 * @supported.api 247 */ 248 public PrintWriter log(PrintWriter out) { 249 return log(this, out); 250 } 251 252 /** 253 * A utility method to format an Exception to a PrintWriter. 254 * 255 * @param xcpt 256 * Exception to log. 257 * @param out 258 * PrintWriter to write exception to. 259 * 260 * @return The out parameter passed in. 261 * @see java.io.PrintWriter 262 * @supported.api 263 */ 264 static public PrintWriter log(Throwable xcpt, PrintWriter out) { 265 266 out.println("-----------"); 267 out.println(xcpt.toString()); 268 out.println("Stack Trace:"); 269 out.print(getStackTrace(xcpt)); 270 out.println("-----------"); 271 out.flush(); 272 return out; 273 } 274 275 /** 276 * Formats a UMSException exception message; includes embedded exceptions. 277 * @supported.api 278 */ 279 public String toString() { 280 281 StringBuilder buf = new StringBuilder(); 282 buf.append("--------------------------------------"); 283 buf.append("Got UMS Exception\n"); 284 285 String msg = getMessage(); 286 if (msg != null && msg.length() > 0) { 287 buf.append("Message: ").append(getMessage()); 288 } 289 290 // Invoke toString() of rootCause first 291 if (rootCause != null) { 292 buf.append("\nLower level exception: "); 293 buf.append(getRootCause()); 294 } 295 296 return buf.toString(); 297 } 298 299 /** 300 * Prints this exception's stack trace to <tt>System.err</tt>. If this 301 * exception has a root exception; the stack trace of the root exception is 302 * printed to <tt>System.err</tt> instead. 303 * @supported.api 304 */ 305 public void printStackTrace() { 306 printStackTrace(System.err); 307 } 308 309 /** 310 * Prints this exception's stack trace to a print stream. If this exception 311 * has a root exception, the stack trace of the root exception is printed to 312 * the print stream instead. 313 * 314 * @param ps 315 * The non-null print stream to which to print. 316 * @supported.api 317 */ 318 public void printStackTrace(java.io.PrintStream ps) { 319 if (rootCause != null) { 320 String superString = super.toString(); 321 synchronized (ps) { 322 ps.print(superString + (superString.endsWith(".") ? "" : ".") 323 + " Root exception is "); 324 rootCause.printStackTrace(ps); 325 } 326 } else { 327 super.printStackTrace(ps); 328 } 329 } 330 331 /** 332 * Prints this exception's stack trace to a print writer. If this exception 333 * has a root exception; the stack trace of the root exception is printed to 334 * the print writer instead. 335 * 336 * @param pw The non-null print writer to which to print. 337 * @supported.api 338 */ 339 public void printStackTrace(java.io.PrintWriter pw) { 340 if (rootCause != null) { 341 String superString = super.toString(); 342 synchronized (pw) { 343 pw.print(superString + (superString.endsWith(".") ? "" : ".") 344 + " Root exception is "); 345 rootCause.printStackTrace(pw); 346 } 347 } else { 348 super.printStackTrace(pw); 349 } 350 } 351 352 /** 353 * Get exception stack trace as a string. 354 * 355 * java.lang.Throwable java.lang.Exception UMSException <name of exception 356 * being thrown> 357 */ 358 static private String getStackTrace(Throwable xcpt) { 359 StringWriter sw = new StringWriter(); 360 PrintWriter pw = new PrintWriter(sw); 361 362 xcpt.printStackTrace(pw); 363 364 return sw.toString(); 365 } 366}