opends/resource/config/synchronization.ldif
@@ -13,16 +13,22 @@ dn: cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config objectClass: top objectClass: ds-cfg-synchronization-provider objectClass: ds-cfg-multimaster-synchronization-provider ds-cfg-synchronization-provider-enabled: true ds-cfg-synchronization-provider-class: org.opends.server.synchronization.plugin.MultimasterSynchronization dn: cn=example, cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config dn: cn=domains, cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config objectClass: top objectClass: ds-cfg-branch cn: domains dn: cn=example, cn=domains, cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config objectClass: top objectClass: ds-cfg-synchronization-provider-config cn: example ds-cfg-synchronization-dn: dc=example,dc=com ds-cfg-changelog-server: host1:8989 ds-cfg-changelog-server: host2:8989 ds-cfg-changelog-server: localhost:8989 ds-cfg-changelog-server: localhost:8990 ds-cfg-directory-server-id: 1 ds-cfg-receive-status: true @@ -31,7 +37,7 @@ objectClass: ds-cfg-synchronization-changelog-server-config cn: Changelog Server ds-cfg-changelog-port: 8989 ds-cfg-changelog-server: host1:8989 ds-cfg-changelog-server: host2:8989 ds-cfg-changelog-server: localhost:8989 ds-cfg-changelog-server: localhost:8990 ds-cfg-changelog-server-id: 1 opends/resource/schema/02-config.ldif
@@ -1634,6 +1634,10 @@ MUST ( ds-task-initialize-domain-dn $ ds-task-initialize-replica-server-id ) MAY ( ds-task-processed-entry-count $ ds-task-unprocessed-entry-count ) X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.94 NAME 'ds-cfg-multimaster-synchronization-provider' SUP ds-cfg-synchronization-provider STRUCTURAL X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.95 NAME 'ds-cfg-dictionary-password-validator' SUP ds-cfg-password-validator STRUCTURAL MUST ( ds-cfg-dictionary-file $ ds-cfg-case-sensitive-validation $ opends/src/admin/defn/org/opends/server/admin/std/ChangelogServerConfiguration.xml
New file @@ -0,0 +1,172 @@ <?xml version="1.0" encoding="utf-8"?> <adm:managed-object name="changelog-server" plural-name="changelog-servers" package="org.opends.server.admin.std" xmlns:adm="http://www.opends.org/admin" xmlns:ldap="http://www.opends.org/admin-ldap"> <adm:synopsis> The <adm:user-friendly-name /> is the server to which Multimaster Domain connects to publish and receive changes to or from other Multimaster Domains. </adm:synopsis> <adm:profile name="ldap"> <ldap:object-class> <ldap:oid>1.3.6.1.4.1.26027.1.2.65</ldap:oid> <ldap:name> ds-cfg-synchronization-changelog-server-config </ldap:name> <ldap:superior>top</ldap:superior> </ldap:object-class> </adm:profile> <adm:property name="changelog-server" multi-valued="true" mandatory="false"> <adm:synopsis> Specifies the addresses of the changelog server to which this <adm:user-friendly-name /> should try to connect at startup time. </adm:synopsis> <adm:description> Adresses must be specified using the syntax: hostname:port </adm:description> <adm:requires-admin-action> <adm:none /> </adm:requires-admin-action> <adm:default-behavior> <adm:undefined /> </adm:default-behavior> <adm:syntax> <adm:string></adm:string> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.160</ldap:oid> <ldap:name>ds-cfg-changelog-server</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="changelog-server-id" multi-valued="false" mandatory="true" read-only="true"> <adm:synopsis> Specifies the server ID of this Changelog Server </adm:synopsis> <adm:description> Each Changelog Server must have a different server ID. </adm:description> <adm:requires-admin-action> <adm:none /> </adm:requires-admin-action> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.278</ldap:oid> <ldap:name>ds-cfg-changelog-server-id</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="window-size" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the window size that will this Domain must use when communicating with changelog servers. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>100</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.288</ldap:oid> <ldap:name>ds-cfg-window-size</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="queue-size" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the number of changes that will be kept in memory for each LDAP server in the topology. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>10000</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.290</ldap:oid> <ldap:name>ds-cfg-changelog-max-queue-size</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="changelog-db-directory" mandatory="false" hidden="false" multi-valued="false" read-only="true"> <adm:synopsis> The path where the <adm:user-friendly-name /> will store all persistent information. </adm:synopsis> <adm:default-behavior> <adm:undefined /> </adm:default-behavior> <adm:syntax> <adm:string></adm:string> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.306</ldap:oid> <ldap:name>ds-cfg-changelog-db-directory</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="changelog-purge-delay" multi-valued="false"> <adm:synopsis> The time (in seconds) after which the <adm:user-friendly-name /> will erase all persistent information. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>86400s</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:duration base-unit="s" allow-unlimited="false" /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.319</ldap:oid> <ldap:name>ds-cfg-changelog-purge-delay</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="changelog-port" mandatory="true" multi-valued="false"> <adm:synopsis> The port on which this <adm:user-friendly-name></adm:user-friendly-name> will wait for connections from other Changelog Servers or LDAP Servers or from LDAP servers. </adm:synopsis> <adm:requires-admin-action> <adm:none /> </adm:requires-admin-action> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.158</ldap:oid> <ldap:name>ds-cfg-changelog-port</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opends/src/admin/defn/org/opends/server/admin/std/MultimasterDomainConfiguration.xml
New file @@ -0,0 +1,211 @@ <?xml version="1.0" encoding="utf-8"?> <adm:managed-object name="multimaster-domain" plural-name="multimaster-domains" package="org.opends.server.admin.std" xmlns:adm="http://www.opends.org/admin" xmlns:ldap="http://www.opends.org/admin-ldap"> <adm:synopsis> The <adm:user-friendly-name /> is used to provide Multimaster Replication of several OpenDS copies of the same data </adm:synopsis> <adm:profile name="ldap"> <ldap:object-class> <ldap:oid>1.3.6.1.4.1.26027.1.2.58</ldap:oid> <ldap:name>ds-cfg-synchronization-provider-config</ldap:name> <ldap:superior>top</ldap:superior> </ldap:object-class> </adm:profile> <adm:property name="changelog-server" multi-valued="true" mandatory="true"> <adm:synopsis> Specifies the addresses of the changelog server to which this <adm:user-friendly-name /> should try to connect at startup time. </adm:synopsis> <adm:description> Adresses must be specified using the syntax: hostname:port </adm:description> <adm:requires-admin-action> <adm:none /> </adm:requires-admin-action> <adm:syntax> <adm:string></adm:string> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.160</ldap:oid> <ldap:name>ds-cfg-changelog-server</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="server-id" multi-valued="false" mandatory="true" read-only="true"> <adm:synopsis> Specifies the server ID of this multimaster provider. </adm:synopsis> <adm:description> Each multimaster provider must have a different server ID. </adm:description> <adm:requires-admin-action> <adm:none /> </adm:requires-admin-action> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.279</ldap:oid> <ldap:name>ds-cfg-directory-server-id</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="synchronization-dn" mandatory="true" multi-valued="false" read-only="true"> <adm:synopsis> Specifies the base dn of the Multimaster Domain </adm:synopsis> <adm:syntax> <adm:dn></adm:dn> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.226</ldap:oid> <ldap:name>ds-cfg-synchronization-dn</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="max-receive-queue" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the maximum length of the receive queue on the changelog server before flow control must be activated. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>0</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.164</ldap:oid> <ldap:name>ds-cfg-max-receive-queue</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="max-receive-delay" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the maximum delay on the changelog server before flow control must be activated. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>0s</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:duration base-unit="s" allow-unlimited="false" upper-limit="2147483647" lower-limit="0" /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.165</ldap:oid> <ldap:name>ds-cfg-max-receive-delay</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="max-send-queue" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the maximum length of the send queue on the changelog server before flow control must be activated. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>0</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.166</ldap:oid> <ldap:name>ds-cfg-max-send-queue</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="max-send-delay" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the maximum send delay on the changelog server before flow control must be activated. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>0s</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:duration upper-limit="2147483647" allow-unlimited="false" lower-limit="0" base-unit="s" /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.167</ldap:oid> <ldap:name>ds-cfg-max-send-delay</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="window-size" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the window size that will this Domain must use when communicating with changelog servers. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>100</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:integer></adm:integer> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.288</ldap:oid> <ldap:name>ds-cfg-window-size</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="heartbeat-interval" mandatory="false" multi-valued="false"> <adm:synopsis> Specifies the heartbeat interval that this Domain must use when communicating with changelog servers. The Domain will expect regular heatbeat coming from the changelog server with this interval if they are not received it will close its connection and connect to another changelog server. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>1000s</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:duration base-unit="ms" allow-unlimited="false" lower-limit="100" /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.305</ldap:oid> <ldap:name>ds-cfg-heartbeat-interval</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opends/src/admin/defn/org/opends/server/admin/std/MultimasterSynchronizationProviderConfiguration.xml
New file @@ -0,0 +1,33 @@ <?xml version="1.0" encoding="utf-8"?> <adm:managed-object name="multimaster-synchronization-provider" plural-name="multimaster-synchronization-providers" package="org.opends.server.admin.std" extends="synchronization-provider" xmlns:adm="http://www.opends.org/admin" xmlns:ldap="http://www.opends.org/admin-ldap" abstract="false"> <adm:synopsis> The <adm:user-friendly-name /> is used to provide Multimaster Replication of several OpenDS copies of the same data </adm:synopsis> <adm:profile name="ldap"> <ldap:object-class> <ldap:oid>1.3.6.1.4.1.26027.1.2.91</ldap:oid> <ldap:name>ds-cfg-multimaster-synchronization-provider</ldap:name> <ldap:superior>ds-cfg-synchronization-provider</ldap:superior> </ldap:object-class> </adm:profile> <adm:relation name="multimaster-domain"> <adm:one-to-many /> <adm:profile name="ldap"> <ldap:rdn-sequence>cn=domains</ldap:rdn-sequence> </adm:profile> </adm:relation> <adm:relation name="changelog-server"> <adm:one-to-zero-or-one /> <adm:profile name="ldap"> <ldap:rdn-sequence>cn=changelog server</ldap:rdn-sequence> </adm:profile> </adm:relation> </adm:managed-object> opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
@@ -21,7 +21,15 @@ </ldap:rdn-sequence> </adm:profile> </adm:relation> <adm:relation name="access-control-handler"> <adm:relation name="synchronization-provider"> <adm:one-to-many /> <adm:profile name="ldap"> <ldap:rdn-sequence> cn=Synchronization Providers, cn=config </ldap:rdn-sequence> </adm:profile> </adm:relation> <adm:relation name="access-control-handler"> <adm:one-to-one /> <adm:profile name="ldap"> <ldap:rdn-sequence> @@ -72,9 +80,7 @@ <adm:relation name="plugin"> <adm:one-to-many /> <adm:profile name="ldap"> <ldap:rdn-sequence> cn=Plugins,cn=config </ldap:rdn-sequence> <ldap:rdn-sequence>cn=Plugins,cn=config</ldap:rdn-sequence> </adm:profile> </adm:relation> <adm:relation name="virtual-attribute"> opends/src/admin/defn/org/opends/server/admin/std/SynchronizationProviderConfiguration.xml
New file @@ -0,0 +1,56 @@ <?xml version="1.0" encoding="utf-8"?> <adm:managed-object name="synchronization-provider" plural-name="synchronization-providers" package="org.opends.server.admin.std" abstract="true" xmlns:adm="http://www.opends.org/admin" xmlns:ldap="http://www.opends.org/admin-ldap"> <adm:synopsis> <adm:user-friendly-plural-name /> are responsible for handling Synchronization of the Directory Server datas with other OpenDS instances or other data repositories. </adm:synopsis> <adm:profile name="ldap"> <ldap:object-class> <ldap:oid>1.3.6.1.4.1.26027.1.2.57</ldap:oid> <ldap:name>ds-cfg-synchronization-provider</ldap:name> <ldap:superior>top</ldap:superior> </ldap:object-class> </adm:profile> <adm:property name="enabled" mandatory="true"> <adm:synopsis> Indicate whether the <adm:user-friendly-name /> is enabled for use. </adm:synopsis> <adm:syntax> <adm:boolean /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.155</ldap:oid> <ldap:name>ds-cfg-synchronization-provider-enabled</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="java-implementation-class" mandatory="true" multi-valued="false"> <adm:synopsis> The fully-qualified name of the Java class that provides the <adm:user-friendly-name /> implementation. </adm:synopsis> <adm:syntax> <adm:java-class> <adm:instance-of> org.opends.server.api.SynchronizationProvider </adm:instance-of> </adm:java-class> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.154</ldap:oid> <ldap:name>ds-cfg-synchronization-provider-class</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opends/src/server/org/opends/server/api/SynchronizationProvider.java
@@ -30,7 +30,7 @@ import java.util.List; import org.opends.server.config.ConfigEntry; import org.opends.server.admin.std.server.SynchronizationProviderCfg; import org.opends.server.config.ConfigException; import org.opends.server.core.AddOperation; import org.opends.server.core.DeleteOperation; @@ -51,8 +51,11 @@ * the Directory Server are properly communicated to other instances, * and potentially to other kinds of applications, so that they can be * updated accordingly. * * @param <T> the configuration for the synchronization provider. */ public abstract class SynchronizationProvider public abstract class SynchronizationProvider<T extends SynchronizationProviderCfg> { @@ -61,9 +64,8 @@ * Performs any initialization that might be necessary for this * synchronization provider. * * @param configEntry The entry containing the configuration * information for this synchronization * provider. * @param config The configuration information for this * synchronization provider. * * @throws ConfigException If the provided entry does not contain * a valid configuration for this @@ -75,8 +77,7 @@ * is not related to the server * configuration. */ public abstract void initializeSynchronizationProvider( ConfigEntry configEntry) public abstract void initializeSynchronizationProvider(T config) throws ConfigException, InitializationException; opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -49,6 +49,7 @@ import org.opends.server.admin.ClassLoaderProvider; import org.opends.server.admin.std.server.PasswordValidatorCfg; import org.opends.server.admin.std.server.SynchronizationProviderCfg; import org.opends.server.api.*; import org.opends.server.api.plugin.PluginType; import org.opends.server.api.plugin.StartupPluginResult; @@ -334,7 +335,8 @@ // The set of synchronization providers that have been registered with the // Directory Server. private CopyOnWriteArrayList<SynchronizationProvider> private CopyOnWriteArrayList<SynchronizationProvider<SynchronizationProviderCfg>> synchronizationProviders; // The set of virtual attributes defined in the server. @@ -630,7 +632,8 @@ directoryServer.shutdownListeners = new CopyOnWriteArrayList<ServerShutdownListener>(); directoryServer.synchronizationProviders = new CopyOnWriteArrayList<SynchronizationProvider>(); new CopyOnWriteArrayList<SynchronizationProvider <SynchronizationProviderCfg>>(); directoryServer.supportedControls = new TreeSet<String>(); directoryServer.supportedFeatures = new TreeSet<String>(); directoryServer.virtualAttributes = @@ -7187,8 +7190,9 @@ * @return The set of synchronization providers that have been registered * with the Directory Server. */ public static CopyOnWriteArrayList<SynchronizationProvider> getSynchronizationProviders() public static CopyOnWriteArrayList<SynchronizationProvider<SynchronizationProviderCfg>> getSynchronizationProviders() { return directoryServer.synchronizationProviders; } @@ -7200,8 +7204,8 @@ * * @param provider The synchronization provider to register. */ public static void registerSynchronizationProvider(SynchronizationProvider provider) public static void registerSynchronizationProvider( SynchronizationProvider<SynchronizationProviderCfg> provider) { directoryServer.synchronizationProviders.add(provider); } opends/src/server/org/opends/server/core/SynchronizationProviderConfigManager.java
@@ -28,33 +28,31 @@ import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import org.opends.server.api.ConfigAddListener; import org.opends.server.api.ConfigChangeListener; import org.opends.server.api.ConfigDeleteListener; import org.opends.server.api.SynchronizationProvider; import org.opends.server.config.BooleanConfigAttribute; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.config.StringConfigAttribute; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DN; import org.opends.server.types.ErrorLogCategory; import org.opends.server.types.ErrorLogSeverity; import org.opends.server.types.InitializationException; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchFilter; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.debug.DebugLogger.debugCaught; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import org.opends.server.types.DebugLogLevel; import static org.opends.server.loggers.Error.*; import static org.opends.server.messages.ConfigMessages.*; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.util.StaticUtils.*; import static org.opends.server.messages.MessageHandler.getMessage; import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import org.opends.server.admin.ClassPropertyDefinition; import org.opends.server.admin.server.ConfigurationAddListener; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.server.ConfigurationDeleteListener; import org.opends.server.admin.server.ServerManagementContext; import org.opends.server.admin.std.meta.SynchronizationProviderCfgDefn; import org.opends.server.admin.std.server.RootCfg; import org.opends.server.admin.std.server.SynchronizationProviderCfg; import org.opends.server.api.SynchronizationProvider; import org.opends.server.config.ConfigException; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.InitializationException; import org.opends.server.types.ResultCode; @@ -66,17 +64,20 @@ * to them while the server is running. */ public class SynchronizationProviderConfigManager implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener implements ConfigurationChangeListener<SynchronizationProviderCfg>, ConfigurationAddListener<SynchronizationProviderCfg>, ConfigurationDeleteListener<SynchronizationProviderCfg> { // The mapping between configuration entry DNs and their corresponding // synchronization provider implementations. private ConcurrentHashMap<DN,SynchronizationProvider> registeredProviders; private ConcurrentHashMap<DN, SynchronizationProvider<SynchronizationProviderCfg>> registeredProviders = new ConcurrentHashMap<DN, SynchronizationProvider<SynchronizationProviderCfg>>(); // The DN of the associated configuration entry. private DN configEntryDN; @@ -107,765 +108,407 @@ public void initializeSynchronizationProviders() throws ConfigException, InitializationException { registeredProviders = new ConcurrentHashMap<DN,SynchronizationProvider>(); // Create an internal server management context and retrieve // the root configuration which has the synchronization provider relation. ServerManagementContext context = ServerManagementContext.getInstance(); RootCfg root = context.getRootConfiguration(); // Register as an add and delete listener so that we can // be notified when new synchronization providers are added or existing // sycnhronization providers are removed. root.addSynchronizationProviderAddListener(this); root.addSynchronizationProviderDeleteListener(this); // Get the configuration entry that is the parent for all synchronization // providers in the server. ConfigEntry providerRoot; try // Initialize existing synchronization providers. for (String name : root.listSynchronizationProviders()) { configEntryDN = DN.decode(DN_SYNCHRONIZATION_PROVIDER_BASE); providerRoot = DirectoryServer.getConfigEntry(configEntryDN); } catch (Exception e) { if (debugEnabled()) // Get the synchronization provider's configuration. // This will automatically decode and validate its properties. SynchronizationProviderCfg config = root.getSynchronizationProvider(name); // Register as a change listener for this synchronization provider // entry so that we can be notified when it is disabled or enabled. config.addChangeListener(this); // Ignore this synchronization provider if it is disabled. if (config.isEnabled()) { debugCaught(DebugLogLevel.ERROR, e); // Perform initialization, load the synchronization provider's // implementation class and initialize it. SynchronizationProvider<SynchronizationProviderCfg> provider = getSynchronizationProvider(config); // Register the synchronization provider with the Directory Server. DirectoryServer.registerSynchronizationProvider(provider); // Put this synchronization provider in the hash map so that we will be // able to find it if it is deleted or disabled. registeredProviders.put(config.dn(), provider); } int msgID = MSGID_CONFIG_SYNCH_CANNOT_GET_CONFIG_BASE; String message = getMessage(msgID, stackTraceToSingleLineString(e)); throw new ConfigException(msgID, message, e); } // If the configuration root entry is null, then assume it doesn't exist. // In that case, then fail. At least that entry must exist in the // configuration, even if there are no synchronization providers defined // below it. if (providerRoot == null) { int msgID = MSGID_CONFIG_SYNCH_BASE_DOES_NOT_EXIST; String message = getMessage(msgID); throw new ConfigException(msgID, message); } // Register as an add and delete listener for the base entry so that we can // be notified if new providers are added or existing providers are removed. providerRoot.registerAddListener(this); providerRoot.registerDeleteListener(this); // Iterate through the set of immediate children below the provider root // entry and register those providers. for (ConfigEntry providerEntry : providerRoot.getChildren().values()) { DN providerDN = providerEntry.getDN(); // Register as a change listener for this provider entry so that we will // be notified of any changes that may be made to it. providerEntry.registerChangeListener(this); // Check to see if this entry appears to contain a synchronization // provider configuration. If not, then fail. try { SearchFilter providerFilter = SearchFilter.createFilterFromString("(objectClass=" + OC_SYNCHRONIZATION_PROVIDER + ")"); if (! providerFilter.matchesEntry(providerEntry.getEntry())) { int msgID = MSGID_CONFIG_SYNCH_ENTRY_DOES_NOT_HAVE_PROVIDER_CONFIG; String message = getMessage(msgID, String.valueOf(providerDN)); throw new ConfigException(msgID, message); } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } int msgID = MSGID_CONFIG_SYNCH_CANNOT_CHECK_FOR_PROVIDER_CONFIG_OC; String message = getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e)); throw new InitializationException(msgID, message, e); } // See if the entry contains an attribute that indicates whether the // synchronization provider should be enabled. If it does not, then fail. // If it is present but set to false, then log a warning and skip it. int msgID = MSGID_CONFIG_SYNCH_DESCRIPTION_PROVIDER_ENABLED; BooleanConfigAttribute enabledStub = new BooleanConfigAttribute(ATTR_SYNCHRONIZATION_PROVIDER_ENABLED, getMessage(msgID), true); try { BooleanConfigAttribute enabledAttr = (BooleanConfigAttribute) providerEntry.getConfigAttribute(enabledStub); if (enabledAttr == null) { msgID = MSGID_CONFIG_SYNCH_PROVIDER_NO_ENABLED_ATTR; String message = getMessage(msgID, String.valueOf(providerDN)); throw new ConfigException(msgID, message); } else if (! enabledAttr.activeValue()) { msgID = MSGID_CONFIG_SYNCH_PROVIDER_DISABLED; String message = getMessage(msgID, String.valueOf(providerDN)); logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_WARNING, message, msgID); continue; } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_DETERMINE_ENABLED_STATE; String message = getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e)); throw new InitializationException(msgID, message, e); } // See if the entry contains an attribute that specifies the class name // for the synchronization provider implementation. If there is no such // attribute, then fail. String providerClassName; msgID = MSGID_CONFIG_SYNCH_DESCRIPTION_PROVIDER_CLASS; StringConfigAttribute classStub = new StringConfigAttribute(ATTR_SYNCHRONIZATION_PROVIDER_CLASS, getMessage(msgID), true, false, true); try { StringConfigAttribute classAttr = (StringConfigAttribute) providerEntry.getConfigAttribute(classStub); if (classAttr == null) { msgID = MSGID_CONFIG_SYNCH_NO_CLASS_ATTR; String message = getMessage(msgID, String.valueOf(providerDN)); throw new ConfigException(msgID, message); } else { providerClassName = classAttr.activeValue(); } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_DETERMINE_CLASS; String message = getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e)); throw new InitializationException(msgID, message, e); } // Load the specified provider class. If an error occurs, then fail. Class providerClass; try { providerClass = DirectoryServer.loadClass(providerClassName); } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_LOAD_PROVIDER_CLASS; String message = getMessage(msgID, String.valueOf(providerClassName), String.valueOf(providerDN), stackTraceToSingleLineString(e)); throw new InitializationException(msgID, message, e); } // Make sure that the specified class is a valid synchronization provider. // If not, then fail. SynchronizationProvider provider; try { provider = (SynchronizationProvider) providerClass.newInstance(); } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_INSTANTIATE_PROVIDER; String message = getMessage(msgID, String.valueOf(providerClassName), String.valueOf(providerDN), stackTraceToSingleLineString(e)); throw new InitializationException(msgID, message, e); } // Perform the necessary initialization for the synchronization provider. // If a problem occurs, then fail. try { provider.initializeSynchronizationProvider(providerEntry); } catch (ConfigException ce) { msgID = MSGID_CONFIG_SYNCH_ERROR_INITIALIZING_PROVIDER; String message = getMessage(msgID, String.valueOf(providerDN), ce.getMessage()); throw new ConfigException(msgID, message, ce); } catch (InitializationException ie) { msgID = MSGID_CONFIG_SYNCH_ERROR_INITIALIZING_PROVIDER; String message = getMessage(msgID, String.valueOf(providerDN), ie.getMessage()); throw new InitializationException(msgID, message, ie); } catch (Exception e) { msgID = MSGID_CONFIG_SYNCH_ERROR_INITIALIZING_PROVIDER; String message = getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e)); throw new ConfigException(msgID, message, e); } // Register the synchronization provider with the Directory Server. DirectoryServer.registerSynchronizationProvider(provider); // Put this provider in the hash so that we will be able to find it if it // is altered. registeredProviders.put(providerDN, provider); } } /** * 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. * * @return <CODE>true</CODE> if the proposed entry contains an acceptable * configuration, or <CODE>false</CODE> if it does not. * {@inheritDoc} */ public boolean configChangeIsAcceptable(ConfigEntry configEntry, StringBuilder unacceptableReason) public ConfigChangeResult applyConfigurationChange( SynchronizationProviderCfg configuration) { DN providerDN = configEntry.getDN(); SynchronizationProvider provider = registeredProviders.get(providerDN); // Check to see if this entry appears to contain a backend configuration. // If not, then reject it. try { SearchFilter providerFilter = SearchFilter.createFilterFromString("(objectClass=" + OC_SYNCHRONIZATION_PROVIDER + ")"); if (! providerFilter.matchesEntry(configEntry.getEntry())) { int msgID = MSGID_CONFIG_SYNCH_ENTRY_DOES_NOT_HAVE_PROVIDER_CONFIG; unacceptableReason.append(getMessage(msgID, String.valueOf(providerDN))); return false; } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } int msgID = MSGID_CONFIG_SYNCH_CANNOT_CHECK_FOR_PROVIDER_CONFIG_OC; unacceptableReason.append(getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e))); return false; } // See if the entry contains an attribute that indicates whether the // provider should be enabled. If it does not, then reject it. int msgID = MSGID_CONFIG_SYNCH_DESCRIPTION_PROVIDER_ENABLED; BooleanConfigAttribute enabledStub = new BooleanConfigAttribute(ATTR_SYNCHRONIZATION_PROVIDER_ENABLED, getMessage(msgID), true); try { BooleanConfigAttribute enabledAttr = (BooleanConfigAttribute) configEntry.getConfigAttribute(enabledStub); if (enabledAttr == null) { msgID = MSGID_CONFIG_SYNCH_PROVIDER_NO_ENABLED_ATTR; unacceptableReason.append(getMessage(msgID, String.valueOf(providerDN))); return false; } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_DETERMINE_ENABLED_STATE; unacceptableReason.append(getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e))); return false; } // See if the entry contains an attribute that specifies the provider class. // If it does not, then fail. String className; msgID = MSGID_CONFIG_SYNCH_DESCRIPTION_PROVIDER_CLASS; StringConfigAttribute classStub = new StringConfigAttribute(ATTR_SYNCHRONIZATION_PROVIDER_CLASS, getMessage(msgID), true, false, true); try { StringConfigAttribute classAttr = (StringConfigAttribute) configEntry.getConfigAttribute(classStub); if (classAttr == null) { msgID = MSGID_CONFIG_SYNCH_NO_CLASS_ATTR; unacceptableReason.append(getMessage(msgID, String.valueOf(providerDN))); return false; } else { className = classAttr.pendingValue(); } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_DETERMINE_CLASS; unacceptableReason.append(getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e))); return false; } // If the provider is currently disabled, or if the class is different from // the one used by the running provider, then make sure that it is // acceptable. if ((provider == null) || (! className.equals(provider.getClass().getName()))) { Class providerClass; try { providerClass = DirectoryServer.loadClass(className); } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_LOAD_PROVIDER_CLASS; unacceptableReason.append(getMessage(msgID, String.valueOf(className), String.valueOf(providerDN), stackTraceToSingleLineString(e))); return false; } try { SynchronizationProvider newProvider = (SynchronizationProvider) providerClass.newInstance(); } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_INSTANTIATE_PROVIDER; unacceptableReason.append(getMessage(msgID, String.valueOf(className), String.valueOf(providerDN), stackTraceToSingleLineString(e))); return false; } } // If we've gotten to this point, then it is acceptable as far as we are // concerned. If it is unacceptable according to the configuration for that // synchronization provider, then the provider itself will need to make that // determination. return true; } /** * Attempts to apply a new configuration to this Directory Server component * based on the provided changed entry. * * @param configEntry The configuration entry that containing the updated * configuration for this component. * * @return Information about the result of processing the configuration * change. */ public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) { DN providerDN = configEntry.getDN(); SynchronizationProvider provider = registeredProviders.get(providerDN); // Default result code. ResultCode resultCode = ResultCode.SUCCESS; boolean adminActionRequired = false; ArrayList<String> messages = new ArrayList<String>(); // Attempt to get the existing synchronization provider. This will only // succeed if it is currently enabled. DN dn = configuration.dn(); SynchronizationProvider<SynchronizationProviderCfg> provider = registeredProviders.get(dn); // Check to see if this entry appears to contain a synchronization provider // configuration. If not, then fail. try // See whether the synchronization provider should be enabled. if (provider == null) { SearchFilter providerFilter = SearchFilter.createFilterFromString("(objectClass=" + OC_SYNCHRONIZATION_PROVIDER + ")"); if (! providerFilter.matchesEntry(configEntry.getEntry())) if (configuration.isEnabled()) { int msgID = MSGID_CONFIG_SYNCH_ENTRY_DOES_NOT_HAVE_PROVIDER_CONFIG; messages.add(getMessage(msgID, String.valueOf(providerDN))); if (resultCode == ResultCode.SUCCESS) // The synchronization provider needs to be enabled. Load, initialize, // and register the synchronization provider as per the add listener // method. try { resultCode = ResultCode.CONSTRAINT_VIOLATION; // Perform initialization, load the synchronization provider's // implementation class and initialize it. provider = getSynchronizationProvider(configuration); // Register the synchronization provider with the Directory Server. DirectoryServer.registerSynchronizationProvider(provider); // Put this synchronization provider in the hash map so that we will // be able to find it if it is deleted or disabled. registeredProviders.put(configuration.dn(), provider); } catch (ConfigException e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); messages.add(e.getMessage()); resultCode = DirectoryServer.getServerErrorResultCode(); } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } int msgID = MSGID_CONFIG_SYNCH_ERROR_INITIALIZING_PROVIDER; messages.add(getMessage(msgID, String.valueOf( configuration.getJavaImplementationClass()), String.valueOf(configuration.dn()), stackTraceToSingleLineString(e))); resultCode = DirectoryServer.getServerErrorResultCode(); } } } catch (Exception e) else { if (debugEnabled()) if (configuration.isEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } int msgID = MSGID_CONFIG_SYNCH_CANNOT_CHECK_FOR_PROVIDER_CONFIG_OC; messages.add(getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e))); if (resultCode == ResultCode.SUCCESS) { resultCode = DirectoryServer.getServerErrorResultCode(); } } // See if the entry contains an attribute that indicates whether the // provider should be enabled. If it does not, then reject it. boolean shouldEnable = false; int msgID = MSGID_CONFIG_SYNCH_DESCRIPTION_PROVIDER_ENABLED; BooleanConfigAttribute enabledStub = new BooleanConfigAttribute(ATTR_SYNCHRONIZATION_PROVIDER_ENABLED, getMessage(msgID), true); try { BooleanConfigAttribute enabledAttr = (BooleanConfigAttribute) configEntry.getConfigAttribute(enabledStub); if (enabledAttr == null) { msgID = MSGID_CONFIG_SYNCH_PROVIDER_NO_ENABLED_ATTR; messages.add(getMessage(msgID, String.valueOf(providerDN))); if (resultCode == ResultCode.SUCCESS) // The synchronization provider is currently active, so we don't // need to do anything. Changes to the class name cannot be // applied dynamically, so if the class name did change then // indicate that administrative action is required for that // change to take effect. String className = configuration.getJavaImplementationClass(); if (!className.equals(provider.getClass().getName())) { resultCode = ResultCode.CONSTRAINT_VIOLATION; adminActionRequired = true; } } else { shouldEnable = enabledAttr.pendingValue(); // The connection handler is being disabled so remove it from // the DirectorySerevr list, shut it down and remove it from the // hash map. DirectoryServer.deregisterSynchronizationProvider(provider); provider.finalizeSynchronizationProvider(); registeredProviders.remove(dn); } } catch (Exception e) // Return the configuration result. return new ConfigChangeResult(resultCode, adminActionRequired, messages); } /** * {@inheritDoc} */ public boolean isConfigurationChangeAcceptable( SynchronizationProviderCfg configuration, List<String> unacceptableReasons) { if (configuration.isEnabled()) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_DETERMINE_ENABLED_STATE; messages.add(getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e))); if (resultCode == ResultCode.SUCCESS) { resultCode = DirectoryServer.getServerErrorResultCode(); } // It's enabled so always validate the class. return isJavaClassAcceptable(configuration, unacceptableReasons); } else { // It's disabled so ignore it. return true; } } // See if the entry contains an attribute that specifies the provider class. // If it does not, then reject it. String className = null; msgID = MSGID_CONFIG_SYNCH_DESCRIPTION_PROVIDER_CLASS; StringConfigAttribute classStub = new StringConfigAttribute(ATTR_SYNCHRONIZATION_PROVIDER_CLASS, getMessage(msgID), true, false, true); try /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationAdd( SynchronizationProviderCfg configuration) { // Default result code. ResultCode resultCode = ResultCode.SUCCESS; boolean adminActionRequired = false; ArrayList<String> messages = new ArrayList<String>(); // Register as a change listener for this synchronization provider entry // so that we will be notified if when it is disabled or enabled. configuration.addChangeListener(this); // Ignore this synchronization provider if it is disabled. if (configuration.isEnabled()) { StringConfigAttribute classAttr = (StringConfigAttribute) configEntry.getConfigAttribute(classStub); if (classAttr == null) { msgID = MSGID_CONFIG_SYNCH_NO_CLASS_ATTR; messages.add(getMessage(msgID, String.valueOf(providerDN))); if (resultCode == ResultCode.SUCCESS) { resultCode = ResultCode.CONSTRAINT_VIOLATION; } } else { className = classAttr.pendingValue(); } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_DETERMINE_CLASS; messages.add(getMessage(msgID, String.valueOf(providerDN), stackTraceToSingleLineString(e))); if (resultCode == ResultCode.SUCCESS) { resultCode = DirectoryServer.getServerErrorResultCode(); } } // If the provider is currently disabled, or if the class is different from // the one used by the running provider, then make sure that it is // acceptable. SynchronizationProvider newProvider = null; if ((resultCode == ResultCode.SUCCESS) && ((provider == null) || (! provider.getClass().getName().equals(className)))) { Class providerClass = null; try { providerClass = DirectoryServer.loadClass(className); // Perform initialization, load the synchronization provider's // implementation class and initialize it. SynchronizationProvider<SynchronizationProviderCfg> provider = getSynchronizationProvider(configuration); // Register the synchronization provider with the Directory Server. DirectoryServer.registerSynchronizationProvider(provider); // Put this synchronization provider in the hash map so that we will be // able to find it if it is deleted or disabled. registeredProviders.put(configuration.dn(), provider); } catch (Exception e) catch (ConfigException e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_LOAD_PROVIDER_CLASS; messages.add(getMessage(msgID, String.valueOf(className), String.valueOf(providerDN), stackTraceToSingleLineString(e))); if (resultCode == ResultCode.SUCCESS) { messages.add(e.getMessage()); resultCode = DirectoryServer.getServerErrorResultCode(); } } try { if (providerClass != null) { newProvider = (SynchronizationProvider) providerClass.newInstance(); } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_INSTANTIATE_PROVIDER; messages.add(getMessage(msgID, String.valueOf(className), String.valueOf(providerDN), stackTraceToSingleLineString(e))); if (resultCode == ResultCode.SUCCESS) { resultCode = DirectoryServer.getServerErrorResultCode(); } int msgID = MSGID_CONFIG_SYNCH_ERROR_INITIALIZING_PROVIDER; messages.add(getMessage(msgID, String.valueOf( configuration.getJavaImplementationClass()), String.valueOf(configuration.dn()), stackTraceToSingleLineString(e))); resultCode = DirectoryServer.getServerErrorResultCode(); } } // Return the configuration result. return new ConfigChangeResult(resultCode, adminActionRequired, messages); } // If everything looks OK, then process the configuration change. if (resultCode == ResultCode.SUCCESS) /** * {@inheritDoc} */ public boolean isConfigurationAddAcceptable( SynchronizationProviderCfg configuration, List<String> unacceptableReasons) { if (configuration.isEnabled()) { // If the provider is currently disabled but should be enabled, then do // so now. if (provider == null) { if (shouldEnable && (newProvider != null)) { try { newProvider.initializeSynchronizationProvider(configEntry); registeredProviders.put(configEntryDN, newProvider); } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } msgID = MSGID_CONFIG_SYNCH_ERROR_INITIALIZING_PROVIDER; messages.add(getMessage(msgID, String.valueOf(configEntryDN), stackTraceToSingleLineString(e))); if (resultCode == ResultCode.SUCCESS) { resultCode = DirectoryServer.getServerErrorResultCode(); } } } } // It's enabled so always validate the class. return isJavaClassAcceptable(configuration, unacceptableReasons); } else { // It's disabled so ignore it. return true; } } // Otherwise, see if the enabled flag or class name changed and indicate // that it will require a restart to take effect. else { if (! shouldEnable) { msgID = MSGID_CONFIG_SYNCH_PROVIDER_HAS_BEEN_DISABLED; messages.add(getMessage(msgID, String.valueOf(configEntryDN))); adminActionRequired = true; } if (! provider.getClass().getName().equals(className)) { msgID = MSGID_CONFIG_SYNCH_PROVIDER_CLASS_CHANGED; messages.add(getMessage(msgID, String.valueOf(configEntryDN), String.valueOf(provider.getClass().getName()), String.valueOf(className))); adminActionRequired = true; } } /** * Check if the class provided in the configuration is an acceptable * java class for a synchronization provider. * * @param configuration The configuration for which the class must be * checked. * @param unacceptableReasons A list containing the reasons why the class is * not acceptable. * * @return true if the class is acceptable or false if not. */ @SuppressWarnings("unchecked") private SynchronizationProvider<SynchronizationProviderCfg> getSynchronizationProvider(SynchronizationProviderCfg configuration) throws ConfigException { String className = configuration.getJavaImplementationClass(); SynchronizationProviderCfgDefn d = SynchronizationProviderCfgDefn.getInstance(); ClassPropertyDefinition pd = d.getJavaImplementationClassPropertyDefinition(); // Load the class Class<? extends SynchronizationProvider> theClass; SynchronizationProvider<SynchronizationProviderCfg> provider; try { theClass = pd.loadClass(className, SynchronizationProvider.class); } catch (Exception e) { // Handle the exception: put a message in the unacceptable reasons. int msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_LOAD_PROVIDER_CLASS; String message = getMessage(msgID, String.valueOf(className), String.valueOf(configuration.dn()), stackTraceToSingleLineString(e)); throw new ConfigException(msgID, message, e); } try { // Instantiate the class. provider = theClass.newInstance(); } catch (Exception e) { // Handle the exception: put a message in the unacceptable reasons. int msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_INSTANTIATE_PROVIDER; String message = getMessage(msgID, String.valueOf(className), String.valueOf(configuration.dn()), stackTraceToSingleLineString(e)); throw new ConfigException(msgID, message, e); } try { // Initialize the Synchronization Provider. provider.initializeSynchronizationProvider(configuration); } catch (Exception e) { // Handle the exception: put a message in the unacceptable reasons. int msgID = MSGID_CONFIG_SYNCH_ERROR_INITIALIZING_PROVIDER; String message = getMessage(msgID, String.valueOf(className), String.valueOf(configuration.dn()), stackTraceToSingleLineString(e)); throw new ConfigException(msgID, message, e); } return provider; } /** * Check if the class provided in the configuration is an acceptable * java class for a synchronization provider. * * @param configuration The configuration for which the class must be * checked. * @param unacceptableReasons A list containing the reasons why the class is * not acceptable. * * @return true if the class is acceptable or false if not. */ private boolean isJavaClassAcceptable( SynchronizationProviderCfg configuration, List<String> unacceptableReasons) { String className = configuration.getJavaImplementationClass(); SynchronizationProviderCfgDefn d = SynchronizationProviderCfgDefn.getInstance(); ClassPropertyDefinition pd = d.getJavaImplementationClassPropertyDefinition(); // Load the class and cast it to a synchronizationProvider. Class<? extends SynchronizationProvider> theClass; try { theClass = pd.loadClass(className, SynchronizationProvider.class); theClass.newInstance(); } catch (Exception e) { // Handle the exception: put a message in the unacceptable reasons. int msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_LOAD_PROVIDER_CLASS; String message = getMessage(msgID, String.valueOf(className), String.valueOf(configuration.dn()), stackTraceToSingleLineString(e)); unacceptableReasons.add(message); return false; } // Check that the implementation class implements the correct interface. try { // Determine the initialization method to use: it must take a // single parameter which is the exact type of the configuration // object. theClass.getMethod("initializeSynchronizationProvider", configuration.definition().getServerConfigurationClass()); } catch (Exception e) { // Handle the exception: put a message in the unacceptable reasons. int msgID = MSGID_CONFIG_SYNCH_UNABLE_TO_INSTANTIATE_PROVIDER; String message = getMessage(msgID, String.valueOf(className), String.valueOf(configuration.dn()), stackTraceToSingleLineString(e)); unacceptableReasons.add(message); return false; } return new ConfigChangeResult(resultCode, adminActionRequired, messages); } /** * Indicates whether the configuration entry that will result from a proposed * add is acceptable to this add listener. * * @param configEntry The configuration entry that will result from * the requested add. * @param unacceptableReason A buffer to which this method can append a * human-readable message explaining why the * proposed entry is not acceptable. * * @return <CODE>true</CODE> if the proposed entry contains an acceptable * configuration, or <CODE>false</CODE> if it does not. */ public boolean configAddIsAcceptable(ConfigEntry configEntry, StringBuilder unacceptableReason) { // NYI // The class is valid as far as we can tell. return true; } /** * Attempts to apply a new configuration based on the provided added entry. * * @param configEntry The new configuration entry that contains the * configuration to apply. * * @return Information about the result of processing the configuration * change. * {@inheritDoc} */ public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) public ConfigChangeResult applyConfigurationDelete( SynchronizationProviderCfg configuration) { // NYI return null; // Default result code. ResultCode resultCode = ResultCode.SUCCESS; boolean adminActionRequired = false; // See if the entry is registered as a synchronization provider. If so, // deregister and stop it. DN dn = configuration.dn(); SynchronizationProvider provider = registeredProviders.get(dn); if (provider != null) { DirectoryServer.deregisterSynchronizationProvider(provider); provider.finalizeSynchronizationProvider(); } return new ConfigChangeResult(resultCode, adminActionRequired); } /** * Indicates whether it is acceptable to remove the provided configuration * entry. * * @param configEntry The configuration entry that will be removed * from the configuration. * @param unacceptableReason A buffer to which this method can append a * human-readable message explaining why the * proposed delete is not acceptable. * * @return <CODE>true</CODE> if the proposed entry may be removed from the * configuration, or <CODE>false</CODE> if not. * {@inheritDoc} */ public boolean configDeleteIsAcceptable(ConfigEntry configEntry, StringBuilder unacceptableReason) public boolean isConfigurationDeleteAcceptable( SynchronizationProviderCfg configuration, List<String> unacceptableReasons) { // NYI // A delete should always be acceptable, so just return true. return true; } /** * Attempts to apply a new configuration based on the provided deleted entry. * * @param configEntry The new configuration entry that has been deleted. * * @return Information about the result of processing the configuration * change. */ public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) { // NYI return null; } } opends/src/server/org/opends/server/synchronization/changelog/Changelog.java
@@ -40,26 +40,24 @@ import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.server.ChangelogServerCfg; import org.opends.server.api.ConfigurableComponent; import org.opends.server.api.DirectoryThread; import org.opends.server.config.ConfigAttribute; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.config.IntegerConfigAttribute; import org.opends.server.config.IntegerWithUnitConfigAttribute; import org.opends.server.config.StringConfigAttribute; import org.opends.server.core.DirectoryServer; import org.opends.server.messages.MessageHandler; import org.opends.server.synchronization.protocol.SocketSession; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DN; import org.opends.server.types.ErrorLogCategory; import org.opends.server.types.ErrorLogSeverity; import org.opends.server.types.ResultCode; import com.sleepycat.je.DatabaseException; @@ -73,7 +71,9 @@ * * It is responsible for creating the changelog cache and managing it */ public class Changelog implements Runnable, ConfigurableComponent public class Changelog implements Runnable, ConfigurableComponent, ConfigurationChangeListener<ChangelogServerCfg> { private short serverId; private String serverURL; @@ -85,7 +85,7 @@ private boolean runListen = true; /* The list of changelog servers configured by the administrator */ private List<String> changelogServers; private Collection<String> changelogServers; /* This table is used to store the list of dn for which we are currently * handling servers. @@ -106,212 +106,30 @@ private long trimAge; // the time (in sec) after which the changes must // de deleted from the persistent storage. static final String CHANGELOG_SERVER_ATTR = "ds-cfg-changelog-server"; static final String SERVER_ID_ATTR = "ds-cfg-changelog-server-id"; static final String CHANGELOG_PORT_ATTR = "ds-cfg-changelog-port"; static final String WINDOW_SIZE_ATTR = "ds-cfg-window-size"; static final String QUEUE_SIZE_ATTR = "ds-cfg-changelog-max-queue-size"; static final String CHANGELOG_DIR_PATH_ATTR = "ds-cfg-changelog-db-directory"; static final String PURGE_DELAY_ATTR = "ds-cfg-changelog-purge-delay"; static final IntegerConfigAttribute changelogPortStub = new IntegerConfigAttribute(CHANGELOG_PORT_ATTR, "changelog port", true, false, false, true, 0, true, 65535); static final IntegerConfigAttribute serverIdStub = new IntegerConfigAttribute(SERVER_ID_ATTR, "server ID", true, false, false, true, 0, true, 65535); static final StringConfigAttribute changelogStub = new StringConfigAttribute(CHANGELOG_SERVER_ATTR, "changelog server information", true, true, false); static final IntegerConfigAttribute windowStub = new IntegerConfigAttribute(WINDOW_SIZE_ATTR, "window size", false, false, false, true, 0, false, 0); static final IntegerConfigAttribute queueSizeStub = new IntegerConfigAttribute(QUEUE_SIZE_ATTR, "changelog queue size", false, false, false, true, 0, false, 0); static final StringConfigAttribute dbDirnameStub = new StringConfigAttribute(CHANGELOG_DIR_PATH_ATTR, "changelog storage directory path", false, false, true); /** * The set of time units that will be used for expressing the * changelog purge delay. */ private static final LinkedHashMap<String,Double> purgeTimeUnits = new LinkedHashMap<String,Double>(); static { purgeTimeUnits.put(TIME_UNIT_SECONDS_ABBR, 1D); purgeTimeUnits.put(TIME_UNIT_SECONDS_FULL, 1D); purgeTimeUnits.put(TIME_UNIT_MINUTES_ABBR, 60D); purgeTimeUnits.put(TIME_UNIT_MINUTES_FULL, 1D); purgeTimeUnits.put(TIME_UNIT_HOURS_ABBR, 60*60D); purgeTimeUnits.put(TIME_UNIT_HOURS_FULL, 60*60D); purgeTimeUnits.put(TIME_UNIT_DAYS_ABBR, 24*60*60D); purgeTimeUnits.put(TIME_UNIT_DAYS_FULL, 24*60*60D); } static final IntegerWithUnitConfigAttribute purgeDelayStub = new IntegerWithUnitConfigAttribute(PURGE_DELAY_ATTR, "changelog purge delay", false, purgeTimeUnits, true, 0, false, 0); /** * Check if a ConfigEntry is valid. * @param config The config entry that needs to be checked. * @param unacceptableReason A description of the reason why the config entry * is not acceptable (if return is false). * @return a boolean indicating if the configEntry is valid. */ public static boolean checkConfigEntry(ConfigEntry config, StringBuilder unacceptableReason) { try { IntegerConfigAttribute changelogPortAttr; changelogPortAttr = (IntegerConfigAttribute) config.getConfigAttribute(changelogPortStub); /* The config must provide a changelog port number */ if (changelogPortAttr == null) { unacceptableReason.append( MessageHandler.getMessage(MSGID_NEED_CHANGELOG_PORT, config.getDN().toString()) ); } /* * read the server Id information * this is a single valued integer, its value must fit on a * short integer */ IntegerConfigAttribute serverIdAttr = (IntegerConfigAttribute) config.getConfigAttribute(serverIdStub); if (serverIdAttr == null) { unacceptableReason.append( MessageHandler.getMessage(MSGID_NEED_SERVER_ID, config.getDN().toString()) ); } return true; } catch (ConfigException e) { return false; } } /** * Creates a new Changelog using the provided configuration entry. * * @param config The configuration entry where configuration can be found. * @throws ConfigException When Configuration entry is invalid. * @param configuration The configuration of this changelog. * @throws ConfigException When Configuration is invalid. */ public Changelog(ConfigEntry config) throws ConfigException public Changelog(ChangelogServerCfg configuration) throws ConfigException { shutdown = false; runListen = true; IntegerConfigAttribute changelogPortAttr = (IntegerConfigAttribute) config.getConfigAttribute(changelogPortStub); /* if there is no changelog port configured, this process must not be a * changelog server */ if (changelogPortAttr == null) { throw new ConfigException(MSGID_NEED_CHANGELOG_PORT, MessageHandler.getMessage(MSGID_NEED_CHANGELOG_PORT, config.getDN().toString()) ); } int changelogPort = changelogPortAttr.activeIntValue(); configAttributes.add(changelogPortAttr); /* * read the server Id information * this is a single valued integer, its value must fit on a * short integer */ IntegerConfigAttribute serverIdAttr = (IntegerConfigAttribute) config.getConfigAttribute(serverIdStub); if (serverIdAttr == null) { throw new ConfigException(MSGID_NEED_SERVER_ID, MessageHandler.getMessage(MSGID_NEED_SERVER_ID, config.getDN().toString()) ); } changelogServerId = (short) serverIdAttr.activeIntValue(); configAttributes.add(serverIdAttr); /* * read the centralized changelog server configuration * this is a multivalued attribute */ StringConfigAttribute changelogServer = (StringConfigAttribute) config.getConfigAttribute(changelogStub); changelogServers = new ArrayList<String>(); if (changelogServer != null) { for (String serverURL : changelogServer.activeValues()) { String[] splitStrings = serverURL.split(":"); try { changelogServers.add( InetAddress.getByName(splitStrings[0]).getHostAddress() + ":" + splitStrings[1]); } catch (UnknownHostException e) { throw new ConfigException(MSGID_UNKNOWN_HOSTNAME, e.getLocalizedMessage()); } } } configAttributes.add(changelogServer); IntegerConfigAttribute windowAttr = (IntegerConfigAttribute) config.getConfigAttribute(windowStub); if (windowAttr == null) rcvWindow = 100; // Attribute is not present : use the default value else { rcvWindow = windowAttr.activeIntValue(); configAttributes.add(windowAttr); } IntegerConfigAttribute queueSizeAttr = (IntegerConfigAttribute) config.getConfigAttribute(queueSizeStub); if (queueSizeAttr == null) queueSize = 10000; // Attribute is not present : use the default value else { queueSize = queueSizeAttr.activeIntValue(); configAttributes.add(queueSizeAttr); } /* * read the storage directory path attribute */ StringConfigAttribute dbDirnameAttr = (StringConfigAttribute) config.getConfigAttribute(dbDirnameStub); if (dbDirnameAttr == null) int changelogPort = configuration.getChangelogPort(); changelogServerId = (short) configuration.getChangelogServerId(); changelogServers = configuration.getChangelogServer(); if (changelogServers == null) changelogServers = new ArrayList<String>(); queueSize = configuration.getQueueSize(); trimAge = configuration.getChangelogPurgeDelay(); dbDirname = configuration.getChangelogDbDirectory(); rcvWindow = configuration.getWindowSize(); if (dbDirname == null) { dbDirname = "changelogDb"; } else { dbDirname = dbDirnameAttr.activeValue(); configAttributes.add(changelogServer); } // Exists or Create // Chech that this path exists or create it. File f = getFileForPath(dbDirname); try { @@ -326,24 +144,8 @@ e.getMessage() + " " + getFileForPath(dbDirname)); } /* * Read the Purge Delay (trim age) attribute */ IntegerWithUnitConfigAttribute purgeDelayAttr = (IntegerWithUnitConfigAttribute) config.getConfigAttribute( purgeDelayStub); if (purgeDelayAttr == null) trimAge = 24*60*60; // not present : use the default value : 1 day else { trimAge = purgeDelayAttr.activeCalculatedValue(); configAttributes.add(purgeDelayAttr); } initialize(changelogServerId, changelogPort); configDn = config.getDN(); DirectoryServer.registerConfigurableComponent(this); configuration.addChangeListener(this); } /** @@ -452,7 +254,7 @@ */ for (String serverURL : changelogServers) { if ((serverURL.compareTo(localURL) != 0) && if ((serverURL.compareTo(this.serverURL) != 0) && (!connectedChangelogs.contains(serverURL))) { this.connect(serverURL, changelogCache.getBaseDn()); @@ -629,7 +431,6 @@ } dbEnv.shutdown(); DirectoryServer.deregisterConfigurableComponent(this); } @@ -659,4 +460,56 @@ { return trimAge * 1000; } /** * Check if the provided configuration is acceptable for add. * * @param configuration The configuration to check. * @param unacceptableReasons When the configuration is not acceptable, this * table is use to return the reasons why this * configuration is not acceptbale. * * @return true if the configuration is acceptable, false other wise. */ public static boolean isConfigurationAcceptable( ChangelogServerCfg configuration, List<String> unacceptableReasons) { int port = configuration.getChangelogPort(); try { ServerSocket tmpSocket = new ServerSocket(); tmpSocket.bind(new InetSocketAddress(port)); tmpSocket.close(); } catch (Exception e) { String message = getMessage(MSGID_COULD_NOT_BIND_CHANGELOG, port, e.getMessage()); unacceptableReasons.add(message); return false; } return true; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange( ChangelogServerCfg configuration) { // TODO : implement this return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * {@inheritDoc} */ public boolean isConfigurationChangeAcceptable( ChangelogServerCfg configuration, List<String> unacceptableReasons) { // TODO : implement this return true; } } opends/src/server/org/opends/server/synchronization/common/LogMessages.java
@@ -48,18 +48,6 @@ CATEGORY_MASK_SYNC | SEVERITY_MASK_MILD_ERROR | 1; /** * Need at least one Changelog Server. */ public static final int MSGID_NEED_CHANGELOG_SERVER = CATEGORY_MASK_SYNC | SEVERITY_MASK_MILD_ERROR | 2; /** * Need to have a server ID. */ public static final int MSGID_NEED_SERVER_ID = CATEGORY_MASK_SYNC | SEVERITY_MASK_MILD_ERROR | 3; /** * Invalid Changelog Server. */ public static final int MSGID_INVALID_CHANGELOG_SERVER = @@ -380,11 +368,7 @@ public static void registerMessages() { MessageHandler.registerMessage(MSGID_SYNC_INVALID_DN, "The Synchronization configuration DN is invalid"); MessageHandler.registerMessage(MSGID_NEED_CHANGELOG_SERVER, "At least one changelog server must be declared"); MessageHandler.registerMessage(MSGID_NEED_SERVER_ID, "The Server Id must be defined"); "The configured DN is already used by another domain."); MessageHandler.registerMessage(MSGID_INVALID_CHANGELOG_SERVER, "Invalid changelog server configuration"); MessageHandler.registerMessage(MSGID_UNKNOWN_HOSTNAME, opends/src/server/org/opends/server/synchronization/plugin/ChangelogBroker.java
@@ -33,8 +33,8 @@ import static org.opends.server.synchronization.common.LogMessages.*; import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.TreeSet; import java.util.concurrent.Semaphore; import java.io.IOException; @@ -75,7 +75,7 @@ public class ChangelogBroker implements InternalSearchListener { private boolean shutdown = false; private List<String> servers; private Collection<String> servers; private boolean connected = false; private final Object lock = new Object(); private String changelogServer = "Not connected"; @@ -158,7 +158,7 @@ * @param servers list of servers used * @throws Exception : in case of errors */ public void start(List<String> servers) public void start(Collection<String> servers) throws Exception { /* @@ -504,7 +504,6 @@ try { SynchronizationMessage msg = session.receive(); if (msg instanceof WindowMessage) { WindowMessage windowMsg = (WindowMessage) msg; @@ -556,7 +555,8 @@ debugInfo("ChangelogBroker Stop Closing session"); } session.close(); if (session != null) session.close(); } catch (IOException e) {} } @@ -695,11 +695,31 @@ return numLostConnections; } private void log(String message) /** * Change some config parameters. * * @param changelogServers The new list of changelog servers. * @param maxReceiveQueue The max size of receive queue. * @param maxReceiveDelay The max receive delay. * @param maxSendQueue The max send queue. * @param maxSendDelay The max Send Delay. * @param window The max window size. * @param heartbeatInterval The heartbeat interval. */ public void changeConfig(Collection<String> changelogServers, int maxReceiveQueue, int maxReceiveDelay, int maxSendQueue, int maxSendDelay, int window, long heartbeatInterval) { int msgID = MSGID_UNKNOWN_TYPE; logError(ErrorLogCategory.SYNCHRONIZATION, ErrorLogSeverity.SEVERE_ERROR, message, msgID); this.servers = changelogServers; this.maxRcvWindow = window; this.heartbeatInterval = heartbeatInterval; this.maxReceiveDelay = maxReceiveDelay; this.maxReceiveQueue = maxReceiveQueue; this.maxSendDelay = maxSendDelay; this.maxSendQueue = maxSendQueue; // TODO : Changing those parameters requires to either restart a new // session with the changelog server or renegociate the parameters that // were sent in the ServerStart message } } opends/src/server/org/opends/server/synchronization/plugin/ChangelogListener.java
New file @@ -0,0 +1,136 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.synchronization.plugin; import java.util.List; import org.opends.server.admin.server.ConfigurationAddListener; import org.opends.server.admin.server.ConfigurationDeleteListener; import org.opends.server.admin.std.server.ChangelogServerCfg; import org.opends.server.admin.std.server.MultimasterSynchronizationProviderCfg; import org.opends.server.config.ConfigException; import org.opends.server.synchronization.changelog.Changelog; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.ResultCode; /** * This class is used to create and object that can * register in the admin framework as a listener for changes, add and delete * on the Changelog Server configuration objects. * */ public class ChangelogListener implements ConfigurationAddListener<ChangelogServerCfg>, ConfigurationDeleteListener<ChangelogServerCfg> { Changelog changelog = null; /** * Build a Changelog Listener from the given Multimaster configuration. * * @param configuration The configuration that will be used to listen * for changelog configuration changes. * * @throws ConfigException if the ChangelogListener can't register for * listening to changes on the provided configuration * object. */ public ChangelogListener( MultimasterSynchronizationProviderCfg configuration) throws ConfigException { configuration.addChangelogServerAddListener(this); configuration.addChangelogServerDeleteListener(this); if (configuration.hasChangelogServer()) { ChangelogServerCfg server = configuration.getChangelogServer(); changelog = new Changelog(server); } } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationAdd( ChangelogServerCfg configuration) { try { changelog = new Changelog(configuration); return new ConfigChangeResult(ResultCode.SUCCESS, false); } catch (ConfigException e) { // we should never get to this point because the configEntry has // already been validated in configAddisAcceptable return new ConfigChangeResult(ResultCode.CONSTRAINT_VIOLATION, false); } } /** * {@inheritDoc} */ public boolean isConfigurationAddAcceptable( ChangelogServerCfg configuration, List<String> unacceptableReasons) { return Changelog.isConfigurationAcceptable( configuration, unacceptableReasons); } /** * Shutdown the Changelog servers. */ public void shutdown() { if (changelog != null) changelog.shutdown(); } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationDelete( ChangelogServerCfg configuration) { // There can be only one changelog, just shutdown the changelog // currently configured. if (changelog != null) { changelog.shutdown(); } return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * {@inheritDoc} */ public boolean isConfigurationDeleteAcceptable( ChangelogServerCfg configuration, List<String> unacceptableReasons) { return true; } } opends/src/server/org/opends/server/synchronization/plugin/MultimasterSynchronization.java
@@ -26,34 +26,35 @@ */ package org.opends.server.synchronization.plugin; import static org.opends.server.synchronization.common.LogMessages.HISTORICAL; import java.util.HashMap; import java.util.List; import java.util.Map; import org.opends.server.admin.server.ConfigurationAddListener; import org.opends.server.admin.server.ConfigurationDeleteListener; import org.opends.server.admin.std.server.MultimasterDomainCfg; import org.opends.server.admin.std.server.MultimasterSynchronizationProviderCfg; import org.opends.server.api.Backend; import org.opends.server.api.BackupTaskListener; import org.opends.server.api.ConfigAddListener; import org.opends.server.api.ConfigChangeListener; import org.opends.server.api.ConfigDeleteListener; import org.opends.server.api.ExportTaskListener; import org.opends.server.api.ImportTaskListener; import org.opends.server.api.RestoreTaskListener; import org.opends.server.api.SynchronizationProvider; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.core.AddOperation; import org.opends.server.synchronization.changelog.Changelog; import org.opends.server.synchronization.common.LogMessages; import org.opends.server.types.DN; import org.opends.server.core.DeleteOperation; import org.opends.server.types.DirectoryException; import org.opends.server.core.DirectoryServer; import org.opends.server.types.Entry; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.core.Operation; import org.opends.server.synchronization.common.LogMessages; import org.opends.server.types.BackupConfig; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DN; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.LDIFExportConfig; import org.opends.server.types.LDIFImportConfig; import org.opends.server.types.Modification; @@ -61,8 +62,6 @@ import org.opends.server.types.ResultCode; import org.opends.server.types.SynchronizationProviderResult; import static org.opends.server.synchronization.common.LogMessages.*; /** * This class is used to load the Synchronization code inside the JVM * and to trigger initialization of the synchronization. @@ -71,19 +70,19 @@ * synchronization code running during the operation process * as pre-op, conflictRsolution, and post-op. */ public class MultimasterSynchronization extends SynchronizationProvider implements ConfigAddListener, ConfigDeleteListener, ConfigChangeListener, BackupTaskListener, RestoreTaskListener, ImportTaskListener, ExportTaskListener public class MultimasterSynchronization extends SynchronizationProvider<MultimasterSynchronizationProviderCfg> implements ConfigurationAddListener<MultimasterDomainCfg>, ConfigurationDeleteListener<MultimasterDomainCfg>, BackupTaskListener, RestoreTaskListener, ImportTaskListener, ExportTaskListener { static String CHANGELOG_DN = "cn=Changelog Server," + "cn=Multimaster Synchronization, cn=Synchronization Providers, cn=config"; static String SYNCHRONIZATION_CLASS = "ds-cfg-synchronization-provider-config"; private DN changelogConfigEntryDn = null; private Changelog changelog = null; private ChangelogListener changelog = null; private static Map<DN, SynchronizationDomain> domains = new HashMap<DN, SynchronizationDomain>() ; @@ -91,46 +90,25 @@ /** * {@inheritDoc} */ public void initializeSynchronizationProvider(ConfigEntry configEntry) @Override public void initializeSynchronizationProvider( MultimasterSynchronizationProviderCfg configuration) throws ConfigException { LogMessages.registerMessages(); configEntry.registerAddListener(this); configEntry.registerDeleteListener(this); changelog = new ChangelogListener(configuration); /* * Read changelog server the changelog configuration entry */ try { changelogConfigEntryDn = DN.decode(CHANGELOG_DN); ConfigEntry config = DirectoryServer.getConfigEntry(changelogConfigEntryDn); /* * If there is no such entry, this process must not be a changelog server */ if (config != null) { changelog = new Changelog(config); } } catch (DirectoryException e) { /* never happens */ throw new ConfigException(MSGID_SYNC_INVALID_DN, "Invalid Changelog configuration DN"); } // Register as an add and delete listener with the root configuration so we // can be notified if Multimaster domain entries are added or removed. configuration.addMultimasterDomainAddListener(this); configuration.addMultimasterDomainDeleteListener(this); /* * Parse the list of entries below configEntry, * create one synchronization domain for each child */ for (ConfigEntry domainEntry : configEntry.getChildren().values()) // Create the list of domains that are already defined. for (String name : configuration.listMultimasterDomains()) { if (domainEntry.hasObjectClass(SYNCHRONIZATION_CLASS)) { createNewSynchronizationDomain(domainEntry); } MultimasterDomainCfg domain = configuration.getMultimasterDomain(name); createNewSynchronizationDomain(domain); } /* @@ -151,124 +129,46 @@ } /** * 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. * * @return <CODE>true</CODE> if the proposed entry contains an acceptable * configuration, or <CODE>false</CODE> if it does not. * {@inheritDoc} */ public boolean configChangeIsAcceptable(ConfigEntry configEntry, StringBuilder unacceptableReason) public boolean isConfigurationAddAcceptable( MultimasterDomainCfg configuration, List<String> unacceptableReasons) { return false; // TODO :NYI } /** * Attempts to apply a new configuration to this Directory Server component * based on the provided changed entry. * * @param configEntry The configuration entry that containing the updated * configuration for this component. * * @return Information about the result of processing the configuration * change. */ public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) { // TODO implement this method return new ConfigChangeResult(ResultCode.SUCCESS, false); return SynchronizationDomain.isConfigurationAcceptable( configuration, unacceptableReasons); } /** * {@inheritDoc} */ public boolean configAddIsAcceptable(ConfigEntry configEntry, StringBuilder unacceptableReason) public ConfigChangeResult applyConfigurationAdd( MultimasterDomainCfg configuration) { // Check if the added entry is the changelog config entry try { if (configEntry.getDN().equals(DN.decode(CHANGELOG_DN))) { return Changelog.checkConfigEntry(configEntry, unacceptableReason); } } catch (DirectoryException e) createNewSynchronizationDomain(configuration); return new ConfigChangeResult(ResultCode.SUCCESS, false); } catch (ConfigException e) { /* never happens */ unacceptableReason.append("Invalid Changelog configuration DN"); return false; // we should never get to this point because the configEntry has // already been validated in configAddisAcceptable return new ConfigChangeResult(ResultCode.CONSTRAINT_VIOLATION, false); } // otherwise it must be a Synchronization domain, check for // presence of the Synchronization configuration object class if (configEntry.hasObjectClass(SYNCHRONIZATION_CLASS)) { return SynchronizationDomain.checkConfigEntry(configEntry, unacceptableReason); } return false; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) { // check if the entry is the changelog configuration entry if (configEntry.getDN().equals(changelogConfigEntryDn)) { try { changelog = new Changelog(configEntry); return new ConfigChangeResult(ResultCode.SUCCESS, false); } catch (ConfigException e) { // we should never get to this point because the configEntry has // already been validated in configAddisAcceptable return new ConfigChangeResult(ResultCode.SUCCESS, false); } } // otherwise it must be a synchronization domain, check for // presence of the Synchronization configuration object class if (configEntry.hasObjectClass(SYNCHRONIZATION_CLASS)) { try { createNewSynchronizationDomain(configEntry); return new ConfigChangeResult(ResultCode.SUCCESS, false); } catch (ConfigException e) { // we should never get to this point because the configEntry has // already been validated in configAddisAcceptable return new ConfigChangeResult(ResultCode.SUCCESS, false); } } // we should never get to this point because the configEntry has // already been validated in configAddisAcceptable return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * Creates a New Synchronization domain from its configEntry, do the * necessary initialization and starts it so that it is * fully operational when this method returns. * @param configEntry The entry whith the configuration of this domain. * @param configuration The entry whith the configuration of this domain. * @throws ConfigException When the configuration is not valid. */ private void createNewSynchronizationDomain(ConfigEntry configEntry) throws ConfigException private void createNewSynchronizationDomain( MultimasterDomainCfg configuration) throws ConfigException { SynchronizationDomain domain; domain = new SynchronizationDomain(configEntry); domain = new SynchronizationDomain(configuration); domains.put(domain.getBaseDN(), domain); domain.start(); } @@ -276,25 +176,7 @@ /** * {@inheritDoc} */ public boolean configDeleteIsAcceptable(ConfigEntry configEntry, StringBuilder unacceptableReason) { // TODO Auto-generated method stub return true; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) { // TODO Auto-generated method stub return null; } /** * {@inheritDoc} */ @Override public void doPostOperation(AddOperation addOperation) { DN dn = addOperation.getEntryDN(); @@ -305,6 +187,7 @@ /** * {@inheritDoc} */ @Override public void doPostOperation(DeleteOperation deleteOperation) { DN dn = deleteOperation.getEntryDN(); @@ -314,6 +197,7 @@ /** * {@inheritDoc} */ @Override public void doPostOperation(ModifyDNOperation modifyDNOperation) { DN dn = modifyDNOperation.getEntryDN(); @@ -536,6 +420,7 @@ * applied to the schema. * */ @Override public void processSchemaChange(List<Modification> modifications) { SynchronizationDomain domain = @@ -651,6 +536,29 @@ domain.backupEnd(); } } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationDelete( MultimasterDomainCfg configuration) { DN dn = configuration.getSynchronizationDN(); SynchronizationDomain domain = domains.remove(dn); if (domain != null) domain.shutdown(); return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * {@inheritDoc} */ public boolean isConfigurationDeleteAcceptable( MultimasterDomainCfg configuration, List<String> unacceptableReasons) { return true; } } opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
@@ -39,14 +39,13 @@ import static org.opends.server.synchronization.common.LogMessages.*; import static org.opends.server.synchronization.plugin.Historical.ENTRYUIDNAME; import static org.opends.server.synchronization.protocol.OperationContext.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.createEntry; import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; import java.io.IOException; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Collection; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -55,20 +54,18 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.DataFormatException; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.server.MultimasterDomainCfg; import org.opends.server.api.Backend; import org.opends.server.api.ConfigurableComponent; import org.opends.server.api.DirectoryThread; import org.opends.server.api.SynchronizationProvider; import org.opends.server.backends.jeb.BackendImpl; import org.opends.server.backends.task.Task; import org.opends.server.backends.task.TaskState; import org.opends.server.config.BooleanConfigAttribute; import org.opends.server.config.ConfigAttribute; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.config.DNConfigAttribute; import org.opends.server.config.IntegerConfigAttribute; import org.opends.server.config.IntegerWithUnitConfigAttribute; import org.opends.server.config.StringConfigAttribute; import org.opends.server.core.AddOperation; import org.opends.server.core.DeleteOperation; @@ -77,7 +74,6 @@ import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.core.Operation; import org.opends.server.messages.MessageHandler; import org.opends.server.protocols.asn1.ASN1Exception; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; @@ -130,7 +126,7 @@ * handle protocol messages from the changelog server. */ public class SynchronizationDomain extends DirectoryThread implements ConfigurableComponent implements ConfigurationChangeListener<MultimasterDomainCfg> { private SynchronizationMonitor monitor; @@ -254,7 +250,7 @@ private int listenerThreadNumber = 10; private boolean receiveStatus = true; private List<String> changelogServers; private Collection<String> changelogServers; private DN baseDN; @@ -263,8 +259,6 @@ private boolean shutdown = false; private DN configDn; private InternalClientConnection conn = InternalClientConnection.getRootConnection(); @@ -273,102 +267,30 @@ private boolean disabled = false; private boolean stateSavingDisabled = false; static final String CHANGELOG_SERVER_ATTR = "ds-cfg-changelog-server"; static final String BASE_DN_ATTR = "ds-cfg-synchronization-dn"; static final String SERVER_ID_ATTR = "ds-cfg-directory-server-id"; static final String RECEIVE_STATUS = "ds-cfg-receive-status"; static final String MAX_RECEIVE_QUEUE = "ds-cfg-max-receive-queue"; static final String MAX_RECEIVE_DELAY = "ds-cfg-max-receive-delay"; static final String MAX_SEND_QUEUE = "ds-cfg-max-send-queue"; static final String MAX_SEND_DELAY = "ds-cfg-max-send-delay"; static final String WINDOW_SIZE = "ds-cfg-window-size"; static final String HEARTBEAT_INTERVAL = "ds-cfg-heartbeat-interval"; private int window = 100; private static final StringConfigAttribute changelogStub = new StringConfigAttribute(CHANGELOG_SERVER_ATTR, "changelog server information", true, true, false); private static final IntegerConfigAttribute serverIdStub = new IntegerConfigAttribute(SERVER_ID_ATTR, "server ID", true, false, false, true, 0, true, 65535); private static final DNConfigAttribute baseDnStub = new DNConfigAttribute(BASE_DN_ATTR, "synchronization base DN", true, false, false); private static final BooleanConfigAttribute receiveStatusStub = new BooleanConfigAttribute(RECEIVE_STATUS, "receive status", false); /** * The set of time units that will be used for expressing the heartbeat * interval. */ private static final LinkedHashMap<String,Double> timeUnits = new LinkedHashMap<String,Double>(); static { timeUnits.put(TIME_UNIT_MILLISECONDS_ABBR, 1D); timeUnits.put(TIME_UNIT_MILLISECONDS_FULL, 1D); timeUnits.put(TIME_UNIT_SECONDS_ABBR, 1000D); timeUnits.put(TIME_UNIT_SECONDS_FULL, 1000D); } /** * Creates a new SynchronizationDomain using configuration from configEntry. * * @param configEntry The ConfigEntry to use to read the configuration of this * SynchronizationDomain. * @param configuration The configuration of this SynchronizationDomain. * @throws ConfigException In case of invalid configuration. */ public SynchronizationDomain(ConfigEntry configEntry) throws ConfigException public SynchronizationDomain(MultimasterDomainCfg configuration) throws ConfigException { super("Synchronization flush"); /* * read the centralized changelog server configuration * this is a multivalued attribute */ StringConfigAttribute changelogServer = (StringConfigAttribute) configEntry.getConfigAttribute(changelogStub); if (changelogServer == null) { throw new ConfigException(MSGID_NEED_CHANGELOG_SERVER, MessageHandler.getMessage(MSGID_NEED_CHANGELOG_SERVER, configEntry.getDN().toString()) ); } changelogServers = changelogServer.activeValues(); configAttributes.add(changelogServer); /* * read the server Id information * this is a single valued integer, its value must fit on a short integer */ IntegerConfigAttribute serverIdAttr = (IntegerConfigAttribute) configEntry.getConfigAttribute(serverIdStub); if (serverIdAttr == null) { throw new ConfigException(MSGID_NEED_SERVER_ID, MessageHandler.getMessage(MSGID_NEED_SERVER_ID, configEntry.getDN().toString()) ); } serverId = (short) serverIdAttr.activeIntValue(); configAttributes.add(serverIdAttr); /* * read the base DN */ DNConfigAttribute baseDn = (DNConfigAttribute) configEntry.getConfigAttribute(baseDnStub); if (baseDn == null) baseDN = null; // Attribute is not present : don't set a limit else baseDN = baseDn.activeValue(); configAttributes.add(baseDn); // Read the configuration parameters. changelogServers = configuration.getChangelogServer(); serverId = (short) configuration.getServerId(); baseDN = configuration.getSynchronizationDN(); maxReceiveQueue = configuration.getMaxReceiveQueue(); maxReceiveDelay = (int) configuration.getMaxReceiveDelay(); maxSendQueue = configuration.getMaxSendQueue(); maxSendDelay = (int) configuration.getMaxSendDelay(); window = configuration.getWindowSize(); heartbeatInterval = configuration.getHeartbeatInterval(); /* * Modify conflicts are solved for all suffixes but the schema suffix @@ -386,114 +308,25 @@ solveConflictFlag = true; } /* * Create a new Persistent Server State that will be used to store * the last ChangeNmber seen from all LDAP servers in the topology. */ state = new PersistentServerState(baseDN); /* * Read the Receive Status. * Create a Synchronization monitor object responsible for publishing * monitoring information below cn=monitor. */ BooleanConfigAttribute receiveStatusAttr = (BooleanConfigAttribute) configEntry.getConfigAttribute(receiveStatusStub); if (receiveStatusAttr != null) { receiveStatus = receiveStatusAttr.activeValue(); configAttributes.add(receiveStatusAttr); } /* * read the synchronization flow control configuration. */ IntegerConfigAttribute maxReceiveQueueStub = new IntegerConfigAttribute(MAX_RECEIVE_QUEUE, "max receive queue", false, false, false, true, 0,false, 0); IntegerConfigAttribute maxReceiveQueueAttr = (IntegerConfigAttribute) configEntry.getConfigAttribute(maxReceiveQueueStub); if (maxReceiveQueueAttr == null) maxReceiveQueue = 0; // Attribute is not present : don't set a limit else { maxReceiveQueue = maxReceiveQueueAttr.activeIntValue(); configAttributes.add(maxReceiveQueueAttr); } IntegerConfigAttribute maxReceiveDelayStub = new IntegerConfigAttribute(MAX_RECEIVE_DELAY, "max receive delay", false, false, false, true, 0, false, 0); IntegerConfigAttribute maxReceiveDelayAttr = (IntegerConfigAttribute) configEntry.getConfigAttribute(maxReceiveDelayStub); if (maxReceiveDelayAttr == null) maxReceiveDelay = 0; // Attribute is not present : don't set a limit else { maxReceiveDelay = maxReceiveDelayAttr.activeIntValue(); configAttributes.add(maxReceiveDelayAttr); } IntegerConfigAttribute maxSendQueueStub = new IntegerConfigAttribute(MAX_SEND_QUEUE, "max send queue", false, false, false, true, 0, false, 0); IntegerConfigAttribute maxSendQueueAttr = (IntegerConfigAttribute) configEntry.getConfigAttribute(maxSendQueueStub); if (maxSendQueueAttr == null) maxSendQueue = 0; // Attribute is not present : don't set a limit else { maxSendQueue = maxSendQueueAttr.activeIntValue(); configAttributes.add(maxSendQueueAttr); } IntegerConfigAttribute maxSendDelayStub = new IntegerConfigAttribute(MAX_SEND_DELAY, "max send delay", false, false, false, true, 0, false, 0); IntegerConfigAttribute maxSendDelayAttr = (IntegerConfigAttribute) configEntry.getConfigAttribute(maxSendDelayStub); if (maxSendDelayAttr == null) maxSendDelay = 0; // Attribute is not present : don't set a limit else { maxSendDelay = maxSendDelayAttr.activeIntValue(); configAttributes.add(maxSendDelayAttr); } Integer window; IntegerConfigAttribute windowStub = new IntegerConfigAttribute(WINDOW_SIZE, "window size", false, false, false, true, 0, false, 0); IntegerConfigAttribute windowAttr = (IntegerConfigAttribute) configEntry.getConfigAttribute(windowStub); if (windowAttr == null) window = 100; // Attribute is not present : use the default value else { window = windowAttr.activeIntValue(); configAttributes.add(windowAttr); } IntegerWithUnitConfigAttribute heartbeatStub = new IntegerWithUnitConfigAttribute(HEARTBEAT_INTERVAL, "heartbeat interval", false, timeUnits, true, 0, false, 0); IntegerWithUnitConfigAttribute heartbeatAttr = (IntegerWithUnitConfigAttribute) configEntry.getConfigAttribute(heartbeatStub); if (heartbeatAttr == null) { // Attribute is not present : use the default value heartbeatInterval = 1000; } else { heartbeatInterval = heartbeatAttr.activeCalculatedValue(); configAttributes.add(heartbeatAttr); } configDn = configEntry.getDN(); DirectoryServer.registerConfigurableComponent(this); monitor = new SynchronizationMonitor(this); DirectoryServer.registerMonitorProvider(monitor); /* * ChangeNumberGenerator is used to create new unique ChangeNumbers * for each operation done on the synchronization domain. */ changeNumberGenerator = new ChangeNumberGenerator(serverId, state); /* * create the broker object used to publish and receive changes */ @@ -519,14 +352,9 @@ * should we stop the modifications ? */ } } /** * {@inheritDoc} */ public DN getConfigurableComponentEntryDN() { return configDn; // listen for changes on the configuration configuration.addChangeListener(this); } /** @@ -537,112 +365,6 @@ return configAttributes; } /** * {@inheritDoc} */ public boolean hasAcceptableConfiguration(ConfigEntry configEntry, List<String> unacceptableReasons) { boolean acceptable = true; StringConfigAttribute changelog = null; try { changelog = (StringConfigAttribute) configEntry.getConfigAttribute(changelogStub); } catch (ConfigException e) { acceptable = false; unacceptableReasons.add("Need at least one changelog server."); } if (changelog == null) { acceptable = false; unacceptableReasons.add("Need at least one changelog server."); } return acceptable; } /** * {@inheritDoc} */ public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry, boolean detailedResults) { StringConfigAttribute changelog = null; List<String> newChangelogServers; boolean newReceiveStatus; try { /* * check if changelog server list changed */ changelog = (StringConfigAttribute) configEntry.getConfigAttribute(changelogStub); newChangelogServers = changelog.activeValues(); boolean sameConf = true; for (String s :newChangelogServers) if (!changelogServers.contains(s)) sameConf = false; for (String s : changelogServers) if (!newChangelogServers.contains(s)) sameConf = false; if (!sameConf) { broker.stop(); changelogServers = newChangelogServers; broker.start(changelogServers); } /* * check if reception should be disabled */ newReceiveStatus = ((BooleanConfigAttribute) configEntry.getConfigAttribute(receiveStatusStub)).activeValue(); if (newReceiveStatus != receiveStatus) { /* * was disabled and moved to enabled */ if (newReceiveStatus) { broker.restartReceive(); for (int i=0; i<listenerThreadNumber; i++) { ListenerThread myThread = new ListenerThread(this); myThread.start(); synchroThreads.add(myThread); } } else { /* was enabled and moved to disabled */ broker.suspendReceive(); // FIXME Need a way to stop these threads. // Setting the shutdown flag does not stop them until they have // consumed and discarded one more message each. // for (ListenerThread thread : synchroThreads) // { // thread.shutdown(); // } synchroThreads.clear(); } receiveStatus = newReceiveStatus; } } catch (Exception e) { /* this should never happen because the parameters have been * validated by hasAcceptableConfiguration */ return new ConfigChangeResult(ResultCode.OPERATIONS_ERROR, false); } return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * Returns the base DN of this SynchronizationDomain. @@ -1041,9 +763,7 @@ public void receiveAck(AckMessage ack) { UpdateMessage update; ChangeNumber changeNumber; changeNumber = ack.getChangeNumber(); ChangeNumber changeNumber = ack.getChangeNumber(); synchronized (pendingChanges) { @@ -1933,51 +1653,6 @@ } /** * Check if a ConfigEntry is valid. * @param configEntry The config entry that needs to be checked. * @param unacceptableReason A description of the reason why the config entry * is not acceptable (if return is false). * @return a boolean indicating if the configEntry is valid. */ public static boolean checkConfigEntry(ConfigEntry configEntry, StringBuilder unacceptableReason) { try { StringConfigAttribute changelogServer = (StringConfigAttribute) configEntry.getConfigAttribute(changelogStub); if (changelogServer == null) { unacceptableReason.append( MessageHandler.getMessage(MSGID_NEED_CHANGELOG_SERVER, configEntry.getDN().toString()) ); return false; } /* * read the server Id information * this is a single valued integer, its value must fit on a short integer */ IntegerConfigAttribute serverIdAttr = (IntegerConfigAttribute) configEntry.getConfigAttribute(serverIdStub); if (serverIdAttr == null) { unacceptableReason.append( MessageHandler.getMessage(MSGID_NEED_SERVER_ID, configEntry.getDN().toString()) ); return false; } } catch (ConfigException e) { unacceptableReason.append(e.getMessage()); return false; } return true; } /** * Get the maximum receive window size. * * @return The maximum receive window size. @@ -2026,7 +1701,6 @@ return broker.getNumLostConnections(); } /** * Check if the domain solve conflicts. * @@ -3109,4 +2783,60 @@ op.setResultCode(ResultCode.SUCCESS); synchronize(op); } /** * Check if the provided configuration is acceptable for add. * * @param configuration The configuration to check. * @param unacceptableReasons When the configuration is not acceptable, this * table is use to return the reasons why this * configuration is not acceptbale. * * @return true if the configuration is acceptable, false other wise. */ public static boolean isConfigurationAcceptable( MultimasterDomainCfg configuration, List<String> unacceptableReasons) { // Check that there is not already a domain with the same DN // TODO : Check that the server id is a short DN dn = configuration.getSynchronizationDN(); if (MultimasterSynchronization.findDomain(dn,null) != null) { String message = getMessage(MSGID_SYNC_INVALID_DN, dn.toString()); unacceptableReasons.add(message); return false; } return true; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange( MultimasterDomainCfg configuration) { // server id and base dn are readonly. // The other parameters needs to be renegociated with the Changelog Server. // so that requires restarting the session with the Changelog Server. changelogServers = configuration.getChangelogServer(); maxReceiveQueue = configuration.getMaxReceiveQueue(); maxReceiveDelay = (int) configuration.getMaxReceiveDelay(); maxSendQueue = configuration.getMaxSendQueue(); maxSendDelay = (int) configuration.getMaxSendDelay(); window = configuration.getWindowSize(); heartbeatInterval = configuration.getHeartbeatInterval(); broker.changeConfig(changelogServers, maxReceiveQueue, maxReceiveDelay, maxSendQueue, maxSendDelay, window, heartbeatInterval); return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * {@inheritDoc} */ public boolean isConfigurationChangeAcceptable( MultimasterDomainCfg configuration, List<String> unacceptableReasons) { return true; } } opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java
@@ -35,6 +35,7 @@ import java.util.TreeSet; import java.util.concurrent.locks.Lock; import org.opends.server.admin.std.server.SynchronizationProviderCfg; import org.opends.server.api.ClientConnection; import org.opends.server.api.SynchronizationProvider; import org.opends.server.backends.task.Task; @@ -298,7 +299,7 @@ if (! mods.isEmpty()) { for (SynchronizationProvider provider : for (SynchronizationProvider<SynchronizationProviderCfg> provider : DirectoryServer.getSynchronizationProviders()) { try opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/InitOnLineTest.java
@@ -26,11 +26,7 @@ */ package org.opends.server.synchronization; import static org.opends.server.config.ConfigConstants.ATTR_TASK_COMPLETION_TIME; import static org.opends.server.config.ConfigConstants.ATTR_TASK_INITIALIZE_DONE; import static org.opends.server.config.ConfigConstants.ATTR_TASK_INITIALIZE_LEFT; import static org.opends.server.config.ConfigConstants.ATTR_TASK_LOG_MESSAGES; import static org.opends.server.config.ConfigConstants.ATTR_TASK_STATE; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.Error.logError; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.server.loggers.debug.DebugLogger.debugInfo; @@ -40,49 +36,35 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.UUID; import org.opends.server.TestCaseUtils; import org.opends.server.backends.task.TaskState; import org.opends.server.config.ConfigEntry; import org.opends.server.core.AddOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ModifyOperation; import org.opends.server.messages.TaskMessages; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.schema.DirectoryStringSyntax; import org.opends.server.synchronization.changelog.Changelog; import org.opends.server.synchronization.changelog.ChangelogFakeConfiguration; import org.opends.server.synchronization.common.LogMessages; import org.opends.server.synchronization.common.ServerState; import org.opends.server.synchronization.plugin.ChangelogBroker; import org.opends.server.synchronization.plugin.SynchronizationDomain; import org.opends.server.synchronization.protocol.ChangelogStartMessage; import org.opends.server.synchronization.protocol.DoneMessage; import org.opends.server.synchronization.protocol.EntryMessage; import org.opends.server.synchronization.protocol.ErrorMessage; import org.opends.server.synchronization.protocol.InitializeRequestMessage; import org.opends.server.synchronization.protocol.InitializeTargetMessage; import org.opends.server.synchronization.protocol.RoutableMessage; import org.opends.server.synchronization.protocol.ServerStartMessage; import org.opends.server.synchronization.protocol.SocketSession; import org.opends.server.synchronization.protocol.SynchronizationMessage; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.ErrorLogCategory; import org.opends.server.types.ErrorLogSeverity; import org.opends.server.types.Modification; import org.opends.server.types.ModificationType; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchFilter; import org.opends.server.types.SearchScope; @@ -193,14 +175,6 @@ // Synchro multi-master synchroPluginStringDN = "cn=Multimaster Synchronization, " + synchroStringDN; String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n"; synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); // Synchro suffix synchroServerEntry = null; @@ -762,26 +736,10 @@ { int chPort = getChangelogPort(changelogId); // Create a changelog server String changelogLdif = "dn: cn=Changelog Server\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-changelog-server-config\n" + "cn: Changelog Server\n" + "ds-cfg-changelog-port: " + chPort + "\n" + "ds-cfg-changelog-server-id: " + changelogId + "\n" // + "ds-cfg-heartbeat-interval: 0 ms\n" + "ds-cfg-window-size: 100" + "\n"; if (changelogId==changelog2ID) { changelogLdif += new String( "ds-cfg-changelog-server: localhost:" + getChangelogPort(changelog1ID)+"\n"); } Entry tmp = TestCaseUtils.entryFromLdifString(changelogLdif); ConfigEntry changelogConfig = new ConfigEntry(tmp, null); Changelog changelog = new Changelog(changelogConfig); ChangelogFakeConfiguration conf = new ChangelogFakeConfiguration(chPort, null, 0, changelogId, 0, 100, null); Changelog changelog = new Changelog(conf); Thread.sleep(1000); return changelog; @@ -806,7 +764,8 @@ { // suffix synchronized String synchroServerStringDN = synchroPluginStringDN; String synchroServerLdif = "dn: cn=example," + synchroServerStringDN + "\n" String synchroServerLdif = "dn: cn=example, cn=domains" + synchroServerStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider-config\n" + "cn: example\n" @@ -1483,6 +1442,6 @@ // fromthe changelog server. server2 = null; } super.cleanEntries(); super.cleanRealEntries(); } } opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ProtocolWindowTest.java
@@ -273,14 +273,6 @@ // Multimaster Synchro plugin synchroPluginStringDN = "cn=Multimaster Synchronization, " + synchroStringDN; String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n"; synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); // Change log String changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN; @@ -294,7 +286,8 @@ changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif); // suffix synchronized String synchroServerStringDN = "cn=example, " + synchroPluginStringDN; String synchroServerStringDN = "cn=example, cn=domains, " + synchroPluginStringDN; String synchroServerLdif = "dn: " + synchroServerStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider-config\n" opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ReSyncTest.java
@@ -89,14 +89,6 @@ // Multimaster Synchro plugin synchroPluginStringDN = "cn=Multimaster Synchronization, " + synchroStringDN; String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n"; synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); // Change log String changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN; @@ -109,7 +101,8 @@ changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif); // suffix synchronized String synchroServerLdif = "dn: cn=example, " + synchroPluginStringDN + "\n" String synchroServerLdif = "dn: cn=example, cn=domains, " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider-config\n" + "cn: example\n" opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SchemaSynchronizationTest.java
@@ -38,6 +38,7 @@ import java.util.List; import org.opends.server.TestCaseUtils; import org.opends.server.admin.std.server.SynchronizationProviderCfg; import org.opends.server.api.SynchronizationProvider; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ModifyOperation; @@ -98,14 +99,6 @@ // Multimaster Synchro plugin synchroPluginStringDN = "cn=Multimaster Synchronization, " + synchroStringDN; String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n"; synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); // Change log String changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN; @@ -118,7 +111,8 @@ changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif); // suffix synchronized String synchroServerLdif = "dn: cn=example, " + synchroPluginStringDN + "\n" String synchroServerLdif = "dn: cn=example, cn=domains, " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider-config\n" + "cn: example\n" @@ -276,7 +270,7 @@ Modification mod = new Modification(ModificationType.ADD, attr); mods.add(mod); for (SynchronizationProvider provider : for (SynchronizationProvider<SynchronizationProviderCfg> provider : DirectoryServer.getSynchronizationProviders()) { provider.processSchemaChange(mods); opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/StressTest.java
@@ -231,14 +231,6 @@ // Multimaster Synchro plugin synchroPluginStringDN = "cn=Multimaster Synchronization, " + synchroStringDN; String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n"; synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); // Change log changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN; @@ -250,7 +242,7 @@ changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif); // suffix synchronized synchroServerStringDN = "cn=example, " + synchroPluginStringDN; synchroServerStringDN = "cn=example, cn=domains, " + synchroPluginStringDN; String synchroServerLdif = "dn: " + synchroServerStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider-config\n" opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
@@ -28,7 +28,6 @@ import static org.opends.server.loggers.Error.logError; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.net.SocketException; @@ -41,8 +40,6 @@ import org.opends.server.DirectoryServerTestCase; import org.opends.server.TestCaseUtils; import org.opends.server.schema.IntegerSyntax; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.internal.InternalClientConnection; @@ -50,7 +47,6 @@ import org.opends.server.protocols.ldap.LDAPFilter; import org.opends.server.synchronization.common.ServerState; import org.opends.server.synchronization.plugin.ChangelogBroker; import org.opends.server.synchronization.plugin.MultimasterSynchronization; import org.opends.server.synchronization.plugin.PersistentServerState; import org.opends.server.types.DN; import org.opends.server.types.Entry; @@ -84,8 +80,7 @@ * Created entries that need to be deleted for cleanup */ protected LinkedList<DN> entryList = new LinkedList<DN>(); protected Entry synchroPluginEntry; protected LinkedList<DN> configEntryList = new LinkedList<DN>(); protected Entry synchroServerEntry; @@ -97,14 +92,10 @@ protected boolean schemaCheck; /** * */ MultimasterSynchronization mms = null; /** * The synchronization plugin entry */ protected String synchroPluginStringDN; protected String synchroPluginStringDN = "cn=Multimaster Synchronization, cn=Synchronization Providers,cn=config"; /** * Set up the environment for performing the tests in this suite. @@ -228,20 +219,19 @@ } } catch (Exception e) { } { } } return broker; } /** * suppress all the entries created by the tests in this class * suppress all the config entries created by the tests in this class */ protected void cleanEntries() protected void cleanConfigEntries() { logError(ErrorLogCategory.SYNCHRONIZATION, ErrorLogSeverity.NOTICE, "SynchronizationTestCase/Cleaning entries" , 1); "SynchronizationTestCase/Cleaning config entries" , 1); DeleteOperation op; // Delete entries @@ -249,6 +239,38 @@ { while (true) { DN dn = configEntryList.removeLast(); logError(ErrorLogCategory.SYNCHRONIZATION, ErrorLogSeverity.NOTICE, "cleaning config entry " + dn, 1); op = new DeleteOperation(connection, InternalClientConnection .nextOperationID(), InternalClientConnection.nextMessageID(), null, dn); op.run(); } } catch (NoSuchElementException e) { // done } } /** * suppress all the real entries created by the tests in this class */ protected void cleanRealEntries() { logError(ErrorLogCategory.SYNCHRONIZATION, ErrorLogSeverity.NOTICE, "SynchronizationTestCase/Cleaning entries" , 1); DeleteOperation op; // Delete entries try { while (true) { DN dn = entryList.removeLast(); logError(ErrorLogCategory.SYNCHRONIZATION, ErrorLogSeverity.NOTICE, @@ -277,20 +299,8 @@ { DirectoryServer.setCheckSchema(schemaCheck); // WORKAROUND FOR BUG #639 - BEGIN - if (mms != null) { logError(ErrorLogCategory.SYNCHRONIZATION, ErrorLogSeverity.NOTICE, "SynchronizationTestCase/FinalizeSynchronization Provider" , 1); DirectoryServer.deregisterSynchronizationProvider(mms); mms.finalizeSynchronizationProvider(); mms = null; } // WORKAROUND FOR BUG #639 - END - cleanEntries(); cleanConfigEntries(); cleanRealEntries(); } /** @@ -298,48 +308,45 @@ */ protected void configureSynchronization() throws Exception { // // Add the Multimaster synchronization plugin String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "objectClass: ds-cfg-multimaster-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: " + "org.opends.server.synchronization.plugin.MultimasterSynchronization\n"; Entry synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); DirectoryServer.getConfigHandler().addEntry(synchroPluginEntry, null); entryList.add(synchroPluginEntry.getDN()); configEntryList.add(synchroPluginEntry.getDN()); assertNotNull(DirectoryServer.getConfigEntry(DN .decode(synchroPluginStringDN)), "Unable to add the Multimaster synchronization plugin"); // WORKAROUND FOR BUG #639 - BEGIN - DN dn = DN.decode(synchroPluginStringDN); ConfigEntry mmsConfigEntry = DirectoryServer.getConfigEntry(dn); mms = new MultimasterSynchronization(); try { mms.initializeSynchronizationProvider(mmsConfigEntry); } catch (ConfigException e) { assertTrue(false, "Unable to initialize the Multimaster synchronization plugin"); } DirectoryServer.registerSynchronizationProvider(mms); // WORKAROUND FOR BUG #639 - END - // // Add the changelog server if (changeLogEntry!=null) { DirectoryServer.getConfigHandler().addEntry(changeLogEntry, null); assertNotNull(DirectoryServer.getConfigEntry(changeLogEntry.getDN()), "Unable to add the changeLog server"); entryList.add(changeLogEntry.getDN()); } if (synchroServerEntry!=null) { // We also have a replicated suffix (synchronization domain) DirectoryServer.getConfigHandler().addEntry(synchroServerEntry, null); assertNotNull(DirectoryServer.getConfigEntry(synchroServerEntry.getDN()), "Unable to add the synchronized suffix"); entryList.add(synchroServerEntry.getDN()); } // domains container entry. String domainsLdif = "dn: " + "cn=domains," + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-branch\n"; Entry domainsEntry = TestCaseUtils.entryFromLdifString(domainsLdif); DirectoryServer.getConfigHandler().addEntry(domainsEntry, null); configEntryList.add(domainsEntry.getDN()); assertNotNull(DirectoryServer.getConfigEntry( DN.decode(synchroPluginStringDN)), "Unable to add the Multimaster synchronization plugin"); // Add the changelog server DirectoryServer.getConfigHandler().addEntry(changeLogEntry, null); assertNotNull(DirectoryServer.getConfigEntry(changeLogEntry.getDN()), "Unable to add the changeLog server"); configEntryList.add(changeLogEntry.getDN()); // We also have a replicated suffix (synchronization domain) DirectoryServer.getConfigHandler().addEntry(synchroServerEntry, null); assertNotNull(DirectoryServer.getConfigEntry(synchroServerEntry.getDN()), "Unable to add the synchronized server"); configEntryList.add(synchroServerEntry.getDN()); } /** opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
@@ -133,14 +133,6 @@ // Multimaster Synchro plugin synchroPluginStringDN = "cn=Multimaster Synchronization, " + synchroStringDN; String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n"; synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); // Change log String changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN; @@ -152,7 +144,8 @@ changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif); // suffix synchronized String synchroServerStringDN = "cn=example, " + synchroPluginStringDN; String synchroServerStringDN = "cn=example, cn=domains, " + synchroPluginStringDN; String synchroServerLdif = "dn: " + synchroServerStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider-config\n" @@ -318,7 +311,7 @@ ErrorLogSeverity.NOTICE, "Starting synchronization test : lostHeartbeatFailover" , 1); cleanEntries(); cleanRealEntries(); final DN baseDn = DN.decode("ou=People,dc=example,dc=com"); @@ -831,7 +824,7 @@ final DN baseDn = DN.decode("ou=People,dc=example,dc=com"); cleanEntries(); cleanRealEntries(); ChangelogBroker broker = openChangelogSession(baseDn, (short) 27, 100, 8989, 1000, true); @@ -886,7 +879,7 @@ "The received synchronization message is not a MODIFY msg"); ModifyMsg modMsg = (ModifyMsg) msg; Operation receivedOp = modMsg.createOperation(connection); modMsg.createOperation(connection); assertTrue(DN.decode(modMsg.getDn()).compareTo(personEntry.getDN()) == 0, "The received MODIFY synchronization message is not for the excepted DN"); @@ -908,7 +901,7 @@ assertTrue(msg instanceof ModifyDNMsg, "The received synchronization message is not a MODIFY DN msg"); ModifyDNMsg moddnMsg = (ModifyDNMsg) msg; receivedOp = moddnMsg.createOperation(connection); moddnMsg.createOperation(connection); assertTrue(DN.decode(moddnMsg.getDn()).compareTo(personEntry.getDN()) == 0, "The received MODIFY_DN message is not for the excepted DN"); @@ -927,7 +920,7 @@ assertTrue(msg instanceof DeleteMsg, "The received synchronization message is not a MODIFY DN msg"); DeleteMsg delMsg = (DeleteMsg) msg; receivedOp = delMsg.createOperation(connection); delMsg.createOperation(connection); assertTrue(DN.decode(delMsg.getDn()).compareTo(DN .decode("uid= new person,ou=People,dc=example,dc=com")) == 0, "The received DELETE message is not for the excepted DN"); opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/changelog/ChangelogFakeConfiguration.java
New file @@ -0,0 +1,190 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.synchronization.changelog; import java.util.SortedSet; import org.opends.server.admin.ManagedObjectDefinition; import org.opends.server.admin.PropertyProvider; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.client.ChangelogServerCfgClient; import org.opends.server.admin.std.server.ChangelogServerCfg; import org.opends.server.types.DN; /** * This Class implements an object that can be used to instantiate * The Changelog class for tests purpose. */ public class ChangelogFakeConfiguration implements ChangelogServerCfg { int port; String dirName; int purgeDelay; int serverId; int queueSize; int windowSize; private SortedSet<String> servers; public ChangelogFakeConfiguration( int port, String dirName, int purgeDelay, int serverId, int queueSize, int windowSize, SortedSet<String> servers) { this.port = port; this.dirName = dirName; if (purgeDelay == 0) { this.purgeDelay = 24*60*60; } else { this.purgeDelay = purgeDelay; } this.serverId = serverId; if (queueSize == 0) { this.queueSize = 10000; } else { this.queueSize = queueSize; } if (windowSize == 0) { this.windowSize = 100; } else { this.windowSize = windowSize; } this.servers = servers; } /** * {@inheritDoc} */ public void addChangeListener( ConfigurationChangeListener<ChangelogServerCfg> listener) { } /** * {@inheritDoc} */ public ManagedObjectDefinition<? extends ChangelogServerCfgClient, ? extends ChangelogServerCfg> definition() { return null; } /** * {@inheritDoc} */ public String getChangelogDbDirectory() { return dirName; } /** * {@inheritDoc} */ public int getChangelogPort() { return port; } /** * {@inheritDoc} */ public long getChangelogPurgeDelay() { return purgeDelay; } /** * {@inheritDoc} */ public SortedSet<String> getChangelogServer() { return servers; } /** * {@inheritDoc} */ public int getChangelogServerId() { return serverId; } /** * {@inheritDoc} */ public int getQueueSize() { return queueSize; } /** * {@inheritDoc} */ public int getWindowSize() { return windowSize; } /** * {@inheritDoc} */ public void removeChangeListener( ConfigurationChangeListener<ChangelogServerCfg> listener) { } /** * {@inheritDoc} */ public DN dn() { return null; } /** * {@inheritDoc} */ public PropertyProvider properties() { return null; } } opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/changelog/ChangelogTest.java
@@ -34,9 +34,10 @@ import java.net.ServerSocket; import java.util.ArrayList; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.opends.server.TestCaseUtils; import org.opends.server.config.ConfigEntry; import org.opends.server.core.ModifyDNOperation; import org.opends.server.synchronization.SynchronizationTestCase; import org.opends.server.synchronization.common.ChangeNumber; @@ -98,17 +99,9 @@ changelogPort = socket.getLocalPort(); socket.close(); String changelogLdif = "dn: cn=Changelog Server\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-changelog-server-config\n" + "cn: Changelog Server\n" + "ds-cfg-changelog-port: "+ changelogPort + "\n" + "ds-cfg-changelog-server-id: 1\n" + "ds-cfg-window-size: 100"; Entry tmp = TestCaseUtils.entryFromLdifString(changelogLdif); ConfigEntry changelogConfig = new ConfigEntry(tmp, null); changelog = new Changelog(changelogConfig); ChangelogFakeConfiguration conf = new ChangelogFakeConfiguration(changelogPort, null, 0, 1, 0, 0, null); changelog = new Changelog(conf); } /** @@ -602,19 +595,13 @@ // for itest=0, create the 2 connected changelog servers // for itest=1, create the 1rst changelog server, the second // one will be created later String changelogLdif = "dn: cn=Changelog Server\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-changelog-server-config\n" + "cn: Changelog Server\n" + "ds-cfg-changelog-port: " + changelogPorts[i] + "\n" + "ds-cfg-changelog-server: localhost:" + ((i == 0) ? changelogPorts[1] : changelogPorts[0]) + "\n" + "ds-cfg-changelog-server-id: " + changelogIds[0] + "\n" + "ds-cfg-window-size: 100" + "\n" + "ds-cfg-changelog-db-directory: changelogDb"+i; Entry tmp = TestCaseUtils.entryFromLdifString(changelogLdif); ConfigEntry changelogConfig = new ConfigEntry(tmp, null); changelogs[i] = new Changelog(changelogConfig); SortedSet<String> servers = new TreeSet<String>(); servers.add( "localhost:" + ((i == 0) ? changelogPorts[1] : changelogPorts[0])); ChangelogFakeConfiguration conf = new ChangelogFakeConfiguration(changelogPorts[i], "changelogDb"+i, 0, changelogIds[i], 0, 100, servers); changelog = new Changelog(conf); } ChangelogBroker broker1 = null; @@ -681,16 +668,13 @@ if (itest > 0) { socket.close(); String changelogLdif = "dn: cn=Changelog Server\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-changelog-server-config\n" + "cn: Changelog Server\n" + "ds-cfg-changelog-port: " + changelogPorts[1] + "\n" + "ds-cfg-changelog-server: localhost:" + changelogPorts[0] + "\n" + "ds-cfg-changelog-server-id: " + changelogIds[1] + "\n"; Entry tmp = TestCaseUtils.entryFromLdifString(changelogLdif); ConfigEntry changelogConfig = new ConfigEntry(tmp, null); changelogs[1] = new Changelog(changelogConfig); SortedSet<String> servers = new TreeSet<String>(); servers.add("localhost:"+changelogPorts[0]); ChangelogFakeConfiguration conf = new ChangelogFakeConfiguration(changelogPorts[1], null, 0, changelogIds[1], 0, 0, null); changelogs[1] = new Changelog(conf); // Connect broker 2 to changelog2 broker2 = openChangelogSession(DN.decode("dc=example,dc=com"), opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/changelog/dbHandlerTest.java
@@ -30,13 +30,11 @@ import java.net.ServerSocket; import org.opends.server.TestCaseUtils; import org.opends.server.config.ConfigEntry; import org.opends.server.synchronization.SynchronizationTestCase; import org.opends.server.synchronization.common.ChangeNumber; import org.opends.server.synchronization.common.ChangeNumberGenerator; import org.opends.server.synchronization.protocol.DeleteMsg; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -56,17 +54,10 @@ socket.close(); // configure a Changelog server. String changelogLdif = "dn: cn=Changelog Server\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-changelog-server-config\n" + "cn: Changelog Server\n" + "ds-cfg-changelog-port: "+ changelogPort + "\n" + "ds-cfg-changelog-server-id: 2\n" + "ds-cfg-changelog-purge-delay: 0 d"; Entry tmp = TestCaseUtils.entryFromLdifString(changelogLdif); ConfigEntry changelogConfig = new ConfigEntry(tmp, null); Changelog changelog = new Changelog(changelogConfig); ChangelogFakeConfiguration conf = new ChangelogFakeConfiguration(changelogPort, null, 0, 2, 0, 100, null); Changelog changelog = new Changelog(conf); // create or clean a directory for the dbHandler String buildRoot = System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT); opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/plugin/HistoricalTest.java
@@ -67,22 +67,6 @@ // Create an internal connection. connection = InternalClientConnection.getRootConnection(); // Top level synchronization provider. String synchroStringDN = "cn=Synchronization Providers,cn=config"; // Multimaster synchronization plugin. synchroPluginStringDN = "cn=Multimaster Synchronization, " + synchroStringDN; String synchroPluginLdif = "dn: " + synchroPluginStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider\n" + "ds-cfg-synchronization-provider-enabled: true\n" + "ds-cfg-synchronization-provider-class: " + "org.opends.server.synchronization.MultimasterSynchronization\n"; synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif); // The synchronization server. String changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN; String changeLogLdif = "dn: " + changeLogStringDN + "\n" @@ -93,7 +77,7 @@ changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif); // The suffix to be synchronized. String synchroServerStringDN = "o=test, " + synchroPluginStringDN; String synchroServerStringDN = "o=test, cn=domains, " + synchroPluginStringDN; String synchroServerLdif = "dn: " + synchroServerStringDN + "\n" + "objectClass: top\n" + "objectClass: ds-cfg-synchronization-provider-config\n" opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/plugin/ModifyConflictTest.java
@@ -38,7 +38,6 @@ import static org.opends.server.synchronization.protocol.OperationContext.*; import org.opends.server.TestAccessLogger; import org.opends.server.core.AddOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ModifyOperation;