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.server;
018
019import static com.forgerock.opendj.ldap.config.ConfigMessages.*;
020
021import org.forgerock.opendj.config.DecodingException;
022import org.forgerock.util.Reject;
023
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.Collections;
027
028import org.forgerock.i18n.LocalizableMessage;
029import org.forgerock.i18n.LocalizableMessageBuilder;
030
031/**
032 * This exception is thrown when the server refuses to use or delete a managed
033 * object due to one or more constraints that cannot be satisfied.
034 */
035public class ConstraintViolationException extends DecodingException {
036
037    /**
038     * Serialization ID.
039     */
040    private static final long serialVersionUID = -4902443848460011875L;
041
042    /** The server managed object. */
043    private final ServerManagedObject<?> managedObject;
044
045    /** Gets the default message. */
046    private static LocalizableMessage getDefaultMessage(Collection<LocalizableMessage> messages) {
047        Reject.ifNull(messages);
048        Reject.ifFalse(!messages.isEmpty(), "messages should not be empty");
049
050        if (messages.size() == 1) {
051            return ERR_CONSTRAINT_VIOLATION_EXCEPTION_SINGLE.get(messages.iterator().next());
052        } else {
053            return ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL.get(getSingleMessage(messages));
054        }
055    }
056
057    /** Merge the messages into a single message. */
058    private static LocalizableMessage getSingleMessage(Collection<LocalizableMessage> messages) {
059        if (messages.size() == 1) {
060            return messages.iterator().next();
061        } else {
062            LocalizableMessageBuilder builder = new LocalizableMessageBuilder();
063
064            boolean isFirst = true;
065            for (LocalizableMessage m : messages) {
066                if (!isFirst) {
067                    builder.append(";  ");
068                }
069                builder.append(m);
070                isFirst = false;
071            }
072
073            return builder.toMessage();
074        }
075    }
076
077    /** The messages describing the constraint violations that occurred. */
078    private final Collection<LocalizableMessage> messages;
079
080    /**
081     * Creates a new constraint violation exception with the provided messages.
082     *
083     * @param managedObject
084     *            The server managed object which caused the constraint
085     *            violations.
086     * @param messages
087     *            The messages describing the constraint violations that
088     *            occurred (must be non-<code>null</code> and non-empty).
089     */
090    public ConstraintViolationException(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> messages) {
091        super(getDefaultMessage(messages));
092
093        this.managedObject = managedObject;
094        this.messages = new ArrayList<>(messages);
095    }
096
097    /**
098     * Creates a new constraint violation exception with the provided message.
099     *
100     * @param managedObject
101     *            The server managed object which caused the constraint
102     *            violations.
103     * @param message
104     *            The message describing the constraint violation that occurred.
105     */
106    public ConstraintViolationException(ServerManagedObject<?> managedObject, LocalizableMessage message) {
107        this(managedObject, Collections.singleton(message));
108    }
109
110    /**
111     * Gets an unmodifiable collection view of the messages describing the
112     * constraint violations that occurred.
113     *
114     * @return Returns an unmodifiable collection view of the messages
115     *         describing the constraint violations that occurred.
116     */
117    public Collection<LocalizableMessage> getMessages() {
118        return Collections.unmodifiableCollection(messages);
119    }
120
121    /**
122     * Creates a single message listing all the messages combined into a single
123     * list separated by semi-colons.
124     *
125     * @return Returns a single message listing all the messages combined into a
126     *         single list separated by semi-colons.
127     */
128    public LocalizableMessage getMessagesAsSingleMessage() {
129        return getSingleMessage(messages);
130    }
131
132    /**
133     * Gets the server managed object which caused the constraint violations.
134     *
135     * @return Returns the server managed object which caused the constraint
136     *         violations.
137     */
138    public ServerManagedObject<?> getManagedObject() {
139        return managedObject;
140    }
141}