/* * 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 legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at 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 Copyright [year] [name of copyright owner]". * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions Copyright 2015-2016 ForgeRock AS. */ package org.forgerock.opendj.config.server; import static com.forgerock.opendj.ldap.config.ConfigMessages.*; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.config.Configuration; import org.forgerock.opendj.config.Constraint; import org.forgerock.opendj.config.InstantiableRelationDefinition; import org.forgerock.opendj.config.ManagedObjectDefinition; import org.forgerock.opendj.config.ManagedObjectPath; import org.forgerock.opendj.config.OptionalRelationDefinition; import org.forgerock.opendj.config.PropertyDefinition; import org.forgerock.opendj.config.PropertyProvider; import org.forgerock.opendj.config.RelationDefinition; import org.forgerock.opendj.config.SetRelationDefinition; import org.forgerock.opendj.config.SingletonRelationDefinition; import org.forgerock.opendj.config.server.spi.ConfigAddListener; import org.forgerock.opendj.config.server.spi.ConfigChangeListener; import org.forgerock.opendj.config.server.spi.ConfigDeleteListener; import org.forgerock.opendj.config.server.spi.ConfigurationRepository; import org.forgerock.opendj.ldap.DN; import org.forgerock.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A server-side managed object. * * @param * The type of server configuration represented by the server managed * object. */ public final class ServerManagedObject implements PropertyProvider { private static final Logger logger = LoggerFactory.getLogger(ServerManagedObject.class); /** * The DN of configuration entry associated with this server managed object, * which is {@code null} for root. */ private DN configDN; private final ServerManagementContext serverContext; private final ConfigurationRepository configRepository; private final ManagedObjectDefinition definition; /** The managed object path identifying this managed object's location. */ private final ManagedObjectPath path; private final Map, SortedSet> properties; /** * Creates an new server side managed object. * * @param path * The managed object path. * @param definition * The managed object definition. * @param properties * The managed object's properties. * @param configDN * The configuration entry associated with the managed object. * @param context * The server management context. */ ServerManagedObject(final ManagedObjectPath path, final ManagedObjectDefinition definition, final Map, SortedSet> properties, final DN configDN, final ServerManagementContext context) { this.definition = definition; this.path = path; this.properties = properties; this.configDN = configDN; this.serverContext = context; this.configRepository = context.getConfigRepository(); } /** * Deregisters an existing configuration add listener. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The configuration add listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. */ public void deregisterAddListener(InstantiableRelationDefinition d, ConfigurationAddListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing server managed object add listener. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The server managed object add listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. */ public void deregisterAddListener(InstantiableRelationDefinition d, ServerManagedObjectAddListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing configuration add listener. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The configuration add listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. */ public void deregisterAddListener(OptionalRelationDefinition d, ConfigurationAddListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing server managed object add listener. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The server managed object add listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. */ public void deregisterAddListener(OptionalRelationDefinition d, ServerManagedObjectAddListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing configuration add listener. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The configuration add listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. */ public void deregisterAddListener(SetRelationDefinition d, ConfigurationAddListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing server managed object add listener. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The server managed object add listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. */ public void deregisterAddListener(SetRelationDefinition d, ServerManagedObjectAddListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing configuration change listener. * * @param listener * The configuration change listener. */ public void deregisterChangeListener(ConfigurationChangeListener listener) { for (ConfigChangeListener l : configRepository.getChangeListeners(configDN)) { if (l instanceof ConfigChangeListenerAdaptor) { ConfigChangeListenerAdaptor adaptor = (ConfigChangeListenerAdaptor) l; ServerManagedObjectChangeListener l2 = adaptor.getServerManagedObjectChangeListener(); if (l2 instanceof ServerManagedObjectChangeListenerAdaptor) { ServerManagedObjectChangeListenerAdaptor adaptor2 = (ServerManagedObjectChangeListenerAdaptor) l2; if (adaptor2.getConfigurationChangeListener() == listener) { adaptor.finalizeChangeListener(); configRepository.deregisterChangeListener(configDN, adaptor); } } } } } /** * Deregisters an existing server managed object change listener. * * @param listener * The server managed object change listener. */ public void deregisterChangeListener(ServerManagedObjectChangeListener listener) { for (ConfigChangeListener l : configRepository.getChangeListeners(configDN)) { if (l instanceof ConfigChangeListenerAdaptor) { ConfigChangeListenerAdaptor adaptor = (ConfigChangeListenerAdaptor) l; if (adaptor.getServerManagedObjectChangeListener() == listener) { adaptor.finalizeChangeListener(); configRepository.deregisterChangeListener(configDN, adaptor); } } } } /** * Deregisters an existing configuration delete listener. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The configuration delete listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. */ public void deregisterDeleteListener(InstantiableRelationDefinition d, ConfigurationDeleteListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The server managed object delete listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. */ public void deregisterDeleteListener(InstantiableRelationDefinition d, ServerManagedObjectDeleteListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing configuration delete listener. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The configuration delete listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. */ public void deregisterDeleteListener(OptionalRelationDefinition d, ConfigurationDeleteListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The server managed object delete listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. */ public void deregisterDeleteListener(OptionalRelationDefinition d, ServerManagedObjectDeleteListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing configuration delete listener. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The configuration delete listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. */ public void deregisterDeleteListener(SetRelationDefinition d, ConfigurationDeleteListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The server managed object delete listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. */ public void deregisterDeleteListener(SetRelationDefinition d, ServerManagedObjectDeleteListener listener) { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Retrieve an instantiable child managed object. * * @param * The requested type of the child server managed object * configuration. * @param d * The instantiable relation definition. * @param name * The name of the child managed object. * @return Returns the instantiable child managed object. * @throws IllegalArgumentException * If the relation definition is not associated with this * managed object's definition. * @throws ConfigException * If the child managed object could not be found or if it could * not be decoded. */ public ServerManagedObject getChild(InstantiableRelationDefinition d, String name) throws ConfigException { validateRelationDefinition(d); return serverContext.getManagedObject(path.child(d, name)); } /** * Retrieve an optional child managed object. * * @param * The requested type of the child server managed object * configuration. * @param d * The optional relation definition. * @return Returns the optional child managed object. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. * @throws ConfigException * If the child managed object could not be found or if it could * not be decoded. */ public ServerManagedObject getChild(OptionalRelationDefinition d) throws ConfigException { validateRelationDefinition(d); return serverContext.getManagedObject(path.child(d)); } /** * Retrieve a set child managed object. * * @param * The requested type of the child server managed object * configuration. * @param d * The set relation definition. * @param name * The name of the child managed object. * @return Returns the set child managed object. * @throws IllegalArgumentException * If the relation definition is not associated with this * managed object's definition or if {@code name} specifies a * managed object definition which is not a sub-type of the * relation's child definition. * @throws ConfigException * If the child managed object could not be found or if it could * not be decoded. */ public ServerManagedObject getChild(SetRelationDefinition d, String name) throws ConfigException { validateRelationDefinition(d); return serverContext.getManagedObject(path.child(d, name)); } /** * Retrieve a singleton child managed object. * * @param * The requested type of the child server managed object * configuration. * @param d * The singleton relation definition. * @return Returns the singleton child managed object. * @throws IllegalArgumentException * If the relation definition is not associated with this * managed object's definition. * @throws ConfigException * If the child managed object could not be found or if it could * not be decoded. */ public ServerManagedObject getChild(SingletonRelationDefinition d) throws ConfigException { validateRelationDefinition(d); return serverContext.getManagedObject(path.child(d)); } /** * Returns the server management context used by this object. * * @return the context */ public ServerManagementContext getServerContext() { return serverContext; } /** * Creates a server configuration view of this managed object. * * @return Returns the server configuration view of this managed object. */ public S getConfiguration() { return definition.createServerConfiguration(this); } /** * Get the DN of the LDAP entry associated with this server managed object. * * @return Returns the DN of the LDAP entry associated with this server * managed object, or an null DN if this is the root managed object. */ public DN getDN() { if (configDN != null) { return configDN; } return DN.rootDN(); } /** * Get the definition associated with this server managed object. * * @return Returns the definition associated with this server managed * object. */ public ManagedObjectDefinition getManagedObjectDefinition() { return definition; } /** * Get the path of this server managed object. * * @return Returns the path of this server managed object. */ public ManagedObjectPath getManagedObjectPath() { return path; } /** * Get the effective value of the specified property. If the property is * multi-valued then just the first value is returned. If the property does * not have a value then its default value is returned if it has one, or * null indicating that any default behavior is applicable. * * @param * The type of the property to be retrieved. * @param d * The property to be retrieved. * @return Returns the property's effective value, or null * indicating that any default behavior is applicable. * @throws IllegalArgumentException * If the property definition is not associated with this * managed object's definition. */ public T getPropertyValue(PropertyDefinition d) { Set values = getPropertyValues(d); if (!values.isEmpty()) { return values.iterator().next(); } return null; } /** * Get the effective values of the specified property. If the property does * not have any values then its default values are returned if it has any, * or an empty set indicating that any default behavior is applicable. * * @param * The type of the property to be retrieved. * @param d * The property to be retrieved. * @return Returns an unmodifiable set containing the property's effective * values. An empty set indicates that the property has no default * values defined and any default behavior is applicable. * @throws IllegalArgumentException * If the property definition is not associated with this * managed object's definition. */ @Override @SuppressWarnings("unchecked") public SortedSet getPropertyValues(PropertyDefinition d) { if (!properties.containsKey(d)) { throw new IllegalArgumentException("Unknown property " + d.getName()); } return Collections.unmodifiableSortedSet((SortedSet) properties.get(d)); } /** * Determines whether or not the optional managed object associated with the * specified optional relations exists. * * @param d * The optional relation definition. * @return Returns true if the optional managed object exists, * false otherwise. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. */ public boolean hasChild(OptionalRelationDefinition d) { validateRelationDefinition(d); return serverContext.managedObjectExists(path.child(d)); } /** * Lists the child managed objects associated with the specified * instantiable relation. * * @param d * The instantiable relation definition. * @return Returns the names of the child managed objects. * @throws IllegalArgumentException * If the relation definition is not associated with this * managed object's definition. */ public String[] listChildren(InstantiableRelationDefinition d) { validateRelationDefinition(d); return serverContext.listManagedObjects(path, d); } /** * Lists the child managed objects associated with the specified set * relation. * * @param d * The set relation definition. * @return Returns the names of the child managed objects. * @throws IllegalArgumentException * If the relation definition is not associated with this * managed object's definition. */ public String[] listChildren(SetRelationDefinition d) { validateRelationDefinition(d); return serverContext.listManagedObjects(path, d); } /** * Register to be notified when new child configurations are added beneath * an instantiable relation. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The configuration add listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. * @throws ConfigException * If the configuration entry associated with the instantiable * relation could not be retrieved. */ public void registerAddListener(InstantiableRelationDefinition d, ConfigurationAddListener listener) throws ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor(listener)); } /** * Register to be notified when new child server managed object are added * beneath an instantiable relation. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The server managed object add listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. * @throws ConfigException * If the configuration entry associated with the instantiable * relation could not be retrieved. */ public void registerAddListener(InstantiableRelationDefinition d, ServerManagedObjectAddListener listener) throws ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<>(serverContext, path, d, listener); registerAddListener(baseDN, adaptor); } /** * Register to be notified when a new child configurations is added beneath * an optional relation. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The configuration add listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. * @throws ConfigException * If the configuration entry associated with the optional * relation could not be retrieved. */ public void registerAddListener(OptionalRelationDefinition d, ConfigurationAddListener listener) throws ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor(listener)); } /** * Register to be notified when a new child server managed object is added * beneath an optional relation. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The server managed object add listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. * @throws ConfigException * If the configuration entry associated with the optional * relation could not be retrieved. */ public void registerAddListener(OptionalRelationDefinition d, ServerManagedObjectAddListener listener) throws ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<>(serverContext, path, d, listener); registerAddListener(baseDN, adaptor); } /** * Register to be notified when new child configurations are added beneath a * set relation. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The configuration add listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. * @throws ConfigException * If the configuration entry associated with the set relation * could not be retrieved. */ public void registerAddListener(SetRelationDefinition d, ConfigurationAddListener listener) throws ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor(listener)); } /** * Register to be notified when new child server managed object are added * beneath a set relation. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The server managed object add listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. * @throws ConfigException * If the configuration entry associated with the set relation * could not be retrieved. */ public void registerAddListener(SetRelationDefinition d, ServerManagedObjectAddListener listener) throws ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<>(serverContext, path, d, listener); registerAddListener(baseDN, adaptor); } /** * Register to be notified when this server managed object is changed. * * @param listener * The configuration change listener. */ public void registerChangeListener(ConfigurationChangeListener listener) { registerChangeListener(new ServerManagedObjectChangeListenerAdaptor(listener)); } /** * Register to be notified when this server managed object is changed. * * @param listener * The server managed object change listener. */ public void registerChangeListener(ServerManagedObjectChangeListener listener) { ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<>(serverContext, path, listener); configRepository.registerChangeListener(configDN, adaptor); // TODO : go toward this // Entry entry; // configBackend.registerChangeListener(entry.getName(), adapter)); // Change listener registration usually signifies that a managed // object has been accepted and added to the server configuration // during initialization post-add. // FIXME: we should prevent multiple invocations in the case where // multiple change listeners are registered for the same object. for (Constraint constraint : definition.getAllConstraints()) { for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) { try { handler.performPostAdd(this); } catch (ConfigException e) { logger.trace("Unable to perform post add", e); } } } } /** * Register to be notified when existing child configurations are deleted * beneath an instantiable relation. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The configuration delete listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. * @throws ConfigException * If the configuration entry associated with the instantiable * relation could not be retrieved. */ public void registerDeleteListener(InstantiableRelationDefinition d, ConfigurationDeleteListener listener) throws ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor(listener)); } /** * Register to be notified when existing child server managed objects are * deleted beneath an instantiable relation. * * @param * The type of the child server configuration object. * @param d * The instantiable relation definition. * @param listener * The server managed objects delete listener. * @throws IllegalArgumentException * If the instantiable relation definition is not associated * with this managed object's definition. * @throws ConfigException * If the configuration entry associated with the instantiable * relation could not be retrieved. */ public void registerDeleteListener(InstantiableRelationDefinition d, ServerManagedObjectDeleteListener listener) throws ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<>(serverContext, path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * Register to be notified when an existing child configuration is deleted * beneath an optional relation. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The configuration delete listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. * @throws ConfigException * If the configuration entry associated with the optional * relation could not be retrieved. */ public void registerDeleteListener(OptionalRelationDefinition d, ConfigurationDeleteListener listener) throws ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor(listener)); } /** * Register to be notified when an existing child server managed object is * deleted beneath an optional relation. * * @param * The type of the child server configuration object. * @param d * The optional relation definition. * @param listener * The server managed object delete listener. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. * @throws ConfigException * If the configuration entry associated with the optional * relation could not be retrieved. */ public void registerDeleteListener(OptionalRelationDefinition d, ServerManagedObjectDeleteListener listener) throws ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<>(serverContext, path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * Register to be notified when existing child configurations are deleted * beneath a set relation. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The configuration delete listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. * @throws ConfigException * If the configuration entry associated with the set relation * could not be retrieved. */ public void registerDeleteListener(SetRelationDefinition d, ConfigurationDeleteListener listener) throws ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor(listener)); } /** * Register to be notified when existing child server managed objects are * deleted beneath a set relation. * * @param * The type of the child server configuration object. * @param d * The set relation definition. * @param listener * The server managed objects delete listener. * @throws IllegalArgumentException * If the set relation definition is not associated with this * managed object's definition. * @throws ConfigException * If the configuration entry associated with the set relation * could not be retrieved. */ public void registerDeleteListener(SetRelationDefinition d, ServerManagedObjectDeleteListener listener) throws ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<>(serverContext, path, d, listener); registerDeleteListener(baseDN, adaptor); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("{ TYPE="); builder.append(definition.getName()); builder.append(", DN=\""); builder.append(getDN()); builder.append('\"'); for (Map.Entry, SortedSet> value : properties.entrySet()) { builder.append(", "); builder.append(value.getKey().getName()); builder.append('='); builder.append(value.getValue()); } builder.append(" }"); return builder.toString(); } /** * Determines whether or not this managed object can be used by the server. * * @throws ConstraintViolationException * If one or more constraints determined that this managed * object cannot be used by the server. */ void ensureIsUsable() throws ConstraintViolationException { // Enforce any constraints. boolean isUsable = true; List reasons = new LinkedList<>(); for (Constraint constraint : definition.getAllConstraints()) { for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) { try { if (!handler.isUsable(this, reasons)) { isUsable = false; } } catch (ConfigException e) { LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e.getMessageObject()); reasons.add(message); isUsable = false; } } } if (!isUsable) { throw new ConstraintViolationException(this, reasons); } } /** * Update the config DN associated with this server managed object. This * is only intended to be used by change listener call backs in order to * update the managed object with the correct config DN. * * @param configDN * The DN of the underlying configuration entry. */ void setConfigDN(DN configDN) { this.configDN = configDN; } /** Deregister an add listener. */ private void deregisterAddListener(DN baseDN, ConfigurationAddListener listener) { try { if (configRepository.hasEntry(baseDN)) { for (ConfigAddListener configListener : configRepository.getAddListeners(baseDN)) { if (configListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor adaptor = (ConfigAddListenerAdaptor) configListener; ServerManagedObjectAddListener smoListener = adaptor.getServerManagedObjectAddListener(); if (smoListener instanceof ServerManagedObjectAddListenerAdaptor) { ServerManagedObjectAddListenerAdaptor adaptor2 = (ServerManagedObjectAddListenerAdaptor) smoListener; if (adaptor2.getConfigurationAddListener() == listener) { configRepository.deregisterAddListener(baseDN, adaptor); } } } } } else { // The relation entry does not exist so check for and deregister // delayed add listener. deregisterDelayedAddListener(baseDN, listener); } } catch (ConfigException e) { // Ignore the exception since this implies deregistration. logger.trace("Unable to deregister add listener", e); } } /** Deregister an add listener. */ private void deregisterAddListener(DN baseDN, ServerManagedObjectAddListener listener) { try { if (configRepository.hasEntry(baseDN)) { for (ConfigAddListener configListener : configRepository.getAddListeners(baseDN)) { if (configListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor adaptor = (ConfigAddListenerAdaptor) configListener; if (adaptor.getServerManagedObjectAddListener() == listener) { configRepository.deregisterAddListener(baseDN, adaptor); } } } } else { // The relation entry does not exist so check for and deregister // delayed add listener. deregisterDelayedAddListener(baseDN, listener); } } catch (ConfigException e) { // Ignore the exception since this implies deregistration. logger.trace("Unable to deregister add listener", e); } } /** * Convenience method to retrieve the initial listener and its intermediate * adaptor from the provided configListener. * * @param * Type of the configuration. * @param configListener * Listener from wich to extract the initial listener. * @return a pair of (intermediate adaptor, intermediate listener) or * {@code Pair.EMPTY} if listener can't be extracted */ // @Checkstyle:off static Pair, ConfigurationAddListener> extractInitialListener(ConfigAddListener configListener) { // @Checkstyle:on Pair, ServerManagedObjectAddListener> pair = extractIntermediateListener(configListener); if (!pair.equals(Pair.EMPTY) && pair.getSecond() instanceof ServerManagedObjectAddListenerAdaptor) { ServerManagedObjectAddListenerAdaptor adaptor2 = (ServerManagedObjectAddListenerAdaptor) pair.getSecond(); return Pair.of(pair.getFirst(), adaptor2.getConfigurationAddListener()); } return Pair.empty(); } /** * Convenience method to retrieve the intermediate listener and its * intermediate adaptor from the provided configListener. * * @param * Type of the configuration. * @param configListener * Listener from wich to extract the initial listener. * @return a pair of (intermediate adaptor, initial listener) or * {@code Pair.EMPTY} if listener can't be extracted */ @SuppressWarnings("unchecked") // @Checkstyle:off static Pair, ServerManagedObjectAddListener> extractIntermediateListener(ConfigAddListener configListener) { // @Checkstyle:on if (configListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor adaptor = (ConfigAddListenerAdaptor) configListener; return Pair.of(adaptor, adaptor.getServerManagedObjectAddListener()); } return Pair.empty(); } /** Deregister a delete listener. */ private void deregisterDeleteListener(DN baseDN, ConfigurationDeleteListener listener) { try { if (configRepository.hasEntry(baseDN)) { for (ConfigDeleteListener l : configRepository.getDeleteListeners(baseDN)) { if (l instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor adaptor = (ConfigDeleteListenerAdaptor) l; ServerManagedObjectDeleteListener l2 = adaptor.getServerManagedObjectDeleteListener(); if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor) { ServerManagedObjectDeleteListenerAdaptor adaptor2 = (ServerManagedObjectDeleteListenerAdaptor) l2; if (adaptor2.getConfigurationDeleteListener() == listener) { configRepository.deregisterDeleteListener(baseDN, adaptor); } } } } } else { // The relation entry does not exist so check for and deregister // delayed add listener. deregisterDelayedDeleteListener(baseDN, listener); } } catch (ConfigException e) { // Ignore the exception since this implies deregistration. logger.trace("Unable to deregister delete listener", e); } } /** Deregister a delete listener. */ private void deregisterDeleteListener(DN baseDN, ServerManagedObjectDeleteListener listener) { try { if (configRepository.hasEntry(baseDN)) { for (ConfigDeleteListener l : configRepository.getDeleteListeners(baseDN)) { if (l instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor adaptor = (ConfigDeleteListenerAdaptor) l; if (adaptor.getServerManagedObjectDeleteListener() == listener) { configRepository.deregisterDeleteListener(baseDN, adaptor); } } } } else { // The relation entry does not exist so check for and deregister // delayed add listener. deregisterDelayedDeleteListener(baseDN, listener); } } catch (ConfigException e) { // Ignore the exception since this implies deregistration. logger.trace("Unable to deregister delete listener", e); } } /** Register an instantiable or optional relation add listener. */ private void registerAddListener(DN baseDN, ConfigAddListener adaptor) throws ConfigException { if (configRepository.hasEntry(baseDN)) { configRepository.registerAddListener(baseDN, adaptor); } else { // The relation entry does not exist yet // so register a delayed add listener. ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor, configRepository); registerDelayedListener(baseDN, delayedListener); } } /** Register a delayed listener with the nearest existing parent entry to the provided base DN. */ private void registerDelayedListener(DN baseDN, ConfigAddListener delayedListener) throws ConfigException { DN currentDN = baseDN.parent(); DN previousDN = currentDN; while (currentDN != null) { if (!configRepository.hasEntry(currentDN)) { delayedListener = new DelayedConfigAddListener(currentDN, delayedListener, configRepository); previousDN = currentDN; currentDN = currentDN.parent(); } else { configRepository.registerAddListener(previousDN, delayedListener); return; } } // No parent entry could be found. LocalizableMessage message = ERR_ADMIN_UNABLE_TO_REGISTER_LISTENER.get(String.valueOf(baseDN)); throw new ConfigException(message); } /** * Deregister a delayed listener with the nearest existing parent * entry to the provided base DN. */ private void deregisterDelayedAddListener(DN baseDN, ConfigurationAddListener listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { if (!configRepository.hasEntry(parentDN)) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) { if (configListener instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener instanceof DelayedConfigAddListener) { delayListener = (DelayedConfigAddListener) configListener; } else { break; } } if (i > 0) { // There are not enough level of wrapping // so this can't be the listener we are looking for. continue; } ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); if (delayedListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor adaptor = (ConfigAddListenerAdaptor) delayedListener; ServerManagedObjectAddListener l2 = adaptor.getServerManagedObjectAddListener(); if (l2 instanceof ServerManagedObjectAddListenerAdaptor) { ServerManagedObjectAddListenerAdaptor adaptor2 = (ServerManagedObjectAddListenerAdaptor) l2; if (adaptor2.getConfigurationAddListener() == listener) { configRepository.deregisterAddListener(parentDN, configListener); } } } } } return; } } } /** * Deregister a delayed listener with the nearest existing parent * entry to the provided base DN. */ private void deregisterDelayedDeleteListener(DN baseDN, ConfigurationDeleteListener listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { if (!configRepository.hasEntry(parentDN)) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener l : configRepository.getAddListeners(parentDN)) { if (l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener instanceof DelayedConfigAddListener) { delayListener = (DelayedConfigAddListener) l; } else { break; } } if (i > 0) { // There are not enough level of wrapping // so this can't be the listener we are looking for. continue; } ConfigDeleteListener delayedListener = delayListener.getDelayedDeleteListener(); if (delayedListener instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor adaptor = (ConfigDeleteListenerAdaptor) delayedListener; ServerManagedObjectDeleteListener l2 = adaptor.getServerManagedObjectDeleteListener(); if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor) { ServerManagedObjectDeleteListenerAdaptor adaptor2 = (ServerManagedObjectDeleteListenerAdaptor) l2; if (adaptor2.getConfigurationDeleteListener() == listener) { configRepository.deregisterAddListener(parentDN, l); } } } } } return; } } } /** * Deregister a delayed listener with the nearest existing parent * entry to the provided base DN. */ private void deregisterDelayedAddListener(DN baseDN, ServerManagedObjectAddListener listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { if (!configRepository.hasEntry(parentDN)) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) { if (configListener instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener instanceof DelayedConfigAddListener) { delayListener = (DelayedConfigAddListener) configListener; } else { break; } } if (i > 0) { // There are not enough level of wrapping // so this can't be the listener we are looking for. continue; } ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); if (delayedListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor adaptor = (ConfigAddListenerAdaptor) delayedListener; if (adaptor.getServerManagedObjectAddListener() == listener) { configRepository.deregisterAddListener(parentDN, configListener); } } } } return; } } } /** * Deregister a delayed listener with the nearest existing parent * entry to the provided base DN. */ private void deregisterDelayedDeleteListener(DN baseDN, ServerManagedObjectDeleteListener listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { if (!configRepository.hasEntry(parentDN)) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) { if (configListener instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener instanceof DelayedConfigAddListener) { delayListener = (DelayedConfigAddListener) configListener; } else { break; } } if (i > 0) { // There are not enough level of wrapping // so this can't be the listener we are looking for. continue; } ConfigDeleteListener delayedListener = delayListener.getDelayedDeleteListener(); if (delayedListener instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor adaptor = (ConfigDeleteListenerAdaptor) delayedListener; if (adaptor.getServerManagedObjectDeleteListener() == listener) { configRepository.deregisterAddListener(parentDN, configListener); } } } } return; } } } /** Register an instantiable or optional relation delete listener. */ private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor) throws ConfigException { if (configRepository.hasEntry(baseDN)) { configRepository.registerDeleteListener(baseDN, adaptor); } else { // The relation entry does not exist yet // so register a delayed add listener. ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor, configRepository); registerDelayedListener(baseDN, delayedListener); } } /** Validate that a relation definition belongs to this managed object. */ private void validateRelationDefinition(RelationDefinition rd) { RelationDefinition tmp = definition.getRelationDefinition(rd.getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + definition.getName()); } } }