/*
* 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: IdRepoException.java,v 1.8 2009/11/19 18:18:47 bhavnab Exp $
*
* Portions Copyrighted 2011-2015 ForgeRock AS.
*/
package com.sun.identity.idm;
import com.sun.identity.shared.debug.Debug;
import com.sun.identity.shared.locale.AMResourceBundleCache;
import com.sun.identity.shared.locale.L10NMessage;
import com.sun.identity.shared.locale.Locale;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.forgerock.opendj.ldap.ResultCode;
/**
* The exception class whose instance is thrown if there is any error during the
* operation of objects of the <code>com.sun.identity.sms</code> package. This
* class maps the exception that occurred at a lower level to a high level
* error. Using the exception status code <code>getExceptionCode()</code> the
* errors are categorized as a <code>ABORT</code>, <code>RETRY</code>,
* <code>CONFIG_PROBLEM</code> or <code>LDAP_OP_FAILED</code> (typically a
* bug).
*
* @supported.all.api
*/
public class IdRepoException extends Exception implements L10NMessage {
// Static variable
private transient AMResourceBundleCache amCache = AMResourceBundleCache
.getInstance();
private transient Debug debug = AMIdentityRepository.debug;
private final static Pattern PATTERN = Pattern.compile("(.*)(?=: (.*?)uid=)|(.*)(?=(.*?)uid=)|(.*)");
// Instance variables
private String message;
private String bundleName;
private String errorCode;
private Object[] args;
private String ldapErrCode = null;
public IdRepoException() {
}
/**
* @param msg
* The message provided by the object which is throwing the
* exception
*/
public IdRepoException(String msg) {
message = msg;
}
public IdRepoException(String msg, String errorCode) {
message = msg;
this.errorCode = errorCode;
}
/**
* This constructor is used to pass the localized error message At this
* level, the locale of the caller is not known and it is not possible to
* throw localized error message at this level. Instead this constructor
* provides Resource Bundle name ,error code and LDAP error code ( in case
* of LDAP related exception for correctly locating the
* error message. The default <code>getMessage()</code> will always return
* English messages only. This is in consistent with current JRE.
*
* @param rbName
* Resource bundle Name to be used for getting localized error
* message.
* @param errorCode
* Key to resource bundle. You can use <code>ResourceBundle rb =
* ResourceBunde.getBundle(rbName,locale);
* String localizedStr = rb.getString(errorCode)</code>.
* @param ldapErrCode
* ldap error code
* @param args
* arguments to message. If it is not present pass the as null.
* @deprecated
* Passing in an ldapErrorCode as a String is not recommended, use the
* OO ctor instead.
*/
@Deprecated
public IdRepoException(String rbName, String errorCode, String ldapErrCode, Object[] args)
{
this.bundleName = rbName;
this.errorCode = errorCode;
this.ldapErrCode = ldapErrCode;
this.args = args;
this.message = getL10NMessage(java.util.Locale.ENGLISH);
}
/**
* This constructor is used to pass the localized error message At this
* level, the locale of the caller is not known and it is not possible to
* throw localized error message at this level. Instead this constructor
* provides Resource Bundle name ,error code and LDAP Result Code ( in case
* of LDAP related exception for correctly locating the
* error message. The default <code>getMessage()</code> will always return
* English messages only. This is in consistent with current JRE.
*
* @param rbName
* Resource bundle Name to be used for getting localized error
* message.
* @param errorCode
* Key to resource bundle. You can use <code>ResourceBundle rb =
* ResourceBunde.getBundle(rbName,locale);
* String localizedStr = rb.getString(errorCode)</code>.
* @param ldapResultCode
* ldap result code
* @param args
* arguments to message. If it is not present pass the as null.
*/
public IdRepoException(String rbName, String errorCode, ResultCode ldapResultCode, Object[] args) {
this.bundleName = rbName;
this.errorCode = errorCode;
this.ldapErrCode = String.valueOf(ldapResultCode.intValue());
this.args = args;
this.message = getL10NMessage(java.util.Locale.ENGLISH);
}
/**
* This constructor is used to pass the localized error message At this
* level, the locale of the caller is not known and it is not possible to
* throw localized error message at this level. Instead this constructor
* provides Resource Bundle name and error code for correctly locating the
* error message. The default <code>getMessage()</code> will always return
* English messages only. This is in consistent with current JRE.
*
* @param rbName
* Resource bundle Name to be used for getting localized error
* message.
* @param errorCode
* Key to resource bundle. You can use <code>ResourceBundle rb =
* ResourceBunde.getBundle(rbName,locale);
* String localizedStr = rb.getString(errorCode)</code>.
* @param args
* arguments to message. If it is not present pass the as null.
*/
public IdRepoException(String rbName, String errorCode, Object[] args) {
this.bundleName = rbName;
this.errorCode = errorCode;
this.args = args;
this.message = getL10NMessage(java.util.Locale.ENGLISH);
}
/**
* Returns a localized error message
*
* @param locale
* Uses the locale object to create the appropriate localized
* error message
* @return localized error message.
* @see #IdRepoException(String, String, Object[])
*/
public String getL10NMessage(java.util.Locale locale) {
String result = errorCode;
if (bundleName != null && locale != null) {
ResourceBundle bundle = amCache.getResBundle(bundleName, locale);
String mid = Locale.getString(bundle, errorCode, debug);
if (args == null || args.length == 0) {
result = mid;
} else {
result = MessageFormat.format(mid, args);
}
}
return result;
}
/**
* Returns <code>ResourceBundle</code> Name associated with this error
* message.
*
* @return <code>ResourceBundle</code> name associated with this error
* message.
* @see #IdRepoException(String, String, Object[])
*/
public String getResourceBundleName() {
return bundleName;
}
/**
* Returns an int representation of <code>ldapErrCode</code>.
* This is to be used with ResultCode.valueOf() which will return a valid
* ResultCode object regardless of the return of this method.
*
* A null or invalid <code>ldapErrorCode</code> will return <code>-1</code>.
*
* @return an int representation of this exception's LDAP error code.
*/
public int getLdapErrorIntCode() {
try {
return Integer.valueOf(ldapErrCode);
} catch (NumberFormatException nfe) {
return -1;
}
}
/**
* Returns error code associated with this error message.
*
* @return Error code associated with this error message.
* @see #IdRepoException(String, String, Object[])
*/
public String getErrorCode() {
return errorCode;
}
/**
* Returns the LDAP error code associated with this error message.
*
* @return Error code associated with this error message and null if
* not caused by <code>LDAPException</code>.
* @see #IdRepoException(String, String, Object[])
*
* @deprecated
* Use #getLdapErrorIntCode() instead. The ldap error code is always an int
*/
@Deprecated
public String getLDAPErrorCode() {
return ldapErrCode;
}
/**
* Replace the LDAP error code associated with this error message.
*
* @see #IdRepoException(String, String, Object[])
*/
public void setLDAPErrorCode(String errorCode) {
ldapErrCode = errorCode;
}
/**
* Returns arguments for formatting this error message.
*
* @return arguments for formatting this error message. You need to use
* <code>MessageFormat</code> class to format the message It can
* be null.
* @see #IdRepoException(String, String, Object[])
*/
public Object[] getMessageArgs() {
return args;
}
public String toString() {
StringBuilder buf = new StringBuilder();
String msg = message;
if (msg != null && msg.length() > 0) {
buf.append("Message:");
buf.append(msg);
buf.append("\n");
}
return buf.toString();
}
/**
* Returns the error message of this exception.
*
* @return String representing the error message
*/
public String getMessage() {
return message;
}
/**
* If this error is an instance of a LDAP Constraint Violated Error (LDAP code 313)
* attempts to return useful information about the error that occured without
* leaking additional information about the system to the calling user.
*
* If this error is not an instance of LDAP Constraint Violated Error, the message
* of the error is returned.
*
* @return a user-facing representation of this exception.
*/
public String getConstraintViolationDetails() {
if (!IdRepoErrorCode.LDAP_EXCEPTION.equals(getErrorCode()) || args == null || args.length < 3) {
return getMessage();
}
String argMatch = (String) args[2];
if (argMatch != null) {
Matcher matcher = PATTERN.matcher(argMatch);
if (matcher.find()) {
return matcher.group(0).trim();
}
}
return "Cannot update attributes due to server's attribute constraints being violated.";
}
}