From 94bbd5bb7c20a490558d8ec97d1be7e3dc492a42 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Sun, 09 Sep 2007 23:08:09 +0000
Subject: [PATCH] Update the server to provide a basic framework for controlling when plugins will be invoked. There are two basic changes:
---
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java | 4
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java | 44
opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java | 176 +++
opends/src/server/org/opends/server/api/plugin/PluginType.java | 90 +
opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java | 144 ++
opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyOperation.java | 148 ++
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java | 4
opends/src/server/org/opends/server/util/ServerConstants.java | 44
opends/tests/unit-tests-testng/resource/config-changes.ldif | 20
opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml | 117 ++
opends/src/server/org/opends/server/types/operation/PostSynchronizationAddOperation.java | 136 ++
opends/resource/schema/02-config.ldif | 27
opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml | 54
opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java | 139 ++
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java | 4
opends/src/server/org/opends/server/core/PluginConfigManager.java | 606 +++++++++-
opends/resource/config/config.ldif | 11
opends/src/admin/defn/org/opends/server/admin/std/UniqueAttributePluginConfiguration.xml | 3
opends/src/server/org/opends/server/types/operation/PostSynchronizationDeleteOperation.java | 78 +
opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java | 16
opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyDNOperation.java | 189 +++
opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java | 1137 ++++++++++++++------
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java | 4
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java | 66 +
opends/src/messages/messages/plugin.properties | 16
25 files changed, 2,833 insertions(+), 444 deletions(-)
diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index 6b9862b..240ee9e 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -1451,6 +1451,7 @@
ds-cfg-7-bit-clean-attribute-type: uid
ds-cfg-7-bit-clean-attribute-type: mail
ds-cfg-7-bit-clean-attribute-type: userPassword
+ds-cfg-invoke-for-internal-operations: true
dn: cn=Entry UUID,cn=Plugins,cn=config
objectClass: top
@@ -1461,6 +1462,7 @@
ds-cfg-plugin-enabled: true
ds-cfg-plugin-type: ldifImport
ds-cfg-plugin-type: preOperationAdd
+ds-cfg-invoke-for-internal-operations: true
dn: cn=LastMod,cn=Plugins,cn=config
objectClass: top
@@ -1472,6 +1474,7 @@
ds-cfg-plugin-type: preOperationAdd
ds-cfg-plugin-type: preOperationModify
ds-cfg-plugin-type: preOperationModifyDN
+ds-cfg-invoke-for-internal-operations: true
dn: cn=LDAP Attribute Description List,cn=Plugins,cn=config
objectClass: top
@@ -1481,6 +1484,7 @@
ds-cfg-plugin-class: org.opends.server.plugins.LDAPADListPlugin
ds-cfg-plugin-enabled: true
ds-cfg-plugin-type: preParseSearch
+ds-cfg-invoke-for-internal-operations: true
dn: cn=Password Policy Import,cn=Plugins,cn=config
objectClass: top
@@ -1492,6 +1496,7 @@
ds-cfg-plugin-type: ldifImport
ds-cfg-default-user-password-storage-scheme-dn: cn=Salted SHA-1,cn=Password Storage Schemes,cn=config
ds-cfg-default-auth-password-storage-scheme-dn: cn=Salted SHA-1,cn=Password Storage Schemes,cn=config
+ds-cfg-invoke-for-internal-operations: false
dn: cn=Profiler,cn=Plugins,cn=config
objectClass: top
@@ -1504,6 +1509,7 @@
ds-cfg-enable-profiling-on-startup: false
ds-cfg-profile-directory: logs
ds-cfg-profile-sample-interval: 10 milliseconds
+ds-cfg-invoke-for-internal-operations: false
dn: cn=Referential Integrity,cn=Plugins,cn=config
objectClass: top
@@ -1517,6 +1523,7 @@
ds-cfg-plugin-type: subordinateModifyDN
ds-cfg-referential-integrity-attribute-type: member
ds-cfg-referential-integrity-attribute-type: uniqueMember
+ds-cfg-invoke-for-internal-operations: true
dn: cn=UID Unique Attribute,cn=Plugins,cn=config
objectClass: top
@@ -1528,7 +1535,11 @@
ds-cfg-plugin-type: preOperationAdd
ds-cfg-plugin-type: preOperationModify
ds-cfg-plugin-type: preOperationModifyDN
+ds-cfg-plugin-type: postSynchronizationAdd
+ds-cfg-plugin-type: postSynchronizationModify
+ds-cfg-plugin-type: postSynchronizationModifyDN
ds-cfg-unique-attribute-type: uid
+ds-cfg-invoke-for-internal-operations: true
dn: cn=Root DNs,cn=config
objectClass: top
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 144ad47..145aeae 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -1658,6 +1658,26 @@
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.490 NAME 'ds-cfg-poll-interval'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.491
+ NAME 'ds-cfg-plugin-order-synchronization-add'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.492
+ NAME 'ds-cfg-plugin-order-synchronization-delete'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.493
+ NAME 'ds-cfg-plugin-order-synchronization-modify'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.494
+ NAME 'ds-cfg-plugin-order-synchronization-modify-dn'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.495
+ NAME 'ds-cfg-invoke-for-internal-operations'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL
MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled )
@@ -1847,7 +1867,8 @@
ds-cfg-password-validator-enabled ) X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.37 NAME 'ds-cfg-plugin' SUP top
STRUCTURAL MUST ( cn $ ds-cfg-plugin-class $ ds-cfg-plugin-enabled $
- ds-cfg-plugin-type ) X-ORIGIN 'OpenDS Directory Server' )
+ ds-cfg-plugin-type ) MAY ds-cfg-invoke-for-internal-operations
+ X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.38 NAME 'ds-cfg-profiler-plugin'
SUP ds-cfg-plugin STRUCTURAL MAY ( ds-cfg-enable-profiling-on-startup $
ds-cfg-profile-directory $ ds-cfg-profile-sample-interval $
@@ -2254,6 +2275,10 @@
ds-cfg-plugin-order-post-response-modify $
ds-cfg-plugin-order-post-response-modify-dn $
ds-cfg-plugin-order-post-response-search $
+ ds-cfg-plugin-order-synchronization-add $
+ ds-cfg-plugin-order-synchronization-delete $
+ ds-cfg-plugin-order-synchronization-modify $
+ ds-cfg-plugin-order-synchronization-modify-dn $
ds-cfg-plugin-order-search-result-entry $
ds-cfg-plugin-order-search-result-reference $
ds-cfg-plugin-order-subordinate-modify-dn $
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
index 1194f54..cc13da3 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
@@ -31,6 +31,7 @@
package="org.opends.server.admin.std" abstract="false"
xmlns:adm="http://www.opends.org/admin"
xmlns:ldap="http://www.opends.org/admin-ldap">
+
<adm:synopsis>
<adm:user-friendly-plural-name />
provide a mechanism for executing custom code at specified points in
@@ -38,7 +39,9 @@
establishment and termination, server startup and shutdown, and LDIF import
and export.
</adm:synopsis>
+
<adm:tag name="core"/>
+
<adm:profile name="ldap">
<ldap:object-class>
<ldap:oid>1.3.6.1.4.1.26027.1.2.37</ldap:oid>
@@ -46,6 +49,7 @@
<ldap:superior>top</ldap:superior>
</ldap:object-class>
</adm:profile>
+
<adm:property name="enabled" mandatory="true">
<adm:synopsis>
Indicate whether the
@@ -62,6 +66,7 @@
</ldap:attribute>
</adm:profile>
</adm:property>
+
<adm:property name="plugin-class" mandatory="true">
<adm:synopsis>
The fully-qualified name of the Java class that provides the
@@ -82,6 +87,7 @@
</ldap:attribute>
</adm:profile>
</adm:property>
+
<adm:property name="plugin-type" mandatory="true" multi-valued="true">
<adm:synopsis>
The plugin types, which define the conditions under which this plugin
@@ -308,6 +314,30 @@
Invoked after sending the search result done message to the client.
</adm:synopsis>
</adm:value>
+ <adm:value name="postsynchronizationadd">
+ <adm:synopsis>
+ Invoked after completing post-synchronization processing for an add
+ operation.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postsynchronizationdelete">
+ <adm:synopsis>
+ Invoked after completing post-synchronization processing for a
+ delete operation.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postsynchronizationmodify">
+ <adm:synopsis>
+ Invoked after completing post-synchronization processing for a
+ modify operation.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postsynchronizationmodifydn">
+ <adm:synopsis>
+ Invoked after completing post-synchronization processing for a
+ modify DN operation.
+ </adm:synopsis>
+ </adm:value>
<adm:value name="searchresultentry">
<adm:synopsis>
Invoked before sending a search result entry to the client.
@@ -339,5 +369,29 @@
</ldap:attribute>
</adm:profile>
</adm:property>
+
+ <adm:property name="invoke-for-internal-operations" mandatory="false">
+ <adm:synopsis>
+ Indicates whether the plugin should be invoked for internal operations.
+ Note that any plugin which may be invoked for internal operations should
+ be careful to ensure that they do not create any new internal operatons
+ that can cause the same plugin to be re-invoked.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.495</ldap:oid>
+ <ldap:name>ds-cfg-invoke-for-internal-operations</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml
index f35b605..c0bce10 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml
@@ -1212,6 +1212,123 @@
</adm:profile>
</adm:property>
+ <adm:property name="plugin-order-post-synchronization-add" mandatory="false">
+ <adm:synopsis>
+ Specifies the order in which post-synchronization add plugins should be
+ loaded and invoked. The value should be a comma-delimited list of plugin
+ names (where the plugin name is the RDN value from the plugin
+ configuration entry DN). The list may include at most one asterisk to
+ indicate the position of any unspecified plugin (and the relative order of
+ those unspecified plugins will be undefined).
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The order in which post-synchronization add plugins are loaded and
+ invoked will be undefined.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.491</ldap:oid>
+ <ldap:name>ds-cfg-plugin-order-post-synchronization-add</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="plugin-order-post-synchronization-delete"
+ mandatory="false">
+ <adm:synopsis>
+ Specifies the order in which post-synchronization delete plugins should be
+ loaded and invoked. The value should be a comma-delimited list of plugin
+ names (where the plugin name is the RDN value from the plugin
+ configuration entry DN). The list may include at most one asterisk to
+ indicate the position of any unspecified plugin (and the relative order of
+ those unspecified plugins will be undefined).
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The order in which post-synchronization delete plugins are loaded and
+ invoked will be undefined.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.492</ldap:oid>
+ <ldap:name>ds-cfg-plugin-order-post-synchronization-delete</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="plugin-order-post-synchronization-modify"
+ mandatory="false">
+ <adm:synopsis>
+ Specifies the order in which post-synchronization modify plugins should be
+ loaded and invoked. The value should be a comma-delimited list of plugin
+ names (where the plugin name is the RDN value from the plugin
+ configuration entry DN). The list may include at most one asterisk to
+ indicate the position of any unspecified plugin (and the relative order of
+ those unspecified plugins will be undefined).
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The order in which post-synchronization modify plugins are loaded and
+ invoked will be undefined.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.493</ldap:oid>
+ <ldap:name>ds-cfg-plugin-order-post-synchronization-modify</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="plugin-order-post-synchronization-modify-dn"
+ mandatory="false">
+ <adm:synopsis>
+ Specifies the order in which post-synchronization modify DN plugins should
+ be loaded and invoked. The value should be a comma-delimited list of
+ plugin names (where the plugin name is the RDN value from the plugin
+ configuration entry DN). The list may include at most one asterisk to
+ indicate the position of any unspecified plugin (and the relative order of
+ those unspecified plugins will be undefined).
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The order in which post-synchronization modify DN plugins are loaded
+ and invoked will be undefined.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.494</ldap:oid>
+ <ldap:name>
+ ds-cfg-plugin-order-post-synchronization-modify-dn
+ </ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
<adm:property name="plugin-order-post-response-search" mandatory="false">
<adm:synopsis>
Specifies the order in which post-response search plugins should be
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/UniqueAttributePluginConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/UniqueAttributePluginConfiguration.xml
index 3c87817..e2054c5 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/UniqueAttributePluginConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/UniqueAttributePluginConfiguration.xml
@@ -63,6 +63,9 @@
<adm:value>preoperationadd</adm:value>
<adm:value>preoperationmodify</adm:value>
<adm:value>preoperationmodifydn</adm:value>
+ <adm:value>postsynchronizationadd</adm:value>
+ <adm:value>postsynchronizationmodify</adm:value>
+ <adm:value>postsynchronizationmodifydn</adm:value>
</adm:defined>
</adm:default-behavior>
</adm:property-override>
diff --git a/opends/src/messages/messages/plugin.properties b/opends/src/messages/messages/plugin.properties
index 8b0a93c..2dfd85e 100644
--- a/opends/src/messages/messages/plugin.properties
+++ b/opends/src/messages/messages/plugin.properties
@@ -379,3 +379,19 @@
SEVERE_ERR_PLUGIN_PWIMPORT_NO_SUCH_DEFAULT_AUTH_SCHEME_104=The password \
policy import plugin references default auth password storage scheme %s \
which is not available for use in the server
+SEVERE_ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION_105=The \
+ post-synchronization %s plugin defined in configuration entry %s threw an \
+ exception when it was invoked for connection %d operation %d: %s
+SEVERE_ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE_106=A unique attribute conflict \
+ was detected for attribute %s: value %s already exists in entry %s
+SEVERE_ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE_107=A unique attribute conflict \
+ was detected for attribute %s during synchronization (connID=%d, opID=%d): \
+ value %s in entry %s conflicts with an existing value in entry %s. Manual \
+ interaction is required to eliminate the conflict
+SEVERE_ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR_108=An internal error occurred \
+ while attempting to determine whether the operation would have resulted in a \
+ unique attribute conflict (result %s, message %s)
+SEVERE_ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR_SYNC_109=An internal error \
+ occurred while attempting to determine whether the synchronization operation \
+ (connID=%d, opID=%d) for entry %s would have resulted in a unique attribute \
+ conflict (result %s, message %s)
diff --git a/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java b/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
index f99b60d..558978f 100644
--- a/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
+++ b/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
@@ -67,6 +67,10 @@
public abstract class DirectoryServerPlugin
<T extends PluginCfg>
{
+ // Indicates whether this plugin should be invoked for internal
+ // operations.
+ private boolean invokeForInternalOps;
+
// The DN of the configuration entry for this plugin.
private DN pluginDN;
@@ -119,20 +123,23 @@
* plugins regardless of type. This should only be called by the
* core Directory Server code during the course of loading a plugin.
*
- * @param pluginDN The DN of the plugin configuration entry.
- * @param pluginTypes The set of plugin types for which this
- * plugin is registered.
+ * @param configuration The configuration for this plugin.
+ * @param pluginTypes The set of plugin types for which this
+ * plugin is registered.
*/
- @org.opends.server.types.PublicAPI(
- stability=org.opends.server.types.StabilityLevel.PRIVATE,
- mayInstantiate=false,
- mayExtend=false,
- mayInvoke=false)
- public final void initializeInternal(DN pluginDN,
+ @org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.PRIVATE,
+ mayInstantiate=false,
+ mayExtend=false,
+ mayInvoke=false)
+ public final void initializeInternal(PluginCfg configuration,
Set<PluginType> pluginTypes)
{
- this.pluginDN = pluginDN;
this.pluginTypes = pluginTypes;
+
+ pluginDN = configuration.dn();
+ invokeForInternalOps =
+ configuration.isInvokeForInternalOperations();
}
@@ -198,6 +205,41 @@
/**
+ * Indicates whether this plugin should be invoked for internal
+ * operations.
+ *
+ * @return {@code true} if this plugin should be invoked for
+ * internal operations, or {@code false} if not.
+ */
+ public final boolean invokeForInternalOperations()
+ {
+ return invokeForInternalOps;
+ }
+
+
+
+ /**
+ * Specifies whether this plugin should be invoked for internal
+ * operations.
+ *
+ * @param invokeForInternalOps Indicates whether this plugin
+ * should be invoked for internal
+ * operations.
+ */
+ @org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.PRIVATE,
+ mayInstantiate=false,
+ mayExtend=false,
+ mayInvoke=false)
+ public final void setInvokeForInternalOperations(
+ boolean invokeForInternalOps)
+ {
+ this.invokeForInternalOps = invokeForInternalOps;
+ }
+
+
+
+ /**
* Performs any processing that should be done when the Directory
* Server is in the process of starting. This method will be called
* after virtually all other initialization has been performed but
@@ -448,6 +490,25 @@
/**
+ * Performs any necessary processing that should be done after the
+ * Directory Server has completed processing for an add operation
+ * performed via synchronization.
+ *
+ * @param addOperation The synchronized add operation for which
+ * processing has been completed.
+ */
+ public void doPostSynchronization(
+ PostSynchronizationAddOperation addOperation)
+ {
+ Message message = ERR_PLUGIN_TYPE_NOT_SUPPORTED.
+ get(String.valueOf(pluginDN),
+ PluginType.POST_SYNCHRONIZATION_ADD.getName());
+ throw new UnsupportedOperationException(message.toString());
+ }
+
+
+
+ /**
* Performs any necessary processing that should be done before the
* Directory Server parses the elements of a bind request.
*
@@ -702,6 +763,25 @@
/**
+ * Performs any necessary processing that should be done after the
+ * Directory Server has completed processing for a delete operation
+ * performed via synchronization.
+ *
+ * @param deleteOperation The synchronized delete operation for
+ * which processing has been completed.
+ */
+ public void doPostSynchronization(
+ PostSynchronizationDeleteOperation deleteOperation)
+ {
+ Message message = ERR_PLUGIN_TYPE_NOT_SUPPORTED.
+ get(String.valueOf(pluginDN),
+ PluginType.POST_SYNCHRONIZATION_DELETE.getName());
+ throw new UnsupportedOperationException(message.toString());
+ }
+
+
+
+ /**
* Performs any necessary processing that should be done before the
* Directory Server parses the elements of an extended request.
*
@@ -875,6 +955,25 @@
/**
+ * Performs any necessary processing that should be done after the
+ * Directory Server has completed processing for a modify operation
+ * performed via synchronization.
+ *
+ * @param modifyOperation The synchronized modify operation for
+ * which processing has been completed.
+ */
+ public void doPostSynchronization(
+ PostSynchronizationModifyOperation modifyOperation)
+ {
+ Message message = ERR_PLUGIN_TYPE_NOT_SUPPORTED.
+ get(String.valueOf(pluginDN),
+ PluginType.POST_SYNCHRONIZATION_MODIFY.getName());
+ throw new UnsupportedOperationException(message.toString());
+ }
+
+
+
+ /**
* Performs any necessary processing that should be done before the
* Directory Server parses the elements of a modify DN request.
*
@@ -1003,6 +1102,26 @@
/**
+ * Performs any necessary processing that should be done after the
+ * Directory Server has completed processing for a modify DN
+ * operation performed via synchronization.
+ *
+ * @param modifyDNOperation The synchronized modify DN operation
+ * for which processing has been
+ * completed.
+ */
+ public void doPostSynchronization(
+ PostSynchronizationModifyDNOperation modifyDNOperation)
+ {
+ Message message = ERR_PLUGIN_TYPE_NOT_SUPPORTED.
+ get(String.valueOf(pluginDN),
+ PluginType.POST_SYNCHRONIZATION_MODIFY_DN.getName());
+ throw new UnsupportedOperationException(message.toString());
+ }
+
+
+
+ /**
* Performs any necessary processing that should be done before the
* Directory Server parses the elements of a search request.
*
diff --git a/opends/src/server/org/opends/server/api/plugin/PluginType.java b/opends/src/server/org/opends/server/api/plugin/PluginType.java
index 79388df..07b67a6 100644
--- a/opends/src/server/org/opends/server/api/plugin/PluginType.java
+++ b/opends/src/server/org/opends/server/api/plugin/PluginType.java
@@ -383,6 +383,41 @@
/**
+ * The plugin type for plugins that are to be invoked just after an
+ * add operation has been completed via synchronization.
+ */
+ POST_SYNCHRONIZATION_ADD(PluginType.NAME_POST_SYNCHRONIZATION_ADD),
+
+
+
+ /**
+ * The plugin type for plugins that are to be invoked just after a
+ * delete operation has been completed via synchronization.
+ */
+ POST_SYNCHRONIZATION_DELETE(
+ PluginType.NAME_POST_SYNCHRONIZATION_DELETE),
+
+
+
+ /**
+ * The plugin type for plugins that are to be invoked just after a
+ * modify operation has been completed via synchronization.
+ */
+ POST_SYNCHRONIZATION_MODIFY(
+ PluginType.NAME_POST_SYNCHRONIZATION_MODIFY),
+
+
+
+ /**
+ * The plugin type for plugins that are to be invoked just after a
+ * modify DN operation has been completed via synchronization.
+ */
+ POST_SYNCHRONIZATION_MODIFY_DN(
+ PluginType.NAME_POST_SYNCHRONIZATION_MODIFY_DN),
+
+
+
+ /**
* The plugin type for plugins that are to be invoked before each
* search result entry is sent to a client.
*/
@@ -744,6 +779,41 @@
/**
+ * The name that will be used for post-synchronization add plugins.
+ */
+ private static final String NAME_POST_SYNCHRONIZATION_ADD =
+ "postsynchronizationadd";
+
+
+
+ /**
+ * The name that will be used for post-synchronization delete
+ * plugins.
+ */
+ private static final String NAME_POST_SYNCHRONIZATION_DELETE =
+ "postsynchronizationdelete";
+
+
+
+ /**
+ * The name that will be used for post-synchronization modify
+ * plugins.
+ */
+ private static final String NAME_POST_SYNCHRONIZATION_MODIFY =
+ "postsynchronizationmodify";
+
+
+
+ /**
+ * The name that will be used for post-synchronization modify DN
+ * plugins.
+ */
+ private static final String NAME_POST_SYNCHRONIZATION_MODIFY_DN =
+ "postsynchronizationmodifydn";
+
+
+
+ /**
* The name that will be used for search result entry plugins.
*/
private static final String NAME_SEARCH_ENTRY = "searchresultentry";
@@ -779,7 +849,7 @@
* types.
*/
private static final Set<String> PLUGIN_TYPE_NAMES =
- new HashSet<String>(46);
+ new HashSet<String>(50);
@@ -788,7 +858,7 @@
* corresponding plugin type.
*/
private static final Map<String,PluginType> PLUGIN_TYPE_MAP =
- new HashMap<String,PluginType>(46);
+ new HashMap<String,PluginType>(50);
@@ -836,6 +906,13 @@
PLUGIN_TYPE_NAMES.add(PluginType.NAME_POST_RESPONSE_MODIFY);
PLUGIN_TYPE_NAMES.add(PluginType.NAME_POST_RESPONSE_MODIFY_DN);
PLUGIN_TYPE_NAMES.add(PluginType.NAME_POST_RESPONSE_SEARCH);
+ PLUGIN_TYPE_NAMES.add(PluginType.NAME_POST_SYNCHRONIZATION_ADD);
+ PLUGIN_TYPE_NAMES.add(
+ PluginType.NAME_POST_SYNCHRONIZATION_DELETE);
+ PLUGIN_TYPE_NAMES.add(
+ PluginType.NAME_POST_SYNCHRONIZATION_MODIFY);
+ PLUGIN_TYPE_NAMES.add(
+ PluginType.NAME_POST_SYNCHRONIZATION_MODIFY_DN);
PLUGIN_TYPE_NAMES.add(PluginType.NAME_SEARCH_ENTRY);
PLUGIN_TYPE_NAMES.add(PluginType.NAME_SEARCH_REFERENCE);
PLUGIN_TYPE_NAMES.add(PluginType.NAME_SUBORDINATE_MODIFY_DN);
@@ -924,6 +1001,15 @@
PluginType.POST_RESPONSE_MODIFY_DN);
PLUGIN_TYPE_MAP.put(PluginType.NAME_POST_RESPONSE_SEARCH,
PluginType.POST_RESPONSE_SEARCH);
+ PLUGIN_TYPE_MAP.put(PluginType.NAME_POST_SYNCHRONIZATION_ADD,
+ PluginType.POST_SYNCHRONIZATION_ADD);
+ PLUGIN_TYPE_MAP.put(PluginType.NAME_POST_SYNCHRONIZATION_DELETE,
+ PluginType.POST_SYNCHRONIZATION_DELETE);
+ PLUGIN_TYPE_MAP.put(PluginType.NAME_POST_SYNCHRONIZATION_MODIFY,
+ PluginType.POST_SYNCHRONIZATION_MODIFY);
+ PLUGIN_TYPE_MAP.put(
+ PluginType.NAME_POST_SYNCHRONIZATION_MODIFY_DN,
+ PluginType.POST_SYNCHRONIZATION_MODIFY_DN);
PLUGIN_TYPE_MAP.put(PluginType.NAME_SEARCH_ENTRY,
PluginType.SEARCH_RESULT_ENTRY);
PLUGIN_TYPE_MAP.put(PluginType.NAME_SEARCH_REFERENCE,
diff --git a/opends/src/server/org/opends/server/core/PluginConfigManager.java b/opends/src/server/org/opends/server/core/PluginConfigManager.java
index 1552f9f..e65bf24 100644
--- a/opends/src/server/org/opends/server/core/PluginConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -25,7 +25,6 @@
* Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
package org.opends.server.core;
-import org.opends.messages.Message;
@@ -41,6 +40,8 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
import org.opends.server.admin.ClassPropertyDefinition;
import org.opends.server.admin.server.ConfigurationAddListener;
import org.opends.server.admin.server.ConfigurationChangeListener;
@@ -66,12 +67,11 @@
import org.opends.server.api.plugin.StartupPluginResult;
import org.opends.server.api.plugin.SubordinateModifyDNPluginResult;
import org.opends.server.config.ConfigException;
+import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
-
-
import org.opends.server.types.InitializationException;
import org.opends.server.types.IntermediateResponse;
import org.opends.server.types.LDIFExportConfig;
@@ -80,7 +80,6 @@
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
-
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.Modification;
import org.opends.server.types.operation.PostOperationAbandonOperation;
@@ -101,6 +100,10 @@
import org.opends.server.types.operation.PostResponseModifyDNOperation;
import org.opends.server.types.operation.PostResponseModifyOperation;
import org.opends.server.types.operation.PostResponseSearchOperation;
+import org.opends.server.types.operation.PostSynchronizationAddOperation;
+import org.opends.server.types.operation.PostSynchronizationDeleteOperation;
+import org.opends.server.types.operation.PostSynchronizationModifyOperation;
+import org.opends.server.types.operation.PostSynchronizationModifyDNOperation;
import org.opends.server.types.operation.PreOperationAddOperation;
import org.opends.server.types.operation.PreOperationBindOperation;
import org.opends.server.types.operation.PreOperationCompareOperation;
@@ -124,13 +127,10 @@
import org.opends.server.types.operation.SubordinateModifyDNOperation;
import org.opends.server.workflowelement.localbackend.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.loggers.ErrorLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.messages.PluginMessages.*;
-
-import org.opends.messages.MessageBuilder;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.util.StaticUtils.*;
@@ -195,6 +195,10 @@
private DirectoryServerPlugin[] postResponseModifyPlugins;
private DirectoryServerPlugin[] postResponseModifyDNPlugins;
private DirectoryServerPlugin[] postResponseSearchPlugins;
+ private DirectoryServerPlugin[] postSynchronizationAddPlugins;
+ private DirectoryServerPlugin[] postSynchronizationDeletePlugins;
+ private DirectoryServerPlugin[] postSynchronizationModifyPlugins;
+ private DirectoryServerPlugin[] postSynchronizationModifyDNPlugins;
private DirectoryServerPlugin[] searchResultEntryPlugins;
private DirectoryServerPlugin[] searchResultReferencePlugins;
private DirectoryServerPlugin[] subordinateModifyDNPlugins;
@@ -223,53 +227,57 @@
{
pluginLock = new ReentrantLock();
- startupPlugins = new DirectoryServerPlugin[0];
- shutdownPlugins = new DirectoryServerPlugin[0];
- postConnectPlugins = new DirectoryServerPlugin[0];
- postDisconnectPlugins = new DirectoryServerPlugin[0];
- ldifImportPlugins = new DirectoryServerPlugin[0];
- ldifExportPlugins = new DirectoryServerPlugin[0];
- preParseAbandonPlugins = new DirectoryServerPlugin[0];
- preParseAddPlugins = new DirectoryServerPlugin[0];
- preParseBindPlugins = new DirectoryServerPlugin[0];
- preParseComparePlugins = new DirectoryServerPlugin[0];
- preParseDeletePlugins = new DirectoryServerPlugin[0];
- preParseExtendedPlugins = new DirectoryServerPlugin[0];
- preParseModifyPlugins = new DirectoryServerPlugin[0];
- preParseModifyDNPlugins = new DirectoryServerPlugin[0];
- preParseSearchPlugins = new DirectoryServerPlugin[0];
- preParseUnbindPlugins = new DirectoryServerPlugin[0];
- preOperationAddPlugins = new DirectoryServerPlugin[0];
- preOperationBindPlugins = new DirectoryServerPlugin[0];
- preOperationComparePlugins = new DirectoryServerPlugin[0];
- preOperationDeletePlugins = new DirectoryServerPlugin[0];
- preOperationExtendedPlugins = new DirectoryServerPlugin[0];
- preOperationModifyPlugins = new DirectoryServerPlugin[0];
- preOperationModifyDNPlugins = new DirectoryServerPlugin[0];
- preOperationSearchPlugins = new DirectoryServerPlugin[0];
- postOperationAbandonPlugins = new DirectoryServerPlugin[0];
- postOperationAddPlugins = new DirectoryServerPlugin[0];
- postOperationBindPlugins = new DirectoryServerPlugin[0];
- postOperationComparePlugins = new DirectoryServerPlugin[0];
- postOperationDeletePlugins = new DirectoryServerPlugin[0];
- postOperationExtendedPlugins = new DirectoryServerPlugin[0];
- postOperationModifyPlugins = new DirectoryServerPlugin[0];
- postOperationModifyDNPlugins = new DirectoryServerPlugin[0];
- postOperationSearchPlugins = new DirectoryServerPlugin[0];
- postOperationUnbindPlugins = new DirectoryServerPlugin[0];
- postResponseAddPlugins = new DirectoryServerPlugin[0];
- postResponseBindPlugins = new DirectoryServerPlugin[0];
- postResponseComparePlugins = new DirectoryServerPlugin[0];
- postResponseDeletePlugins = new DirectoryServerPlugin[0];
- postResponseExtendedPlugins = new DirectoryServerPlugin[0];
- postResponseModifyPlugins = new DirectoryServerPlugin[0];
- postResponseModifyDNPlugins = new DirectoryServerPlugin[0];
- postResponseSearchPlugins = new DirectoryServerPlugin[0];
- searchResultEntryPlugins = new DirectoryServerPlugin[0];
- searchResultReferencePlugins = new DirectoryServerPlugin[0];
- subordinateModifyDNPlugins = new DirectoryServerPlugin[0];
- intermediateResponsePlugins = new DirectoryServerPlugin[0];
- registeredPlugins =
+ startupPlugins = new DirectoryServerPlugin[0];
+ shutdownPlugins = new DirectoryServerPlugin[0];
+ postConnectPlugins = new DirectoryServerPlugin[0];
+ postDisconnectPlugins = new DirectoryServerPlugin[0];
+ ldifImportPlugins = new DirectoryServerPlugin[0];
+ ldifExportPlugins = new DirectoryServerPlugin[0];
+ preParseAbandonPlugins = new DirectoryServerPlugin[0];
+ preParseAddPlugins = new DirectoryServerPlugin[0];
+ preParseBindPlugins = new DirectoryServerPlugin[0];
+ preParseComparePlugins = new DirectoryServerPlugin[0];
+ preParseDeletePlugins = new DirectoryServerPlugin[0];
+ preParseExtendedPlugins = new DirectoryServerPlugin[0];
+ preParseModifyPlugins = new DirectoryServerPlugin[0];
+ preParseModifyDNPlugins = new DirectoryServerPlugin[0];
+ preParseSearchPlugins = new DirectoryServerPlugin[0];
+ preParseUnbindPlugins = new DirectoryServerPlugin[0];
+ preOperationAddPlugins = new DirectoryServerPlugin[0];
+ preOperationBindPlugins = new DirectoryServerPlugin[0];
+ preOperationComparePlugins = new DirectoryServerPlugin[0];
+ preOperationDeletePlugins = new DirectoryServerPlugin[0];
+ preOperationExtendedPlugins = new DirectoryServerPlugin[0];
+ preOperationModifyPlugins = new DirectoryServerPlugin[0];
+ preOperationModifyDNPlugins = new DirectoryServerPlugin[0];
+ preOperationSearchPlugins = new DirectoryServerPlugin[0];
+ postOperationAbandonPlugins = new DirectoryServerPlugin[0];
+ postOperationAddPlugins = new DirectoryServerPlugin[0];
+ postOperationBindPlugins = new DirectoryServerPlugin[0];
+ postOperationComparePlugins = new DirectoryServerPlugin[0];
+ postOperationDeletePlugins = new DirectoryServerPlugin[0];
+ postOperationExtendedPlugins = new DirectoryServerPlugin[0];
+ postOperationModifyPlugins = new DirectoryServerPlugin[0];
+ postOperationModifyDNPlugins = new DirectoryServerPlugin[0];
+ postOperationSearchPlugins = new DirectoryServerPlugin[0];
+ postOperationUnbindPlugins = new DirectoryServerPlugin[0];
+ postResponseAddPlugins = new DirectoryServerPlugin[0];
+ postResponseBindPlugins = new DirectoryServerPlugin[0];
+ postResponseComparePlugins = new DirectoryServerPlugin[0];
+ postResponseDeletePlugins = new DirectoryServerPlugin[0];
+ postResponseExtendedPlugins = new DirectoryServerPlugin[0];
+ postResponseModifyPlugins = new DirectoryServerPlugin[0];
+ postResponseModifyDNPlugins = new DirectoryServerPlugin[0];
+ postResponseSearchPlugins = new DirectoryServerPlugin[0];
+ postSynchronizationAddPlugins = new DirectoryServerPlugin[0];
+ postSynchronizationDeletePlugins = new DirectoryServerPlugin[0];
+ postSynchronizationModifyPlugins = new DirectoryServerPlugin[0];
+ postSynchronizationModifyDNPlugins = new DirectoryServerPlugin[0];
+ searchResultEntryPlugins = new DirectoryServerPlugin[0];
+ searchResultReferencePlugins = new DirectoryServerPlugin[0];
+ subordinateModifyDNPlugins = new DirectoryServerPlugin[0];
+ intermediateResponsePlugins = new DirectoryServerPlugin[0];
+ registeredPlugins =
new ConcurrentHashMap<DN,
DirectoryServerPlugin<? extends PluginCfg>>();
}
@@ -404,8 +412,8 @@
if (initialize)
{
Method method = plugin.getClass().getMethod("initializeInternal",
- DN.class, Set.class);
- method.invoke(plugin, configuration.dn(), pluginTypes);
+ PluginCfg.class, Set.class);
+ method.invoke(plugin, configuration, pluginTypes);
method = plugin.getClass().getMethod("initializePlugin", Set.class,
configuration.definition().getServerConfigurationClass());
@@ -511,6 +519,14 @@
case SEARCHRESULTREFERENCE: return PluginType.SEARCH_RESULT_REFERENCE;
case SUBORDINATEMODIFYDN: return PluginType.SUBORDINATE_MODIFY_DN;
case INTERMEDIATERESPONSE: return PluginType.INTERMEDIATE_RESPONSE;
+ case POSTSYNCHRONIZATIONADD:
+ return PluginType.POST_SYNCHRONIZATION_ADD;
+ case POSTSYNCHRONIZATIONDELETE:
+ return PluginType.POST_SYNCHRONIZATION_DELETE;
+ case POSTSYNCHRONIZATIONMODIFY:
+ return PluginType.POST_SYNCHRONIZATION_MODIFY;
+ case POSTSYNCHRONIZATIONMODIFYDN:
+ return PluginType.POST_SYNCHRONIZATION_MODIFY_DN;
default: return null;
}
}
@@ -819,6 +835,30 @@
addPlugin(postResponseSearchPlugins, plugin, t,
pluginRootConfig.getPluginOrderPostResponseSearch());
break;
+ case POST_SYNCHRONIZATION_ADD:
+ postSynchronizationAddPlugins =
+ addPlugin(postSynchronizationAddPlugins, plugin, t,
+ pluginRootConfig.
+ getPluginOrderPostSynchronizationAdd());
+ break;
+ case POST_SYNCHRONIZATION_DELETE:
+ postSynchronizationDeletePlugins =
+ addPlugin(postSynchronizationDeletePlugins, plugin, t,
+ pluginRootConfig.
+ getPluginOrderPostSynchronizationDelete());
+ break;
+ case POST_SYNCHRONIZATION_MODIFY:
+ postSynchronizationModifyPlugins =
+ addPlugin(postSynchronizationModifyPlugins, plugin, t,
+ pluginRootConfig.
+ getPluginOrderPostSynchronizationModify());
+ break;
+ case POST_SYNCHRONIZATION_MODIFY_DN:
+ postSynchronizationModifyDNPlugins =
+ addPlugin(postSynchronizationModifyDNPlugins, plugin, t,
+ pluginRootConfig.
+ getPluginOrderPostSynchronizationModifyDN());
+ break;
case SEARCH_RESULT_ENTRY:
searchResultEntryPlugins =
addPlugin(searchResultEntryPlugins, plugin, t,
@@ -1244,6 +1284,22 @@
postResponseSearchPlugins = removePlugin(postResponseSearchPlugins,
plugin);
break;
+ case POST_SYNCHRONIZATION_ADD:
+ postSynchronizationAddPlugins =
+ removePlugin(postSynchronizationAddPlugins, plugin);
+ break;
+ case POST_SYNCHRONIZATION_DELETE:
+ postSynchronizationDeletePlugins =
+ removePlugin(postSynchronizationDeletePlugins, plugin);
+ break;
+ case POST_SYNCHRONIZATION_MODIFY:
+ postSynchronizationModifyPlugins =
+ removePlugin(postSynchronizationModifyPlugins, plugin);
+ break;
+ case POST_SYNCHRONIZATION_MODIFY_DN:
+ postSynchronizationModifyDNPlugins =
+ removePlugin(postSynchronizationModifyDNPlugins, plugin);
+ break;
case SEARCH_RESULT_ENTRY:
searchResultEntryPlugins = removePlugin(searchResultEntryPlugins,
plugin);
@@ -1740,6 +1796,12 @@
for (DirectoryServerPlugin p : preParseAbandonPlugins)
{
+ if (abandonOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(abandonOperation);
@@ -1816,6 +1878,12 @@
for (DirectoryServerPlugin p : preParseAddPlugins)
{
+ if (addOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(addOperation);
@@ -1889,6 +1957,12 @@
for (DirectoryServerPlugin p : preParseBindPlugins)
{
+ if (bindOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(bindOperation);
@@ -1962,6 +2036,12 @@
for (DirectoryServerPlugin p : preParseComparePlugins)
{
+ if (compareOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(compareOperation);
@@ -2038,6 +2118,12 @@
for (DirectoryServerPlugin p : preParseDeletePlugins)
{
+ if (deleteOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(deleteOperation);
@@ -2114,6 +2200,12 @@
for (DirectoryServerPlugin p : preParseExtendedPlugins)
{
+ if (extendedOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(extendedOperation);
@@ -2178,21 +2270,27 @@
* Invokes the set of pre-parse modify plugins that have been configured in
* the Directory Server.
*
- * @param operation The modify operation for which to invoke the
+ * @param modifyOperation The modify operation for which to invoke the
* pre-parse plugins.
*
* @return The result of processing the pre-parse modify plugins.
*/
public PreParsePluginResult invokePreParseModifyPlugins(
- PreParseModifyOperation operation)
+ PreParseModifyOperation modifyOperation)
{
PreParsePluginResult result = null;
for (DirectoryServerPlugin p : preParseModifyPlugins)
{
+ if (modifyOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
- result = p.doPreParse(operation);
+ result = p.doPreParse(modifyOperation);
}
catch (Exception e)
{
@@ -2202,15 +2300,16 @@
}
Message message = ERR_PLUGIN_PRE_PARSE_PLUGIN_EXCEPTION.
- get(operation.getOperationType().getOperationName(),
+ get(modifyOperation.getOperationType().getOperationName(),
String.valueOf(p.getPluginEntryDN()),
- operation.getConnectionID(), operation.getOperationID(),
+ modifyOperation.getConnectionID(),
+ modifyOperation.getOperationID(),
stackTraceToSingleLineString(e));
logError(message);
- operation.setResultCode(
+ modifyOperation.setResultCode(
DirectoryServer.getServerErrorResultCode());
- operation.appendErrorMessage(message);
+ modifyOperation.appendErrorMessage(message);
return new PreParsePluginResult(false, false, true);
}
@@ -2218,15 +2317,15 @@
if (result == null)
{
Message message = ERR_PLUGIN_PRE_PARSE_PLUGIN_RETURNED_NULL.
- get(operation.getOperationType().getOperationName(),
+ get(modifyOperation.getOperationType().getOperationName(),
String.valueOf(p.getPluginEntryDN()),
- operation.getConnectionID(),
- String.valueOf(operation.getOperationID()));
+ modifyOperation.getConnectionID(),
+ String.valueOf(modifyOperation.getOperationID()));
logError(message);
- operation.setResultCode(
+ modifyOperation.setResultCode(
DirectoryServer.getServerErrorResultCode());
- operation.appendErrorMessage(message);
+ modifyOperation.appendErrorMessage(message);
return new PreParsePluginResult(false, false, true);
}
@@ -2265,6 +2364,12 @@
for (DirectoryServerPlugin p : preParseModifyDNPlugins)
{
+ if (modifyDNOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(modifyDNOperation);
@@ -2341,6 +2446,12 @@
for (DirectoryServerPlugin p : preParseSearchPlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(searchOperation);
@@ -2417,6 +2528,12 @@
for (DirectoryServerPlugin p : preParseUnbindPlugins)
{
+ if (unbindOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreParse(unbindOperation);
@@ -2493,6 +2610,12 @@
for (DirectoryServerPlugin p : preOperationAddPlugins)
{
+ if (addOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(addOperation);
@@ -2565,6 +2688,12 @@
for (DirectoryServerPlugin p : preOperationBindPlugins)
{
+ if (bindOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(bindOperation);
@@ -2638,6 +2767,12 @@
for (DirectoryServerPlugin p : preOperationComparePlugins)
{
+ if (compareOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(compareOperation);
@@ -2714,6 +2849,12 @@
for (DirectoryServerPlugin p : preOperationDeletePlugins)
{
+ if (deleteOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(deleteOperation);
@@ -2790,6 +2931,12 @@
for (DirectoryServerPlugin p : preOperationExtendedPlugins)
{
+ if (extendedOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(extendedOperation);
@@ -2866,6 +3013,12 @@
for (DirectoryServerPlugin p : preOperationModifyPlugins)
{
+ if (modifyOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(modifyOperation);
@@ -2942,6 +3095,12 @@
for (DirectoryServerPlugin p : preOperationModifyDNPlugins)
{
+ if (modifyDNOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(modifyDNOperation);
@@ -3018,6 +3177,12 @@
for (DirectoryServerPlugin p : preOperationSearchPlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPreOperation(searchOperation);
@@ -3094,6 +3259,12 @@
for (DirectoryServerPlugin p : postOperationAbandonPlugins)
{
+ if (abandonOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(abandonOperation);
@@ -3170,6 +3341,12 @@
for (DirectoryServerPlugin p : postOperationAddPlugins)
{
+ if (addOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(addOperation);
@@ -3242,6 +3419,12 @@
for (DirectoryServerPlugin p : postOperationBindPlugins)
{
+ if (bindOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(bindOperation);
@@ -3315,6 +3498,12 @@
for (DirectoryServerPlugin p : postOperationComparePlugins)
{
+ if (compareOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(compareOperation);
@@ -3391,6 +3580,12 @@
for (DirectoryServerPlugin p : postOperationDeletePlugins)
{
+ if (deleteOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(deleteOperation);
@@ -3467,6 +3662,12 @@
for (DirectoryServerPlugin p : postOperationExtendedPlugins)
{
+ if (extendedOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(extendedOperation);
@@ -3543,6 +3744,12 @@
for (DirectoryServerPlugin p : postOperationModifyPlugins)
{
+ if (modifyOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(modifyOperation);
@@ -3619,6 +3826,12 @@
for (DirectoryServerPlugin p : postOperationModifyDNPlugins)
{
+ if (modifyDNOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(modifyDNOperation);
@@ -3695,6 +3908,12 @@
for (DirectoryServerPlugin p : postOperationSearchPlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(searchOperation);
@@ -3771,6 +3990,12 @@
for (DirectoryServerPlugin p : postOperationUnbindPlugins)
{
+ if (unbindOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostOperation(unbindOperation);
@@ -3847,6 +4072,12 @@
for (DirectoryServerPlugin p : postResponseAddPlugins)
{
+ if (addOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(addOperation);
@@ -3913,6 +4144,12 @@
for (DirectoryServerPlugin p : postResponseBindPlugins)
{
+ if (bindOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(bindOperation);
@@ -3980,6 +4217,12 @@
for (DirectoryServerPlugin p : postResponseComparePlugins)
{
+ if (compareOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(compareOperation);
@@ -4048,6 +4291,12 @@
for (DirectoryServerPlugin p : postResponseDeletePlugins)
{
+ if (deleteOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(deleteOperation);
@@ -4116,6 +4365,12 @@
for (DirectoryServerPlugin p : postResponseExtendedPlugins)
{
+ if (extendedOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(extendedOperation);
@@ -4184,6 +4439,12 @@
for (DirectoryServerPlugin p : postResponseModifyPlugins)
{
+ if (modifyOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(modifyOperation);
@@ -4252,6 +4513,12 @@
for (DirectoryServerPlugin p : postResponseModifyDNPlugins)
{
+ if (modifyDNOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(modifyDNOperation);
@@ -4320,6 +4587,12 @@
for (DirectoryServerPlugin p : postResponseSearchPlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.doPostResponse(searchOperation);
@@ -4370,6 +4643,151 @@
return result;
}
+
+
+ /**
+ * Invokes the set of post-synchronization add plugins that have been
+ * configured in the Directory Server.
+ *
+ * @param addOperation The add operation for which to invoke the
+ * post-synchronization plugins.
+ */
+ public void invokePostSynchronizationAddPlugins(
+ PostSynchronizationAddOperation addOperation)
+ {
+ for (DirectoryServerPlugin p : postSynchronizationAddPlugins)
+ {
+ try
+ {
+ p.doPostSynchronization(addOperation);
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION.
+ get(addOperation.getOperationType().getOperationName(),
+ String.valueOf(p.getPluginEntryDN()),
+ addOperation.getConnectionID(), addOperation.getOperationID(),
+ stackTraceToSingleLineString(e));
+ logError(message);
+ }
+ }
+ }
+
+
+
+ /**
+ * Invokes the set of post-synchronization delete plugins that have been
+ * configured in the Directory Server.
+ *
+ * @param deleteOperation The delete operation for which to invoke the
+ * post-synchronization plugins.
+ */
+ public void invokePostSynchronizationDeletePlugins(
+ PostSynchronizationDeleteOperation deleteOperation)
+ {
+ for (DirectoryServerPlugin p : postSynchronizationDeletePlugins)
+ {
+ try
+ {
+ p.doPostSynchronization(deleteOperation);
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION.
+ get(deleteOperation.getOperationType().getOperationName(),
+ String.valueOf(p.getPluginEntryDN()),
+ deleteOperation.getConnectionID(),
+ deleteOperation.getOperationID(),
+ stackTraceToSingleLineString(e));
+ logError(message);
+ }
+ }
+ }
+
+
+
+ /**
+ * Invokes the set of post-synchronization modify plugins that have been
+ * configured in the Directory Server.
+ *
+ * @param modifyOperation The modify operation for which to invoke the
+ * post-synchronization plugins.
+ */
+ public void invokePostSynchronizationModifyPlugins(
+ PostSynchronizationModifyOperation modifyOperation)
+ {
+ for (DirectoryServerPlugin p : postSynchronizationModifyPlugins)
+ {
+ try
+ {
+ p.doPostSynchronization(modifyOperation);
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION.
+ get(modifyOperation.getOperationType().getOperationName(),
+ String.valueOf(p.getPluginEntryDN()),
+ modifyOperation.getConnectionID(),
+ modifyOperation.getOperationID(),
+ stackTraceToSingleLineString(e));
+ logError(message);
+ }
+ }
+ }
+
+
+
+ /**
+ * Invokes the set of post-synchronization modify DN plugins that have been
+ * configured in the Directory Server.
+ *
+ * @param modifyDNOperation The modify DN operation for which to invoke the
+ * post-synchronization plugins.
+ */
+ public void invokePostSynchronizationModifyDNPlugins(
+ PostSynchronizationModifyDNOperation modifyDNOperation)
+ {
+ for (DirectoryServerPlugin p : postSynchronizationModifyDNPlugins)
+ {
+ try
+ {
+ p.doPostSynchronization(modifyDNOperation);
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION.
+ get(modifyDNOperation.getOperationType().getOperationName(),
+ String.valueOf(p.getPluginEntryDN()),
+ modifyDNOperation.getConnectionID(),
+ modifyDNOperation.getOperationID(),
+ stackTraceToSingleLineString(e));
+ logError(message);
+ }
+ }
+ }
+
+
+
/**
* Invokes the set of search result entry plugins that have been configured
* in the Directory Server.
@@ -4388,6 +4806,12 @@
for (DirectoryServerPlugin p : searchResultEntryPlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.processSearchEntry(searchOperation, searchEntry);
@@ -4438,6 +4862,8 @@
return result;
}
+
+
/**
* Invokes the set of search result entry plugins that have been configured
* in the Directory Server.
@@ -4456,6 +4882,18 @@
for (DirectoryServerPlugin p : searchResultEntryPlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.processSearchEntry(searchOperation, searchEntry);
@@ -4506,6 +4944,8 @@
return result;
}
+
+
/**
* Invokes the set of search result reference plugins that have been
* configured in the Directory Server.
@@ -4524,6 +4964,12 @@
for (DirectoryServerPlugin p : searchResultReferencePlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.processSearchReference(searchOperation, searchReference);
@@ -4574,6 +5020,8 @@
return result;
}
+
+
/**
* Invokes the set of search result reference plugins that have been
* configured in the Directory Server.
@@ -4592,6 +5040,12 @@
for (DirectoryServerPlugin p : searchResultReferencePlugins)
{
+ if (searchOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
result = p.processSearchReference(searchOperation, searchReference);
@@ -4667,6 +5121,12 @@
for (DirectoryServerPlugin p : subordinateModifyDNPlugins)
{
+ if (modifyDNOperation.isInternalOperation() &&
+ (! p.invokeForInternalOperations()))
+ {
+ continue;
+ }
+
try
{
DirectoryServerPlugin<? extends PluginCfg> gp =
@@ -4972,7 +5432,8 @@
// then we shouldn't do anything with it although if the class has changed
// then we'll at least need to indicate that administrative action is
// required. If the mapper is disabled, then instantiate the class and
- // initialize and register it as an identity mapper.
+ // initialize and register it as an identity mapper. Also, update the
+ // plugin to indicate whether it should be invoked for internal operations.
String className = configuration.getPluginClass();
if (existingPlugin != null)
{
@@ -4981,6 +5442,9 @@
adminActionRequired = true;
}
+ existingPlugin.setInvokeForInternalOperations(
+ configuration.isInvokeForInternalOperations());
+
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
diff --git a/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
index a7a7e16..33b767d 100644
--- a/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
@@ -465,6 +465,10 @@
StringBuilder buffer = new StringBuilder(50);
buffer.append("# ");
buffer.append(TimeThread.getLocalTime());
+ buffer.append("; conn=");
+ buffer.append(addOperation.getConnectionID());
+ buffer.append("; op=");
+ buffer.append(addOperation.getOperationID());
buffer.append(EOL);
buffer.append("dn:");
@@ -598,6 +602,10 @@
StringBuilder buffer = new StringBuilder(50);
buffer.append("# ");
buffer.append(TimeThread.getLocalTime());
+ buffer.append("; conn=");
+ buffer.append(deleteOperation.getConnectionID());
+ buffer.append("; op=");
+ buffer.append(deleteOperation.getOperationID());
buffer.append(EOL);
buffer.append("dn:");
@@ -676,6 +684,10 @@
StringBuilder buffer = new StringBuilder(50);
buffer.append("# ");
buffer.append(TimeThread.getLocalTime());
+ buffer.append("; conn=");
+ buffer.append(modifyOperation.getConnectionID());
+ buffer.append("; op=");
+ buffer.append(modifyOperation.getOperationID());
buffer.append(EOL);
buffer.append("dn:");
@@ -777,6 +789,10 @@
StringBuilder buffer = new StringBuilder(50);
buffer.append("# ");
buffer.append(TimeThread.getLocalTime());
+ buffer.append("; conn=");
+ buffer.append(modifyDNOperation.getConnectionID());
+ buffer.append("; op=");
+ buffer.append(modifyDNOperation.getOperationID());
buffer.append(EOL);
buffer.append("dn:");
diff --git a/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java b/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
index 9c9a8d8..279164f 100644
--- a/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
+++ b/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
@@ -26,47 +26,104 @@
*/
package org.opends.server.plugins;
-import org.opends.server.admin.std.server.UniqueAttributePluginCfg;
-import org.opends.server.admin.std.meta.PluginCfgDefn;
+
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opends.messages.Message;
import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.meta.PluginCfgDefn;
+import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.admin.std.server.UniqueAttributePluginCfg;
+import org.opends.server.api.AlertGenerator;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreOperationPluginResult;
import org.opends.server.config.ConfigException;
-import org.opends.server.types.*;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DereferencePolicy;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.RDN;
+import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SearchResultEntry;
+import org.opends.server.types.SearchScope;
+import org.opends.server.types.operation.PostSynchronizationAddOperation;
+import org.opends.server.types.operation.PostSynchronizationModifyDNOperation;
+import org.opends.server.types.operation.PostSynchronizationModifyOperation;
import org.opends.server.types.operation.PreOperationAddOperation;
import org.opends.server.types.operation.PreOperationModifyDNOperation;
import org.opends.server.types.operation.PreOperationModifyOperation;
-import org.opends.server.types.operation.PreOperationOperation;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.messages.Message;
-import static org.opends.messages.PluginMessages.*;
-import java.util.*;
+import static org.opends.messages.PluginMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.util.ServerConstants.*;
+
+
/**
- * This class implements a Directory Server plugin that performs attribute
- * uniqueness checking on the add, modify and modifyDN operations. If the
- * operation is eligible for checking based on a set of configuration criteria,
- * then the operation's attribute values will be checked, using that
- * configuration criteria, for uniqueness against the server's values to
- * determine if the operation can proceed.
+ * This class implements a Directory Server plugin that can be used to ensure
+ * that all values for a given attribute or set of attributes are unique within
+ * the server (or optionally, below a specified set of base DNs). It will
+ * examine all add, modify, and modify DN operations to determine whether any
+ * new conflicts are introduced. If a conflict is detected then the operation
+ * will be rejected, unless that operation is being applied through
+ * synchronization in which case an alert will be generated to notify
+ * administrators of the problem.
*/
public class UniqueAttributePlugin
extends DirectoryServerPlugin<UniqueAttributePluginCfg>
- implements ConfigurationChangeListener<UniqueAttributePluginCfg> {
+ implements ConfigurationChangeListener<UniqueAttributePluginCfg>,
+ AlertGenerator
+{
+ /**
+ * The debug log tracer that will be used for this plugin.
+ */
+ private static final DebugTracer TRACER = getTracer();
+
+
+
+ /**
+ * The pre-operation plugin result that should be returned if an operation
+ * would have resulted in a unique attribute conflict.
+ */
+ private static final PreOperationPluginResult FAILED_PREOP_RESULT =
+ new PreOperationPluginResult(false, false, false, true);
+
+
+
+ /**
+ * The set of attributes that will be requested when performing internal
+ * search operations. This indicates that no attributes should be returned.
+ */
+ private static final LinkedHashSet<String> SEARCH_ATTRS =
+ new LinkedHashSet<String>(1);
+ static
+ {
+ SEARCH_ATTRS.add("1.1");
+ }
+
+
//Current plugin configuration.
private UniqueAttributePluginCfg currentConfiguration;
- //List of attribute types that must be unique.
- private LinkedHashSet<AttributeType> uniqueAttributeTypes =
- new LinkedHashSet<AttributeType>();
-//List of base DNs that limit the scope of the uniqueness checking.
- private LinkedHashSet<DN> baseDNs = new LinkedHashSet<DN>();
/**
* {@inheritDoc}
@@ -74,37 +131,710 @@
@Override()
public final void initializePlugin(Set<PluginType> pluginTypes,
UniqueAttributePluginCfg configuration)
- throws ConfigException {
+ throws ConfigException
+ {
configuration.addUniqueAttributeChangeListener(this);
currentConfiguration = configuration;
+ DirectoryServer.registerAlertGenerator(this);
+
for (PluginType t : pluginTypes)
- switch (t) {
+ {
+ switch (t)
+ {
case PRE_OPERATION_ADD:
case PRE_OPERATION_MODIFY:
case PRE_OPERATION_MODIFY_DN:
+ case POST_SYNCHRONIZATION_ADD:
+ case POST_SYNCHRONIZATION_MODIFY:
+ case POST_SYNCHRONIZATION_MODIFY_DN:
// These are acceptable.
break;
+
default:
Message message =
ERR_PLUGIN_UNIQUEATTR_INVALID_PLUGIN_TYPE.get(t.toString());
throw new ConfigException(message);
}
- //Load base DNs if any.
- for(DN baseDN : configuration.getUniqueAttributeBaseDN())
- baseDNs.add(baseDN);
- //Load attribute types if any.
- for(AttributeType attributeType : configuration.getUniqueAttributeType())
- uniqueAttributeTypes.add(attributeType);
+ }
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final void finalizePlugin()
+ {
+ currentConfiguration.removeUniqueAttributeChangeListener(this);
+ DirectoryServer.deregisterAlertGenerator(this);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final PreOperationPluginResult
+ doPreOperation(PreOperationAddOperation addOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+ Entry entry = addOperation.getEntryToAdd();
+
+ Set<DN> baseDNs = getBaseDNs(config, entry.getDN());
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return PreOperationPluginResult.SUCCESS;
+ }
+
+ for (AttributeType t : config.getUniqueAttributeType())
+ {
+ List<Attribute> attrList = entry.getAttribute(t);
+ if (attrList != null)
+ {
+ for (Attribute a : attrList)
+ {
+ for (AttributeValue v : a.getValues())
+ {
+ try
+ {
+ DN conflictDN = getConflictingEntryDN(baseDNs, entry.getDN(),
+ config, v);
+ if (conflictDN != null)
+ {
+ addOperation.appendErrorMessage(
+ ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(t.getNameOrOID(),
+ v.getStringValue(), conflictDN.toString()));
+ addOperation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message m = ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR.get(
+ de.getResultCode().toString(),
+ de.getMessageObject());
+
+ addOperation.setResultCode(
+ DirectoryServer.getServerErrorResultCode());
+ addOperation.appendErrorMessage(m);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+ }
+ }
+ }
+
+ return PreOperationPluginResult.SUCCESS;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final PreOperationPluginResult
+ doPreOperation(PreOperationModifyOperation modifyOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+ DN entryDN = modifyOperation.getEntryDN();
+
+ Set<DN> baseDNs = getBaseDNs(config, entryDN);
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return PreOperationPluginResult.SUCCESS;
+ }
+
+ for (Modification m : modifyOperation.getModifications())
+ {
+ Attribute a = m.getAttribute();
+ AttributeType t = a.getAttributeType();
+ if (! config.getUniqueAttributeType().contains(t))
+ {
+ // This modification isn't for a unique attribute.
+ continue;
+ }
+
+ switch (m.getModificationType())
+ {
+ case ADD:
+ case REPLACE:
+ for (AttributeValue v : a.getValues())
+ {
+ try
+ {
+ DN conflictDN = getConflictingEntryDN(baseDNs, entryDN, config,
+ v);
+ if (conflictDN != null)
+ {
+ modifyOperation.appendErrorMessage(
+ ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(t.getNameOrOID(),
+ v.getStringValue(), conflictDN.toString()));
+ modifyOperation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message message = ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR.get(
+ de.getResultCode().toString(),
+ de.getMessageObject());
+
+ modifyOperation.setResultCode(
+ DirectoryServer.getServerErrorResultCode());
+ modifyOperation.appendErrorMessage(message);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+ break;
+
+ case INCREMENT:
+ // We could calculate the new value, but we'll just take it from the
+ // updated entry.
+ List<Attribute> attrList =
+ modifyOperation.getModifiedEntry().getAttribute(t,
+ a.getOptions());
+ if (attrList != null)
+ {
+ for (Attribute updatedAttr : attrList)
+ {
+ if (! updatedAttr.optionsEqual(a.getOptions()))
+ {
+ continue;
+ }
+
+ for (AttributeValue v : updatedAttr.getValues())
+ {
+ try
+ {
+ DN conflictDN = getConflictingEntryDN(baseDNs, entryDN,
+ config, v);
+ if (conflictDN != null)
+ {
+ modifyOperation.appendErrorMessage(
+ ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
+ t.getNameOrOID(), v.getStringValue(),
+ conflictDN.toString()));
+ modifyOperation.setResultCode(
+ ResultCode.CONSTRAINT_VIOLATION);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message message = ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR.get(
+ de.getResultCode().toString(),
+ de.getMessageObject());
+
+ modifyOperation.setResultCode(
+ DirectoryServer.getServerErrorResultCode());
+ modifyOperation.appendErrorMessage(message);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ // We don't need to look at this modification because it's not a
+ // modification type of interest.
+ continue;
+ }
+ }
+
+ return PreOperationPluginResult.SUCCESS;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final PreOperationPluginResult doPreOperation(
+ PreOperationModifyDNOperation modifyDNOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+
+ Set<DN> baseDNs = getBaseDNs(config,
+ modifyDNOperation.getUpdatedEntry().getDN());
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return PreOperationPluginResult.SUCCESS;
+ }
+
+ RDN newRDN = modifyDNOperation.getNewRDN();
+ for (int i=0; i < newRDN.getNumValues(); i++)
+ {
+ AttributeType t = newRDN.getAttributeType(i);
+ if (! config.getUniqueAttributeType().contains(t))
+ {
+ // We aren't interested in this attribute type.
+ continue;
+ }
+
+ try
+ {
+ AttributeValue v = newRDN.getAttributeValue(i);
+ DN conflictDN = getConflictingEntryDN(baseDNs,
+ modifyDNOperation.getEntryDN(), config, v);
+ if (conflictDN != null)
+ {
+ modifyDNOperation.appendErrorMessage(
+ ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(t.getNameOrOID(),
+ v.getStringValue(), conflictDN.toString()));
+ modifyDNOperation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message m = ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR.get(
+ de.getResultCode().toString(),
+ de.getMessageObject());
+
+ modifyDNOperation.setResultCode(
+ DirectoryServer.getServerErrorResultCode());
+ modifyDNOperation.appendErrorMessage(m);
+ return FAILED_PREOP_RESULT;
+ }
+ }
+
+ return PreOperationPluginResult.SUCCESS;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final void doPostSynchronization(
+ PostSynchronizationAddOperation addOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+ Entry entry = addOperation.getEntryToAdd();
+
+ Set<DN> baseDNs = getBaseDNs(config, entry.getDN());
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return;
+ }
+
+ for (AttributeType t : config.getUniqueAttributeType())
+ {
+ List<Attribute> attrList = entry.getAttribute(t);
+ if (attrList != null)
+ {
+ for (Attribute a : attrList)
+ {
+ for (AttributeValue v : a.getValues())
+ {
+ try
+ {
+ DN conflictDN = getConflictingEntryDN(baseDNs, entry.getDN(),
+ config, v);
+ if (conflictDN != null)
+ {
+ Message m = ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE.get(
+ t.getNameOrOID(),
+ addOperation.getConnectionID(),
+ addOperation.getOperationID(),
+ v.getStringValue(),
+ entry.getDN().toString(),
+ conflictDN.toString());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_CONFLICT, m);
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message m = ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR_SYNC.get(
+ addOperation.getConnectionID(),
+ addOperation.getOperationID(),
+ entry.getDN().toString(),
+ de.getResultCode().toString(),
+ de.getMessageObject());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_ERROR, m);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final void doPostSynchronization(
+ PostSynchronizationModifyOperation modifyOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+ DN entryDN = modifyOperation.getEntryDN();
+
+ Set<DN> baseDNs = getBaseDNs(config, entryDN);
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return;
+ }
+
+ for (Modification m : modifyOperation.getModifications())
+ {
+ Attribute a = m.getAttribute();
+ AttributeType t = a.getAttributeType();
+ if (! config.getUniqueAttributeType().contains(t))
+ {
+ // This modification isn't for a unique attribute.
+ continue;
+ }
+
+ switch (m.getModificationType())
+ {
+ case ADD:
+ case REPLACE:
+ for (AttributeValue v : a.getValues())
+ {
+ try
+ {
+ DN conflictDN = getConflictingEntryDN(baseDNs, entryDN, config,
+ v);
+ if (conflictDN != null)
+ {
+ Message message = ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE.get(
+ t.getNameOrOID(),
+ modifyOperation.getConnectionID(),
+ modifyOperation.getOperationID(),
+ v.getStringValue(),
+ entryDN.toString(),
+ conflictDN.toString());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_CONFLICT,
+ message);
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message message = ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR_SYNC.get(
+ modifyOperation.getConnectionID(),
+ modifyOperation.getOperationID(),
+ entryDN.toString(),
+ de.getResultCode().toString(),
+ de.getMessageObject());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_ERROR, message);
+ }
+ }
+ break;
+
+ case INCREMENT:
+ // We could calculate the new value, but we'll just take it from the
+ // updated entry.
+ List<Attribute> attrList =
+ modifyOperation.getModifiedEntry().getAttribute(t,
+ a.getOptions());
+ if (attrList != null)
+ {
+ for (Attribute updatedAttr : attrList)
+ {
+ if (! updatedAttr.optionsEqual(a.getOptions()))
+ {
+ continue;
+ }
+
+ for (AttributeValue v : updatedAttr.getValues())
+ {
+ try
+ {
+ DN conflictDN = getConflictingEntryDN(baseDNs, entryDN,
+ config, v);
+ if (conflictDN != null)
+ {
+ Message message = ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE.get(
+ t.getNameOrOID(),
+ modifyOperation.getConnectionID(),
+ modifyOperation.getOperationID(),
+ v.getStringValue(),
+ entryDN.toString(),
+ conflictDN.toString());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_CONFLICT,
+ message);
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message message =
+ ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR_SYNC.get(
+ modifyOperation.getConnectionID(),
+ modifyOperation.getOperationID(),
+ entryDN.toString(),
+ de.getResultCode().toString(),
+ de.getMessageObject());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_ERROR,
+ message);
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ // We don't need to look at this modification because it's not a
+ // modification type of interest.
+ continue;
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final void doPostSynchronization(
+ PostSynchronizationModifyDNOperation modifyDNOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+
+ Set<DN> baseDNs = getBaseDNs(config,
+ modifyDNOperation.getUpdatedEntry().getDN());
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return;
+ }
+
+ RDN newRDN = modifyDNOperation.getNewRDN();
+ for (int i=0; i < newRDN.getNumValues(); i++)
+ {
+ AttributeType t = newRDN.getAttributeType(i);
+ if (! config.getUniqueAttributeType().contains(t))
+ {
+ // We aren't interested in this attribute type.
+ continue;
+ }
+
+ try
+ {
+ AttributeValue v = newRDN.getAttributeValue(i);
+ DN conflictDN = getConflictingEntryDN(baseDNs,
+ modifyDNOperation.getEntryDN(), config, v);
+ if (conflictDN != null)
+ {
+ Message m =
+ ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE.get(
+ t.getNameOrOID(),
+ modifyDNOperation.getConnectionID(),
+ modifyDNOperation.getOperationID(),
+ v.getStringValue(),
+ modifyDNOperation.getUpdatedEntry().getDN().toString(),
+ conflictDN.toString());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_CONFLICT, m);
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ Message m = ERR_PLUGIN_UNIQUEATTR_INTERNAL_ERROR_SYNC.get(
+ modifyDNOperation.getConnectionID(),
+ modifyDNOperation.getOperationID(),
+ modifyDNOperation.getUpdatedEntry().getDN().toString(),
+ de.getResultCode().toString(),
+ de.getMessageObject());
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_UNIQUE_ATTR_SYNC_ERROR, m);
+ }
+ }
+ }
+
+
+
+ /**
+ * Retrieves the set of base DNs below which uniqueness checks should be
+ * performed. If no uniqueness checks should be performed for the specified
+ * entry, then {@code null} will be returned.
+ *
+ * @param config The plugin configuration to use to make the determination.
+ * @param entryDN The DN of the entry for which the checks will be
+ * performed.
+ */
+ private Set<DN> getBaseDNs(UniqueAttributePluginCfg config, DN entryDN)
+ {
+ Set<DN> baseDNs = config.getUniqueAttributeBaseDN();
+ if ((baseDNs == null) || baseDNs.isEmpty())
+ {
+ baseDNs = DirectoryServer.getPublicNamingContexts().keySet();
+ }
+
+ for (DN baseDN : baseDNs)
+ {
+ if (entryDN.isDescendantOf(baseDN))
+ {
+ return baseDNs;
+ }
+ }
+
+ return null;
+ }
+
+
+
+ /**
+ * Retrieves the DN of the first entry identified that conflicts with the
+ * provided value.
+ *
+ * @param baseDNs The set of base DNs below which the search is to be
+ * performed.
+ * @param targetDN The DN of the entry at which the change is targeted. If
+ * a conflict is found in that entry, then it will be
+ * ignored.
+ * @param config The plugin configuration to use when making the
+ * determination.
+ * @param value The value for which to identify any conflicting entries.
+ *
+ * @return The DN of the first entry identified that contains a conflicting
+ * value.
+ *
+ * @throws DirectoryException If a problem occurred while attempting to
+ * make the determination.
+ */
+ private DN getConflictingEntryDN(Set<DN> baseDNs, DN targetDN,
+ UniqueAttributePluginCfg config,
+ AttributeValue value)
+ throws DirectoryException
+ {
+ SearchFilter filter;
+ Set<AttributeType> attrTypes = config.getUniqueAttributeType();
+ if (attrTypes.size() == 1)
+ {
+ filter = SearchFilter.createEqualityFilter(attrTypes.iterator().next(),
+ value);
+ }
+ else
+ {
+ ArrayList<SearchFilter> equalityFilters =
+ new ArrayList<SearchFilter>(attrTypes.size());
+ for (AttributeType t : attrTypes)
+ {
+ equalityFilters.add(SearchFilter.createEqualityFilter(t, value));
+ }
+ filter = SearchFilter.createORFilter(equalityFilters);
+ }
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ for (DN baseDN : baseDNs)
+ {
+ InternalSearchOperation searchOperation =
+ conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
+ DereferencePolicy.NEVER_DEREF_ALIASES, 2, 0,
+ false, filter, SEARCH_ATTRS);
+ for (SearchResultEntry e : searchOperation.getSearchEntries())
+ {
+ if (! e.getDN().equals(targetDN))
+ {
+ return e.getDN();
+ }
+ }
+
+ switch (searchOperation.getResultCode())
+ {
+ case SUCCESS:
+ case NO_SUCH_OBJECT:
+ // These are fine. Either the search was successful or the base DN
+ // didn't exist.
+ break;
+
+ default:
+ // An error occurred that prevented the search from completing
+ // successfully.
+ throw new DirectoryException(searchOperation.getResultCode(),
+ searchOperation.getErrorMessage().toMessage());
+ }
+ }
+
+ // If we've gotten here, then no conflict was found.
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public boolean isConfigurationAcceptable(PluginCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ UniqueAttributePluginCfg cfg = (UniqueAttributePluginCfg) configuration;
+ return isConfigurationChangeAcceptable(cfg, unacceptableReasons);
+ }
+
+
+
/**
* {@inheritDoc}
*/
public boolean isConfigurationChangeAcceptable(
- UniqueAttributePluginCfg configuration,
- List<Message> unacceptableReasons) {
+ UniqueAttributePluginCfg configuration,
+ List<Message> unacceptableReasons)
+ {
boolean configAcceptable = true;
for (PluginCfgDefn.PluginType pluginType : configuration.getPluginType())
{
@@ -113,12 +843,15 @@
case PREOPERATIONADD:
case PREOPERATIONMODIFY:
case PREOPERATIONMODIFYDN:
+ case POSTSYNCHRONIZATIONADD:
+ case POSTSYNCHRONIZATIONMODIFY:
+ case POSTSYNCHRONIZATIONMODIFYDN:
// These are acceptable.
break;
default:
- Message message =
- ERR_PLUGIN_UNIQUEATTR_INVALID_PLUGIN_TYPE.get(pluginType.toString());
+ Message message = ERR_PLUGIN_UNIQUEATTR_INVALID_PLUGIN_TYPE.get(
+ pluginType.toString());
unacceptableReasons.add(message);
configAcceptable = false;
}
@@ -126,337 +859,53 @@
return configAcceptable;
}
+
+
/**
* {@inheritDoc}
*/
public ConfigChangeResult applyConfigurationChange(
- UniqueAttributePluginCfg newConfiguration) {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<Message> messages = new ArrayList<Message>();
- LinkedHashSet<AttributeType> newUniqueattributeTypes=
- new LinkedHashSet<AttributeType>();
- LinkedHashSet<DN> newConfiguredBaseDNs = new LinkedHashSet<DN>();
- //Load base DNs from new configuration.
- for(DN baseDN : newConfiguration.getUniqueAttributeBaseDN())
- newConfiguredBaseDNs.add(baseDN);
- //Load attribute types from new configuration.
- for(AttributeType attributeType : newConfiguration.getUniqueAttributeType())
- newUniqueattributeTypes.add(attributeType);
- //Switch to the new lists and configurations.
- baseDNs = newConfiguredBaseDNs;
- uniqueAttributeTypes = newUniqueattributeTypes;
+ UniqueAttributePluginCfg newConfiguration)
+ {
currentConfiguration = newConfiguration;
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
+
+
/**
* {@inheritDoc}
*/
- @Override()
- public final PreOperationPluginResult
- doPreOperation(PreOperationAddOperation addOperation) {
- PreOperationPluginResult pluginResult=PreOperationPluginResult.SUCCESS;
- DN entryDN=addOperation.getEntryDN();
- if(isEntryUniquenessCandidate(entryDN)) {
- List<AttributeValue> valueList =
- getEntryAttributeValues(addOperation.getEntryToAdd());
- if(!searchAllBaseDNs(valueList, entryDN))
- pluginResult = getPluginErrorResult(addOperation,
- ERR_PLUGIN_UNIQUEATTR_ADD_NOT_UNIQUE.get(entryDN.toString()));
- }
- return pluginResult;
+ public DN getComponentEntryDN()
+ {
+ return currentConfiguration.dn();
}
+
+
/**
* {@inheritDoc}
*/
- @Override()
- public final PreOperationPluginResult
- doPreOperation(PreOperationModifyOperation modifyOperation) {
- PreOperationPluginResult pluginResult=PreOperationPluginResult.SUCCESS;
- DN entryDN = modifyOperation.getEntryDN();
- if(isEntryUniquenessCandidate(entryDN)) {
- List<AttributeValue> valueList =
- getModificationAttributeValues(modifyOperation.getModifications(),
- modifyOperation.getModifiedEntry());
- if(!searchAllBaseDNs(valueList, entryDN))
- pluginResult = getPluginErrorResult(modifyOperation,
- ERR_PLUGIN_UNIQUEATTR_MOD_NOT_UNIQUE.get(entryDN.toString()));
- }
- return pluginResult;
+ public String getClassName()
+ {
+ return UniqueAttributePlugin.class.getName();
}
+
+
/**
* {@inheritDoc}
*/
- @Override()
- public final PreOperationPluginResult
- doPreOperation(PreOperationModifyDNOperation modifyDNOperation) {
- PreOperationPluginResult pluginResult=PreOperationPluginResult.SUCCESS;
- DN entryDN=modifyDNOperation.getOriginalEntry().getDN();
- //If the operation has a new superior DN then use that, since any moves
- //need to make sure there are no conflicts in the new superior base DN.
- if(modifyDNOperation.getNewSuperior() != null)
- entryDN = modifyDNOperation.getNewSuperior();
- if(isEntryUniquenessCandidate(entryDN)) {
- List<AttributeValue> valueList =
- getRDNAttributeValues(modifyDNOperation.getNewRDN());
- if(!searchAllBaseDNs(valueList, entryDN))
- pluginResult = getPluginErrorResult(modifyDNOperation,
- ERR_PLUGIN_UNIQUEATTR_MODDN_NOT_UNIQUE.get(entryDN.toString()));
- }
- return pluginResult;
- }
+ public LinkedHashMap<String,String> getAlerts()
+ {
+ LinkedHashMap<String,String> alerts = new LinkedHashMap<String,String>(2);
- /**
- * Determine if the specified DN is a candidate for attribute uniqueness
- * checking. Checking is skipped if the the unique attribute type list is
- * empty or if there are base DNS configured and the specified DN is not a
- * descendant of any of them. Checking is performed for all other cases.
- *
- * @param dn The DN to check.
- *
- * @return Returns <code>true</code> if the operation needs uniqueness
- * checking performed.
- */
- private boolean
- isEntryUniquenessCandidate(DN dn) {
- if(uniqueAttributeTypes.isEmpty())
- return false;
- else if(baseDNs.isEmpty())
- return true;
- else {
- for(DN baseDN : baseDNs)
- if(baseDN.isAncestorOf(dn))
- return true;
- }
- return false;
- }
+ alerts.put(ALERT_TYPE_UNIQUE_ATTR_SYNC_CONFLICT,
+ ALERT_DESCRIPTION_UNIQUE_ATTR_SYNC_CONFLICT);
+ alerts.put(ALERT_TYPE_UNIQUE_ATTR_SYNC_ERROR,
+ ALERT_DESCRIPTION_UNIQUE_ATTR_SYNC_ERROR);
- /**
- * Returns a plugin result instance indicating that the operation should be
- * terminated; that no further pre-operation processing should be performed
- * and that the server should send the response immediately. It also adds
- * a CONSTRAINT_VIOLATION result code and the specified error message to
- * the specified operation.
- *
- * @param operation The operation to add the result code and message to.
- *
- * @param message The message to add to the operation.
- *
- * @return Returns a plugin result instance that halts further processing
- * on this operation.
- */
- private PreOperationPluginResult
- getPluginErrorResult(PreOperationOperation operation, Message message) {
- operation.appendErrorMessage(message);
- operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
- return new PreOperationPluginResult(false, false, true);
- }
-
- /**
- * Searches all of the the attribute types of the specified RDN for matches
- * in the unique attribute type list. If matches are found, then the
- * corresponding values are added to a list of values that will be eventually
- * searched for uniqueness.
-
- * @param rdn The RDN to examine.
- *
- * @return Returns a list of attribute values from the RDN that matches the
- * unique attribute type list.
- */
- private List<AttributeValue> getRDNAttributeValues(RDN rdn) {
- LinkedList<AttributeValue> valueList=
- new LinkedList<AttributeValue>();
- int numAVAs = rdn.getNumValues();
- for (int i = 0; i < numAVAs; i++) {
- if(uniqueAttributeTypes.contains(rdn.getAttributeType(i)))
- valueList.add(rdn.getAttributeValue(i));
- }
- return valueList;
- }
-
- /**
- * Searches all of the attribute types of the specified entry for matches
- * in the unique attribute type list. Ff matches are found, then the
- * corresponding values are added to a list of values that will eventually
- * be searched for uniqueness.
- *
- * @param entry The entry to examine.
- *
- * @return Returns a list of attribute values from the entry that matches the
- * unique attribute type list.
- */
- private List<AttributeValue> getEntryAttributeValues(Entry entry) {
- LinkedList<AttributeValue> valueList=new LinkedList<AttributeValue>();
- for(AttributeType attributeType : uniqueAttributeTypes) {
- if(entry.hasAttribute(attributeType)) {
- List<Attribute> attrList=entry.getAttribute(attributeType);
- for (Attribute a : attrList)
- valueList.addAll(a.getValues());
- }
- }
- return valueList;
- }
-
- /**
- * Iterate over the unique attribute type list calling a method that will
- * search the specified modification list for each attribute type and add
- * the corresponding values to a list of values.
- *
- * @param modificationList The modification list to search over.
- *
- * @param modifedEntry The copy of the entry with modifications applied.
- *
- * @return Returns a list of attribute values from the modification list
- * that matches the unique attribute type list.
- */
- private List<AttributeValue>
- getModificationAttributeValues(List<Modification> modificationList,
- Entry modifedEntry) {
- LinkedList<AttributeValue> valueList =
- new LinkedList<AttributeValue>();
- for(AttributeType attributeType : uniqueAttributeTypes)
- getModValuesForAttribute(modificationList, attributeType, valueList,
- modifedEntry);
- return valueList;
- }
-
- /**
- * Searches the specified modification list for the provided attribute type.
- * If a match is found than the attribute value is added to a list of
- * attribute values that will be eventually searched for uniqueness.
- *
- * @param modificationList The modification list to search over.
- *
- * @param attributeType The attribute type to search for.
- *
- * @param valueList A list of attribute values to put the values in.
- *
- * @param modifiedEntry A copy of the entry with modifications applied.
- */
- private void
- getModValuesForAttribute(List<Modification> modificationList,
- AttributeType attributeType,
- LinkedList<AttributeValue> valueList,
- Entry modifiedEntry) {
-
- for(Modification modification : modificationList) {
- ModificationType modType=modification.getModificationType();
- //Skip delete modifications or modifications on attribute types not
- //matching the specified type.
- if(modType == ModificationType.DELETE ||
- !modification.getAttribute().getAttributeType().equals(attributeType))
- continue;
- //Increment uses modified entry to get value for the attribute type.
- if(modType == ModificationType.INCREMENT) {
- List<Attribute> modifiedAttrs =
- modifiedEntry.getAttribute(attributeType,
- modification.getAttribute().getOptions());
- if (modifiedAttrs != null) {
- for (Attribute a : modifiedAttrs)
- valueList.addAll(a.getValues());
- }
- } else {
- Attribute modifiedAttribute=modification.getAttribute();
- if(modifiedAttribute.hasValue())
- valueList.addAll(modifiedAttribute.getValues());
- }
- }
- }
-
-
- /**
- * Iterates over the base DNs configured by the plugin entry searching for
- * value matches. If the base DN list is empty then the public naming
- * contexts are used instead.
- *
- * @param valueList The list of values to search for.
- *
- * @param entryDN The DN of the entry related to the operation.
- *
- * @return Returns <code>true</code> if a value is unique.
- */
- private boolean
- searchAllBaseDNs(List<AttributeValue> valueList, DN entryDN) {
- if(valueList.isEmpty())
- return true;
- if(baseDNs.isEmpty()) {
- for(DN baseDN : DirectoryServer.getPublicNamingContexts().keySet()) {
- if(searchBaseDN(valueList, baseDN, entryDN))
- return false;
- }
- } else {
- for(DN baseDN : baseDNs) {
- if(searchBaseDN(valueList, baseDN, entryDN))
- return false;
- }
- }
- return true;
- }
-
- /**
- * Search a single base DN for all the values in a specified value list.
- * A filter is created to search all the attribute at once for each
- * value in the list.
- *
- * @param valueList The list of values to search for.
- *
- * @param baseDN The base DN to base the search at.
- *
- * @param entryDN The DN of the entry related to the operation.
- *
- * @return Returns <code>true</code> if the values are not unique under the
- * under the base DN.
- */
- private boolean
- searchBaseDN(List<AttributeValue> valueList, DN baseDN,
- DN entryDN) {
- //Filter set to hold component filters.
- HashSet<SearchFilter> componentFilters=new HashSet<SearchFilter>();
- for(AttributeValue value : valueList) {
- //Iterate over the unique attribute list and build a equality filter
- //using each attribute type in the list and the current value being
- //matched.
- for(AttributeType attributeType : uniqueAttributeTypes)
- componentFilters.add(SearchFilter.createEqualityFilter(attributeType,
- value));
- //Perform the search using the OR filter created from the filter
- //components created above.
- InternalClientConnection conn =
- InternalClientConnection.getRootConnection();
- InternalSearchOperation operation = conn.processSearch(baseDN,
- SearchScope.WHOLE_SUBTREE,
- DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, true,
- SearchFilter.createORFilter(componentFilters),
- null);
- switch (operation.getResultCode()) {
- case SUCCESS:
- break;
-
- case NO_SUCH_OBJECT:
- //This base DN doesn't exist, return false.
- return false;
-
- case SIZE_LIMIT_EXCEEDED:
- case TIME_LIMIT_EXCEEDED:
- case ADMIN_LIMIT_EXCEEDED:
- default:
- //Couldn't determine if the attribute is unique because an
- //administrative limit was reached during the search. Fail the
- //operation by returning true. Possibly log an error here?
- return true;
- }
- for (SearchResultEntry entry : operation.getSearchEntries()) {
- //Only allow the entry DN to exist. The user might be modifying
- //the attribute values and putting the same value back. Any other entry
- //means the value is not unique.
- if(!entry.getDN().equals(entryDN))
- return true;
- }
- componentFilters.clear();
- }
- return false;
+ return alerts;
}
}
+
diff --git a/opends/src/server/org/opends/server/types/operation/PostSynchronizationAddOperation.java b/opends/src/server/org/opends/server/types/operation/PostSynchronizationAddOperation.java
new file mode 100644
index 0000000..3a7fb5a
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/operation/PostSynchronizationAddOperation.java
@@ -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.types.operation;
+
+
+
+import java.util.List;
+import java.util.Map;
+
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.types.ObjectClass;
+import org.opends.server.types.RawAttribute;
+
+
+
+/**
+ * This class defines a set of methods that are available for use by
+ * post-synchronization plugins for add operations. Note that this
+ * interface is intended only to define an API for use by plugins and
+ * is not intended to be implemented by any custom classes.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
+ mayInstantiate=false,
+ mayExtend=false,
+ mayInvoke=true)
+public interface PostSynchronizationAddOperation
+ extends PostSynchronizationOperation
+{
+ /**
+ * Retrieves the DN of the entry to add in a raw, unparsed form as
+ * it was included in the request. This may or may not actually
+ * contain a valid DN, since no validation will have been performed
+ * on it.
+ *
+ * @return The DN of the entry in a raw, unparsed form.
+ */
+ public ByteString getRawEntryDN();
+
+
+
+ /**
+ * Retrieves the set of attributes in their raw, unparsed form as
+ * read from the client request. Some of these attributes may be
+ * invalid as no validation will have been performed on them. The
+ * returned list must not be altered by the caller.
+ *
+ * @return The set of attributes in their raw, unparsed form as
+ * read from the client request.
+ */
+ public List<RawAttribute> getRawAttributes();
+
+
+
+ /**
+ * Retrieves the DN of the entry to add.
+ *
+ * @return The DN of the entry to add.
+ */
+ public DN getEntryDN();
+
+
+
+ /**
+ * Retrieves the set of processed objectclasses for the entry to
+ * add. The contents of the returned map must not be altered by the
+ * caller.
+ *
+ * @return The set of processed objectclasses for the entry to add.
+ */
+ public Map<ObjectClass,String> getObjectClasses();
+
+
+
+ /**
+ * Retrieves the set of processed user attributes for the entry to
+ * add. The contents of the returned map must not be altered by the
+ * caller.
+ *
+ * @return The set of processed user attributes for the entry to
+ * add.
+ */
+ public Map<AttributeType,List<Attribute>> getUserAttributes();
+
+
+
+ /**
+ * Retrieves the set of processed operational attributes for the
+ * entry to add. The contents of the returned map must not be
+ * altered by the caller.
+ *
+ * @return The set of processed operational attributes for the
+ * entry to add.
+ */
+ public Map<AttributeType,List<Attribute>>
+ getOperationalAttributes();
+
+
+
+ /**
+ * Retrieves the entry to be added to the server. The contents of
+ * the returned entry must not be altered by the caller.
+ *
+ * @return The entry to be added to the server.
+ */
+ public Entry getEntryToAdd();
+}
+
diff --git a/opends/src/server/org/opends/server/types/operation/PostSynchronizationDeleteOperation.java b/opends/src/server/org/opends/server/types/operation/PostSynchronizationDeleteOperation.java
new file mode 100644
index 0000000..e40837d
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/operation/PostSynchronizationDeleteOperation.java
@@ -0,0 +1,78 @@
+/*
+ * 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.types.operation;
+
+
+
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+
+
+
+/**
+ * This class defines a set of methods that are available for use by
+ * post-synchronization plugins for delete operations. Note that this
+ * interface is intended only to define an API for use by plugins and
+ * is not intended to be implemented by any custom classes.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
+ mayInstantiate=false,
+ mayExtend=false,
+ mayInvoke=true)
+public interface PostSynchronizationDeleteOperation
+ extends PostSynchronizationOperation
+{
+ /**
+ * Retrieves the raw, unprocessed entry DN as included in the client
+ * request.
+ *
+ * @return The raw, unprocessed entry DN as included in the client
+ * request.
+ */
+ public ByteString getRawEntryDN();
+
+
+
+ /**
+ * Retrieves the DN of the entry to delete.
+ *
+ * @return The DN of the entry to delete.
+ */
+ public DN getEntryDN();
+
+
+
+ /**
+ * Retrieves the entry to be deleted.
+ *
+ * @return The entry to be deleted.
+ */
+ public Entry getEntryToDelete();
+}
+
diff --git a/opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyDNOperation.java b/opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyDNOperation.java
new file mode 100644
index 0000000..eb8225e
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyDNOperation.java
@@ -0,0 +1,189 @@
+/*
+ * 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.types.operation;
+
+
+
+import java.util.List;
+
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.RDN;
+
+
+
+/**
+ * This class defines a set of methods that are available for use by
+ * post-synchronization plugins for modify DN operations. Note that
+ * this interface is intended only to define an API for use by plugins
+ * and is not intended to be implemented by any custom classes.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
+ mayInstantiate=false,
+ mayExtend=false,
+ mayInvoke=true)
+public interface PostSynchronizationModifyDNOperation
+ extends PostSynchronizationOperation
+{
+ /**
+ * Retrieves the raw, unprocessed entry DN as included in the client
+ * request. The DN that is returned may or may not be a valid DN,
+ * since no validation will have been performed upon it.
+ *
+ * @return The raw, unprocessed entry DN as included in the client
+ * request.
+ */
+ public ByteString getRawEntryDN();
+
+
+
+ /**
+ * Retrieves the DN of the entry to rename. This should not be
+ * called by pre-parse plugins because the processed DN will not be
+ * available yet. Instead, they should call the
+ * <CODE>getRawEntryDN</CODE> method.
+ *
+ * @return The DN of the entry to rename, or <CODE>null</CODE> if
+ * the raw entry DN has not yet been processed.
+ */
+ public DN getEntryDN();
+
+
+
+ /**
+ * Retrieves the raw, unprocessed newRDN as included in the request
+ * from the client. This may or may not contain a valid RDN, as no
+ * validation will have been performed on it.
+ *
+ * @return The raw, unprocessed newRDN as included in the request
+ * from the client.
+ */
+ public ByteString getRawNewRDN();
+
+
+
+ /**
+ * Retrieves the new RDN to use for the entry. This should not be
+ * called by pre-parse plugins, because the processed newRDN will
+ * not yet be available. Pre-parse plugins should instead use the
+ * <CODE>getRawNewRDN</CODE> method.
+ *
+ * @return The new RDN to use for the entry, or <CODE>null</CODE>
+ * if the raw newRDN has not yet been processed.
+ */
+ public RDN getNewRDN();
+
+
+
+ /**
+ * Indicates whether the current RDN value should be removed from
+ * the entry.
+ *
+ * @return <CODE>true</CODE> if the current RDN value should be
+ * removed from the entry, or <CODE>false</CODE> if not.
+ */
+ public boolean deleteOldRDN();
+
+
+
+ /**
+ * Retrieves the raw, unprocessed newSuperior from the client
+ * request. This may or may not contain a valid DN, as no
+ * validation will have been performed on it.
+ *
+ * @return The raw, unprocessed newSuperior from the client
+ * request, or <CODE>null</CODE> if there is none.
+ */
+ public ByteString getRawNewSuperior();
+
+
+
+ /**
+ * Retrieves the newSuperior DN for the entry. This should not be
+ * called by pre-parse plugins, because the processed DN will not
+ * yet be available at that time. Instead, they should use the
+ * <CODE>getRawNewSuperior</CODE> method.
+ *
+ * @return The newSuperior DN for the entry, or <CODE>null</CODE>
+ * if there is no newSuperior DN for this request or if the
+ * raw newSuperior has not yet been processed.
+ */
+ public DN getNewSuperior();
+
+
+
+ /**
+ * Retrieves the set of modifications applied to attributes of the
+ * target entry in the course of processing this modify DN
+ * operation. This will include attribute-level changes from the
+ * modify DN itself (e.g., removing old RDN values if deleteOldRDN
+ * is set, or adding new RDN values that don't already exist), but
+ * it may also be used by pre-operation plugins to cause additional
+ * changes in the entry. In this case, those plugins may add
+ * modifications to this list through the
+ * <CODE>addModification</CODE> method (the list returned from this
+ * method should not be modified directly) if any changes should be
+ * processed in addition to the core modify DN processing. Backends
+ * may read this list to identify which attribute-level changes were
+ * applied in order to more easily apply updates to attribute
+ * indexes.
+ *
+ * @return The set of modifications applied to attributes during
+ * the course of the modify DN processing, or
+ * <CODE>null</CODE> if that information is not yet
+ * available (e.g., during pre-parse plugins).
+ */
+ public List<Modification> getModifications();
+
+
+
+ /**
+ * Retrieves the current entry, before it is renamed. This will not
+ * be available to pre-parse plugins or during the conflict
+ * resolution portion of the synchronization processing.
+ *
+ * @return The current entry, or <CODE>null</CODE> if it is not yet
+ * available.
+ */
+ public Entry getOriginalEntry();
+
+
+
+ /**
+ * Retrieves the new entry, as it will appear after it is renamed.
+ * This will not be available to pre-parse plugins or during the
+ * conflict resolution portion of the synchronization processing.
+ *
+ * @return The updated entry, or <CODE>null</CODE> if it is not yet
+ * available.
+ */
+ public Entry getUpdatedEntry();
+}
+
diff --git a/opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyOperation.java b/opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyOperation.java
new file mode 100644
index 0000000..45c6f72
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/operation/PostSynchronizationModifyOperation.java
@@ -0,0 +1,148 @@
+/*
+ * 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.types.operation;
+
+
+
+import java.util.List;
+
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.RawModification;
+
+
+
+/**
+ * This class defines a set of methods that are available for use by
+ * post-synchronization plugins for modify operations. Note that this
+ * interface is intended only to define an API for use by plugins and
+ * is not intended to be implemented by any custom classes.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
+ mayInstantiate=false,
+ mayExtend=false,
+ mayInvoke=true)
+public interface PostSynchronizationModifyOperation
+ extends PostSynchronizationOperation
+{
+ /**
+ * Retrieves the raw, unprocessed entry DN as included in the client
+ * request. The DN that is returned may or may not be a valid DN,
+ * since no validation will have been performed upon it.
+ *
+ * @return The raw, unprocessed entry DN as included in the client
+ * request.
+ */
+ public ByteString getRawEntryDN();
+
+
+
+ /**
+ * Retrieves the DN of the entry to modify.
+ *
+ * @return The DN of the entry to modify.
+ */
+ public DN getEntryDN();
+
+
+
+ /**
+ * Retrieves the set of raw, unprocessed modifications as included
+ * in the client request. Note that this may contain one or more
+ * invalid modifications, as no validation will have been performed
+ * on this information. The list returned must not be altered by
+ * the caller.
+ *
+ * @return The set of raw, unprocessed modifications as included
+ * in the client request.
+ */
+ public List<RawModification> getRawModifications();
+
+
+
+ /**
+ * Retrieves the set of modifications for this modify operation.
+ Its contents should not be altered.
+ *
+ * @return The set of modifications for this modify operation.
+ */
+ public List<Modification> getModifications();
+
+
+
+ /**
+ * Retrieves the current entry before any modifications are applied.
+ * It should not be modified by the caller.
+ *
+ * @return The current entry before any modifications are applied.
+ */
+ public Entry getCurrentEntry();
+
+
+
+ /**
+ * Retrieves the modified entry that is to be written to the
+ * backend. It should not be modified by the caller.
+ *
+ * @return The modified entry that is to be written to the backend.
+ */
+ public Entry getModifiedEntry();
+
+
+
+ /**
+ * Retrieves the set of clear-text current passwords for the user,
+ * if available. This will only be available if the modify
+ * operation contains one or more delete elements that target the
+ * password attribute and provide the values to delete in the clear.
+ * This list should not be altered by the caller.
+ *
+ * @return The set of clear-text current password values as
+ * provided in the modify request, or <CODE>null</CODE> if
+ * there were none.
+ */
+ public List<AttributeValue> getCurrentPasswords();
+
+
+
+ /**
+ * Retrieves the set of clear-text new passwords for the user, if
+ * available. This will only be available if the modify operation
+ * contains one or more add or replace elements that target the
+ * password attribute and provide the values in the clear. This
+ * list should not be altered by the caller.
+ *
+ * @return The set of clear-text new passwords as provided in the
+ * modify request, or <CODE>null</CODE> if there were none.
+ */
+ public List<AttributeValue> getNewPasswords();
+}
+
diff --git a/opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java b/opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java
new file mode 100644
index 0000000..ed8e0e9
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java
@@ -0,0 +1,144 @@
+/*
+ * 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.types.operation;
+import org.opends.messages.MessageBuilder;
+
+
+import java.util.List;
+
+import org.opends.server.types.DN;
+import org.opends.server.types.ResultCode;
+
+
+
+/**
+ * This class defines a set of methods that are available for use by
+ * post-synchronization plugins for all types of operations. Note
+ * that this interface is intended only to define an API for use by
+ * plugins and is not intended to be implemented by any custom
+ * classes.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
+ mayInstantiate=false,
+ mayExtend=false,
+ mayInvoke=true)
+public interface PostSynchronizationOperation
+ extends PluginOperation
+{
+ /**
+ * Retrieves the result code for this operation.
+ *
+ * @return The result code associated for this operation, or
+ * <CODE>UNDEFINED</CODE> if the operation has not yet
+ * completed.
+ */
+ public ResultCode getResultCode();
+
+
+
+ /**
+ * Retrieves the error message for this operation. Its contents may
+ * be altered by the caller.
+ *
+ * @return The error message for this operation.
+ */
+ public MessageBuilder getErrorMessage();
+
+
+
+ /**
+ * Retrieves the additional log message for this operation, which
+ * should be written to the log but not included in the response to
+ * the client. The contents of this buffer may be altered by the
+ * caller.
+ *
+ * @return The additional log message for this operation.
+ */
+ public MessageBuilder getAdditionalLogMessage();
+
+
+
+ /**
+ * Retrieves the matched DN for this operation.
+ *
+ * @return The matched DN for this operation, or <CODE>null</CODE>
+ * if the operation has not yet completed or does not have
+ * a matched DN.
+ */
+ public DN getMatchedDN();
+
+
+
+ /**
+ * Retrieves the set of referral URLs for this operation. Its
+ * contents must not be altered by the caller.
+ *
+ * @return The set of referral URLs for this operation, or
+ * <CODE>null</CODE> if the operation is not yet complete
+ * or does not have a set of referral URLs.
+ */
+ public List<String> getReferralURLs();
+
+
+
+ /**
+ * Retrieves the authorization DN for this operation. In many
+ * cases, it will be the same as the DN of the authenticated user
+ * for the underlying connection, or the null DN if no
+ * authentication has been performed on that connection. However,
+ * it may be some other value if special processing has been
+ * requested (e.g., the operation included a proxied authorization
+ * control).
+ *
+ * @return The authorization DN for this operation.
+ */
+ public DN getAuthorizationDN();
+
+
+
+ /**
+ * Retrieves the time that processing stopped for this operation.
+ * This will actually hold a time immediately before the response
+ * was sent to the client.
+ *
+ * @return The time that processing stopped for this operation.
+ */
+ public long getProcessingStopTime();
+
+
+
+ /**
+ * Retrieves the length of time in milliseconds that the server
+ * spent processing this operation.
+ *
+ * @return The length of time in milliseconds that the server spent
+ * processing this operation.
+ */
+ public long getProcessingTime();
+}
+
diff --git a/opends/src/server/org/opends/server/util/ServerConstants.java b/opends/src/server/org/opends/server/util/ServerConstants.java
index 2d54cca..704801e 100644
--- a/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -1703,6 +1703,50 @@
/**
+ * The description for the alert type that will be used for the alert
+ * notification generated if a unique attribute conflict is detected during
+ * synchronization processing.
+ */
+ public static final String ALERT_DESCRIPTION_UNIQUE_ATTR_SYNC_CONFLICT =
+ "This alert type will be used to provide notification that a unique " +
+ "attribute conflict has been detected during synchronization " +
+ "processing.";
+
+
+
+ /**
+ * The alert type string that will be used for the alert notification
+ * generated if a unique attribute conflict is detected during synchronization
+ * processing.
+ */
+ public static final String ALERT_TYPE_UNIQUE_ATTR_SYNC_CONFLICT =
+ "org.opends.server.UniqueAttributeSynchronizationConflict";
+
+
+
+ /**
+ * The description for the alert type that will be used for the alert
+ * notification generated if an error occurs while attempting to perform
+ * unique attribute conflict detection during synchronization processing.
+ */
+ public static final String ALERT_DESCRIPTION_UNIQUE_ATTR_SYNC_ERROR =
+ "This alert type will be used to provide notification that an error " +
+ "occurred while attempting to perform unique attribute conflict " +
+ "detection during synchronization processing.";
+
+
+
+ /**
+ * The alert type string that will be used for the alert notification
+ * generated if an error occurs while attempting to perform unique attribute
+ * conflict detection during synchronization processing.
+ */
+ public static final String ALERT_TYPE_UNIQUE_ATTR_SYNC_ERROR =
+ "org.opends.server.UniqueAttributeSynchronizationError";
+
+
+
+ /**
* The name of the default password storage scheme that will be used for new
* passwords.
*/
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
index 9d06f82..5d0df11 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -63,6 +63,7 @@
import org.opends.server.types.operation.PostOperationAddOperation;
import org.opends.server.types.operation.PostResponseAddOperation;
import org.opends.server.types.operation.PreOperationAddOperation;
+import org.opends.server.types.operation.PostSynchronizationAddOperation;
import org.opends.server.util.TimeThread;
/**
@@ -72,7 +73,8 @@
public class LocalBackendAddOperation extends AddOperationWrapper
implements PreOperationAddOperation,
PostOperationAddOperation,
- PostResponseAddOperation
+ PostResponseAddOperation,
+ PostSynchronizationAddOperation
{
// The entry being added to the server.
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
index b2d68ad..ebd4182 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -33,6 +33,7 @@
import org.opends.server.types.operation.PostOperationDeleteOperation;
import org.opends.server.types.operation.PostResponseDeleteOperation;
import org.opends.server.types.operation.PreOperationDeleteOperation;
+import org.opends.server.types.operation.PostSynchronizationDeleteOperation;
/**
* This class defines an operation used to delete an entry in a local backend
@@ -41,7 +42,8 @@
public class LocalBackendDeleteOperation extends DeleteOperationWrapper
implements PreOperationDeleteOperation,
PostOperationDeleteOperation,
- PostResponseDeleteOperation
+ PostResponseDeleteOperation,
+ PostSynchronizationDeleteOperation
{
// The entry to be deleted.
private Entry entry;
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
index 02db5e9..b1e1b32 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -32,6 +32,7 @@
import org.opends.server.types.operation.PostOperationModifyDNOperation;
import org.opends.server.types.operation.PostResponseModifyDNOperation;
import org.opends.server.types.operation.PreOperationModifyDNOperation;
+import org.opends.server.types.operation.PostSynchronizationModifyDNOperation;
/**
* This class defines an operation used to move an entry in a local backend
@@ -41,7 +42,8 @@
extends ModifyDNOperationWrapper
implements PreOperationModifyDNOperation,
PostOperationModifyDNOperation,
- PostResponseModifyDNOperation
+ PostResponseModifyDNOperation,
+ PostSynchronizationModifyDNOperation
{
// The current entry, before it is renamed.
private Entry currentEntry;
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index 28449d3..2339824 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -37,6 +37,7 @@
import org.opends.server.types.operation.PostOperationModifyOperation;
import org.opends.server.types.operation.PostResponseModifyOperation;
import org.opends.server.types.operation.PreOperationModifyOperation;
+import org.opends.server.types.operation.PostSynchronizationModifyOperation;
/**
* This class defines an operation used to modify an entry in a local backend
@@ -45,7 +46,8 @@
public class LocalBackendModifyOperation extends ModifyOperationWrapper
implements PreOperationModifyOperation,
PostOperationModifyOperation,
- PostResponseModifyOperation
+ PostResponseModifyOperation,
+ PostSynchronizationModifyOperation
{
// The current entry, before any changes are applied.
private Entry currentEntry = null;
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
index 903ae3c..255cd3f 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -2416,8 +2416,15 @@
// Indicate that it is now too late to attempt to cancel the operation.
localOp.setCancelResult(CancelResult.TOO_LATE);
- // Invoke the post-operation modify plugins.
- if (! skipPostOperation)
+ // Invoke the post-operation or post-synchronization modify plugins.
+ if (localOp.isSynchronizationOperation())
+ {
+ if (localOp.getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationModifyPlugins(localOp);
+ }
+ }
+ else if (! skipPostOperation)
{
// FIXME -- Should this also be done while holding the locks?
PostOperationPluginResult postOpResult =
@@ -5893,8 +5900,15 @@
localOp.setCancelResult(CancelResult.TOO_LATE);
- // Invoke the post-operation add plugins.
- if (! skipPostOperation)
+ // Invoke the post-operation or post-synchronization add plugins.
+ if (localOp.isSynchronizationOperation())
+ {
+ if (localOp.getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationAddPlugins(localOp);
+ }
+ }
+ else if (! skipPostOperation)
{
// FIXME -- Should this also be done while holding the locks?
PostOperationPluginResult postOpResult =
@@ -6672,8 +6686,15 @@
localOp.setCancelResult(CancelResult.TOO_LATE);
- // Invoke the post-operation delete plugins.
- if (! skipPostOperation)
+ // Invoke the post-operation or post-synchronization delete plugins.
+ if (localOp.isSynchronizationOperation())
+ {
+ if (localOp.getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationDeletePlugins(localOp);
+ }
+ }
+ else if (! skipPostOperation)
{
PostOperationPluginResult postOperationResult =
pluginConfigManager.invokePostOperationDeletePlugins(localOp);
@@ -8498,8 +8519,15 @@
op.setCancelResult(CancelResult.TOO_LATE);
- // Invoke the post-operation modify DN plugins.
- if (! skipPostOperation)
+ // Invoke the post-operation or post-synchronization modify DN plugins.
+ if (op.isSynchronizationOperation())
+ {
+ if (op.getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationModifyDNPlugins(op);
+ }
+ }
+ else if (! skipPostOperation)
{
PostOperationPluginResult postOperationResult =
pluginConfigManager.invokePostOperationModifyDNPlugins(op);
diff --git a/opends/tests/unit-tests-testng/resource/config-changes.ldif b/opends/tests/unit-tests-testng/resource/config-changes.ldif
index b26cc6f..ac3a9bb 100644
--- a/opends/tests/unit-tests-testng/resource/config-changes.ldif
+++ b/opends/tests/unit-tests-testng/resource/config-changes.ldif
@@ -48,6 +48,14 @@
replace: ds-cfg-suppress-internal-operations
ds-cfg-suppress-internal-operations: false
+dn: cn=File-Based Audit Logger,cn=Loggers,cn=config
+changetype: modify
+replace: ds-cfg-logger-enabled
+ds-cfg-logger-enabled: true
+-
+replace: ds-cfg-suppress-internal-operations
+ds-cfg-suppress-internal-operations: false
+
dn: cn=Test Password Validator,cn=Password Validators,cn=config
changetype: add
objectClass: top
@@ -166,6 +174,7 @@
ds-cfg-plugin-type: preOperationModify
ds-cfg-plugin-type: preOperationModifyDN
ds-cfg-plugin-type: preOperationSearch
+ds-cfg-invoke-for-internal-operations: true
dn: cn=Disconnect Client Plugin,cn=Plugins,cn=config
changetype: add
@@ -210,6 +219,7 @@
ds-cfg-plugin-type: postResponseModify
ds-cfg-plugin-type: postResponseModifyDN
ds-cfg-plugin-type: postResponseSearch
+ds-cfg-invoke-for-internal-operations: true
dn: cn=Invocation Counter Plugin,cn=Plugins,cn=config
changetype: add
@@ -254,6 +264,9 @@
ds-cfg-plugin-type: postResponseModify
ds-cfg-plugin-type: postResponseModifyDN
ds-cfg-plugin-type: postResponseSearch
+ds-cfg-plugin-type: postSynchronizationAdd
+ds-cfg-plugin-type: postSynchronizationModify
+ds-cfg-plugin-type: postSynchronizationModifyDN
ds-cfg-plugin-type: searchResultEntry
ds-cfg-plugin-type: searchResultReference
ds-cfg-plugin-type: subordinateModifyDN
@@ -264,6 +277,7 @@
ds-cfg-plugin-type: ldifExport
ds-cfg-plugin-type: startup
ds-cfg-plugin-type: shutdown
+ds-cfg-invoke-for-internal-operations: true
dn: cn=Short Circuit Plugin,cn=Plugins,cn=config
changetype: add
@@ -290,6 +304,7 @@
ds-cfg-plugin-type: preOperationModify
ds-cfg-plugin-type: preOperationModifyDN
ds-cfg-plugin-type: preOperationSearch
+ds-cfg-invoke-for-internal-operations: true
dn: cn=Update PreOperation Plugin,cn=Plugins,cn=config
changetype: add
@@ -300,6 +315,7 @@
ds-cfg-plugin-enabled: true
ds-cfg-plugin-type: preOperationAdd
ds-cfg-plugin-type: preOperationModify
+ds-cfg-invoke-for-internal-operations: true
dn: cn=UID Unique Attribute ,cn=Plugins,cn=config
changeType: modify
@@ -328,7 +344,11 @@
ds-cfg-plugin-type: preOperationAdd
ds-cfg-plugin-type: preOperationModify
ds-cfg-plugin-type: preOperationModifyDN
+ds-cfg-plugin-type: postSynchronizationAdd
+ds-cfg-plugin-type: postSynchronizationModify
+ds-cfg-plugin-type: postSynchronizationModifyDN
ds-cfg-unique-attribute-type: bootParameter
+ds-cfg-invoke-for-internal-operations: true
dn: cn=JKS,cn=Key Manager Providers,cn=config
changetype: modify
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
index 86afa40..96e387c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
@@ -37,9 +37,13 @@
import org.testng.annotations.Test;
import org.testng.annotations.BeforeClass;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.PluginCfgDefn;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.plugins.NullPlugin;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
import org.opends.server.types.operation.*;
import org.opends.server.TestCaseUtils;
import org.opends.messages.Message;
@@ -464,6 +468,34 @@
expectedPublicMethods.add(sigList);
sigList = new LinkedList<String>();
+ sigList.add("doPostSynchronization");
+ sigList.add("void");
+ sigList.add("org.opends.server.types.operation." +
+ "PostSynchronizationAddOperation");
+ expectedPublicMethods.add(sigList);
+
+ sigList = new LinkedList<String>();
+ sigList.add("doPostSynchronization");
+ sigList.add("void");
+ sigList.add("org.opends.server.types.operation." +
+ "PostSynchronizationDeleteOperation");
+ expectedPublicMethods.add(sigList);
+
+ sigList = new LinkedList<String>();
+ sigList.add("doPostSynchronization");
+ sigList.add("void");
+ sigList.add("org.opends.server.types.operation." +
+ "PostSynchronizationModifyOperation");
+ expectedPublicMethods.add(sigList);
+
+ sigList = new LinkedList<String>();
+ sigList.add("doPostSynchronization");
+ sigList.add("void");
+ sigList.add("org.opends.server.types.operation." +
+ "PostSynchronizationModifyDNOperation");
+ expectedPublicMethods.add(sigList);
+
+ sigList = new LinkedList<String>();
sigList.add("processSearchEntry");
sigList.add("org.opends.server.api.plugin.SearchEntryPluginResult");
sigList.add("org.opends.server.types.operation.SearchEntrySearchOperation");
@@ -498,7 +530,7 @@
sigList = new LinkedList<String>();
sigList.add("initializeInternal");
sigList.add("void");
- sigList.add("org.opends.server.types.DN");
+ sigList.add("org.opends.server.admin.std.server.PluginCfg");
sigList.add("java.util.Set");
expectedPublicMethods.add(sigList);
@@ -513,6 +545,17 @@
expectedPublicMethods.add(sigList);
sigList = new LinkedList<String>();
+ sigList.add("invokeForInternalOperations");
+ sigList.add("boolean");
+ expectedPublicMethods.add(sigList);
+
+ sigList = new LinkedList<String>();
+ sigList.add("setInvokeForInternalOperations");
+ sigList.add("void");
+ sigList.add("boolean");
+ expectedPublicMethods.add(sigList);
+
+ sigList = new LinkedList<String>();
sigList.add("getClass");
sigList.add("java.lang.Class");
expectedPublicMethods.add(sigList);
@@ -676,6 +719,69 @@
public void testGetPluginEntryDN()
throws Exception
{
+ Entry pluginEntry = TestCaseUtils.makeEntry(
+ "dn: cn=Null Plugin,cn=Plugins,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-plugin",
+ "cn: Null Plugin",
+ "ds-cfg-plugin-class: org.opends.server.plugins.NullPlugin",
+ "ds-cfg-plugin-enabled: true",
+ "ds-cfg-plugin-type: startup",
+ "ds-cfg-plugin-type: shutdown",
+ "ds-cfg-plugin-type: postConnect",
+ "ds-cfg-plugin-type: postDisconnect",
+ "ds-cfg-plugin-type: ldifImport",
+ "ds-cfg-plugin-type: ldifExport",
+ "ds-cfg-plugin-type: preParseAbandon",
+ "ds-cfg-plugin-type: preParseAdd",
+ "ds-cfg-plugin-type: preParsebind",
+ "ds-cfg-plugin-type: preParseCompare",
+ "ds-cfg-plugin-type: preParseDelete",
+ "ds-cfg-plugin-type: preParseExtended",
+ "ds-cfg-plugin-type: preParseModify",
+ "ds-cfg-plugin-type: preParseModifyDN",
+ "ds-cfg-plugin-type: preParseSearch",
+ "ds-cfg-plugin-type: preParseUnbind",
+ "ds-cfg-plugin-type: preOperationAdd",
+ "ds-cfg-plugin-type: preOperationbind",
+ "ds-cfg-plugin-type: preOperationCompare",
+ "ds-cfg-plugin-type: preOperationDelete",
+ "ds-cfg-plugin-type: preOperationExtended",
+ "ds-cfg-plugin-type: preOperationModify",
+ "ds-cfg-plugin-type: preOperationModifyDN",
+ "ds-cfg-plugin-type: preOperationSearch",
+ "ds-cfg-plugin-type: postOperationAbandon",
+ "ds-cfg-plugin-type: postOperationAdd",
+ "ds-cfg-plugin-type: postOperationbind",
+ "ds-cfg-plugin-type: postOperationCompare",
+ "ds-cfg-plugin-type: postOperationDelete",
+ "ds-cfg-plugin-type: postOperationExtended",
+ "ds-cfg-plugin-type: postOperationModify",
+ "ds-cfg-plugin-type: postOperationModifyDN",
+ "ds-cfg-plugin-type: postOperationSearch",
+ "ds-cfg-plugin-type: postOperationUnbind",
+ "ds-cfg-plugin-type: postResponseAdd",
+ "ds-cfg-plugin-type: postResponsebind",
+ "ds-cfg-plugin-type: postResponseCompare",
+ "ds-cfg-plugin-type: postResponseDelete",
+ "ds-cfg-plugin-type: postResponseExtended",
+ "ds-cfg-plugin-type: postResponseModify",
+ "ds-cfg-plugin-type: postResponseModifyDN",
+ "ds-cfg-plugin-type: postResponseSearch",
+ "ds-cfg-plugin-type: postsynchronizationAdd",
+ "ds-cfg-plugin-type: postsynchronizationDelete",
+ "ds-cfg-plugin-type: postsynchronizationModify",
+ "ds-cfg-plugin-type: postsynchronizationModifyDN",
+ "ds-cfg-plugin-type: searchResultEntry",
+ "ds-cfg-plugin-type: searchResultReference",
+ "ds-cfg-plugin-type: subordinateModifyDN",
+ "ds-cfg-plugin-type: intermediateResponse");
+
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(PluginCfgDefn.getInstance(),
+ pluginEntry);
+
+
NullPlugin nullPlugin = new NullPlugin();
DN pluginEntryDN = DN.decode("cn=Null Plugin,cn=Plugins,cn=config");
@@ -685,7 +791,7 @@
pluginTypes.add(t);
}
- nullPlugin.initializeInternal(pluginEntryDN, pluginTypes);
+ nullPlugin.initializeInternal(configuration, pluginTypes);
assertEquals(nullPlugin.getPluginEntryDN(), pluginEntryDN);
}
@@ -700,8 +806,70 @@
public void testGetPluginTypes()
throws Exception
{
+ Entry pluginEntry = TestCaseUtils.makeEntry(
+ "dn: cn=Null Plugin,cn=Plugins,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-plugin",
+ "cn: Null Plugin",
+ "ds-cfg-plugin-class: org.opends.server.plugins.NullPlugin",
+ "ds-cfg-plugin-enabled: true",
+ "ds-cfg-plugin-type: startup",
+ "ds-cfg-plugin-type: shutdown",
+ "ds-cfg-plugin-type: postConnect",
+ "ds-cfg-plugin-type: postDisconnect",
+ "ds-cfg-plugin-type: ldifImport",
+ "ds-cfg-plugin-type: ldifExport",
+ "ds-cfg-plugin-type: preParseAbandon",
+ "ds-cfg-plugin-type: preParseAdd",
+ "ds-cfg-plugin-type: preParsebind",
+ "ds-cfg-plugin-type: preParseCompare",
+ "ds-cfg-plugin-type: preParseDelete",
+ "ds-cfg-plugin-type: preParseExtended",
+ "ds-cfg-plugin-type: preParseModify",
+ "ds-cfg-plugin-type: preParseModifyDN",
+ "ds-cfg-plugin-type: preParseSearch",
+ "ds-cfg-plugin-type: preParseUnbind",
+ "ds-cfg-plugin-type: preOperationAdd",
+ "ds-cfg-plugin-type: preOperationbind",
+ "ds-cfg-plugin-type: preOperationCompare",
+ "ds-cfg-plugin-type: preOperationDelete",
+ "ds-cfg-plugin-type: preOperationExtended",
+ "ds-cfg-plugin-type: preOperationModify",
+ "ds-cfg-plugin-type: preOperationModifyDN",
+ "ds-cfg-plugin-type: preOperationSearch",
+ "ds-cfg-plugin-type: postOperationAbandon",
+ "ds-cfg-plugin-type: postOperationAdd",
+ "ds-cfg-plugin-type: postOperationbind",
+ "ds-cfg-plugin-type: postOperationCompare",
+ "ds-cfg-plugin-type: postOperationDelete",
+ "ds-cfg-plugin-type: postOperationExtended",
+ "ds-cfg-plugin-type: postOperationModify",
+ "ds-cfg-plugin-type: postOperationModifyDN",
+ "ds-cfg-plugin-type: postOperationSearch",
+ "ds-cfg-plugin-type: postOperationUnbind",
+ "ds-cfg-plugin-type: postResponseAdd",
+ "ds-cfg-plugin-type: postResponsebind",
+ "ds-cfg-plugin-type: postResponseCompare",
+ "ds-cfg-plugin-type: postResponseDelete",
+ "ds-cfg-plugin-type: postResponseExtended",
+ "ds-cfg-plugin-type: postResponseModify",
+ "ds-cfg-plugin-type: postResponseModifyDN",
+ "ds-cfg-plugin-type: postResponseSearch",
+ "ds-cfg-plugin-type: postsynchronizationAdd",
+ "ds-cfg-plugin-type: postsynchronizationDelete",
+ "ds-cfg-plugin-type: postsynchronizationModify",
+ "ds-cfg-plugin-type: postsynchronizationModifyDN",
+ "ds-cfg-plugin-type: searchResultEntry",
+ "ds-cfg-plugin-type: searchResultReference",
+ "ds-cfg-plugin-type: subordinateModifyDN",
+ "ds-cfg-plugin-type: intermediateResponse");
+
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(PluginCfgDefn.getInstance(),
+ pluginEntry);
+
+
NullPlugin nullPlugin = new NullPlugin();
- DN pluginEntryDN = DN.decode("cn=Null Plugin,cn=Plugins,cn=config");
HashSet<PluginType> pluginTypes = new HashSet<PluginType>();
for (PluginType t : PluginType.values())
@@ -709,7 +877,7 @@
pluginTypes.add(t);
}
- nullPlugin.initializeInternal(pluginEntryDN, pluginTypes);
+ nullPlugin.initializeInternal(configuration, pluginTypes);
assertEquals(nullPlugin.getPluginTypes(), pluginTypes);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java
index fa77cfa..735636e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java
@@ -89,6 +89,8 @@
private static AtomicInteger preOperationCounter = new AtomicInteger(0);
private static AtomicInteger postOperationCounter = new AtomicInteger(0);
private static AtomicInteger postResponseCounter = new AtomicInteger(0);
+ private static AtomicInteger postSynchronizationCounter =
+ new AtomicInteger(0);
private static AtomicInteger searchEntryCounter = new AtomicInteger(0);
private static AtomicInteger searchReferenceCounter = new AtomicInteger(0);
private static AtomicInteger subordinateModifyDNCounter =
@@ -704,6 +706,69 @@
* {@inheritDoc}
*/
@Override()
+ public void doPostSynchronization(PostSynchronizationAddOperation
+ addOperation)
+ {
+ postSynchronizationCounter.incrementAndGet();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public void doPostSynchronization(PostSynchronizationModifyOperation
+ modifyOperation)
+ {
+ postSynchronizationCounter.incrementAndGet();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public void doPostSynchronization(PostSynchronizationModifyDNOperation
+ modifyDNOperation)
+ {
+ postSynchronizationCounter.incrementAndGet();
+ }
+
+
+
+ /**
+ * Retrieves the number of times that the post-synchronization plugins have
+ * been called since the last reset.
+ *
+ * @return The number of times that the post-synchronization plugins have
+ * been called since the last reset.
+ */
+ public static int getPostSynchronizationCount()
+ {
+ return postSynchronizationCounter.get();
+ }
+
+
+
+ /**
+ * Resets the post-synchronization plugin invocation count to zero.
+ *
+ * @return The post-synchronization plugin invocation count before it was
+ * reset.
+ */
+ public static int resetPostSynchronizationCount()
+ {
+ return postSynchronizationCounter.getAndSet(0);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
public SearchEntryPluginResult
processSearchEntry(SearchEntrySearchOperation searchOperation,
SearchResultEntry searchEntry)
@@ -1031,6 +1096,7 @@
resetPreOperationCount();
resetPostOperationCount();
resetPostResponseCount();
+ resetPostSynchronizationCount();
resetSearchEntryCount();
resetSearchReferenceCount();
resetSubordinateModifyDNCount();
--
Gitblit v1.10.0