opendj-admin/pom.xml
@@ -32,6 +32,10 @@ <artifactId>i18n-core</artifactId> </dependency> <dependency> <groupId>org.forgerock.commons</groupId> <artifactId>i18n-slf4j</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> @@ -423,60 +427,6 @@ </plugin> </plugins> <pluginManagement> <plugins> <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. --> <plugin> <groupId>org.eclipse.m2e</groupId> <artifactId>lifecycle-mapping</artifactId> <version>1.0.0</version> <configuration> <lifecycleMappingMetadata> <pluginExecutions> <pluginExecution> <pluginExecutionFilter> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <versionRange>[1.8,)</versionRange> <goals> <goal>parse-version</goal> </goals> </pluginExecutionFilter> <action> <ignore></ignore> </action> </pluginExecution> <pluginExecution> <pluginExecutionFilter> <groupId>org.codehaus.mojo</groupId> <artifactId>templating-maven-plugin</artifactId> <versionRange>[1.0-alpha-3,)</versionRange> <goals> <goal>filter-sources</goal> </goals> </pluginExecutionFilter> <action> <ignore></ignore> </action> </pluginExecution> <pluginExecution> <pluginExecutionFilter> <groupId>org.codehaus.mojo</groupId> <artifactId>xml-maven-plugin</artifactId> <versionRange>[1.0,)</versionRange> <goals> <goal>transform</goal> </goals> </pluginExecutionFilter> <action> <ignore></ignore> </action> </pluginExecution> </pluginExecutions> </lifecycleMappingMetadata> </configuration> </plugin> </plugins> </pluginManagement> </build> <reporting> opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java
@@ -150,7 +150,7 @@ ManagedObjectDefinitionI18NResource resource = ManagedObjectDefinitionI18NResource.getInstance(); String property = "property." + propertyName + ".requires-admin-action.synopsis"; try { return resource.getLocalizableMessage(definition, property, locale); return resource.getMessage(definition, property, locale); } catch (MissingResourceException e) { return null; } opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -28,8 +28,6 @@ import static org.opends.server.loggers.debug.DebugLogger.*; import java.util.LinkedList; import java.util.List; @@ -46,14 +44,12 @@ import org.opends.server.admin.SetRelationDefinition; import org.opends.server.admin.DefinitionDecodingException.Reason; import org.opends.server.api.ConfigAddListener; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.AttributeValue; import org.opends.server.types.ConfigChangeResult; import org.forgerock.opendj.ldap.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.ResultCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.forgerock.opendj.ldap.ResultCode; @@ -68,10 +64,7 @@ final class ConfigAddListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements ConfigAddListener { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); private static final Logger debugLogger = LoggerFactory.getLogger(ConfigAddListenerAdaptor.class); // Cached managed object between accept/apply callbacks. private ServerManagedObject<? extends S> cachedManagedObject; @@ -196,9 +189,7 @@ try { handler.performPostAdd(cachedManagedObject); } catch (ConfigException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } debugLogger.trace("Unable to perform post add", e); } } } @@ -257,7 +248,7 @@ } // Let the add listener decide. List<LocalizableMessage> reasons = new LinkedList<Message>(); List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>(); if (listener.isConfigurationAddAcceptable(cachedManagedObject, reasons)) { return true; } else { opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
@@ -26,9 +26,7 @@ */ package org.opends.server.admin.server; import static org.opends.server.loggers.debug.DebugLogger.*; import static com.forgerock.opendj.ldap.AdminMessages.*; import java.util.Collection; import java.util.HashSet; @@ -36,9 +34,12 @@ import java.util.List; import java.util.Set; import org.opends.messages.AdminMessages; import com.forgerock.opendj.ldap.AdminMessages; import com.forgerock.opendj.util.StaticUtils; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider; import org.opends.server.admin.AbstractManagedObjectDefinition; import org.opends.server.admin.AliasDefaultBehaviorProvider; @@ -55,438 +56,367 @@ import org.opends.server.admin.UndefinedDefaultBehaviorProvider; import org.opends.server.api.ConfigChangeListener; import org.opends.server.api.ConfigDeleteListener; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.loggers.ErrorLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.ConfigChangeResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.forgerock.opendj.ldap.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.ResultCode; import org.opends.server.util.StaticUtils; import org.forgerock.opendj.ldap.ResultCode; /** * An adaptor class which converts {@link ConfigChangeListener} * call-backs to {@link ServerManagedObjectChangeListener} * call-backs. * An adaptor class which converts {@link ConfigChangeListener} call-backs to * {@link ServerManagedObjectChangeListener} call-backs. * * @param <S> * The type of server configuration handled by the change * listener. * The type of server configuration handled by the change listener. */ final class ConfigChangeListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements ConfigChangeListener { final class ConfigChangeListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements ConfigChangeListener { /** * A default behavior visitor used for determining the set of * dependencies. * * @param <T> * The type of property. */ private static final class Visitor<T> implements DefaultBehaviorProviderVisitor<T, Void, ManagedObjectPath<?, ?>> { private static final Logger debugLogger = LoggerFactory.getLogger(ConfigChangeListenerAdaptor.class); private static final LocalizedLogger adminLogger = LocalizedLogger.getLocalizedLogger( ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST.get("").resourceName()); /** * Finds the dependencies associated with the provided property * definition. * A default behavior visitor used for determining the set of dependencies. * * @param <T> * @param path * The current base path used for relative name * resolution. * @param pd * The property definition. * @param dependencies * Add dependencies names to this collection. * The type of property. */ public static <T> void find(ManagedObjectPath<?, ?> path, PropertyDefinition<T> pd, Collection<DN> dependencies) { Visitor<T> v = new Visitor<T>(dependencies); DefaultBehaviorProvider<T> db = pd.getDefaultBehaviorProvider(); db.accept(v, path); private static final class Visitor<T> implements DefaultBehaviorProviderVisitor<T, Void, ManagedObjectPath<?, ?>> { /** * Finds the dependencies associated with the provided property * definition. * * @param <T> * @param path * The current base path used for relative name resolution. * @param pd * The property definition. * @param dependencies * Add dependencies names to this collection. */ public static <T> void find(ManagedObjectPath<?, ?> path, PropertyDefinition<T> pd, Collection<DN> dependencies) { Visitor<T> v = new Visitor<T>(dependencies); DefaultBehaviorProvider<T> db = pd.getDefaultBehaviorProvider(); db.accept(v, path); } // The names of entries that this change listener depends on. private final Collection<DN> dependencies; // Prevent instantiation. private Visitor(Collection<DN> dependencies) { this.dependencies = dependencies; } /** * {@inheritDoc} */ public Void visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { ManagedObjectPath<?, ?> next = d.getManagedObjectPath(); dependencies.add(DNBuilder.create(next)); // If the dependent property uses inherited defaults then // recursively get those as well. String propertyName = d.getPropertyName(); AbstractManagedObjectDefinition<?, ?> mod = d.getManagedObjectDefinition(); PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName); find(next, pd, dependencies); return null; } /** * {@inheritDoc} */ public Void visitAlias(AliasDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { return null; } /** * {@inheritDoc} */ public Void visitDefined(DefinedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { return null; } /** * {@inheritDoc} */ public Void visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { ManagedObjectPath<?, ?> next = d.getManagedObjectPath(p); dependencies.add(DNBuilder.create(next)); // If the dependent property uses inherited defaults then // recursively get those as well. String propertyName = d.getPropertyName(); AbstractManagedObjectDefinition<?, ?> mod = d.getManagedObjectDefinition(); PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName); find(next, pd, dependencies); return null; } /** * {@inheritDoc} */ public Void visitUndefined(UndefinedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { return null; } } // Cached managed object between accept/apply call-backs. private ServerManagedObject<? extends S> cachedManagedObject; // The delete listener which is used to remove this listener and any // dependencies. private final ConfigDeleteListener cleanerListener; // The names of entries that this change listener depends on. private final Collection<DN> dependencies; private final Set<DN> dependencies; // The listener used to notify this listener when dependency entries // are modified. private final ConfigChangeListener dependencyListener; // The DN associated with this listener. private final DN dn; // Prevent instantiation. private Visitor(Collection<DN> dependencies) { this.dependencies = dependencies; } // The underlying change listener. private final ServerManagedObjectChangeListener<? super S> listener; // The managed object path. private final ManagedObjectPath<?, S> path; /** * {@inheritDoc} * Create a new configuration change listener adaptor. * * @param path * The managed object path. * @param listener * The underlying change listener. */ public Void visitAbsoluteInherited( AbsoluteInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { ManagedObjectPath<?, ?> next = d.getManagedObjectPath(); dependencies.add(DNBuilder.create(next)); public ConfigChangeListenerAdaptor(ManagedObjectPath<?, S> path, ServerManagedObjectChangeListener<? super S> listener) { this.path = path; this.dn = DNBuilder.create(path); this.listener = listener; this.cachedManagedObject = null; // If the dependent property uses inherited defaults then // recursively get those as well. String propertyName = d.getPropertyName(); AbstractManagedObjectDefinition<?, ?> mod = d .getManagedObjectDefinition(); PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName); find(next, pd, dependencies); // This change listener should be notified when dependent entries // are modified. Determine the dependencies and register change // listeners against them. this.dependencies = new HashSet<DN>(); this.dependencyListener = new ConfigChangeListener() { return null; } /** * {@inheritDoc} */ public Void visitAlias(AliasDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { return null; } /** * {@inheritDoc} */ public Void visitDefined(DefinedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { return null; } /** * {@inheritDoc} */ public Void visitRelativeInherited( RelativeInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { ManagedObjectPath<?, ?> next = d.getManagedObjectPath(p); dependencies.add(DNBuilder.create(next)); // If the dependent property uses inherited defaults then // recursively get those as well. String propertyName = d.getPropertyName(); AbstractManagedObjectDefinition<?, ?> mod = d .getManagedObjectDefinition(); PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName); find(next, pd, dependencies); return null; } /** * {@inheritDoc} */ public Void visitUndefined(UndefinedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) { return null; } } /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // Cached managed object between accept/apply call-backs. private ServerManagedObject<? extends S> cachedManagedObject; // The delete listener which is used to remove this listener and any // dependencies. private final ConfigDeleteListener cleanerListener; // The names of entries that this change listener depends on. private final Set<DN> dependencies; // The listener used to notify this listener when dependency entries // are modified. private final ConfigChangeListener dependencyListener; // The DN associated with this listener. private final DN dn; // The underlying change listener. private final ServerManagedObjectChangeListener<? super S> listener; // The managed object path. private final ManagedObjectPath<?, S> path; /** * Create a new configuration change listener adaptor. * * @param path * The managed object path. * @param listener * The underlying change listener. */ public ConfigChangeListenerAdaptor(ManagedObjectPath<?, S> path, ServerManagedObjectChangeListener<? super S> listener) { this.path = path; this.dn = DNBuilder.create(path); this.listener = listener; this.cachedManagedObject = null; // This change listener should be notified when dependent entries // are modified. Determine the dependencies and register change // listeners against them. this.dependencies = new HashSet<DN>(); this.dependencyListener = new ConfigChangeListener() { public ConfigChangeResult applyConfigurationChange( ConfigEntry configEntry) { ConfigEntry dependentConfigEntry = getConfigEntry(dn); if (dependentConfigEntry != null) { return ConfigChangeListenerAdaptor.this .applyConfigurationChange(dependentConfigEntry); } else { // The dependent entry was not found. configEntry.deregisterChangeListener(this); return new ConfigChangeResult(ResultCode.SUCCESS, false); } } public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { ConfigEntry dependentConfigEntry = getConfigEntry(dn); if (dependentConfigEntry != null) { return ConfigChangeListenerAdaptor.this.configChangeIsAcceptable( dependentConfigEntry, unacceptableReason, configEntry); } else { // The dependent entry was not found. configEntry.deregisterChangeListener(this); return true; } } }; AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition(); for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) { Visitor.find(path, pd, dependencies); } for (DN entryDN : dependencies) { // Be careful not to register listeners against the dependent // entry itself. if (!entryDN.equals(dn)) { ConfigEntry configEntry = getConfigEntry(entryDN); if (configEntry != null) { configEntry.registerChangeListener(dependencyListener); } } } // Register a delete listener against the parent which will // finalize this change listener when the monitored configuration // entry is removed. this.cleanerListener = new ConfigDeleteListener() { public ConfigChangeResult applyConfigurationDelete( ConfigEntry configEntry) { // Perform finalization if the deleted entry is the monitored // entry. if (configEntry.getDN().equals(dn)) { finalizeChangeListener(); } return new ConfigChangeResult(ResultCode.SUCCESS, false); } public boolean configDeleteIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { // Always acceptable. return true; } }; DN parent = dn.getParent(); if (parent != null) { ConfigEntry configEntry = getConfigEntry(dn.getParent()); if (configEntry != null) { configEntry.registerDeleteListener(cleanerListener); } } } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) { // Looking at the ConfigFileHandler implementation reveals // that this ConfigEntry will actually be a different object to // the one passed in the previous call-back (it will have the same // content though). This configuration entry has the correct // listener lists. cachedManagedObject.setConfigEntry(configEntry); ConfigChangeResult result = listener .applyConfigurationChange(cachedManagedObject); // Now apply post constraint call-backs. if (result.getResultCode() == ResultCode.SUCCESS) { ManagedObjectDefinition<?, ?> d = cachedManagedObject .getManagedObjectDefinition(); for (Constraint constraint : d.getAllConstraints()) { for (ServerConstraintHandler handler : constraint .getServerConstraintHandlers()) { try { handler.performPostModify(cachedManagedObject); } catch (ConfigException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) { ConfigEntry dependentConfigEntry = getConfigEntry(dn); if (dependentConfigEntry != null) { return ConfigChangeListenerAdaptor.this.applyConfigurationChange(dependentConfigEntry); } else { // The dependent entry was not found. configEntry.deregisterChangeListener(this); return new ConfigChangeResult(ResultCode.SUCCESS, false); } } } public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { ConfigEntry dependentConfigEntry = getConfigEntry(dn); if (dependentConfigEntry != null) { return ConfigChangeListenerAdaptor.this.configChangeIsAcceptable(dependentConfigEntry, unacceptableReason, configEntry); } else { // The dependent entry was not found. configEntry.deregisterChangeListener(this); return true; } } }; AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition(); for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) { Visitor.find(path, pd, dependencies); } } for (DN entryDN : dependencies) { // Be careful not to register listeners against the dependent // entry itself. if (!entryDN.equals(dn)) { ConfigEntry configEntry = getConfigEntry(entryDN); if (configEntry != null) { configEntry.registerChangeListener(dependencyListener); } } } // Register a delete listener against the parent which will // finalize this change listener when the monitored configuration // entry is removed. this.cleanerListener = new ConfigDeleteListener() { public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) { // Perform finalization if the deleted entry is the monitored // entry. if (configEntry.getDN().equals(dn)) { finalizeChangeListener(); } return new ConfigChangeResult(ResultCode.SUCCESS, false); } public boolean configDeleteIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { // Always acceptable. return true; } }; DN parent = dn.parent(); if (parent != null) { ConfigEntry configEntry = getConfigEntry(dn.parent(); if (configEntry != null) { configEntry.registerDeleteListener(cleanerListener); } } } return result; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) { // Looking at the ConfigFileHandler implementation reveals // that this ConfigEntry will actually be a different object to // the one passed in the previous call-back (it will have the same // content though). This configuration entry has the correct // listener lists. cachedManagedObject.setConfigEntry(configEntry); ConfigChangeResult result = listener.applyConfigurationChange(cachedManagedObject); // Now apply post constraint call-backs. if (result.getResultCode() == ResultCode.SUCCESS) { ManagedObjectDefinition<?, ?> d = cachedManagedObject.getManagedObjectDefinition(); for (Constraint constraint : d.getAllConstraints()) { for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) { try { handler.performPostModify(cachedManagedObject); } catch (ConfigException e) { debugLogger.trace("Unable to perform post modify", e); } } } } /** * {@inheritDoc} */ public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { return configChangeIsAcceptable(configEntry, unacceptableReason, configEntry); } /** * Indicates whether the configuration entry that will result from a * proposed modification is acceptable to this change listener. * * @param configEntry * The configuration entry that will result from the * requested update. * @param unacceptableReason * A buffer to which this method can append a * human-readable message explaining why the proposed * change is not acceptable. * @param newConfigEntry * The configuration entry that caused the notification * (will be different from <code>configEntry</code> if a * dependency was modified). * @return <CODE>true</CODE> if the proposed entry contains an * acceptable configuration, or <CODE>false</CODE> if it * does not. */ public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason, ConfigEntry newConfigEntry) { try { ServerManagementContext context = ServerManagementContext.getInstance(); cachedManagedObject = context.decode(path, configEntry, newConfigEntry); } catch (DecodingException e) { unacceptableReason.append(e.getMessageObject()); return false; return result; } // Give up immediately if a constraint violation occurs. try { cachedManagedObject.ensureIsUsable(); } catch (ConstraintViolationException e) { generateUnacceptableReason(e.getMessages(), unacceptableReason); return false; /** * {@inheritDoc} */ public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { return configChangeIsAcceptable(configEntry, unacceptableReason, configEntry); } // Let the change listener decide. List<LocalizableMessage> reasons = new LinkedList<Message>(); if (listener.isConfigurationChangeAcceptable(cachedManagedObject,reasons)) { return true; } else { generateUnacceptableReason(reasons, unacceptableReason); return false; } } /** * Indicates whether the configuration entry that will result from a * proposed modification is acceptable to this change listener. * * @param configEntry * The configuration entry that will result from the requested * update. * @param unacceptableReason * A buffer to which this method can append a human-readable * message explaining why the proposed change is not acceptable. * @param newConfigEntry * The configuration entry that caused the notification (will be * different from <code>configEntry</code> if a dependency was * modified). * @return <CODE>true</CODE> if the proposed entry contains an acceptable * configuration, or <CODE>false</CODE> if it does not. */ public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason, ConfigEntry newConfigEntry) { try { ServerManagementContext context = ServerManagementContext.getInstance(); cachedManagedObject = context.decode(path, configEntry, newConfigEntry); } catch (DecodingException e) { unacceptableReason.append(e.getMessageObject()); return false; } // Give up immediately if a constraint violation occurs. try { cachedManagedObject.ensureIsUsable(); } catch (ConstraintViolationException e) { generateUnacceptableReason(e.getMessages(), unacceptableReason); return false; } /** * Finalizes this configuration change listener adaptor. This method * must be called before this change listener is removed. */ public void finalizeChangeListener() { // Remove the dependency listeners. for (DN dependency : dependencies) { ConfigEntry listenerConfigEntry = getConfigEntry(dependency); if (listenerConfigEntry != null) { listenerConfigEntry.deregisterChangeListener(dependencyListener); } // Let the change listener decide. List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>(); if (listener.isConfigurationChangeAcceptable(cachedManagedObject, reasons)) { return true; } else { generateUnacceptableReason(reasons, unacceptableReason); return false; } } // Now remove the cleaner listener as it will no longer be // needed. ConfigEntry parentConfigEntry = getConfigEntry(dn.getParent()); if (parentConfigEntry != null) { parentConfigEntry.deregisterDeleteListener(cleanerListener); /** * Finalizes this configuration change listener adaptor. This method must be * called before this change listener is removed. */ public void finalizeChangeListener() { // Remove the dependency listeners. for (DN dependency : dependencies) { ConfigEntry listenerConfigEntry = getConfigEntry(dependency); if (listenerConfigEntry != null) { listenerConfigEntry.deregisterChangeListener(dependencyListener); } } // Now remove the cleaner listener as it will no longer be // needed. ConfigEntry parentConfigEntry = getConfigEntry(dn.parent(); if (parentConfigEntry != null) { parentConfigEntry.deregisterDeleteListener(cleanerListener); } } } /** * Get the server managed object change listener associated with * this adaptor. * * @return Returns the server managed object change listener * associated with this adaptor. */ ServerManagedObjectChangeListener<? super S> getServerManagedObjectChangeListener() { return listener; } // Returns the named configuration entry or null if it could not be // retrieved. private ConfigEntry getConfigEntry(DN dn) { try { ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn); if (configEntry != null) { return configEntry; } else { LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST .get(String.valueOf(dn)); ErrorLogger.logError(message); } } catch (ConfigException e) { // The dependent entry could not be retrieved. if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } LocalizableMessage message = AdminMessages.ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get( String.valueOf(dn), StaticUtils.getExceptionMessage(e)); ErrorLogger.logError(message); /** * Get the server managed object change listener associated with this * adaptor. * * @return Returns the server managed object change listener associated with * this adaptor. */ ServerManagedObjectChangeListener<? super S> getServerManagedObjectChangeListener() { return listener; } return null; } // Returns the named configuration entry or null if it could not be // retrieved. private ConfigEntry getConfigEntry(DN dn) { try { ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn); if (configEntry != null) { return configEntry; } else { adminLogger.error(ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST, String.valueOf(dn)); } } catch (ConfigException e) { debugLogger.trace("The dependent entry could not be retrieved", e); adminLogger.error(ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT, String.valueOf(dn), StaticUtils.getExceptionMessage(e)); } return null; } } opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
@@ -26,16 +26,14 @@ */ package org.opends.server.admin.server; import static com.forgerock.opendj.ldap.AdminMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import java.util.LinkedList; import java.util.List; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.opends.server.admin.Configuration; import org.opends.server.admin.Constraint; import org.opends.server.admin.DecodingException; @@ -47,256 +45,222 @@ import org.opends.server.admin.SetRelationDefinition; import org.opends.server.admin.DefinitionDecodingException.Reason; import org.opends.server.api.ConfigDeleteListener; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.AttributeValue; import org.opends.server.types.ConfigChangeResult; import org.forgerock.opendj.ldap.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.ResultCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.forgerock.opendj.ldap.ResultCode; /** * An adaptor class which converts {@link ConfigDeleteListener} * callbacks to {@link ServerManagedObjectDeleteListener} callbacks. * An adaptor class which converts {@link ConfigDeleteListener} callbacks to * {@link ServerManagedObjectDeleteListener} callbacks. * * @param <S> * The type of server configuration handled by the delete * listener. * The type of server configuration handled by the delete listener. */ final class ConfigDeleteListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements ConfigDeleteListener { final class ConfigDeleteListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements ConfigDeleteListener { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); private static final Logger debugLogger = LoggerFactory.getLogger(ConfigDeleteListenerAdaptor.class); // Cached managed object between accept/apply callbacks. private ServerManagedObject<? extends S> cachedManagedObject; // Cached managed object between accept/apply callbacks. private ServerManagedObject<? extends S> cachedManagedObject; // The instantiable relation. private final InstantiableRelationDefinition<?, S> instantiableRelation; // The instantiable relation. private final InstantiableRelationDefinition<?, S> instantiableRelation; // The set relation. private final SetRelationDefinition<?, S> setRelation; // The set relation. private final SetRelationDefinition<?, S> setRelation; // The underlying delete listener. private final ServerManagedObjectDeleteListener<S> listener; // The underlying delete listener. private final ServerManagedObjectDeleteListener<S> listener; // The optional relation. private final OptionalRelationDefinition<?, S> optionalRelation; // The optional relation. private final OptionalRelationDefinition<?, S> optionalRelation; // The managed object path of the parent. private final ManagedObjectPath<?, ?> path; // The managed object path of the parent. private final ManagedObjectPath<?, ?> path; /** * Create a new configuration delete listener adaptor for an * instantiable relation. * * @param path * The managed object path of the parent. * @param relation * The instantiable relation. * @param listener * The underlying delete listener. */ public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, InstantiableRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) { this.path = path; this.optionalRelation = null; this.instantiableRelation = relation; this.setRelation = null; this.listener = listener; this.cachedManagedObject = null; } /** * Create a new configuration delete listener adaptor for an * optional relation. * * @param path * The managed object path of the parent. * @param relation * The optional relation. * @param listener * The underlying delete listener. */ public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, OptionalRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) { this.path = path; this.optionalRelation = relation; this.instantiableRelation = null; this.setRelation = null; this.listener = listener; this.cachedManagedObject = null; } /** * Create a new configuration delete listener adaptor for an * set relation. * * @param path * The managed object path of the parent. * @param relation * The set relation. * @param listener * The underlying delete listener. */ public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, SetRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) { this.path = path; this.optionalRelation = null; this.instantiableRelation = null; this.setRelation = relation; this.listener = listener; this.cachedManagedObject = null; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) { if (optionalRelation != null) { // Optional managed objects are located directly beneath the // parent and have a well-defined name. We need to make sure // that we are handling the correct entry. ManagedObjectPath<?, ?> childPath = path.child(optionalRelation); DN expectedDN = DNBuilder.create(childPath); if (!configEntry.getDN().equals(expectedDN)) { // Doesn't apply to us. return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * Create a new configuration delete listener adaptor for an instantiable * relation. * * @param path * The managed object path of the parent. * @param relation * The instantiable relation. * @param listener * The underlying delete listener. */ public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, InstantiableRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) { this.path = path; this.optionalRelation = null; this.instantiableRelation = relation; this.setRelation = null; this.listener = listener; this.cachedManagedObject = null; } // Cached objects are guaranteed to be from previous acceptable // callback. ConfigChangeResult result = listener .applyConfigurationDelete(cachedManagedObject); /** * Create a new configuration delete listener adaptor for an optional * relation. * * @param path * The managed object path of the parent. * @param relation * The optional relation. * @param listener * The underlying delete listener. */ public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, OptionalRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) { this.path = path; this.optionalRelation = relation; this.instantiableRelation = null; this.setRelation = null; this.listener = listener; this.cachedManagedObject = null; } // Now apply post constraint call-backs. if (result.getResultCode() == ResultCode.SUCCESS) { ManagedObjectDefinition<?, ?> d = cachedManagedObject .getManagedObjectDefinition(); for (Constraint constraint : d.getAllConstraints()) { for (ServerConstraintHandler handler : constraint .getServerConstraintHandlers()) { try { handler.performPostDelete(cachedManagedObject); } catch (ConfigException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); /** * Create a new configuration delete listener adaptor for an set relation. * * @param path * The managed object path of the parent. * @param relation * The set relation. * @param listener * The underlying delete listener. */ public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, SetRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) { this.path = path; this.optionalRelation = null; this.instantiableRelation = null; this.setRelation = relation; this.listener = listener; this.cachedManagedObject = null; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) { if (optionalRelation != null) { // Optional managed objects are located directly beneath the // parent and have a well-defined name. We need to make sure // that we are handling the correct entry. ManagedObjectPath<?, ?> childPath = path.child(optionalRelation); DN expectedDN = DNBuilder.create(childPath); if (!configEntry.getDN().equals(expectedDN)) { // Doesn't apply to us. return new ConfigChangeResult(ResultCode.SUCCESS, false); } } } } // Cached objects are guaranteed to be from previous acceptable // callback. ConfigChangeResult result = listener.applyConfigurationDelete(cachedManagedObject); // Now apply post constraint call-backs. if (result.getResultCode() == ResultCode.SUCCESS) { ManagedObjectDefinition<?, ?> d = cachedManagedObject.getManagedObjectDefinition(); for (Constraint constraint : d.getAllConstraints()) { for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) { try { handler.performPostDelete(cachedManagedObject); } catch (ConfigException e) { debugLogger.trace("Unable to perform post delete", e); } } } } return result; } return result; } /** * {@inheritDoc} */ public boolean configDeleteIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { DN dn = configEntry.getDN(); AttributeValue av = dn.rdn().getAttributeValue(0); String name = av.getValue().toString().trim(); /** * {@inheritDoc} */ public boolean configDeleteIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { DN dn = configEntry.getDN(); AttributeValue av = dn.getRDN().getAttributeValue(0); String name = av.getValue().toString().trim(); try { ManagedObjectPath<?, ? extends S> childPath; if (instantiableRelation != null) { childPath = path.child(instantiableRelation, name); } else if (setRelation != null) { try { childPath = path.child(setRelation, name); } catch (IllegalArgumentException e) { throw new DefinitionDecodingException(setRelation .getChildDefinition(), Reason.WRONG_TYPE_INFORMATION); ManagedObjectPath<?, ? extends S> childPath; if (instantiableRelation != null) { childPath = path.child(instantiableRelation, name); } else if (setRelation != null) { try { childPath = path.child(setRelation, name); } catch (IllegalArgumentException e) { throw new DefinitionDecodingException(setRelation.getChildDefinition(), Reason.WRONG_TYPE_INFORMATION); } } else { // Optional managed objects are located directly beneath the // parent and have a well-defined name. We need to make sure // that we are handling the correct entry. childPath = path.child(optionalRelation); DN expectedDN = DNBuilder.create(childPath); if (!dn.equals(expectedDN)) { // Doesn't apply to us. return true; } } ServerManagementContext context = ServerManagementContext.getInstance(); cachedManagedObject = context.decode(childPath, configEntry); } catch (DecodingException e) { unacceptableReason.append(e.getMessageObject()); return false; } } else { // Optional managed objects are located directly beneath the // parent and have a well-defined name. We need to make sure // that we are handling the correct entry. childPath = path.child(optionalRelation); DN expectedDN = DNBuilder.create(childPath); if (!dn.equals(expectedDN)) { // Doesn't apply to us. return true; List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>(); // Enforce any constraints. boolean isDeleteAllowed = true; ManagedObjectDefinition<?, ?> d = cachedManagedObject.getManagedObjectDefinition(); for (Constraint constraint : d.getAllConstraints()) { for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) { try { if (!handler.isDeleteAllowed(cachedManagedObject, reasons)) { isDeleteAllowed = false; } } catch (ConfigException e) { LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e.getMessageObject()); reasons.add(message); isDeleteAllowed = false; } } } } ServerManagementContext context = ServerManagementContext.getInstance(); cachedManagedObject = context.decode(childPath, configEntry); } catch (DecodingException e) { unacceptableReason.append(e.getMessageObject()); return false; } List<LocalizableMessage> reasons = new LinkedList<Message>(); // Enforce any constraints. boolean isDeleteAllowed = true; ManagedObjectDefinition<?, ?> d = cachedManagedObject .getManagedObjectDefinition(); for (Constraint constraint : d.getAllConstraints()) { for (ServerConstraintHandler handler : constraint .getServerConstraintHandlers()) { try { if (!handler.isDeleteAllowed(cachedManagedObject, reasons)) { isDeleteAllowed = false; } } catch (ConfigException e) { LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e .getMessageObject()); reasons.add(message); isDeleteAllowed = false; // Give up immediately if a constraint violation occurs. if (!isDeleteAllowed) { generateUnacceptableReason(reasons, unacceptableReason); return false; } } // Let the delete listener decide. if (listener.isConfigurationDeleteAcceptable(cachedManagedObject, reasons)) { return true; } else { generateUnacceptableReason(reasons, unacceptableReason); return false; } } // Give up immediately if a constraint violation occurs. if (!isDeleteAllowed) { generateUnacceptableReason(reasons, unacceptableReason); return false; /** * Get the server managed object delete listener associated with this * adaptor. * * @return Returns the server managed object delete listener associated with * this adaptor. */ ServerManagedObjectDeleteListener<S> getServerManagedObjectDeleteListener() { return listener; } // Let the delete listener decide. if (listener.isConfigurationDeleteAcceptable(cachedManagedObject, reasons)) { return true; } else { generateUnacceptableReason(reasons, unacceptableReason); return false; } } /** * Get the server managed object delete listener associated with * this adaptor. * * @return Returns the server managed object delete listener * associated with this adaptor. */ ServerManagedObjectDeleteListener<S> getServerManagedObjectDeleteListener() { return listener; } } opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java
@@ -25,124 +25,104 @@ * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.server.admin.server; import org.forgerock.i18n.LocalizableMessage; import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; import static com.forgerock.opendj.util.StaticUtils.*; import org.opends.server.admin.DefinitionDecodingException; import org.opends.server.config.ConfigException; import org.opends.messages.AdminMessages; import org.opends.server.util.DynamicConstants; import com.forgerock.opendj.ldap.AdminMessages; import org.forgerock.opendj.ldap.DN; /** * A utility class for converting admin exceptions to config exceptions. */ final class ConfigExceptionFactory { // The singleton instance. private static final ConfigExceptionFactory INSTANCE = new ConfigExceptionFactory(); // The singleton instance. private static final ConfigExceptionFactory INSTANCE = new ConfigExceptionFactory(); // Prevent instantiation. private ConfigExceptionFactory() { // Do nothing. } /** * Get the configuration exception factory instance. * * @return Returns the configuration exception factory instance. */ public static ConfigExceptionFactory getInstance() { return INSTANCE; } // Prevent instantiation. private ConfigExceptionFactory() { // Do nothing. } /** * Create a configuration exception from a definition decoding exception. * * @param dn * The dn of the configuration entry that could not be decoded. * @param e * The definition decoding exception * @return Returns the configuration exception. */ public ConfigException createDecodingExceptionAdaptor(DN dn, DefinitionDecodingException e) { LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(String.valueOf(dn), stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD)); return new ConfigException(message, e); } /** * Create a configuration exception from a server managed object decoding * exception. * * @param e * The server managed object decoding exception. * @return Returns the configuration exception. */ public ConfigException createDecodingExceptionAdaptor(ServerManagedObjectDecodingException e) { DN dn = e.getPartialManagedObject().getDN(); LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(String.valueOf(dn), stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD)); return new ConfigException(message, e); } /** * Get the configuration exception factory instance. * * @return Returns the configuration exception factory instance. */ public static ConfigExceptionFactory getInstance() { return INSTANCE; } /** * Create a configuration exception from a constraints violation decoding * exception. * * @param e * The constraints violation decoding exception. * @return Returns the configuration exception. */ public ConfigException createDecodingExceptionAdaptor(ConstraintViolationException e) { DN dn = e.getManagedObject().getDN(); LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(String.valueOf(dn), stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD)); return new ConfigException(message, e); } /** * Create an exception that describes a problem that occurred when * attempting to load and instantiate a class. * * @param dn * The dn of the configuration entry was being processed. * @param className * The name of the class that could not be loaded or * instantiated. * @param e * The exception that occurred. * @return Returns the configuration exception. */ /** * Create a configuration exception from a definition decoding exception. * * @param dn * The dn of the configuration entry that could not be decoded. * @param e * The definition decoding exception * @return Returns the configuration exception. */ public ConfigException createDecodingExceptionAdaptor(DN dn, DefinitionDecodingException e) { LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM. get(String.valueOf(dn), stackTraceToSingleLineString(e)); return new ConfigException(message, e); } /** * Create a configuration exception from a server managed object decoding * exception. * * @param e * The server managed object decoding exception. * @return Returns the configuration exception. */ public ConfigException createDecodingExceptionAdaptor( ServerManagedObjectDecodingException e) { DN dn = e.getPartialManagedObject().getDN(); LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get( String.valueOf(dn), stackTraceToSingleLineString(e)); return new ConfigException(message, e); } /** * Create a configuration exception from a constraints violation * decoding exception. * * @param e * The constraints violation decoding exception. * @return Returns the configuration exception. */ public ConfigException createDecodingExceptionAdaptor( ConstraintViolationException e) { DN dn = e.getManagedObject().getDN(); LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM .get(String.valueOf(dn), stackTraceToSingleLineString(e)); return new ConfigException(message, e); } /** * Create an exception that describes a problem that occurred when * attempting to load and instantiate a class. * * @param dn * The dn of the configuration entry was being processed. * @param className * The name of the class that could not be loaded or * instantiated. * @param e * The exception that occurred. * @return Returns the configuration exception. */ public ConfigException createClassLoadingExceptionAdaptor(DN dn, String className, Exception e) { LocalizableMessage message = AdminMessages.ERR_ADMIN_CANNOT_INSTANTIATE_CLASS. get(String.valueOf(className), String.valueOf(dn), stackTraceToSingleLineString(e)); return new ConfigException(message, e); } public ConfigException createClassLoadingExceptionAdaptor(DN dn, String className, Exception e) { LocalizableMessage message = AdminMessages.ERR_ADMIN_CANNOT_INSTANTIATE_CLASS.get(String.valueOf(className), String.valueOf(dn), stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD)); return new ConfigException(message, e); } } opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java
@@ -25,53 +25,46 @@ * Copyright 2007-2008 Sun Microsystems, Inc. */ package org.opends.server.admin.server; import org.forgerock.i18n.LocalizableMessage; import java.util.List; import org.opends.server.admin.Configuration; import org.opends.server.types.ConfigChangeResult; /** * This interface defines the methods that a Directory Server * configurable component should implement if it wishes to be able to * receive notifications when a its associated configuration is * changed. * This interface defines the methods that a Directory Server configurable * component should implement if it wishes to be able to receive notifications * when a its associated configuration is changed. * * @param <T> * The type of configuration that this listener should be * notified about. * The type of configuration that this listener should be notified * about. */ public interface ConfigurationChangeListener<T extends Configuration> { /** * Indicates whether the proposed change to the configuration is * acceptable to this change listener. * * @param configuration * The new configuration containing the changes. * @param unacceptableReasons * A list that can be used to hold messages about why the * provided configuration is not acceptable. * @return Returns <code>true</code> if the proposed change is * acceptable, or <code>false</code> if it is not. */ public boolean isConfigurationChangeAcceptable(T configuration, List<LocalizableMessage> unacceptableReasons); /** * Indicates whether the proposed change to the configuration is acceptable * to this change listener. * * @param configuration * The new configuration containing the changes. * @param unacceptableReasons * A list that can be used to hold messages about why the * provided configuration is not acceptable. * @return Returns <code>true</code> if the proposed change is acceptable, * or <code>false</code> if it is not. */ public boolean isConfigurationChangeAcceptable(T configuration, List<LocalizableMessage> unacceptableReasons); /** * Applies the configuration changes to this change listener. * * @param configuration * The new configuration containing the changes. * @return Returns information about the result of changing the * configuration. */ public ConfigChangeResult applyConfigurationChange(T configuration); /** * Applies the configuration changes to this change listener. * * @param configuration * The new configuration containing the changes. * @return Returns information about the result of changing the * configuration. */ public ConfigChangeResult applyConfigurationChange(T configuration); } opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java
@@ -25,52 +25,46 @@ * Copyright 2007-2008 Sun Microsystems, Inc. */ package org.opends.server.admin.server; import org.forgerock.i18n.LocalizableMessage; import java.util.List; import org.opends.server.admin.Configuration; import org.opends.server.types.ConfigChangeResult; /** * This interface defines the methods that a Directory Server * configurable component should implement if it wishes to be able to * receive notifications when an existing configuration is deleted. * This interface defines the methods that a Directory Server configurable * component should implement if it wishes to be able to receive notifications * when an existing configuration is deleted. * * @param <T> * The type of configuration that this listener should be * notified about. * The type of configuration that this listener should be notified * about. */ public interface ConfigurationDeleteListener<T extends Configuration> { /** * Indicates whether the proposed deletion of an existing * configuration is acceptable to this delete listener. * * @param configuration * The configuration that will be deleted. * @param unacceptableReasons * A list that can be used to hold messages about why the * provided configuration is not acceptable. * @return Returns <code>true</code> if the proposed deletion is * acceptable, or <code>false</code> if it is not. */ public boolean isConfigurationDeleteAcceptable(T configuration, List<LocalizableMessage> unacceptableReasons); /** * Indicates whether the proposed deletion of an existing configuration is * acceptable to this delete listener. * * @param configuration * The configuration that will be deleted. * @param unacceptableReasons * A list that can be used to hold messages about why the * provided configuration is not acceptable. * @return Returns <code>true</code> if the proposed deletion is acceptable, * or <code>false</code> if it is not. */ public boolean isConfigurationDeleteAcceptable(T configuration, List<LocalizableMessage> unacceptableReasons); /** * Deletes an existing configuration from this delete listener. * * @param configuration * The existing configuration that will be deleted. * @return Returns information about the result of deleting the * configuration. */ public ConfigChangeResult applyConfigurationDelete(T configuration); /** * Deletes an existing configuration from this delete listener. * * @param configuration * The existing configuration that will be deleted. * @return Returns information about the result of deleting the * configuration. */ public ConfigChangeResult applyConfigurationDelete(T configuration); } opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java
@@ -24,12 +24,10 @@ * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.server.admin.server; import static com.forgerock.opendj.ldap.AdminMessages.*; import static com.forgerock.opendj.util.Validator.*; import java.util.ArrayList; import java.util.Collection; @@ -38,142 +36,115 @@ import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; import org.opends.server.admin.DecodingException; import static com.forgerock.opendj.util.Validator.*; /** * This exception is thrown when the server refuses to use or delete a * managed object due to one or more constraints that cannot be * satisfied. * This exception is thrown when the server refuses to use or delete a managed * object due to one or more constraints that cannot be satisfied. */ public class ConstraintViolationException extends DecodingException { /** * Serialization ID. */ private static final long serialVersionUID = -4902443848460011875L; /** * Serialization ID. */ private static final long serialVersionUID = -4902443848460011875L; // The server managed object. private final ServerManagedObject<?> managedObject; // The server managed object. private final ServerManagedObject<?> managedObject; // Gets the default message. private static LocalizableMessage getDefaultMessage(Collection<LocalizableMessage> messages) { ensureNotNull(messages); ensureTrue(!messages.isEmpty(), "messages should not be empty"); // Gets the default message. private static LocalizableMessage getDefaultMessage(Collection<Message> messages) { Validator.ensureNotNull(messages); Validator.ensureTrue(!messages.isEmpty()); if (messages.size() == 1) { return ERR_CONSTRAINT_VIOLATION_EXCEPTION_SINGLE.get(messages.iterator() .next()); } else { return ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL .get(getSingleMessage(messages)); } } // Merge the messages into a single message. private static LocalizableMessage getSingleMessage(Collection<Message> messages) { if (messages.size() == 1) { return messages.iterator().next(); } else { LocalizableMessageBuilder builder = new MessageBuilder(); boolean isFirst = true; for (LocalizableMessage m : messages) { if (!isFirst) { builder.append("; "); if (messages.size() == 1) { return ERR_CONSTRAINT_VIOLATION_EXCEPTION_SINGLE.get(messages.iterator().next()); } else { return ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL.get(getSingleMessage(messages)); } builder.append(m); isFirst = false; } return builder.toMessage(); } } // The messages describing the constraint violations that occurred. private final Collection<LocalizableMessage> messages; // Merge the messages into a single message. private static LocalizableMessage getSingleMessage(Collection<LocalizableMessage> messages) { if (messages.size() == 1) { return messages.iterator().next(); } else { LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); boolean isFirst = true; for (LocalizableMessage m : messages) { if (!isFirst) { builder.append("; "); } builder.append(m); isFirst = false; } return builder.toMessage(); } } /** * Creates a new constraint violation exception with the provided * messages. * * @param managedObject * The server managed object which caused the constraint * violations. * @param messages * The messages describing the constraint violations that * occurred (must be non-<code>null</code> and * non-empty). */ public ConstraintViolationException(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> messages) { super(getDefaultMessage(messages)); // The messages describing the constraint violations that occurred. private final Collection<LocalizableMessage> messages; this.managedObject = managedObject; this.messages = new ArrayList<LocalizableMessage>(messages); } /** * Creates a new constraint violation exception with the provided messages. * * @param managedObject * The server managed object which caused the constraint * violations. * @param messages * The messages describing the constraint violations that * occurred (must be non-<code>null</code> and non-empty). */ public ConstraintViolationException(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> messages) { super(getDefaultMessage(messages)); this.managedObject = managedObject; this.messages = new ArrayList<LocalizableMessage>(messages); } /** * Creates a new constraint violation exception with the provided message. * * @param managedObject * The server managed object which caused the constraint * violations. * @param message * The message describing the constraint violation that occurred. */ public ConstraintViolationException(ServerManagedObject<?> managedObject, LocalizableMessage message) { this(managedObject, Collections.singleton(message)); } /** * Creates a new constraint violation exception with the provided * message. * * @param managedObject * The server managed object which caused the constraint * violations. * @param message * The message describing the constraint violation that * occurred. */ public ConstraintViolationException(ServerManagedObject<?> managedObject, LocalizableMessage message) { this(managedObject, Collections.singleton(message)); } /** * Gets an unmodifiable collection view of the messages describing the * constraint violations that occurred. * * @return Returns an unmodifiable collection view of the messages * describing the constraint violations that occurred. */ public Collection<LocalizableMessage> getMessages() { return Collections.unmodifiableCollection(messages); } /** * Creates a single message listing all the messages combined into a single * list separated by semi-colons. * * @return Returns a single message listing all the messages combined into a * single list separated by semi-colons. */ public LocalizableMessage getMessagesAsSingleMessage() { return getSingleMessage(messages); } /** * Gets an unmodifiable collection view of the messages describing * the constraint violations that occurred. * * @return Returns an unmodifiable collection view of the messages * describing the constraint violations that occurred. */ public Collection<LocalizableMessage> getMessages() { return Collections.unmodifiableCollection(messages); } /** * Creates a single message listing all the messages combined into a * single list separated by semi-colons. * * @return Returns a single message listing all the messages * combined into a single list separated by semi-colons. */ public LocalizableMessage getMessagesAsSingleMessage() { return getSingleMessage(messages); } /** * Gets the server managed object which caused the constraint * violations. * * @return Returns the server managed object which caused the * constraint violations. */ public ServerManagedObject<?> getManagedObject() { return managedObject; } /** * Gets the server managed object which caused the constraint violations. * * @return Returns the server managed object which caused the constraint * violations. */ public ServerManagedObject<?> getManagedObject() { return managedObject; } } opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java
@@ -27,64 +27,47 @@ package org.opends.server.admin.server; import org.forgerock.opendj.ldap.DN; import org.opends.server.admin.LDAPProfile; import org.opends.server.admin.ManagedObjectPath; import org.opends.server.admin.RelationDefinition; import org.opends.server.types.DirectoryException; /** * A factory class for creating <code>DN</code>s from managed * object paths. * A factory class for creating <code>DN</code>s from managed object paths. */ final class DNBuilder { /** * Creates a new DN representing the specified managed object path. * * @param path * The managed object path. * @return Returns a new DN representing the specified managed * object path. */ public static DN create(ManagedObjectPath<?, ?> path) { return path.toDN(); } /** * Creates a new DN representing the specified managed object path * and relation. * * @param path * The managed object path. * @param relation * The child relation. * @return Returns a new DN representing the specified managed * object path and relation. */ public static DN create(ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> relation) { DN dn = path.toDN(); try { LDAPProfile profile = LDAPProfile.getInstance(); DN localName = DN.decode(profile.getRelationRDNSequence(relation)); return dn.concat(localName); } catch (DirectoryException e) { throw new RuntimeException(e); /** * Creates a new DN representing the specified managed object path. * * @param path * The managed object path. * @return Returns a new DN representing the specified managed object path. */ public static DN create(ManagedObjectPath<?, ?> path) { return path.toDN(); } } /** * Creates a new DN representing the specified managed object path and * relation. * * @param path * The managed object path. * @param relation * The child relation. * @return Returns a new DN representing the specified managed object path * and relation. */ public static DN create(ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> relation) { DN dn = path.toDN(); LDAPProfile profile = LDAPProfile.getInstance(); DN localName = DN.valueOf(profile.getRelationRDNSequence(relation)); return dn.child(localName); } // Prevent instantiation. private DNBuilder() { // No implementation required. } // Prevent instantiation. private DNBuilder() { // No implementation required. } } opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java
@@ -26,166 +26,139 @@ */ package org.opends.server.admin.server; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.api.ConfigAddListener; import org.opends.server.api.ConfigDeleteListener; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.types.ConfigChangeResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.forgerock.opendj.ldap.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.ResultCode; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.i18n.LocalizableMessageBuilder; /** * A configuration add listener which will monitor a parent entry to * see when a specified child entry has been added. When the child * entry is added the add listener will automatically register its * "delayed" add or delete listener. * A configuration add listener which will monitor a parent entry to see when a * specified child entry has been added. When the child entry is added the add * listener will automatically register its "delayed" add or delete listener. */ final class DelayedConfigAddListener implements ConfigAddListener { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); private static final Logger debugLogger = LoggerFactory.getLogger(DelayedConfigAddListener.class); // The name of the parent entry. private final DN parent; // The name of the parent entry. private final DN parent; // The name of the subordinate entry which should have an add or // delete listener registered with it when it is created. private final DN child; // The name of the subordinate entry which should have an add or // delete listener registered with it when it is created. private final DN child; // The add listener to be registered with the subordinate entry when // it is added (or null if a delete listener should be registered). private final ConfigAddListener delayedAddListener; // The add listener to be registered with the subordinate entry when // it is added (or null if a delete listener should be registered). private final ConfigAddListener delayedAddListener; // The delete listener to be registered with the subordinate entry // when it is added (or null if an add listener should be // registered). private final ConfigDeleteListener delayedDeleteListener; // The delete listener to be registered with the subordinate entry // when it is added (or null if an add listener should be // registered). private final ConfigDeleteListener delayedDeleteListener; /** * Create a new delayed add listener which will register an add * listener with the specified entry when it is added. * * @param child * The name of the subordinate entry which should have an * add listener registered with it when it is created. * @param addListener * The add listener to be added to the subordinate entry * when it is added. */ public DelayedConfigAddListener(DN child, ConfigAddListener addListener) { this.parent = child.getParent(); this.child = child; this.delayedAddListener = addListener; this.delayedDeleteListener = null; } /** * Create a new delayed add listener which will register a delete * listener with the specified entry when it is added. * * @param child * The name of the subordinate entry which should have a * delete listener registered with it when it is created. * @param deleteListener * The delete listener to be added to the subordinate entry * when it is added. */ public DelayedConfigAddListener(DN child, ConfigDeleteListener deleteListener) { this.parent = child.getParent(); this.child = child; this.delayedAddListener = null; this.delayedDeleteListener = deleteListener; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) { if (configEntry.getDN().equals(child)) { // The subordinate entry matched our criteria so register the // listener(s). if (delayedAddListener != null) { configEntry.registerAddListener(delayedAddListener); } if (delayedDeleteListener != null) { configEntry.registerDeleteListener(delayedDeleteListener); } // We are no longer needed. try { ConfigEntry myEntry = DirectoryServer.getConfigEntry(parent); if (myEntry != null) { myEntry.deregisterAddListener(this); } } catch (ConfigException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // Ignore this error as it implies that this listener has // already been deregistered. } /** * Create a new delayed add listener which will register an add listener * with the specified entry when it is added. * * @param child * The name of the subordinate entry which should have an add * listener registered with it when it is created. * @param addListener * The add listener to be added to the subordinate entry when it * is added. */ public DelayedConfigAddListener(DN child, ConfigAddListener addListener) { this.parent = child.parent(); this.child = child; this.delayedAddListener = addListener; this.delayedDeleteListener = null; } return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * Create a new delayed add listener which will register a delete listener * with the specified entry when it is added. * * @param child * The name of the subordinate entry which should have a delete * listener registered with it when it is created. * @param deleteListener * The delete listener to be added to the subordinate entry when * it is added. */ public DelayedConfigAddListener(DN child, ConfigDeleteListener deleteListener) { this.parent = child.parent(); this.child = child; this.delayedAddListener = null; this.delayedDeleteListener = deleteListener; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) { if (configEntry.getDN().equals(child)) { // The subordinate entry matched our criteria so register the // listener(s). if (delayedAddListener != null) { configEntry.registerAddListener(delayedAddListener); } if (delayedDeleteListener != null) { configEntry.registerDeleteListener(delayedDeleteListener); } /** * {@inheritDoc} */ public boolean configAddIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { // Always acceptable. return true; } // We are no longer needed. try { ConfigEntry myEntry = DirectoryServer.getConfigEntry(parent); if (myEntry != null) { myEntry.deregisterAddListener(this); } } catch (ConfigException e) { debugLogger.trace("Unable to deregister add listener", e); // Ignore this error as it implies that this listener has // already been deregistered. } } return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * {@inheritDoc} */ public boolean configAddIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) { // Always acceptable. return true; } /** * Gets the delayed add listener. * <p> * This method is provided for unit-testing. * * @return Returns the delayed add listener, or <code>null</code> * if this listener is delaying a delete listener. */ ConfigAddListener getDelayedAddListener() { return delayedAddListener; } /** * Gets the delayed add listener. * <p> * This method is provided for unit-testing. * * @return Returns the delayed add listener, or <code>null</code> if this * listener is delaying a delete listener. */ ConfigAddListener getDelayedAddListener() { return delayedAddListener; } /** * Gets the delayed delete listener. * <p> * This method is provided for unit-testing. * * @return Returns the delayed delete listener, or <code>null</code> * if this listener is delaying a add listener. */ ConfigDeleteListener getDelayedDeleteListener() { return delayedDeleteListener; } /** * Gets the delayed delete listener. * <p> * This method is provided for unit-testing. * * @return Returns the delayed delete listener, or <code>null</code> if this * listener is delaying a add listener. */ ConfigDeleteListener getDelayedDeleteListener() { return delayedDeleteListener; } } opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java
@@ -26,168 +26,146 @@ */ package org.opends.server.admin.server; import java.util.Collection; import org.forgerock.i18n.LocalizableMessage; import org.opends.server.config.ConfigException; /** * An interface for performing server-side constraint validation. * <p> * Constraints are evaluated immediately before and after write * operations are performed. Server-side constraints are evaluated in * two phases: the first phase determines if the proposed add, delete, * or modification is acceptable according to the constraint. If one * or more constraints fails, the write write operation is refused, * and the client will receive an * <code>OperationRejectedException</code> exception. The second * phase is invoked once the add, delete, or modification request has * been allowed and any changes applied. The second phase gives the * constraint handler a chance to register listener call-backs if * required. * Constraints are evaluated immediately before and after write operations are * performed. Server-side constraints are evaluated in two phases: the first * phase determines if the proposed add, delete, or modification is acceptable * according to the constraint. If one or more constraints fails, the write * write operation is refused, and the client will receive an * <code>OperationRejectedException</code> exception. The second phase is * invoked once the add, delete, or modification request has been allowed and * any changes applied. The second phase gives the constraint handler a chance * to register listener call-backs if required. * <p> * A server constraint handler must override at least one of the * provided methods. * A server constraint handler must override at least one of the provided * methods. * * @see org.opends.server.admin.Constraint */ public abstract class ServerConstraintHandler { /** * Creates a new server constraint handler. */ protected ServerConstraintHandler() { // No implementation required. } /** * Creates a new server constraint handler. */ protected ServerConstraintHandler() { // No implementation required. } /** * Determines whether or not the existing managed object can be deleted from * the server's configuration. For example, an implementation might enforce * referential integrity by preventing referenced managed objects from being * deleted. * <p> * If the constraint is not satisfied, the implementation must return * <code>false</code> and add a message describing why the managed object * cannot be deleted. * <p> * The default implementation is to return <code>true</code>. * * @param managedObject * The managed object which is about to be deleted. * @param unacceptableReasons * A list of messages to which error messages should be added. * @return Returns <code>true</code> if this constraint is satisfied, or * <code>false</code> if it is not and the managed object cannot be * deleted. * @throws ConfigException * If an configuration exception prevented this constraint from * being evaluated. */ public boolean isDeleteAllowed(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> unacceptableReasons) throws ConfigException { return true; } /** * Determines whether or not the provided managed object can be used by the * server. This method is invoked each time a managed object is decoded by * the administration framework: when an attempt is made to add a new * configuration, modify an existing configuration, or during server * initialization. If the constraint is not satisfied the managed object * will be rejected. * <p> * If the constraint is not satisfied, the implementation must return * <code>false</code> and add a message describing why the managed object is * not usable. * <p> * The default implementation is to return <code>true</code>. * * @param managedObject * The new managed object. * @param unacceptableReasons * A list of messages to which error messages should be added. * @return Returns <code>true</code> if this constraint is satisfied, or * <code>false</code> if it is not and the managed object cannot be * used. * @throws ConfigException * If an configuration exception prevented this constraint from * being evaluated. */ public boolean isUsable(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> unacceptableReasons) throws ConfigException { return true; } /** * Determines whether or not the existing managed object can be * deleted from the server's configuration. For example, an * implementation might enforce referential integrity by preventing * referenced managed objects from being deleted. * <p> * If the constraint is not satisfied, the implementation must * return <code>false</code> and add a message describing why the * managed object cannot be deleted. * <p> * The default implementation is to return <code>true</code>. * * @param managedObject * The managed object which is about to be deleted. * @param unacceptableReasons * A list of messages to which error messages should be * added. * @return Returns <code>true</code> if this constraint is * satisfied, or <code>false</code> if it is not and the * managed object cannot be deleted. * @throws ConfigException * If an configuration exception prevented this constraint * from being evaluated. */ public boolean isDeleteAllowed(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> unacceptableReasons) throws ConfigException { return true; } /** * Performs any post-add processing required by this constraint. This method * is invoked after a new managed object has been accepted for use by the * administration framework. This might occur during initialization or when * a managed object is added at run-time. * <p> * The default implementation is to do nothing. * * @param managedObject * The managed object which has just been added to the server's * configuration. * @throws ConfigException * If the post-add processing fails due to a configuration * exception. */ public void performPostAdd(ServerManagedObject<?> managedObject) throws ConfigException { // Do nothing. } /** * Performs any post-delete processing required by this constraint. This * method is invoked after a managed object has been accepted for deletion * from the server's configuration. * <p> * The default implementation is to do nothing. * * @param managedObject * The managed object which was deleted. * @throws ConfigException * If the post-delete processing fails due to a configuration * exception. */ public void performPostDelete(ServerManagedObject<?> managedObject) throws ConfigException { // Do nothing. } /** * Determines whether or not the provided managed object can be used * by the server. This method is invoked each time a managed object * is decoded by the administration framework: when an attempt is * made to add a new configuration, modify an existing * configuration, or during server initialization. If the constraint * is not satisfied the managed object will be rejected. * <p> * If the constraint is not satisfied, the implementation must * return <code>false</code> and add a message describing why the * managed object is not usable. * <p> * The default implementation is to return <code>true</code>. * * @param managedObject * The new managed object. * @param unacceptableReasons * A list of messages to which error messages should be * added. * @return Returns <code>true</code> if this constraint is * satisfied, or <code>false</code> if it is not and the * managed object cannot be used. * @throws ConfigException * If an configuration exception prevented this constraint * from being evaluated. */ public boolean isUsable(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> unacceptableReasons) throws ConfigException { return true; } /** * Performs any post-add processing required by this constraint. * This method is invoked after a new managed object has been * accepted for use by the administration framework. This might * occur during initialization or when a managed object is added at * run-time. * <p> * The default implementation is to do nothing. * * @param managedObject * The managed object which has just been added to the * server's configuration. * @throws ConfigException * If the post-add processing fails due to a configuration * exception. */ public void performPostAdd(ServerManagedObject<?> managedObject) throws ConfigException { // Do nothing. } /** * Performs any post-delete processing required by this constraint. * This method is invoked after a managed object has been accepted * for deletion from the server's configuration. * <p> * The default implementation is to do nothing. * * @param managedObject * The managed object which was deleted. * @throws ConfigException * If the post-delete processing fails due to a * configuration exception. */ public void performPostDelete(ServerManagedObject<?> managedObject) throws ConfigException { // Do nothing. } /** * Performs any post-modify processing required by this constraint. * This method is invoked after changes to an existing managed * object have been accepted. * <p> * The default implementation is to do nothing. * * @param managedObject * The managed object which was modified. * @throws ConfigException * If the post-modify processing fails due to a * configuration exception. */ public void performPostModify(ServerManagedObject<?> managedObject) throws ConfigException { // Do nothing. } /** * Performs any post-modify processing required by this constraint. This * method is invoked after changes to an existing managed object have been * accepted. * <p> * The default implementation is to do nothing. * * @param managedObject * The managed object which was modified. * @throws ConfigException * If the post-modify processing fails due to a configuration * exception. */ public void performPostModify(ServerManagedObject<?> managedObject) throws ConfigException { // Do nothing. } } opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java
@@ -27,7 +27,8 @@ package org.opends.server.admin.server; import static com.forgerock.opendj.ldap.AdminMessages.*; import static com.forgerock.opendj.util.StaticUtils.*; import java.util.Collections; import java.util.LinkedList; @@ -36,6 +37,7 @@ import java.util.Set; import java.util.SortedSet; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.ldap.DN; import org.opends.server.admin.Configuration; import org.opends.server.admin.Constraint; @@ -52,1641 +54,1359 @@ import org.opends.server.api.ConfigChangeListener; import org.opends.server.api.ConfigDeleteListener; import org.opends.server.config.ConfigException; import org.opends.server.util.DynamicConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A server-side managed object. * * @param <S> * The type of server configuration represented by the server * managed object. * The type of server configuration represented by the server managed * object. */ public final class ServerManagedObject<S extends Configuration> implements PropertyProvider { public final class ServerManagedObject<S extends Configuration> implements PropertyProvider { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); private static final Logger logger = LoggerFactory.getLogger(ServerManagedObject.class); // The configuration entry associated with this server managed // object (null if root). private ConfigEntry configEntry; // The configuration entry associated with this server managed // object (null if root). private ConfigEntry configEntry; // The management context. private final ServerManagementContext context = ServerManagementContext .getInstance(); // The management context. private final ServerManagementContext context = ServerManagementContext.getInstance(); // The managed object's definition. private final ManagedObjectDefinition<?, S> definition; // The managed object's definition. private final ManagedObjectDefinition<?, S> definition; // The managed object path identifying this managed object's // location. private final ManagedObjectPath<?, S> path; // The managed object path identifying this managed object's // location. private final ManagedObjectPath<?, S> path; // The managed object's properties. private final Map<PropertyDefinition<?>, SortedSet<?>> properties; // The managed object's properties. private final Map<PropertyDefinition<?>, SortedSet<?>> properties; /** * Creates an new server side managed object. * * @param path * The managed object path. * @param d * The managed object definition. * @param properties * The managed object's properties. * @param configEntry * The configuration entry associated with the managed * object. */ ServerManagedObject(ManagedObjectPath<?, S> path, ManagedObjectDefinition<?, S> d, Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) { this.definition = d; this.path = path; this.properties = properties; this.configEntry = configEntry; } /** * Deregisters an existing configuration add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener( InstantiableRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing server managed object add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener( InstantiableRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing configuration add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener( OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).getParent(); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing server managed object add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener( OptionalRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).getParent(); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing configuration add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener( SetRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing server managed object add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener( SetRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException { 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<? super S> listener) { for (ConfigChangeListener l : configEntry.getChangeListeners()) { 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(); configEntry.deregisterChangeListener(adaptor); } } } } } /** * Deregisters an existing server managed object change listener. * * @param listener * The server managed object change listener. */ public void deregisterChangeListener( ServerManagedObjectChangeListener<? super S> listener) { for (ConfigChangeListener l : configEntry.getChangeListeners()) { if (l instanceof ConfigChangeListenerAdaptor) { ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l; if (adaptor.getServerManagedObjectChangeListener() == listener) { adaptor.finalizeChangeListener(); configEntry.deregisterChangeListener(adaptor); } } } } /** * Deregisters an existing configuration delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener( InstantiableRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener( InstantiableRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing configuration delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener( OptionalRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).getParent(); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener( OptionalRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).getParent(); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing configuration delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener( SetRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener( SetRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Retrieve an instantiable child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild( InstantiableRelationDefinition<?, M> d, String name) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d, name)); } /** * Retrieve an optional child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild( OptionalRelationDefinition<?, M> d) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d)); } /** * Retrieve a set child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild( SetRelationDefinition<?, M> d, String name) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d, name)); } /** * Retrieve a singleton child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild( SingletonRelationDefinition<?, M> d) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d)); } /** * 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 (configEntry != null) { return configEntry.getDN(); } else { return DN.nullDN(); } } /** * Get the definition associated with this server managed object. * * @return Returns the definition associated with this server * managed object. */ public ManagedObjectDefinition<?, S> getManagedObjectDefinition() { return definition; } /** * Get the path of this server managed object. * * @return Returns the path of this server managed object. */ public ManagedObjectPath<?, S> 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 <code>null</code> indicating that * any default behavior is applicable. * * @param <T> * The type of the property to be retrieved. * @param d * The property to be retrieved. * @return Returns the property's effective value, or * <code>null</code> indicating that any default behavior * is applicable. * @throws IllegalArgumentException * If the property definition is not associated with this * managed object's definition. */ public <T> T getPropertyValue(PropertyDefinition<T> d) throws IllegalArgumentException { Set<T> values = getPropertyValues(d); if (values.isEmpty()) { return null; } else { return values.iterator().next(); } } /** * 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 <T> * 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. */ @SuppressWarnings("unchecked") public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d) throws IllegalArgumentException { if (!properties.containsKey(d)) { throw new IllegalArgumentException("Unknown property " + d.getName()); } return Collections.unmodifiableSortedSet((SortedSet<T>) 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 <code>true</code> if the optional managed * object exists, <code>false</code> otherwise. * @throws IllegalArgumentException * If the optional relation definition is not associated * with this managed object's definition. */ public boolean hasChild(OptionalRelationDefinition<?, ?> d) throws IllegalArgumentException { validateRelationDefinition(d); return context.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) throws IllegalArgumentException { validateRelationDefinition(d); return context.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) throws IllegalArgumentException { validateRelationDefinition(d); return context.listManagedObjects(path, d); } /** * Register to be notified when new child configurations are added * beneath an instantiable relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener( InstantiableRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>( listener)); } /** * Register to be notified when new child server managed object are * added beneath an instantiable relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener( InstantiableRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener); registerAddListener(baseDN, adaptor); } /** * Register to be notified when a new child configurations is added * beneath an optional relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener( OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>( listener)); } /** * Register to be notified when a new child server managed object is * added beneath an optional relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener( OptionalRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).getParent(); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener); registerAddListener(baseDN, adaptor); } /** * Register to be notified when new child configurations are added * beneath a set relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener( SetRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>( listener)); } /** * Register to be notified when new child server managed object are * added beneath a set relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener( SetRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(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<? super S> listener) { registerChangeListener(new ServerManagedObjectChangeListenerAdaptor<S>( listener)); } /** * Register to be notified when this server managed object is * changed. * * @param listener * The server managed object change listener. */ public void registerChangeListener( ServerManagedObjectChangeListener<? super S> listener) { ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(path, listener); configEntry.registerChangeListener(adaptor); // 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) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } } } /** * Register to be notified when existing child configurations are * deleted beneath an instantiable relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener( InstantiableRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>( listener)); } /** * Register to be notified when existing child server managed * objects are deleted beneath an instantiable relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener( InstantiableRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * Register to be notified when an existing child configuration is * deleted beneath an optional relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener( OptionalRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>( listener)); } /** * Register to be notified when an existing child server managed * object is deleted beneath an optional relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener( OptionalRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).getParent(); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * Register to be notified when existing child configurations are * deleted beneath a set relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener( SetRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>( listener)); } /** * Register to be notified when existing child server managed * objects are deleted beneath a set relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener( SetRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * {@inheritDoc} */ @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<PropertyDefinition<?>, 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<LocalizableMessage> reasons = new LinkedList<Message>(); 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; } } /** * Creates an new server side managed object. * * @param path * The managed object path. * @param d * The managed object definition. * @param properties * The managed object's properties. * @param configEntry * The configuration entry associated with the managed object. */ ServerManagedObject(ManagedObjectPath<?, S> path, ManagedObjectDefinition<?, S> d, Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) { this.definition = d; this.path = path; this.properties = properties; this.configEntry = configEntry; } if (!isUsable) { throw new ConstraintViolationException(this, reasons); } } /** * Deregisters an existing configuration add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); /** * Update the config entry 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 entry. * * @param configEntry * The configuration entry. */ void setConfigEntry(ConfigEntry configEntry) { this.configEntry = configEntry; } // Deregister an add listener. private <M extends Configuration> void deregisterAddListener(DN baseDN, ConfigurationAddListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigAddListener l : configEntry.getAddListeners()) { if (l instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l; ServerManagedObjectAddListener<?> l2 = adaptor .getServerManagedObjectAddListener(); if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) { ServerManagedObjectAddListenerAdaptor<?> adaptor2 = (ServerManagedObjectAddListenerAdaptor<?>) l2; if (adaptor2.getConfigurationAddListener() == listener) { configEntry.deregisterAddListener(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. if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } // Deregister an add listener. private <M extends Configuration> void deregisterAddListener(DN baseDN, ServerManagedObjectAddListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigAddListener l : configEntry.getAddListeners()) { if (l instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l; if (adaptor.getServerManagedObjectAddListener() == listener) { configEntry.deregisterAddListener(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. if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } // Deregister a delete listener. private <M extends Configuration> void deregisterDeleteListener(DN baseDN, ConfigurationDeleteListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigDeleteListener l : configEntry.getDeleteListeners()) { if (l instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l; ServerManagedObjectDeleteListener<?> l2 = adaptor .getServerManagedObjectDeleteListener(); if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) { ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = (ServerManagedObjectDeleteListenerAdaptor<?>) l2; if (adaptor2.getConfigurationDeleteListener() == listener) { configEntry.deregisterDeleteListener(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. if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } // Deregister a delete listener. private <M extends Configuration> void deregisterDeleteListener(DN baseDN, ServerManagedObjectDeleteListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigDeleteListener l : configEntry.getDeleteListeners()) { if (l instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l; if (adaptor.getServerManagedObjectDeleteListener() == listener) { configEntry.deregisterDeleteListener(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. if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } // Gets a config entry required for a listener and throws a config // exception on failure or returns null if the entry does not exist. private ConfigEntry getListenerConfigEntry(DN dn) throws ConfigException { // Attempt to retrieve the listener base entry. ConfigEntry configEntry; try { configEntry = DirectoryServer.getConfigEntry(dn); } catch (ConfigException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } LocalizableMessage message = ERR_ADMIN_CANNOT_GET_LISTENER_BASE.get( String.valueOf(dn), stackTraceToSingleLineString(e)); throw new ConfigException(message, e); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } return configEntry; } /** * Deregisters an existing server managed object add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); // Register an instantiable or optional relation add listener. private void registerAddListener(DN baseDN, ConfigAddListener adaptor) throws IllegalArgumentException, ConfigException { ConfigEntry relationEntry = getListenerConfigEntry(baseDN); if (relationEntry != null) { relationEntry.registerAddListener(adaptor); } else { // The relation entry does not exist yet so register a delayed // add listener. ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor); 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 parentDN = baseDN.getParent(); while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { delayedListener = new DelayedConfigAddListener(parentDN, delayedListener); parentDN = parentDN.getParent(); } else { relationEntry.registerAddListener(delayedListener); return; } DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } // No parent entry could be found. LocalizableMessage message = ERR_ADMIN_UNABLE_TO_REGISTER_LISTENER .get(String.valueOf(baseDN)); throw new ConfigException(message); } /** * Deregisters an existing configuration add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); // Deregister a delayed listener with the nearest existing parent // entry to the provided base DN. private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN, ConfigurationAddListener<M> listener) throws ConfigException { DN parentDN = baseDN.getParent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.getParent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if(l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; DN baseDN = DNBuilder.create(path, d).parent(); deregisterAddListener(baseDN, listener); } int i = delayWrappers; for(; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if(wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) { delayListener = (DelayedConfigAddListener) l; } else { break; } } /** * Deregisters an existing server managed object add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); if(i > 0) { // There are not enough level of wrapping so this can't be // the listener we are looking for. continue; } DN baseDN = DNBuilder.create(path, d).parent(); deregisterAddListener(baseDN, listener); } ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); /** * Deregisters an existing configuration add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); if (delayedListener != null && delayedListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener; ServerManagedObjectAddListener<?> l2 = adaptor .getServerManagedObjectAddListener(); if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) { ServerManagedObjectAddListenerAdaptor<?> adaptor2 = (ServerManagedObjectAddListenerAdaptor<?>) l2; if (adaptor2.getConfigurationAddListener() == listener) { relationEntry.deregisterAddListener(l); DN baseDN = DNBuilder.create(path, d); deregisterAddListener(baseDN, listener); } /** * Deregisters an existing server managed object add listener. * * @param <M> * 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 <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException { 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<? super S> listener) { for (ConfigChangeListener l : configEntry.getChangeListeners()) { 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(); configEntry.deregisterChangeListener(adaptor); } } } } } } return; } } } // Deregister a delayed listener with the nearest existing parent // entry to the provided base DN. private <M extends Configuration> void deregisterDelayedDeleteListener( DN baseDN, ConfigurationDeleteListener<M> listener) throws ConfigException { DN parentDN = baseDN.getParent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.getParent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if(l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; int i = delayWrappers; for(; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if(wrappedListener != null && 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 != null && delayedListener instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener; ServerManagedObjectDeleteListener<?> l2 = adaptor .getServerManagedObjectDeleteListener(); if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) { ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = (ServerManagedObjectDeleteListenerAdaptor<?>) l2; if (adaptor2.getConfigurationDeleteListener() == listener) { relationEntry.deregisterAddListener(l); /** * Deregisters an existing server managed object change listener. * * @param listener * The server managed object change listener. */ public void deregisterChangeListener(ServerManagedObjectChangeListener<? super S> listener) { for (ConfigChangeListener l : configEntry.getChangeListeners()) { if (l instanceof ConfigChangeListenerAdaptor) { ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l; if (adaptor.getServerManagedObjectChangeListener() == listener) { adaptor.finalizeChangeListener(); configEntry.deregisterChangeListener(adaptor); } } } } } return; } } } // Deregister a delayed listener with the nearest existing parent // entry to the provided base DN. private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN, ServerManagedObjectAddListener<M> listener) throws ConfigException { DN parentDN = baseDN.getParent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.getParent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if(l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; /** * Deregisters an existing configuration delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener(InstantiableRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); int i = delayWrappers; for(; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if(wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) { delayListener = (DelayedConfigAddListener) l; } else { break; } } DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } if(i > 0) { // There are not enough level of wrapping so this can't be // the listener we are looking for. continue; } /** * Deregisters an existing server managed object delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener(InstantiableRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } if (delayedListener != null && delayedListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener; if (adaptor.getServerManagedObjectAddListener() == listener) { relationEntry.deregisterAddListener(l); } } } /** * Deregisters an existing configuration delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener(OptionalRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener(OptionalRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing configuration delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener(SetRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Deregisters an existing server managed object delete listener. * * @param <M> * 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 <M extends Configuration> void deregisterDeleteListener(SetRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); deregisterDeleteListener(baseDN, listener); } /** * Retrieve an instantiable child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild(InstantiableRelationDefinition<?, M> d, String name) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d, name)); } /** * Retrieve an optional child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild(OptionalRelationDefinition<?, M> d) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d)); } /** * Retrieve a set child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild(SetRelationDefinition<?, M> d, String name) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d, name)); } /** * Retrieve a singleton child managed object. * * @param <M> * 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 <M extends Configuration> ServerManagedObject<? extends M> getChild(SingletonRelationDefinition<?, M> d) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); return context.getManagedObject(path.child(d)); } /** * 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 (configEntry != null) { return configEntry.getDN(); } else { return DN.rootDN(); } return; } } } /** * Get the definition associated with this server managed object. * * @return Returns the definition associated with this server managed * object. */ public ManagedObjectDefinition<?, S> getManagedObjectDefinition() { return definition; } // Deregister a delayed listener with the nearest existing parent // entry to the provided base DN. private <M extends Configuration> void deregisterDelayedDeleteListener( DN baseDN, ServerManagedObjectDeleteListener<M> listener) throws ConfigException { DN parentDN = baseDN.getParent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.getParent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if(l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; /** * Get the path of this server managed object. * * @return Returns the path of this server managed object. */ public ManagedObjectPath<?, S> getManagedObjectPath() { return path; } int i = delayWrappers; for(; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if(wrappedListener != null && 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 != null && delayedListener instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener; if (adaptor.getServerManagedObjectDeleteListener() == listener) { relationEntry.deregisterAddListener(l); } } } /** * 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 * <code>null</code> indicating that any default behavior is applicable. * * @param <T> * The type of the property to be retrieved. * @param d * The property to be retrieved. * @return Returns the property's effective value, or <code>null</code> * indicating that any default behavior is applicable. * @throws IllegalArgumentException * If the property definition is not associated with this * managed object's definition. */ public <T> T getPropertyValue(PropertyDefinition<T> d) throws IllegalArgumentException { Set<T> values = getPropertyValues(d); if (values.isEmpty()) { return null; } else { return values.iterator().next(); } return; } } } // Register an instantiable or optional relation delete listener. private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor) throws ConfigException { ConfigEntry relationEntry = getListenerConfigEntry(baseDN); if (relationEntry != null) { relationEntry.registerDeleteListener(adaptor); } else { // The relation entry does not exist yet so register a delayed // add listener. ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor); registerDelayedListener(baseDN, delayedListener); /** * 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 <T> * 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. */ @SuppressWarnings("unchecked") public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d) throws IllegalArgumentException { if (!properties.containsKey(d)) { throw new IllegalArgumentException("Unknown property " + d.getName()); } return Collections.unmodifiableSortedSet((SortedSet<T>) properties.get(d)); } } // Validate that a relation definition belongs to this managed // object. private void validateRelationDefinition(RelationDefinition<?, ?> rd) throws IllegalArgumentException { RelationDefinition<?, ?> tmp = definition.getRelationDefinition(rd .getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + definition.getName()); /** * Determines whether or not the optional managed object associated with the * specified optional relations exists. * * @param d * The optional relation definition. * @return Returns <code>true</code> if the optional managed object exists, * <code>false</code> otherwise. * @throws IllegalArgumentException * If the optional relation definition is not associated with * this managed object's definition. */ public boolean hasChild(OptionalRelationDefinition<?, ?> d) throws IllegalArgumentException { validateRelationDefinition(d); return context.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) throws IllegalArgumentException { validateRelationDefinition(d); return context.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) throws IllegalArgumentException { validateRelationDefinition(d); return context.listManagedObjects(path, d); } /** * Register to be notified when new child configurations are added beneath * an instantiable relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener(InstantiableRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener)); } /** * Register to be notified when new child server managed object are added * beneath an instantiable relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener(InstantiableRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener); registerAddListener(baseDN, adaptor); } /** * Register to be notified when a new child configurations is added beneath * an optional relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener(OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener)); } /** * Register to be notified when a new child server managed object is added * beneath an optional relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener(OptionalRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener); registerAddListener(baseDN, adaptor); } /** * Register to be notified when new child configurations are added beneath a * set relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener(SetRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException { registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener)); } /** * Register to be notified when new child server managed object are added * beneath a set relation. * * @param <M> * 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 <M extends Configuration> void registerAddListener(SetRelationDefinition<?, M> d, ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(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<? super S> listener) { registerChangeListener(new ServerManagedObjectChangeListenerAdaptor<S>(listener)); } /** * Register to be notified when this server managed object is changed. * * @param listener * The server managed object change listener. */ public void registerChangeListener(ServerManagedObjectChangeListener<? super S> listener) { ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(path, listener); configEntry.registerChangeListener(adaptor); // 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 <M> * 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 <M extends Configuration> void registerDeleteListener(InstantiableRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener)); } /** * Register to be notified when existing child server managed objects are * deleted beneath an instantiable relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener(InstantiableRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * Register to be notified when an existing child configuration is deleted * beneath an optional relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener(OptionalRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener)); } /** * Register to be notified when an existing child server managed object is * deleted beneath an optional relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener(OptionalRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d).parent(); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * Register to be notified when existing child configurations are deleted * beneath a set relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener(SetRelationDefinition<?, M> d, ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener)); } /** * Register to be notified when existing child server managed objects are * deleted beneath a set relation. * * @param <M> * 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 <M extends Configuration> void registerDeleteListener(SetRelationDefinition<?, M> d, ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException { validateRelationDefinition(d); DN baseDN = DNBuilder.create(path, d); ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener); registerDeleteListener(baseDN, adaptor); } /** * {@inheritDoc} */ @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<PropertyDefinition<?>, 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<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>(); 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 entry 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 entry. * * @param configEntry * The configuration entry. */ void setConfigEntry(ConfigEntry configEntry) { this.configEntry = configEntry; } // Deregister an add listener. private <M extends Configuration> void deregisterAddListener(DN baseDN, ConfigurationAddListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigAddListener l : configEntry.getAddListeners()) { if (l instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l; ServerManagedObjectAddListener<?> l2 = adaptor.getServerManagedObjectAddListener(); if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) { ServerManagedObjectAddListenerAdaptor<?> adaptor2 = (ServerManagedObjectAddListenerAdaptor<?>) l2; if (adaptor2.getConfigurationAddListener() == listener) { configEntry.deregisterAddListener(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 <M extends Configuration> void deregisterAddListener(DN baseDN, ServerManagedObjectAddListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigAddListener l : configEntry.getAddListeners()) { if (l instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l; if (adaptor.getServerManagedObjectAddListener() == listener) { configEntry.deregisterAddListener(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 a delete listener. private <M extends Configuration> void deregisterDeleteListener(DN baseDN, ConfigurationDeleteListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigDeleteListener l : configEntry.getDeleteListeners()) { if (l instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l; ServerManagedObjectDeleteListener<?> l2 = adaptor.getServerManagedObjectDeleteListener(); if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) { ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = (ServerManagedObjectDeleteListenerAdaptor<?>) l2; if (adaptor2.getConfigurationDeleteListener() == listener) { configEntry.deregisterDeleteListener(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 <M extends Configuration> void deregisterDeleteListener(DN baseDN, ServerManagedObjectDeleteListener<M> listener) { try { ConfigEntry configEntry = getListenerConfigEntry(baseDN); if (configEntry != null) { for (ConfigDeleteListener l : configEntry.getDeleteListeners()) { if (l instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l; if (adaptor.getServerManagedObjectDeleteListener() == listener) { configEntry.deregisterDeleteListener(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); } } // Gets a config entry required for a listener and throws a config // exception on failure or returns null if the entry does not exist. private ConfigEntry getListenerConfigEntry(DN dn) throws ConfigException { // Attempt to retrieve the listener base entry. ConfigEntry configEntry; try { configEntry = DirectoryServer.getConfigEntry(dn); } catch (ConfigException e) { logger.trace("Unable to get listener base entry", e); LocalizableMessage message = ERR_ADMIN_CANNOT_GET_LISTENER_BASE.get(String.valueOf(dn), stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD)); throw new ConfigException(message, e); } return configEntry; } // Register an instantiable or optional relation add listener. private void registerAddListener(DN baseDN, ConfigAddListener adaptor) throws IllegalArgumentException, ConfigException { ConfigEntry relationEntry = getListenerConfigEntry(baseDN); if (relationEntry != null) { relationEntry.registerAddListener(adaptor); } else { // The relation entry does not exist yet so register a delayed // add listener. ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor); 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 parentDN = baseDN.parent(); while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { delayedListener = new DelayedConfigAddListener(parentDN, delayedListener); parentDN = parentDN.parent(); } else { relationEntry.registerAddListener(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 <M extends Configuration> void deregisterDelayedAddListener(DN baseDN, ConfigurationAddListener<M> listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if (l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener != null && 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; } ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); if (delayedListener != null && delayedListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener; ServerManagedObjectAddListener<?> l2 = adaptor.getServerManagedObjectAddListener(); if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) { ServerManagedObjectAddListenerAdaptor<?> adaptor2 = (ServerManagedObjectAddListenerAdaptor<?>) l2; if (adaptor2.getConfigurationAddListener() == listener) { relationEntry.deregisterAddListener(l); } } } } } return; } } } // Deregister a delayed listener with the nearest existing parent // entry to the provided base DN. private <M extends Configuration> void deregisterDelayedDeleteListener(DN baseDN, ConfigurationDeleteListener<M> listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if (l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener != null && 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 != null && delayedListener instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener; ServerManagedObjectDeleteListener<?> l2 = adaptor.getServerManagedObjectDeleteListener(); if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) { ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = (ServerManagedObjectDeleteListenerAdaptor<?>) l2; if (adaptor2.getConfigurationDeleteListener() == listener) { relationEntry.deregisterAddListener(l); } } } } } return; } } } // Deregister a delayed listener with the nearest existing parent // entry to the provided base DN. private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN, ServerManagedObjectAddListener<M> listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if (l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener != null && 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; } ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); if (delayedListener != null && delayedListener instanceof ConfigAddListenerAdaptor) { ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener; if (adaptor.getServerManagedObjectAddListener() == listener) { relationEntry.deregisterAddListener(l); } } } } return; } } } // Deregister a delayed listener with the nearest existing parent // entry to the provided base DN. private <M extends Configuration> void deregisterDelayedDeleteListener(DN baseDN, ServerManagedObjectDeleteListener<M> listener) throws ConfigException { DN parentDN = baseDN.parent(); int delayWrappers = 0; while (parentDN != null) { ConfigEntry relationEntry = getListenerConfigEntry(parentDN); if (relationEntry == null) { parentDN = parentDN.parent(); delayWrappers++; } else { for (ConfigAddListener l : relationEntry.getAddListeners()) { if (l instanceof DelayedConfigAddListener) { DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; ConfigAddListener wrappedListener; int i = delayWrappers; for (; i > 0; i--) { wrappedListener = delayListener.getDelayedAddListener(); if (wrappedListener != null && 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 != null && delayedListener instanceof ConfigDeleteListenerAdaptor) { ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener; if (adaptor.getServerManagedObjectDeleteListener() == listener) { relationEntry.deregisterAddListener(l); } } } } return; } } } // Register an instantiable or optional relation delete listener. private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor) throws ConfigException { ConfigEntry relationEntry = getListenerConfigEntry(baseDN); if (relationEntry != null) { relationEntry.registerDeleteListener(adaptor); } else { // The relation entry does not exist yet so register a delayed // add listener. ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor); registerDelayedListener(baseDN, delayedListener); } } // Validate that a relation definition belongs to this managed // object. private void validateRelationDefinition(RelationDefinition<?, ?> rd) throws IllegalArgumentException { RelationDefinition<?, ?> tmp = definition.getRelationDefinition(rd.getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + definition.getName()); } } } opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java
@@ -27,8 +27,6 @@ package org.opends.server.admin.server; import static com.forgerock.opendj.ldap.AdminMessages.*; import java.util.Collection; @@ -42,107 +40,90 @@ import org.opends.server.admin.PropertyException; import static com.forgerock.opendj.util.Validator.*; /** * The requested server managed object was found but one or more of * its properties could not be decoded successfully. * The requested server managed object was found but one or more of its * properties could not be decoded successfully. */ public class ServerManagedObjectDecodingException extends DecodingException { /** * Version ID required by serializable classes. */ private static final long serialVersionUID = 1598401431084729853L; /** * Version ID required by serializable classes. */ private static final long serialVersionUID = 1598401431084729853L; // Create the message. private static LocalizableMessage createMessage(ServerManagedObject<?> partialManagedObject, Collection<PropertyException> causes) { ensureNotNull(causes); ensureTrue(!causes.isEmpty(), "causes should nnot be empty"); ManagedObjectDefinition<?, ?> d = partialManagedObject.getManagedObjectDefinition(); if (causes.size() == 1) { return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_SINGLE.get(d.getUserFriendlyName(), causes.iterator().next() .getLocalizableMessageObject()); } else { LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); // Create the message. private static LocalizableMessage createMessage( ServerManagedObject<?> partialManagedObject, Collection<PropertyException> causes) { ensureNotNull(causes); ensureTrue(!causes.isEmpty(), "causes should nnot be empty"); boolean isFirst = true; for (PropertyException cause : causes) { if (!isFirst) { builder.append("; "); } builder.append(cause.getLocalizableMessageObject()); isFirst = false; } ManagedObjectDefinition<?, ?> d = partialManagedObject .getManagedObjectDefinition(); if (causes.size() == 1) { return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_SINGLE.get(d .getUserFriendlyName(), causes.iterator().next().getMessageObject()); } else { LocalizableMessageBuilder builder = new MessageBuilder(); boolean isFirst = true; for (PropertyException cause : causes) { if (!isFirst) { builder.append("; "); return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_PLURAL.get(d.getUserFriendlyName(), builder.toMessage()); } builder.append(cause.getMessageObject()); isFirst = false; } return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_PLURAL.get(d .getUserFriendlyName(), builder.toMessage()); } } // The exception(s) that caused this decoding exception. private final Collection<PropertyException> causes; // The exception(s) that caused this decoding exception. private final Collection<PropertyException> causes; // The partially created server managed object. private final ServerManagedObject<?> partialManagedObject; // The partially created server managed object. private final ServerManagedObject<?> partialManagedObject; /** * Create a new property decoding exception. * * @param partialManagedObject * The partially created server managed object containing * properties which were successfully decoded and empty * properties for those which were not (this may include empty * mandatory properties). * @param causes * The exception(s) that caused this decoding exception. */ public ServerManagedObjectDecodingException(ServerManagedObject<?> partialManagedObject, Collection<PropertyException> causes) { super(createMessage(partialManagedObject, causes)); this.partialManagedObject = partialManagedObject; this.causes = Collections.unmodifiableList(new LinkedList<PropertyException>(causes)); } /** * Create a new property decoding exception. * * @param partialManagedObject * The partially created server managed object containing * properties which were successfully decoded and empty * properties for those which were not (this may include * empty mandatory properties). * @param causes * The exception(s) that caused this decoding exception. */ public ServerManagedObjectDecodingException( ServerManagedObject<?> partialManagedObject, Collection<PropertyException> causes) { super(createMessage(partialManagedObject, causes)); /** * Get an unmodifiable collection view of the causes of this exception. * * @return Returns an unmodifiable collection view of the causes of this * exception. */ public Collection<PropertyException> getCauses() { return causes; } this.partialManagedObject = partialManagedObject; this.causes = Collections .unmodifiableList(new LinkedList<PropertyException>(causes)); } /** * Get an unmodifiable collection view of the causes of this * exception. * * @return Returns an unmodifiable collection view of the causes of * this exception. */ public Collection<PropertyException> getCauses() { return causes; } /** * Get the partially created server managed object containing * properties which were successfully decoded and empty properties * for those which were not (this may include empty mandatory * properties). * * @return Returns the partially created server managed object * containing properties which were successfully decoded and * empty properties for those which were not (this may * include empty mandatory properties). */ public ServerManagedObject<?> getPartialManagedObject() { return partialManagedObject; } /** * Get the partially created server managed object containing properties * which were successfully decoded and empty properties for those which were * not (this may include empty mandatory properties). * * @return Returns the partially created server managed object containing * properties which were successfully decoded and empty properties * for those which were not (this may include empty mandatory * properties). */ public ServerManagedObject<?> getPartialManagedObject() { return partialManagedObject; } } opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java
@@ -27,11 +27,7 @@ package org.opends.server.admin.server; import static com.forgerock.opendj.ldap.AdminMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.util.StaticUtils.*; import java.util.ArrayList; import java.util.Collection; @@ -76,911 +72,783 @@ import org.opends.server.admin.UndefinedDefaultBehaviorProvider; import org.opends.server.admin.UnknownPropertyDefinitionException; import org.opends.server.admin.DefinitionDecodingException.Reason; import org.opends.server.admin.std.meta.RootCfgDefn; import org.opends.server.admin.std.server.RootCfg; import org.opends.server.api.AttributeValueDecoder; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; import org.forgerock.opendj.admin.meta.RootCfgDefn; import org.forgerock.opendj.admin.server.RootCfg; import org.forgerock.opendj.ldap.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DirectoryException; /** * Server management connection context. */ public final class ServerManagementContext { /** * A default behavior visitor used for retrieving the default values * of a property. * * @param <T> * The type of the property. */ private class DefaultValueFinder<T> implements DefaultBehaviorProviderVisitor<T, Collection<T>, Void> { /** * A default behavior visitor used for retrieving the default values of a * property. * * @param <T> * The type of the property. */ private class DefaultValueFinder<T> implements DefaultBehaviorProviderVisitor<T, Collection<T>, Void> { // Any exception that occurred whilst retrieving inherited default // values. private DefaultBehaviorException exception = null; // Any exception that occurred whilst retrieving inherited default // values. private DefaultBehaviorException exception = null; // Optional new configuration entry which does not yet exist in // the configuration back-end. private final ConfigEntry newConfigEntry; // Optional new configuration entry which does not yet exist in // the configuration back-end. private final ConfigEntry newConfigEntry; // The path of the managed object containing the next property. private ManagedObjectPath<?, ?> nextPath = null; // The path of the managed object containing the next property. private ManagedObjectPath<?, ?> nextPath = null; // The next property whose default values were required. private PropertyDefinition<T> nextProperty = null; // The next property whose default values were required. private PropertyDefinition<T> nextProperty = null; // Private constructor. private DefaultValueFinder(ConfigEntry newConfigEntry) { this.newConfigEntry = newConfigEntry; } /** * {@inheritDoc} */ public Collection<T> visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(), d.getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } /** * {@inheritDoc} */ public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d, Void p) { Collection<String> stringValues = d.getDefaultValues(); List<T> values = new ArrayList<T>(stringValues.size()); for (String stringValue : stringValues) { try { values.add(nextProperty.decodeValue(stringValue)); } catch (IllegalPropertyValueStringException e) { exception = new DefaultBehaviorException(nextProperty, e); break; } } return values; } /** * {@inheritDoc} */ public Collection<T> visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(nextPath), d.getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } // Find the default values for the next path/property. private Collection<T> find(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd) throws DefaultBehaviorException { nextPath = p; nextProperty = pd; Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept(this, null); if (exception != null) { throw exception; } if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { throw new DefaultBehaviorException(pd, new PropertyIsSingleValuedException(pd)); } return values; } // Get an inherited property value. @SuppressWarnings("unchecked") private Collection<T> getInheritedProperty(ManagedObjectPath target, AbstractManagedObjectDefinition<?, ?> d, String propertyName) throws DefaultBehaviorException { // First check that the requested type of managed object // corresponds to the path. AbstractManagedObjectDefinition<?, ?> supr = target.getManagedObjectDefinition(); if (!supr.isParentOf(d)) { throw new DefaultBehaviorException(nextProperty, new DefinitionDecodingException(supr, Reason.WRONG_TYPE_INFORMATION)); } // Save the current property in case of recursion. PropertyDefinition<T> pd1 = nextProperty; try { // Get the actual managed object definition. DN dn = DNBuilder.create(target); ConfigEntry configEntry; if (newConfigEntry != null && newConfigEntry.getDN().equals(dn)) { configEntry = newConfigEntry; } else { configEntry = getManagedObjectConfigEntry(dn); } DefinitionResolver resolver = new MyDefinitionResolver(configEntry); ManagedObjectDefinition<?, ?> mod = d.resolveManagedObjectDefinition(resolver); PropertyDefinition<T> pd2; try { PropertyDefinition<?> pdTmp = mod.getPropertyDefinition(propertyName); pd2 = pd1.getClass().cast(pdTmp); } catch (IllegalArgumentException e) { throw new PropertyNotFoundException(propertyName); } catch (ClassCastException e) { // FIXME: would be nice to throw a better exception here. throw new PropertyNotFoundException(propertyName); } List<AttributeValue> values = getAttribute(mod, pd2, configEntry); if (values.isEmpty()) { // Recursively retrieve this property's default values. Collection<T> tmp = find(target, pd2); Collection<T> pvalues = new ArrayList<T>(tmp.size()); for (T value : tmp) { pd1.validateValue(value); pvalues.add(value); } return pvalues; } else { Collection<T> pvalues = new ArrayList<T>(values.size()); for (AttributeValue value : values) { pvalues.add(ValueDecoder.decode(pd1, value)); } return pvalues; } } catch (DefinitionDecodingException e) { throw new DefaultBehaviorException(pd1, e); } catch (PropertyNotFoundException e) { throw new DefaultBehaviorException(pd1, e); } catch (IllegalPropertyValueException e) { throw new DefaultBehaviorException(pd1, e); } catch (IllegalPropertyValueStringException e) { throw new DefaultBehaviorException(pd1, e); } catch (ConfigException e) { throw new DefaultBehaviorException(pd1, e); } } } /** * A definition resolver that determines the managed object definition from * the object classes of a ConfigEntry. */ private class MyDefinitionResolver implements DefinitionResolver { // The config entry. private final ConfigEntry entry; // Private constructor. private MyDefinitionResolver(ConfigEntry entry) { this.entry = entry; } /** * {@inheritDoc} */ public boolean matches(AbstractManagedObjectDefinition<?, ?> d) { String oc = LDAPProfile.getInstance().getObjectClass(d); return entry.hasObjectClass(oc); } } /** * A visitor which is used to decode property LDAP values. */ private static final class ValueDecoder extends PropertyDefinitionVisitor<Object, String> { /** * Decodes the provided property LDAP value. * * @param <PD> * The type of the property. * @param pd * The property definition. * @param value * The LDAP string representation. * @return Returns the decoded LDAP value. * @throws IllegalPropertyValueStringException * If the property value could not be decoded because it was * invalid. */ public static <PD> PD decode(PropertyDefinition<PD> pd, AttributeValue value) throws IllegalPropertyValueStringException { String s = value.getValue().toString(); return pd.castValue(pd.accept(new ValueDecoder(), s)); } // Prevent instantiation. private ValueDecoder() { // No implementation required. } /** * {@inheritDoc} */ @Override public <C extends ConfigurationClient, S extends Configuration> Object visitAggregation( AggregationPropertyDefinition<C, S> d, String p) { // Aggregations values are stored as full DNs in LDAP, but // just their common name is exposed in the admin framework. try { Reference<C, S> reference = Reference.parseDN(d.getParentPath(), d.getRelationDefinition(), p); return reference.getName(); } catch (IllegalArgumentException e) { throw new IllegalPropertyValueStringException(d, p); } } /** * {@inheritDoc} */ @Override public <T> Object visitUnknown(PropertyDefinition<T> d, String p) throws UnknownPropertyDefinitionException { // By default the property definition's decoder will do. return d.decodeValue(p); } } // Singleton instance. private final static ServerManagementContext INSTANCE = new ServerManagementContext(); /** * The root server managed object. */ private static final ServerManagedObject<RootCfg> ROOT = new ServerManagedObject<RootCfg>( ManagedObjectPath.emptyPath(), RootCfgDefn.getInstance(), Collections.<PropertyDefinition<?>, SortedSet<?>> emptyMap(), null); /** * Get the single server-side management context. * * @return Returns the single server-side management context. */ public static ServerManagementContext getInstance() { return INSTANCE; } // Private constructor. private DefaultValueFinder(ConfigEntry newConfigEntry) { this.newConfigEntry = newConfigEntry; private ServerManagementContext() { // No implementation required. } /** * {@inheritDoc} * Gets the named managed object. * * @param <C> * The type of client managed object configuration that the path * definition refers to. * @param <S> * The type of server managed object configuration that the path * definition refers to. * @param path * The path of the managed object. * @return Returns the named managed object. * @throws ConfigException * If the named managed object could not be found or if it could * not be decoded. */ public Collection<T> visitAbsoluteInherited( AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(), d .getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } /** * {@inheritDoc} */ public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d, Void p) { Collection<String> stringValues = d.getDefaultValues(); List<T> values = new ArrayList<T>(stringValues.size()); for (String stringValue : stringValues) { try { values.add(nextProperty.decodeValue(stringValue)); } catch (IllegalPropertyValueStringException e) { exception = new DefaultBehaviorException(nextProperty, e); break; } } return values; } /** * {@inheritDoc} */ public Collection<T> visitRelativeInherited( RelativeInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(nextPath), d .getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } // Find the default values for the next path/property. private Collection<T> find(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd) throws DefaultBehaviorException { nextPath = p; nextProperty = pd; Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept( this, null); if (exception != null) { throw exception; } if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { throw new DefaultBehaviorException(pd, new PropertyIsSingleValuedException(pd)); } return values; } // Get an inherited property value. @SuppressWarnings("unchecked") private Collection<T> getInheritedProperty(ManagedObjectPath target, AbstractManagedObjectDefinition<?, ?> d, String propertyName) throws DefaultBehaviorException { // First check that the requested type of managed object // corresponds to the path. AbstractManagedObjectDefinition<?, ?> supr = target .getManagedObjectDefinition(); if (!supr.isParentOf(d)) { throw new DefaultBehaviorException( nextProperty, new DefinitionDecodingException(supr, Reason.WRONG_TYPE_INFORMATION)); } // Save the current property in case of recursion. PropertyDefinition<T> pd1 = nextProperty; try { // Get the actual managed object definition. DN dn = DNBuilder.create(target); ConfigEntry configEntry; if (newConfigEntry != null && newConfigEntry.getDN().equals(dn)) { configEntry = newConfigEntry; } else { configEntry = getManagedObjectConfigEntry(dn); public <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> getManagedObject( ManagedObjectPath<C, S> path) throws ConfigException { // Be careful to handle the root configuration. if (path.isEmpty()) { return (ServerManagedObject<S>) getRootConfigurationManagedObject(); } // Get the configuration entry. DN targetDN = DNBuilder.create(path); ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN); try { ServerManagedObject<? extends S> managedObject; managedObject = decode(path, configEntry); // Enforce any constraints. managedObject.ensureIsUsable(); return managedObject; } catch (DefinitionDecodingException e) { throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(targetDN, e); } catch (ServerManagedObjectDecodingException e) { throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(e); } catch (ConstraintViolationException e) { throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(e); } } /** * Gets the effective value of a property in the named managed object. * * @param <C> * The type of client managed object configuration that the path * definition refers to. * @param <S> * The type of server managed object configuration that the path * definition refers to. * @param <PD> * The type of the property to be retrieved. * @param path * The path of the managed object containing the property. * @param pd * The property to be retrieved. * @return Returns the property's effective value, or <code>null</code> if * there are no values defined. * @throws IllegalArgumentException * If the property definition is not associated with the * referenced managed object's definition. * @throws PropertyException * If the managed object was found but the requested property * could not be decoded. * @throws ConfigException * If the named managed object could not be found or if it could * not be decoded. */ public <C extends ConfigurationClient, S extends Configuration, PD> PD getPropertyValue( ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, ConfigException, PropertyException { SortedSet<PD> values = getPropertyValues(path, pd); if (values.isEmpty()) { return null; } else { return values.first(); } } /** * Gets the effective values of a property in the named managed object. * * @param <C> * The type of client managed object configuration that the path * definition refers to. * @param <S> * The type of server managed object configuration that the path * definition refers to. * @param <PD> * The type of the property to be retrieved. * @param path * The path of the managed object containing the property. * @param pd * The property to be retrieved. * @return Returns the property's effective values, or an empty set if there * are no values defined. * @throws IllegalArgumentException * If the property definition is not associated with the * referenced managed object's definition. * @throws PropertyException * If the managed object was found but the requested property * could not be decoded. * @throws ConfigException * If the named managed object could not be found or if it could * not be decoded. */ @SuppressWarnings("unchecked") public <C extends ConfigurationClient, S extends Configuration, PD> SortedSet<PD> getPropertyValues( ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, ConfigException, PropertyException { // Check that the requested property is from the definition // associated with the path. AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition(); PropertyDefinition<?> tmp = d.getPropertyDefinition(pd.getName()); if (tmp != pd) { throw new IllegalArgumentException("The property " + pd.getName() + " is not associated with a " + d.getName()); } // Determine the exact type of managed object referenced by the // path. DN dn = DNBuilder.create(path); ConfigEntry configEntry = getManagedObjectConfigEntry(dn); DefinitionResolver resolver = new MyDefinitionResolver(configEntry); ManagedObjectDefinition<?, ?> mod = d .resolveManagedObjectDefinition(resolver); ManagedObjectDefinition<? extends C, ? extends S> mod; PropertyDefinition<T> pd2; try { PropertyDefinition<?> pdTmp = mod.getPropertyDefinition(propertyName); pd2 = pd1.getClass().cast(pdTmp); } catch (IllegalArgumentException e) { throw new PropertyNotFoundException(propertyName); } catch (ClassCastException e) { // FIXME: would be nice to throw a better exception here. throw new PropertyNotFoundException(propertyName); mod = d.resolveManagedObjectDefinition(resolver); } catch (DefinitionDecodingException e) { throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(dn, e); } List<AttributeValue> values = getAttribute(mod, pd2, configEntry); if (values.isEmpty()) { // Recursively retrieve this property's default values. Collection<T> tmp = find(target, pd2); Collection<T> pvalues = new ArrayList<T>(tmp.size()); for (T value : tmp) { pd1.validateValue(value); pvalues.add(value); } return pvalues; } else { Collection<T> pvalues = new ArrayList<T>(values.size()); for (AttributeValue value : values) { pvalues.add(ValueDecoder.decode(pd1, value)); } return pvalues; } } catch (DefinitionDecodingException e) { throw new DefaultBehaviorException(pd1, e); } catch (PropertyNotFoundException e) { throw new DefaultBehaviorException(pd1, e); } catch (IllegalPropertyValueException e) { throw new DefaultBehaviorException(pd1, e); } catch (IllegalPropertyValueStringException e) { throw new DefaultBehaviorException(pd1, e); } catch (ConfigException e) { throw new DefaultBehaviorException(pd1, e); } // Make sure we use the correct property definition, the // provided one might have been overridden in the resolved // definition. pd = (PropertyDefinition<PD>) mod.getPropertyDefinition(pd.getName()); List<AttributeValue> values = getAttribute(mod, pd, configEntry); return decodeProperty(path.asSubType(mod), pd, values, null); } } /** * A definition resolver that determines the managed object * definition from the object classes of a ConfigEntry. */ private class MyDefinitionResolver implements DefinitionResolver { // The config entry. private final ConfigEntry entry; // Private constructor. private MyDefinitionResolver(ConfigEntry entry) { this.entry = entry; } /** * {@inheritDoc} */ public boolean matches(AbstractManagedObjectDefinition<?, ?> d) { String oc = LDAPProfile.getInstance().getObjectClass(d); return entry.hasObjectClass(oc); } } /** * A visitor which is used to decode property LDAP values. */ private static final class ValueDecoder extends PropertyDefinitionVisitor<Object, String> { /** * Decodes the provided property LDAP value. * Get the root configuration manager associated with this management * context. * * @param <PD> * The type of the property. * @param pd * The property definition. * @param value * The LDAP string representation. * @return Returns the decoded LDAP value. * @throws IllegalPropertyValueStringException * If the property value could not be decoded because it * was invalid. * @return Returns the root configuration manager associated with this * management context. */ public static <PD> PD decode(PropertyDefinition<PD> pd, AttributeValue value) throws IllegalPropertyValueStringException { String s = value.getValue().toString(); return pd.castValue(pd.accept(new ValueDecoder(), s)); public RootCfg getRootConfiguration() { return getRootConfigurationManagedObject().getConfiguration(); } // Prevent instantiation. private ValueDecoder() { // No implementation required. } /** * {@inheritDoc} * Get the root configuration server managed object associated with this * management context. * * @return Returns the root configuration server managed object associated * with this management context. */ @Override public <C extends ConfigurationClient, S extends Configuration> Object visitAggregation(AggregationPropertyDefinition<C, S> d, String p) { // Aggregations values are stored as full DNs in LDAP, but // just their common name is exposed in the admin framework. try { Reference<C, S> reference = Reference.parseDN(d.getParentPath(), d .getRelationDefinition(), p); return reference.getName(); } catch (IllegalArgumentException e) { throw new IllegalPropertyValueStringException(d, p); } public ServerManagedObject<RootCfg> getRootConfigurationManagedObject() { return ROOT; } /** * {@inheritDoc} * Lists the child managed objects of the named parent managed object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The instantiable relation definition. * @return Returns the names of the child managed objects. * @throws IllegalArgumentException * If the relation definition is not associated with the parent * managed object's definition. */ @Override public <T> Object visitUnknown(PropertyDefinition<T> d, String p) throws UnknownPropertyDefinitionException { // By default the property definition's decoder will do. return d.decodeValue(p); } } public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd) throws IllegalArgumentException { validateRelationDefinition(parent, rd); // Singleton instance. private final static ServerManagementContext INSTANCE = new ServerManagementContext(); /** * The root server managed object. */ private static final ServerManagedObject<RootCfg> ROOT = new ServerManagedObject<RootCfg>( ManagedObjectPath.emptyPath(), RootCfgDefn.getInstance(), Collections .<PropertyDefinition<?>, SortedSet<?>> emptyMap(), null); /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); /** * Get the single server-side management context. * * @return Returns the single server-side management context. */ public static ServerManagementContext getInstance() { return INSTANCE; } // Private constructor. private ServerManagementContext() { // No implementation required. } /** * Gets the named managed object. * * @param <C> * The type of client managed object configuration that the * path definition refers to. * @param <S> * The type of server managed object configuration that the * path definition refers to. * @param path * The path of the managed object. * @return Returns the named managed object. * @throws ConfigException * If the named managed object could not be found or if it * could not be decoded. */ @SuppressWarnings("unchecked") public <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> getManagedObject( ManagedObjectPath<C, S> path) throws ConfigException { // Be careful to handle the root configuration. if (path.isEmpty()) { return (ServerManagedObject<S>) getRootConfigurationManagedObject(); } // Get the configuration entry. DN targetDN = DNBuilder.create(path); ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN); try { ServerManagedObject<? extends S> managedObject; managedObject = decode(path, configEntry); // Enforce any constraints. managedObject.ensureIsUsable(); return managedObject; } catch (DefinitionDecodingException e) { throw ConfigExceptionFactory.getInstance() .createDecodingExceptionAdaptor(targetDN, e); } catch (ServerManagedObjectDecodingException e) { throw ConfigExceptionFactory.getInstance() .createDecodingExceptionAdaptor(e); } catch (ConstraintViolationException e) { throw ConfigExceptionFactory.getInstance() .createDecodingExceptionAdaptor(e); } } /** * Gets the effective value of a property in the named managed * object. * * @param <C> * The type of client managed object configuration that the * path definition refers to. * @param <S> * The type of server managed object configuration that the * path definition refers to. * @param <PD> * The type of the property to be retrieved. * @param path * The path of the managed object containing the property. * @param pd * The property to be retrieved. * @return Returns the property's effective value, or * <code>null</code> if there are no values defined. * @throws IllegalArgumentException * If the property definition is not associated with the * referenced managed object's definition. * @throws PropertyException * If the managed object was found but the requested * property could not be decoded. * @throws ConfigException * If the named managed object could not be found or if it * could not be decoded. */ public <C extends ConfigurationClient, S extends Configuration, PD> PD getPropertyValue(ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, ConfigException, PropertyException { SortedSet<PD> values = getPropertyValues(path, pd); if (values.isEmpty()) { return null; } else { return values.first(); } } /** * Gets the effective values of a property in the named managed * object. * * @param <C> * The type of client managed object configuration that the * path definition refers to. * @param <S> * The type of server managed object configuration that the * path definition refers to. * @param <PD> * The type of the property to be retrieved. * @param path * The path of the managed object containing the property. * @param pd * The property to be retrieved. * @return Returns the property's effective values, or an empty set * if there are no values defined. * @throws IllegalArgumentException * If the property definition is not associated with the * referenced managed object's definition. * @throws PropertyException * If the managed object was found but the requested * property could not be decoded. * @throws ConfigException * If the named managed object could not be found or if it * could not be decoded. */ @SuppressWarnings("unchecked") public <C extends ConfigurationClient, S extends Configuration, PD> SortedSet<PD> getPropertyValues(ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, ConfigException, PropertyException { // Check that the requested property is from the definition // associated with the path. AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition(); PropertyDefinition<?> tmp = d.getPropertyDefinition(pd.getName()); if (tmp != pd) { throw new IllegalArgumentException("The property " + pd.getName() + " is not associated with a " + d.getName()); } // Determine the exact type of managed object referenced by the // path. DN dn = DNBuilder.create(path); ConfigEntry configEntry = getManagedObjectConfigEntry(dn); DefinitionResolver resolver = new MyDefinitionResolver(configEntry); ManagedObjectDefinition<? extends C, ? extends S> mod; try { mod = d.resolveManagedObjectDefinition(resolver); } catch (DefinitionDecodingException e) { throw ConfigExceptionFactory.getInstance() .createDecodingExceptionAdaptor(dn, e); } // Make sure we use the correct property definition, the // provided one might have been overridden in the resolved // definition. pd = (PropertyDefinition<PD>) mod.getPropertyDefinition(pd.getName()); List<AttributeValue> values = getAttribute(mod, pd, configEntry); return decodeProperty(path.asSubType(mod), pd, values, null); } /** * Get the root configuration manager associated with this * management context. * * @return Returns the root configuration manager associated with * this management context. */ public RootCfg getRootConfiguration() { return getRootConfigurationManagedObject().getConfiguration(); } /** * Get the root configuration server managed object associated with * this management context. * * @return Returns the root configuration server managed object * associated with this management context. */ public ServerManagedObject<RootCfg> getRootConfigurationManagedObject() { return ROOT; } /** * Lists the child managed objects of the named parent managed * object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The instantiable relation definition. * @return Returns the names of the child managed objects. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. */ public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd) throws IllegalArgumentException { validateRelationDefinition(parent, rd); // Get the target entry. DN targetDN = DNBuilder.create(parent, rd); ConfigEntry configEntry; try { configEntry = DirectoryServer.getConfigEntry(targetDN); } catch (ConfigException e) { return new String[0]; } if (configEntry == null) { return new String[0]; } // Retrieve the children. Set<DN> children = configEntry.getChildren().keySet(); ArrayList<String> names = new ArrayList<String>(children.size()); for (DN child : children) { // Assume that RDNs are single-valued and can be trimmed. AttributeValue av = child.getRDN().getAttributeValue(0); names.add(av.getValue().toString().trim()); } return names.toArray(new String[names.size()]); } /** * Lists the child managed objects of the named parent managed * object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The set relation definition. * @return Returns the names of the child managed objects. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. */ public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd) throws IllegalArgumentException { validateRelationDefinition(parent, rd); // Get the target entry. DN targetDN = DNBuilder.create(parent, rd); ConfigEntry configEntry; try { configEntry = DirectoryServer.getConfigEntry(targetDN); } catch (ConfigException e) { return new String[0]; } if (configEntry == null) { return new String[0]; } // Retrieve the children. Set<DN> children = configEntry.getChildren().keySet(); ArrayList<String> names = new ArrayList<String>(children.size()); for (DN child : children) { // Assume that RDNs are single-valued and can be trimmed. AttributeValue av = child.getRDN().getAttributeValue(0); names.add(av.toString().trim()); } return names.toArray(new String[names.size()]); } /** * Determines whether or not the named managed object exists. * * @param path * The path of the named managed object. * @return Returns <code>true</code> if the named managed object * exists, <code>false</code> otherwise. */ public boolean managedObjectExists(ManagedObjectPath<?, ?> path) { // Get the configuration entry. DN targetDN = DNBuilder.create(path); try { return (getManagedObjectConfigEntry(targetDN) != null); } catch (ConfigException e) { // Assume it doesn't exist. return false; } } /** * Decodes a configuration entry into the required type of server * managed object. * * @param <C> * The type of client managed object configuration that the * path definition refers to. * @param <S> * The type of server managed object configuration that the * path definition refers to. * @param path * The location of the server managed object. * @param configEntry * The configuration entry that should be decoded. * @return Returns the new server-side managed object from the * provided definition and configuration entry. * @throws DefinitionDecodingException * If the managed object's type could not be determined. * @throws ServerManagedObjectDecodingException * If one or more of the managed object's properties could * not be decoded. */ <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode( ManagedObjectPath<C, S> path, ConfigEntry configEntry) throws DefinitionDecodingException, ServerManagedObjectDecodingException { return decode(path, configEntry, null); } /** * Decodes a configuration entry into the required type of server * managed object. * * @param <C> * The type of client managed object configuration that the * path definition refers to. * @param <S> * The type of server managed object configuration that the * path definition refers to. * @param path * The location of the server managed object. * @param configEntry * The configuration entry that should be decoded. * @param newConfigEntry * Optional new configuration that does not exist yet in * the configuration back-end. This will be used for * resolving inherited default values. * @return Returns the new server-side managed object from the * provided definition and configuration entry. * @throws DefinitionDecodingException * If the managed object's type could not be determined. * @throws ServerManagedObjectDecodingException * If one or more of the managed object's properties could * not be decoded. */ <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode( ManagedObjectPath<C, S> path, ConfigEntry configEntry, ConfigEntry newConfigEntry) throws DefinitionDecodingException, ServerManagedObjectDecodingException { // First determine the correct definition to use for the entry. // This could either be the provided definition, or one of its // sub-definitions. DefinitionResolver resolver = new MyDefinitionResolver(configEntry); AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition(); ManagedObjectDefinition<? extends C, ? extends S> mod = d .resolveManagedObjectDefinition(resolver); // Build the managed object's properties. List<PropertyException> exceptions = new LinkedList<PropertyException>(); Map<PropertyDefinition<?>, SortedSet<?>> properties = new HashMap<PropertyDefinition<?>, SortedSet<?>>(); for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) { List<AttributeValue> values = getAttribute(mod, pd, configEntry); try { SortedSet<?> pvalues = decodeProperty(path, pd, values, newConfigEntry); properties.put(pd, pvalues); } catch (PropertyException e) { exceptions.add(e); } } // If there were no decoding problems then return the managed // object, otherwise throw an operations exception. ServerManagedObject<? extends S> mo = decodeAux(path, mod, properties, configEntry); if (exceptions.isEmpty()) { return mo; } else { throw new ServerManagedObjectDecodingException(mo, exceptions); } } // Decode helper method required to avoid generics warning. private <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<S> decodeAux( ManagedObjectPath<? super C, ? super S> path, ManagedObjectDefinition<C, S> d, Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) { ManagedObjectPath<C, S> newPath = path.asSubType(d); return new ServerManagedObject<S>(newPath, d, properties, configEntry); } // Create a property using the provided string values. private <T> SortedSet<T> decodeProperty(ManagedObjectPath<?, ?> path, PropertyDefinition<T> pd, List<AttributeValue> values, ConfigEntry newConfigEntry) throws PropertyException { PropertyException exception = null; SortedSet<T> pvalues = new TreeSet<T>(pd); if (!values.isEmpty()) { // The property has values defined for it. for (AttributeValue value : values) { // Get the target entry. DN targetDN = DNBuilder.create(parent, rd); ConfigEntry configEntry; try { pvalues.add(ValueDecoder.decode(pd, value)); } catch (IllegalPropertyValueStringException e) { exception = e; configEntry = DirectoryServer.getConfigEntry(targetDN); } catch (ConfigException e) { return new String[0]; } } } else { // No values defined so get the defaults. try { pvalues.addAll(getDefaultValues(path, pd, newConfigEntry)); } catch (DefaultBehaviorException e) { exception = e; } if (configEntry == null) { return new String[0]; } // Retrieve the children. Set<DN> children = configEntry.getChildren().keySet(); ArrayList<String> names = new ArrayList<String>(children.size()); for (DN child : children) { // Assume that RDNs are single-valued and can be trimmed. AttributeValue av = child.rdn().getAttributeValue(0); names.add(av.getValue().toString().trim()); } return names.toArray(new String[names.size()]); } if (pvalues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { // This exception takes precedence over previous exceptions. exception = new PropertyIsSingleValuedException(pd); T value = pvalues.first(); pvalues.clear(); pvalues.add(value); /** * Lists the child managed objects of the named parent managed object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The set relation definition. * @return Returns the names of the child managed objects. * @throws IllegalArgumentException * If the relation definition is not associated with the parent * managed object's definition. */ public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd) throws IllegalArgumentException { validateRelationDefinition(parent, rd); // Get the target entry. DN targetDN = DNBuilder.create(parent, rd); ConfigEntry configEntry; try { configEntry = DirectoryServer.getConfigEntry(targetDN); } catch (ConfigException e) { return new String[0]; } if (configEntry == null) { return new String[0]; } // Retrieve the children. Set<DN> children = configEntry.getChildren().keySet(); ArrayList<String> names = new ArrayList<String>(children.size()); for (DN child : children) { // Assume that RDNs are single-valued and can be trimmed. AttributeValue av = child.rdn().getAttributeValue(0); names.add(av.toString().trim()); } return names.toArray(new String[names.size()]); } if (pvalues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) { // The values maybe empty because of a previous exception. if (exception == null) { exception = new PropertyIsMandatoryException(pd); } /** * Determines whether or not the named managed object exists. * * @param path * The path of the named managed object. * @return Returns <code>true</code> if the named managed object exists, * <code>false</code> otherwise. */ public boolean managedObjectExists(ManagedObjectPath<?, ?> path) { // Get the configuration entry. DN targetDN = DNBuilder.create(path); try { return (getManagedObjectConfigEntry(targetDN) != null); } catch (ConfigException e) { // Assume it doesn't exist. return false; } } if (exception != null) { throw exception; } else { return pvalues; } } // Gets the attribute associated with a property from a ConfigEntry. private List<AttributeValue> getAttribute(ManagedObjectDefinition<?, ?> d, PropertyDefinition<?> pd, ConfigEntry configEntry) { // TODO: we create a default attribute type if it is // undefined. We should log a warning here if this is the case // since the attribute should have been defined. String attrID = LDAPProfile.getInstance().getAttributeName(d, pd); AttributeType type = DirectoryServer.getAttributeType(attrID, true); AttributeValueDecoder<AttributeValue> decoder = new AttributeValueDecoder<AttributeValue>() { public AttributeValue decode(AttributeValue value) throws DirectoryException { return value; } }; List<AttributeValue> values = new LinkedList<AttributeValue>(); try { configEntry.getEntry().getAttributeValues(type, decoder, values); } catch (DirectoryException e) { // Should not happen. throw new RuntimeException(e); } return values; } // Get the default values for the specified property. private <T> Collection<T> getDefaultValues(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd, ConfigEntry newConfigEntry) throws DefaultBehaviorException { DefaultValueFinder<T> v = new DefaultValueFinder<T>(newConfigEntry); return v.find(p, pd); } // Gets a config entry required for a managed object and throws a // config exception on failure. private ConfigEntry getManagedObjectConfigEntry( DN dn) throws ConfigException { ConfigEntry configEntry; try { configEntry = DirectoryServer.getConfigEntry(dn); } catch (ConfigException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } LocalizableMessage message = ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get( String.valueOf(dn), stackTraceToSingleLineString(e)); throw new ConfigException(message, e); /** * Decodes a configuration entry into the required type of server managed * object. * * @param <C> * The type of client managed object configuration that the path * definition refers to. * @param <S> * The type of server managed object configuration that the path * definition refers to. * @param path * The location of the server managed object. * @param configEntry * The configuration entry that should be decoded. * @return Returns the new server-side managed object from the provided * definition and configuration entry. * @throws DefinitionDecodingException * If the managed object's type could not be determined. * @throws ServerManagedObjectDecodingException * If one or more of the managed object's properties could not * be decoded. */ <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode( ManagedObjectPath<C, S> path, ConfigEntry configEntry) throws DefinitionDecodingException, ServerManagedObjectDecodingException { return decode(path, configEntry, null); } // The configuration handler is free to return null indicating // that the entry does not exist. if (configEntry == null) { LocalizableMessage message = ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST .get(String.valueOf(dn)); throw new ConfigException(message); /** * Decodes a configuration entry into the required type of server managed * object. * * @param <C> * The type of client managed object configuration that the path * definition refers to. * @param <S> * The type of server managed object configuration that the path * definition refers to. * @param path * The location of the server managed object. * @param configEntry * The configuration entry that should be decoded. * @param newConfigEntry * Optional new configuration that does not exist yet in the * configuration back-end. This will be used for resolving * inherited default values. * @return Returns the new server-side managed object from the provided * definition and configuration entry. * @throws DefinitionDecodingException * If the managed object's type could not be determined. * @throws ServerManagedObjectDecodingException * If one or more of the managed object's properties could not * be decoded. */ <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode( ManagedObjectPath<C, S> path, ConfigEntry configEntry, ConfigEntry newConfigEntry) throws DefinitionDecodingException, ServerManagedObjectDecodingException { // First determine the correct definition to use for the entry. // This could either be the provided definition, or one of its // sub-definitions. DefinitionResolver resolver = new MyDefinitionResolver(configEntry); AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition(); ManagedObjectDefinition<? extends C, ? extends S> mod = d.resolveManagedObjectDefinition(resolver); // Build the managed object's properties. List<PropertyException> exceptions = new LinkedList<PropertyException>(); Map<PropertyDefinition<?>, SortedSet<?>> properties = new HashMap<PropertyDefinition<?>, SortedSet<?>>(); for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) { List<AttributeValue> values = getAttribute(mod, pd, configEntry); try { SortedSet<?> pvalues = decodeProperty(path, pd, values, newConfigEntry); properties.put(pd, pvalues); } catch (PropertyException e) { exceptions.add(e); } } // If there were no decoding problems then return the managed // object, otherwise throw an operations exception. ServerManagedObject<? extends S> mo = decodeAux(path, mod, properties, configEntry); if (exceptions.isEmpty()) { return mo; } else { throw new ServerManagedObjectDecodingException(mo, exceptions); } } return configEntry; } // Validate that a relation definition belongs to the path. private void validateRelationDefinition(ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> rd) throws IllegalArgumentException { AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition(); RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + d.getName()); // Decode helper method required to avoid generics warning. private <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<S> decodeAux( ManagedObjectPath<? super C, ? super S> path, ManagedObjectDefinition<C, S> d, Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) { ManagedObjectPath<C, S> newPath = path.asSubType(d); return new ServerManagedObject<S>(newPath, d, properties, configEntry); } } // Create a property using the provided string values. private <T> SortedSet<T> decodeProperty(ManagedObjectPath<?, ?> path, PropertyDefinition<T> pd, List<AttributeValue> values, ConfigEntry newConfigEntry) throws PropertyException { PropertyException exception = null; SortedSet<T> pvalues = new TreeSet<T>(pd); if (!values.isEmpty()) { // The property has values defined for it. for (AttributeValue value : values) { try { pvalues.add(ValueDecoder.decode(pd, value)); } catch (IllegalPropertyValueStringException e) { exception = e; } } } else { // No values defined so get the defaults. try { pvalues.addAll(getDefaultValues(path, pd, newConfigEntry)); } catch (DefaultBehaviorException e) { exception = e; } } if (pvalues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { // This exception takes precedence over previous exceptions. exception = new PropertyIsSingleValuedException(pd); T value = pvalues.first(); pvalues.clear(); pvalues.add(value); } if (pvalues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) { // The values maybe empty because of a previous exception. if (exception == null) { exception = new PropertyIsMandatoryException(pd); } } if (exception != null) { throw exception; } else { return pvalues; } } // Gets the attribute associated with a property from a ConfigEntry. private List<AttributeValue> getAttribute(ManagedObjectDefinition<?, ?> d, PropertyDefinition<?> pd, ConfigEntry configEntry) { // TODO: we create a default attribute type if it is // undefined. We should log a warning here if this is the case // since the attribute should have been defined. String attrID = LDAPProfile.getInstance().getAttributeName(d, pd); AttributeType type = DirectoryServer.getAttributeType(attrID, true); AttributeValueDecoder<AttributeValue> decoder = new AttributeValueDecoder<AttributeValue>() { public AttributeValue decode(AttributeValue value) throws DirectoryException { return value; } }; List<AttributeValue> values = new LinkedList<AttributeValue>(); try { configEntry.getEntry().getAttributeValues(type, decoder, values); } catch (DirectoryException e) { // Should not happen. throw new RuntimeException(e); } return values; } // Get the default values for the specified property. private <T> Collection<T> getDefaultValues(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd, ConfigEntry newConfigEntry) throws DefaultBehaviorException { DefaultValueFinder<T> v = new DefaultValueFinder<T>(newConfigEntry); return v.find(p, pd); } // Gets a config entry required for a managed object and throws a // config exception on failure. private ConfigEntry getManagedObjectConfigEntry(DN dn) throws ConfigException { ConfigEntry configEntry; try { configEntry = DirectoryServer.getConfigEntry(dn); } catch (ConfigException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } LocalizableMessage message = ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get(String.valueOf(dn), stackTraceToSingleLineString(e)); throw new ConfigException(message, e); } // The configuration handler is free to return null indicating // that the entry does not exist. if (configEntry == null) { LocalizableMessage message = ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST.get(String.valueOf(dn)); throw new ConfigException(message); } return configEntry; } // Validate that a relation definition belongs to the path. private void validateRelationDefinition(ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> rd) throws IllegalArgumentException { AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition(); RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + d.getName()); } } }