001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2009-2010 Sun Microsystems, Inc.
015 * Portions copyright 2011-2015 ForgeRock AS.
016 */
017package org.forgerock.opendj.ldap;
018
019import java.io.IOException;
020
021import org.forgerock.opendj.ldap.responses.Responses;
022import org.forgerock.opendj.ldap.responses.Result;
023
024/**
025 * Thrown when the result code returned in a Result indicates that the Request
026 * was unsuccessful. This class can be sub-classed in order to implement
027 * application specific exceptions.
028 */
029@SuppressWarnings("serial")
030public class LdapException extends IOException {
031
032    /**
033     * Creates a new LDAP exception with the provided result code and an
034     * empty diagnostic message.
035     *
036     * @param resultCode
037     *            The result code.
038     * @return The new LDAP exception.
039     * @throws IllegalArgumentException
040     *             If the provided result code does not represent a failure.
041     * @throws NullPointerException
042     *             If {@code resultCode} was {@code null}.
043     */
044    public static LdapException newLdapException(ResultCode resultCode) {
045        return newLdapException(resultCode, null, null);
046    }
047
048    /**
049     * Creates a new LDAP exception with the provided result code and
050     * diagnostic message.
051     *
052     * @param resultCode
053     *            The result code.
054     * @param diagnosticMessage
055     *            The diagnostic message, which may be empty or {@code null}
056     *            indicating that none was provided.
057     * @return The new LDAP exception.
058     * @throws IllegalArgumentException
059     *             If the provided result code does not represent a failure.
060     * @throws NullPointerException
061     *             If {@code resultCode} was {@code null}.
062     */
063    public static LdapException newLdapException(ResultCode resultCode,
064            CharSequence diagnosticMessage) {
065        return newLdapException(resultCode, diagnosticMessage, null);
066    }
067
068    /**
069     * Creates a new LDAP exception with the provided result code and
070     * cause. The diagnostic message will be taken from the cause, if provided.
071     *
072     * @param resultCode
073     *            The result code.
074     * @param cause
075     *            The throwable cause, which may be {@code null} indicating that
076     *            none was provided.
077     * @return The new LDAP exception.
078     * @throws IllegalArgumentException
079     *             If the provided result code does not represent a failure.
080     * @throws NullPointerException
081     *             If {@code resultCode} was {@code null}.
082     */
083    public static LdapException newLdapException(ResultCode resultCode, Throwable cause) {
084        return newLdapException(resultCode, null, cause);
085    }
086
087    /**
088     * Creates a new LDAP exception with the provided result code,
089     * diagnostic message, and cause.
090     *
091     * @param resultCode
092     *            The result code.
093     * @param diagnosticMessage
094     *            The diagnostic message, which may be empty or {@code null}
095     *            indicating that none was provided.
096     * @param cause
097     *            The throwable cause, which may be {@code null} indicating that
098     *            none was provided.
099     * @return The new LDAP exception.
100     * @throws IllegalArgumentException
101     *             If the provided result code does not represent a failure.
102     * @throws NullPointerException
103     *             If {@code resultCode} was {@code null}.
104     */
105    public static LdapException newLdapException(ResultCode resultCode,
106            CharSequence diagnosticMessage, Throwable cause) {
107        final Result result = Responses.newResult(resultCode);
108        if (diagnosticMessage != null) {
109            result.setDiagnosticMessage(diagnosticMessage.toString());
110        } else if (cause != null) {
111            result.setDiagnosticMessage(cause.getLocalizedMessage());
112        }
113        result.setCause(cause);
114        return newLdapException(result);
115    }
116
117    /**
118     * Creates a new LDAP exception using the provided result.
119     *
120     * @param result
121     *            The result whose result code indicates a failure.
122     * @return The LDAP exception wrapping the provided result.
123     * @throws IllegalArgumentException
124     *             If the provided result does not represent a failure.
125     * @throws NullPointerException
126     *             If {@code result} was {@code null}.
127     */
128    public static LdapException newLdapException(final Result result) {
129        if (!result.getResultCode().isExceptional()) {
130            throw new IllegalArgumentException("Attempted to wrap a successful result: " + result);
131        }
132
133        switch (result.getResultCode().asEnum()) {
134        case ASSERTION_FAILED:
135            return new AssertionFailureException(result);
136        case AUTH_METHOD_NOT_SUPPORTED:
137        case CLIENT_SIDE_AUTH_UNKNOWN:
138        case INAPPROPRIATE_AUTHENTICATION:
139        case INVALID_CREDENTIALS:
140            return new AuthenticationException(result);
141        case AUTHORIZATION_DENIED:
142        case CONFIDENTIALITY_REQUIRED:
143        case INSUFFICIENT_ACCESS_RIGHTS:
144        case STRONG_AUTH_REQUIRED:
145            return new AuthorizationException(result);
146        case CLIENT_SIDE_USER_CANCELLED:
147        case CANCELLED:
148            return new CancelledResultException(result);
149        case CLIENT_SIDE_SERVER_DOWN:
150        case CLIENT_SIDE_CONNECT_ERROR:
151        case CLIENT_SIDE_DECODING_ERROR:
152        case CLIENT_SIDE_ENCODING_ERROR:
153            return new ConnectionException(result);
154        case ATTRIBUTE_OR_VALUE_EXISTS:
155        case NO_SUCH_ATTRIBUTE:
156        case CONSTRAINT_VIOLATION:
157        case ENTRY_ALREADY_EXISTS:
158        case INVALID_ATTRIBUTE_SYNTAX:
159        case INVALID_DN_SYNTAX:
160        case NAMING_VIOLATION:
161        case NOT_ALLOWED_ON_NONLEAF:
162        case NOT_ALLOWED_ON_RDN:
163        case OBJECTCLASS_MODS_PROHIBITED:
164        case OBJECTCLASS_VIOLATION:
165        case UNDEFINED_ATTRIBUTE_TYPE:
166            return new ConstraintViolationException(result);
167        case REFERRAL:
168            return new ReferralException(result);
169        case NO_SUCH_OBJECT:
170        case CLIENT_SIDE_NO_RESULTS_RETURNED:
171            return new EntryNotFoundException(result);
172        case CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED:
173            return new MultipleEntriesFoundException(result);
174        case CLIENT_SIDE_TIMEOUT:
175        case TIME_LIMIT_EXCEEDED:
176            return new TimeoutResultException(result);
177        default:
178            return new LdapException(result);
179        }
180    }
181
182    private static String getMessage(final Result result) {
183        if (result.getDiagnosticMessage() == null || result.getDiagnosticMessage().isEmpty()) {
184            return result.getResultCode().toString();
185        } else {
186            return result.getResultCode() + ": " + result.getDiagnosticMessage();
187        }
188    }
189
190    private final Result result;
191
192    /**
193     * Creates a new LDAP exception using the provided result.
194     *
195     * @param result
196     *            The error result.
197     */
198    protected LdapException(final Result result) {
199        super(getMessage(result), result.getCause());
200        this.result = result;
201    }
202
203    /**
204     * Returns the error result which caused this exception to be thrown. The
205     * type of result returned corresponds to the expected result type of the
206     * original request.
207     *
208     * @return The error result which caused this exception to be thrown.
209     */
210    public final Result getResult() {
211        return result;
212    }
213}