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: IdRepoException.java,v 1.8 2009/11/19 18:18:47 bhavnab Exp $ 026 * 027 * Portions Copyrighted 2011-2015 ForgeRock AS. 028 */ 029package com.sun.identity.idm; 030 031import com.sun.identity.shared.debug.Debug; 032import com.sun.identity.shared.locale.AMResourceBundleCache; 033import com.sun.identity.shared.locale.L10NMessage; 034import com.sun.identity.shared.locale.Locale; 035import java.text.MessageFormat; 036import java.util.ResourceBundle; 037import java.util.regex.Matcher; 038import java.util.regex.Pattern; 039 040import org.forgerock.opendj.ldap.ResultCode; 041 042/** 043 * The exception class whose instance is thrown if there is any error during the 044 * operation of objects of the <code>com.sun.identity.sms</code> package. This 045 * class maps the exception that occurred at a lower level to a high level 046 * error. Using the exception status code <code>getExceptionCode()</code> the 047 * errors are categorized as a <code>ABORT</code>, <code>RETRY</code>, 048 * <code>CONFIG_PROBLEM</code> or <code>LDAP_OP_FAILED</code> (typically a 049 * bug). 050 * 051 * @supported.all.api 052 */ 053public class IdRepoException extends Exception implements L10NMessage { 054 055 // Static variable 056 private transient AMResourceBundleCache amCache = AMResourceBundleCache 057 .getInstance(); 058 059 private transient Debug debug = AMIdentityRepository.debug; 060 061 private final static Pattern PATTERN = Pattern.compile("(.*)(?=: (.*?)uid=)|(.*)(?=(.*?)uid=)|(.*)"); 062 063 // Instance variables 064 private String message; 065 066 private String bundleName; 067 068 private String errorCode; 069 070 private Object[] args; 071 072 private String ldapErrCode = null; 073 074 public IdRepoException() { 075 } 076 077 /** 078 * @param msg 079 * The message provided by the object which is throwing the 080 * exception 081 */ 082 public IdRepoException(String msg) { 083 message = msg; 084 } 085 086 public IdRepoException(String msg, String errorCode) { 087 message = msg; 088 this.errorCode = errorCode; 089 } 090 091 /** 092 * This constructor is used to pass the localized error message At this 093 * level, the locale of the caller is not known and it is not possible to 094 * throw localized error message at this level. Instead this constructor 095 * provides Resource Bundle name ,error code and LDAP error code ( in case 096 * of LDAP related exception for correctly locating the 097 * error message. The default <code>getMessage()</code> will always return 098 * English messages only. This is in consistent with current JRE. 099 * 100 * @param rbName 101 * Resource bundle Name to be used for getting localized error 102 * message. 103 * @param errorCode 104 * Key to resource bundle. You can use <code>ResourceBundle rb = 105 * ResourceBunde.getBundle(rbName,locale); 106 * String localizedStr = rb.getString(errorCode)</code>. 107 * @param ldapErrCode 108 * ldap error code 109 * @param args 110 * arguments to message. If it is not present pass the as null. 111 * @deprecated 112 * Passing in an ldapErrorCode as a String is not recommended, use the 113 * OO ctor instead. 114 */ 115 @Deprecated 116 public IdRepoException(String rbName, String errorCode, String ldapErrCode, Object[] args) 117 { 118 this.bundleName = rbName; 119 this.errorCode = errorCode; 120 this.ldapErrCode = ldapErrCode; 121 this.args = args; 122 this.message = getL10NMessage(java.util.Locale.ENGLISH); 123 } 124 125 /** 126 * This constructor is used to pass the localized error message At this 127 * level, the locale of the caller is not known and it is not possible to 128 * throw localized error message at this level. Instead this constructor 129 * provides Resource Bundle name ,error code and LDAP Result Code ( in case 130 * of LDAP related exception for correctly locating the 131 * error message. The default <code>getMessage()</code> will always return 132 * English messages only. This is in consistent with current JRE. 133 * 134 * @param rbName 135 * Resource bundle Name to be used for getting localized error 136 * message. 137 * @param errorCode 138 * Key to resource bundle. You can use <code>ResourceBundle rb = 139 * ResourceBunde.getBundle(rbName,locale); 140 * String localizedStr = rb.getString(errorCode)</code>. 141 * @param ldapResultCode 142 * ldap result code 143 * @param args 144 * arguments to message. If it is not present pass the as null. 145 */ 146 public IdRepoException(String rbName, String errorCode, ResultCode ldapResultCode, Object[] args) { 147 this.bundleName = rbName; 148 this.errorCode = errorCode; 149 this.ldapErrCode = String.valueOf(ldapResultCode.intValue()); 150 this.args = args; 151 this.message = getL10NMessage(java.util.Locale.ENGLISH); 152 } 153 154 /** 155 * This constructor is used to pass the localized error message At this 156 * level, the locale of the caller is not known and it is not possible to 157 * throw localized error message at this level. Instead this constructor 158 * provides Resource Bundle name and error code for correctly locating the 159 * error message. The default <code>getMessage()</code> will always return 160 * English messages only. This is in consistent with current JRE. 161 * 162 * @param rbName 163 * Resource bundle Name to be used for getting localized error 164 * message. 165 * @param errorCode 166 * Key to resource bundle. You can use <code>ResourceBundle rb = 167 * ResourceBunde.getBundle(rbName,locale); 168 * String localizedStr = rb.getString(errorCode)</code>. 169 * @param args 170 * arguments to message. If it is not present pass the as null. 171 */ 172 public IdRepoException(String rbName, String errorCode, Object[] args) { 173 this.bundleName = rbName; 174 this.errorCode = errorCode; 175 this.args = args; 176 this.message = getL10NMessage(java.util.Locale.ENGLISH); 177 } 178 179 /** 180 * Returns a localized error message 181 * 182 * @param locale 183 * Uses the locale object to create the appropriate localized 184 * error message 185 * @return localized error message. 186 * @see #IdRepoException(String, String, Object[]) 187 */ 188 public String getL10NMessage(java.util.Locale locale) { 189 String result = errorCode; 190 if (bundleName != null && locale != null) { 191 ResourceBundle bundle = amCache.getResBundle(bundleName, locale); 192 String mid = Locale.getString(bundle, errorCode, debug); 193 if (args == null || args.length == 0) { 194 result = mid; 195 } else { 196 result = MessageFormat.format(mid, args); 197 } 198 } 199 return result; 200 } 201 202 /** 203 * Returns <code>ResourceBundle</code> Name associated with this error 204 * message. 205 * 206 * @return <code>ResourceBundle</code> name associated with this error 207 * message. 208 * @see #IdRepoException(String, String, Object[]) 209 */ 210 public String getResourceBundleName() { 211 return bundleName; 212 } 213 214 /** 215 * Returns an int representation of <code>ldapErrCode</code>. 216 * This is to be used with ResultCode.valueOf() which will return a valid 217 * ResultCode object regardless of the return of this method. 218 * 219 * A null or invalid <code>ldapErrorCode</code> will return <code>-1</code>. 220 * 221 * @return an int representation of this exception's LDAP error code. 222 */ 223 public int getLdapErrorIntCode() { 224 try { 225 return Integer.valueOf(ldapErrCode); 226 } catch (NumberFormatException nfe) { 227 return -1; 228 } 229 } 230 231 /** 232 * Returns error code associated with this error message. 233 * 234 * @return Error code associated with this error message. 235 * @see #IdRepoException(String, String, Object[]) 236 */ 237 public String getErrorCode() { 238 return errorCode; 239 } 240 241 /** 242 * Returns the LDAP error code associated with this error message. 243 * 244 * @return Error code associated with this error message and null if 245 * not caused by <code>LDAPException</code>. 246 * @see #IdRepoException(String, String, Object[]) 247 * 248 * @deprecated 249 * Use #getLdapErrorIntCode() instead. The ldap error code is always an int 250 */ 251 @Deprecated 252 public String getLDAPErrorCode() { 253 return ldapErrCode; 254 } 255 256 /** 257 * Replace the LDAP error code associated with this error message. 258 * 259 * @see #IdRepoException(String, String, Object[]) 260 */ 261 public void setLDAPErrorCode(String errorCode) { 262 ldapErrCode = errorCode; 263 } 264 265 /** 266 * Returns arguments for formatting this error message. 267 * 268 * @return arguments for formatting this error message. You need to use 269 * <code>MessageFormat</code> class to format the message It can 270 * be null. 271 * @see #IdRepoException(String, String, Object[]) 272 */ 273 public Object[] getMessageArgs() { 274 return args; 275 } 276 277 public String toString() { 278 StringBuilder buf = new StringBuilder(); 279 String msg = message; 280 if (msg != null && msg.length() > 0) { 281 buf.append("Message:"); 282 buf.append(msg); 283 buf.append("\n"); 284 } 285 return buf.toString(); 286 } 287 288 /** 289 * Returns the error message of this exception. 290 * 291 * @return String representing the error message 292 */ 293 public String getMessage() { 294 return message; 295 } 296 297 /** 298 * If this error is an instance of a LDAP Constraint Violated Error (LDAP code 313) 299 * attempts to return useful information about the error that occured without 300 * leaking additional information about the system to the calling user. 301 * 302 * If this error is not an instance of LDAP Constraint Violated Error, the message 303 * of the error is returned. 304 * 305 * @return a user-facing representation of this exception. 306 */ 307 public String getConstraintViolationDetails() { 308 if (!IdRepoErrorCode.LDAP_EXCEPTION.equals(getErrorCode()) || args == null || args.length < 3) { 309 return getMessage(); 310 } 311 312 String argMatch = (String) args[2]; 313 314 if (argMatch != null) { 315 Matcher matcher = PATTERN.matcher(argMatch); 316 317 if (matcher.find()) { 318 return matcher.group(0).trim(); 319 } 320 } 321 322 return "Cannot update attributes due to server's attribute constraints being violated."; 323 } 324}