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 2008 Sun Microsystems, Inc.
015 * Portions Copyright 2015-2016 ForgeRock AS.
016 */
017package org.forgerock.opendj.config.client;
018
019import static com.forgerock.opendj.ldap.config.ConfigMessages.*;
020
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.Collections;
024
025import org.forgerock.i18n.LocalizableMessage;
026import org.forgerock.i18n.LocalizableMessageBuilder;
027import org.forgerock.util.Reject;
028
029/**
030 * This exception is thrown when the client or server refuses to create, delete,
031 * or modify a managed object due to one or more constraints that cannot be
032 * satisfied.
033 * <p>
034 * Operations can be rejected either by a client-side constraint violation
035 * triggered by {@link ClientConstraintHandler}, or by a server-side error.
036 * <p>
037 * For example, the Directory Server might not be able perform an operation due
038 * to some OS related problem, such as lack of disk space, or missing files.
039 */
040public class OperationRejectedException extends AdminClientException {
041
042    /**
043     * The type of operation that caused this exception.
044     */
045    public enum OperationType {
046        /**
047         * A managed object could not be created.
048         */
049        CREATE,
050
051        /**
052         * A managed object could not be deleted.
053         */
054        DELETE,
055
056        /**
057         * A managed object could not be modified.
058         */
059        MODIFY;
060    }
061
062    /**
063     * Serialization ID.
064     */
065    private static final long serialVersionUID = 8547688890613079044L;
066
067    /** Gets the default message. */
068    private static LocalizableMessage getDefaultMessage(Collection<LocalizableMessage> messages) {
069        Reject.ifNull(messages);
070        Reject.ifFalse(!messages.isEmpty(), "Messages should not be empty");
071
072        if (messages.size() == 1) {
073            return ERR_OPERATION_REJECTED_EXCEPTION_SINGLE.get(messages.iterator().next());
074        } else {
075            return ERR_OPERATION_REJECTED_EXCEPTION_PLURAL.get(getSingleMessage(messages));
076        }
077    }
078
079    /** Merge the messages into a single message. */
080    private static LocalizableMessage getSingleMessage(Collection<LocalizableMessage> messages) {
081        if (messages.size() == 1) {
082            return messages.iterator().next();
083        } else {
084            LocalizableMessageBuilder builder = new LocalizableMessageBuilder();
085
086            boolean isFirst = true;
087            for (LocalizableMessage m : messages) {
088                if (!isFirst) {
089                    builder.append(";  ");
090                }
091                builder.append(m);
092                isFirst = false;
093            }
094
095            return builder.toMessage();
096        }
097    }
098
099    /** The messages describing the constraint violations that occurred. */
100    private final Collection<LocalizableMessage> messages;
101
102    /** The type of operation that caused this exception. */
103    private final OperationType type;
104
105    /** The user friendly name of the component that caused this exception. */
106    private final LocalizableMessage ufn;
107
108    /**
109     * Creates a new operation rejected exception with a default message.
110     *
111     * @param type
112     *            The type of operation that caused this exception.
113     * @param ufn
114     *            The user friendly name of the component that caused this
115     *            exception.
116     */
117    public OperationRejectedException(OperationType type, LocalizableMessage ufn) {
118        this(type, ufn, ERR_OPERATION_REJECTED_DEFAULT.get());
119    }
120
121    /**
122     * Creates a new operation rejected exception with the provided messages.
123     *
124     * @param type
125     *            The type of operation that caused this exception.
126     * @param ufn
127     *            The user friendly name of the component that caused this
128     *            exception.
129     * @param messages
130     *            The messages describing the constraint violations that
131     *            occurred (must be non-<code>null</code> and non-empty).
132     */
133    public OperationRejectedException(OperationType type, LocalizableMessage ufn,
134        Collection<LocalizableMessage> messages) {
135        super(getDefaultMessage(messages));
136
137        this.messages = new ArrayList<>(messages);
138        this.type = type;
139        this.ufn = ufn;
140    }
141
142    /**
143     * Creates a new operation rejected exception with the provided message.
144     *
145     * @param type
146     *            The type of operation that caused this exception.
147     * @param ufn
148     *            The user friendly name of the component that caused this
149     *            exception.
150     * @param message
151     *            The message describing the constraint violation that occurred.
152     */
153    public OperationRejectedException(OperationType type, LocalizableMessage ufn, LocalizableMessage message) {
154        this(type, ufn, Collections.singleton(message));
155    }
156
157    /**
158     * Gets an unmodifiable collection view of the messages describing the
159     * constraint violations that occurred.
160     *
161     * @return Returns an unmodifiable collection view of the messages
162     *         describing the constraint violations that occurred.
163     */
164    public Collection<LocalizableMessage> getMessages() {
165        return Collections.unmodifiableCollection(messages);
166    }
167
168    /**
169     * Creates a single message listing all the messages combined into a single
170     * list separated by semi-colons.
171     *
172     * @return Returns a single message listing all the messages combined into a
173     *         single list separated by semi-colons.
174     */
175    public LocalizableMessage getMessagesAsSingleMessage() {
176        return getSingleMessage(messages);
177    }
178
179    /**
180     * Gets the type of operation that caused this exception.
181     *
182     * @return Returns the type of operation that caused this exception.
183     */
184    public OperationType getOperationType() {
185        return type;
186    }
187
188    /**
189     * Gets the user friendly name of the component that caused this exception.
190     *
191     * @return Returns the user friendly name of the component that caused this
192     *         exception.
193     */
194    public LocalizableMessage getUserFriendlyName() {
195        return ufn;
196    }
197
198}