From 403b6a83e7d68de2b5159c3421b8d91d704566bb Mon Sep 17 00:00:00 2001
From: jdemendi <jdemendi@localhost>
Date: Tue, 30 Oct 2007 13:09:42 +0000
Subject: [PATCH] s set of files provides the workflow configuration manual mode.
---
opends/resource/schema/02-config.ldif | 66 +
opends/src/server/org/opends/server/core/NetworkGroup.java | 115 +
opends/src/admin/defn/org/opends/server/admin/std/NetworkGroupConfiguration.xml | 107 +
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java | 142 ++
opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java | 448 ++++++++
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ValidateConfigDefinitionsTest.java | 4
opends/src/server/org/opends/server/core/WorkflowConfigManager.java | 313 +++++
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml | 41
opends/src/admin/defn/org/opends/server/admin/std/LocalBackendWorkflowElementConfiguration.xml | 71 +
opends/src/server/org/opends/server/workflowelement/LeafWorkflowElement.java | 27
opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml | 34
opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml | 132 ++
opends/src/messages/messages/config.properties | 20
opends/src/server/org/opends/server/core/DirectoryServer.java | 390 +++++-
opends/src/server/org/opends/server/core/WorkflowTopologyNode.java | 17
opends/src/server/org/opends/server/core/NetworkGroupConfigManager.java | 305 +++++
opends/src/admin/defn/org/opends/server/admin/std/WorkflowElementConfiguration.xml | 111 ++
opends/src/server/org/opends/server/workflowelement/WorkflowElement.java | 142 ++
opends/src/server/org/opends/server/core/RootDseWorkflowTopology.java | 6
opends/src/server/org/opends/server/core/CoreConfigManager.java | 20
opends/src/server/org/opends/server/core/WorkflowImpl.java | 61 +
opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java | 689 ++++++++++++
22 files changed, 3,091 insertions(+), 170 deletions(-)
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 2a0ebe5..d052a4a 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -2133,6 +2133,40 @@
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.435
+ NAME 'ds-cfg-network-group-id'
+ 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.436
+ NAME 'ds-cfg-workflow-id'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.437
+ NAME 'ds-cfg-workflow'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.438
+ NAME 'ds-cfg-workflow-element-id'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.439
+ NAME 'ds-cfg-workflow-element'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.440
+ NAME 'ds-cfg-workflow-configuration-mode'
+ 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.441
+ NAME 'ds-cfg-backend'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ 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
@@ -2531,6 +2565,7 @@
ds-cfg-disabled-privilege $
ds-cfg-return-bind-error-messages $
ds-cfg-idle-time-limit $
+ ds-cfg-workflow-configuration-mode $
ds-cfg-save-config-on-successful-startup )
X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.40
@@ -3599,3 +3634,34 @@
ds-cfg-key-length-bits $ ds-cfg-symmetric-key )
MAY ds-cfg-key-compromised-time
X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.176
+ NAME 'ds-cfg-network-group'
+ SUP top
+ STRUCTURAL
+ MUST ( ds-cfg-network-group-id $
+ ds-cfg-enabled $
+ ds-cfg-workflow )
+ X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.177
+ NAME 'ds-cfg-workflow'
+ SUP top
+ STRUCTURAL
+ MUST ( ds-cfg-workflow-id $
+ ds-cfg-enabled $
+ ds-cfg-workflow-element $
+ ds-cfg-base-dn )
+ X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.178
+ NAME 'ds-cfg-workflow-element'
+ SUP top
+ STRUCTURAL
+ MUST ( ds-cfg-workflow-element-id $
+ ds-cfg-enabled $
+ ds-cfg-java-class )
+ X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.179
+ NAME 'ds-cfg-local-backend-workflow-element'
+ SUP ds-cfg-workflow-element
+ STRUCTURAL
+ MUST ( ds-cfg-backend )
+ X-ORIGIN 'OpenDS Directory Server' )
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
index f149772..e6e2f59 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
@@ -725,5 +725,39 @@
</adm:profile>
</adm:property>
+ <adm:property name="workflow-configuration-mode">
+ <adm:synopsis>
+ Specifies the workflow configuration mode (auto vs. manual).
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>auto</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:enumeration>
+ <adm:value name="auto">
+ <adm:synopsis>
+ In the "auto" configuration mode there is no workflow
+ configuration. The workflows are created automatically
+ based on the backend configuration. There will be one
+ workflow per backend base DN.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="manual">
+ <adm:synopsis>
+ In the "manual" configuration mode each workflow is created
+ according to its description in the configuration.
+ </adm:synopsis>
+ </adm:value>
+ </adm:enumeration>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-workflow-configuration-mode</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/LocalBackendWorkflowElementConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/LocalBackendWorkflowElementConfiguration.xml
new file mode 100644
index 0000000..d32d2e5
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/LocalBackendWorkflowElementConfiguration.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+
+<adm:managed-object
+ name="local-backend-workflow-element"
+ plural-name="local-backend-workflow-elements"
+ package="org.opends.server.admin.std"
+ extends="workflow-element"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+
+ <adm:synopsis>
+ The <adm:user-friendly-name /> provides access to a local backend.
+ </adm:synopsis>
+
+ <adm:tag name="user-management"/>
+
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-local-backend-workflow-element</ldap:name>
+ <ldap:superior>ds-cfg-workflow-element</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+
+ <adm:property name="backend"
+ mandatory="true"
+ read-only="true"
+ multi-valued="false">
+ <adm:synopsis>
+ Identifies the backend accessed by the workflow element.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:aggregation relation-name="backend" parent-path="/">
+ <adm:target-is-enabled-condition>
+ <adm:contains property="enabled" value="true" />
+ </adm:target-is-enabled-condition>
+ </adm:aggregation>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-backend</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/NetworkGroupConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/NetworkGroupConfiguration.xml
new file mode 100644
index 0000000..0c30178
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/NetworkGroupConfiguration.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+
+<adm:managed-object
+ name="network-group"
+ plural-name="network-groups"
+ package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The <adm:user-friendly-name /> is used to classify incoming connections.
+ </adm:synopsis>
+ <adm:tag name="user-management"/>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-network-group</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+
+ <adm:property name="enabled"
+ mandatory="true"
+ multi-valued="false">
+ <adm:synopsis>
+ Indicates whether the <adm:user-friendly-name />
+ is enabled for use in the server.
+ </adm:synopsis>
+ <adm:description>
+ If a network group is not enabled, then its contents will not be
+ accessible when processing operations.
+ </adm:description>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="network-group-id" mandatory="true" read-only="true"
+ multi-valued="false">
+ <adm:synopsis>
+ Provides a name that will be used to identify the associated
+ <adm:user-friendly-name />.
+ </adm:synopsis>
+ <adm:description>
+ The name must be unique among all <adm:user-friendly-name />
+ in the server.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-network-group-id</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="workflow" mandatory="true" read-only="true"
+ multi-valued="true">
+ <adm:synopsis>
+ Identifies a workflow in the network group.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:aggregation relation-name="workflow" parent-path="/">
+ <adm:target-is-enabled-condition>
+ <adm:contains property="enabled" value="true" />
+ </adm:target-is-enabled-condition>
+ </adm:aggregation>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-workflow</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
index 2e662c8..f00a95c 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
@@ -422,6 +422,47 @@
</cli:relation>
</adm:profile>
</adm:relation>
+
+ <adm:relation name="network-group">
+ <adm:one-to-many naming-property="network-group-id"/>
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=Network Groups,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ <adm:profile name="cli">
+ <cli:relation>
+ <cli:default-property name="enabled" />
+ </cli:relation>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="workflow">
+ <adm:one-to-many naming-property="workflow-id"/>
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=Workflows,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ <adm:profile name="cli">
+ <cli:relation>
+ <cli:default-property name="enabled" />
+ </cli:relation>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="workflow-element">
+ <adm:one-to-many naming-property="workflow-element-id"/>
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=Workflow elements,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ <adm:profile name="cli">
+ <cli:relation>
+ <cli:default-property name="enabled" />
+ </cli:relation>
+ </adm:profile>
+ </adm:relation>
+
<adm:product-name>OpenDS Directory Server</adm:product-name>
<adm:tag-definition name="logging">
<adm:synopsis>Logging</adm:synopsis>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml
new file mode 100644
index 0000000..72711f1
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+
+<adm:managed-object
+ name="workflow"
+ plural-name="workflows"
+ package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The <adm:user-friendly-name /> is list of tasks applied on a DIT.
+ </adm:synopsis>
+ <adm:tag name="user-management"/>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-workflow</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+
+ <adm:property name="enabled"
+ mandatory="true"
+ read-only="false"
+ multi-valued="false">
+ <adm:synopsis>
+ Indicates whether the <adm:user-friendly-name />
+ is enabled for use in the server.
+ </adm:synopsis>
+ <adm:description>
+ If a workflow is not enabled, then its contents will not be
+ accessible when processing operations.
+ </adm:description>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="workflow-id"
+ mandatory="true"
+ read-only="true"
+ multi-valued="false">
+ <adm:synopsis>
+ Provides a name that will be used to identify the associated
+ <adm:user-friendly-name />.
+ </adm:synopsis>
+ <adm:description>
+ The name must be unique among all <adm:user-friendly-name />
+ in the server.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-workflow-id</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="workflow-element"
+ mandatory="true"
+ read-only="false"
+ multi-valued="false">
+ <adm:synopsis>
+ The <adm:user-friendly-name /> identifies the root task of the worklfow.
+ </adm:synopsis>
+ <adm:description>
+ All the tasks in the worklfow are organized in a tree. The root element
+ of the tree is identified by the <adm:user-friendly-name />.
+ </adm:description>
+ <adm:syntax>
+ <adm:aggregation relation-name="workflow-element" parent-path="/">
+ <adm:target-is-enabled-condition>
+ <adm:contains property="enabled" value="true" />
+ </adm:target-is-enabled-condition>
+ </adm:aggregation>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-workflow-element</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="base-dn"
+ mandatory="true"
+ read-only="false"
+ multi-valued="false">
+ <adm:synopsis>
+ The <adm:user-friendly-name /> specifies the base DN of the data
+ targeted by the worlflow.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-base-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property></adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/WorkflowElementConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/WorkflowElementConfiguration.xml
new file mode 100644
index 0000000..7eaaa2a
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/WorkflowElementConfiguration.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+
+<adm:managed-object
+ name="workflow-element"
+ plural-name="workflow-elements"
+ package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+
+ <adm:synopsis>
+ The <adm:user-friendly-name /> is a task part of a worklfow.
+ </adm:synopsis>
+
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-workflow-element</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+
+ <adm:property name="enabled"
+ mandatory="true"
+ read-only="false"
+ multi-valued="false">
+ <adm:synopsis>
+ Indicates whether the <adm:user-friendly-name />
+ is enabled for use in the server.
+ </adm:synopsis>
+ <adm:description>
+ If a workflow element is not enabled, then its contents will not be
+ accessible when processing operations.
+ </adm:description>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="workflow-element-id"
+ mandatory="true"
+ read-only="true"
+ multi-valued="false">
+ <adm:synopsis>
+ Provides a name that will be used to identify the associated
+ <adm:user-friendly-name />.
+ </adm:synopsis>
+ <adm:description>
+ The name must be unique among all <adm:user-friendly-name />
+ in the server.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-workflow-element-id</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+
+ <adm:property name="java-class" mandatory="true">
+ <adm:synopsis>
+ The fully-qualified name of the Java class that provides the
+ <adm:user-friendly-name />
+ implementation.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:java-class>
+ <adm:instance-of>
+ org.opends.server.workflowelement.WorkflowElement
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-java-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/messages/messages/config.properties b/opends/src/messages/messages/config.properties
index 156c3f7..d25ed4f 100644
--- a/opends/src/messages/messages/config.properties
+++ b/opends/src/messages/messages/config.properties
@@ -2109,3 +2109,23 @@
%s will not take effect until the component for which it is set is restarted
SEVERE_ERR_CONFIG_LOGGING_CANNOT_OPEN_FILE_709=An error occurred while \
attempting to open the configured log file %s for logger %s: %s
+SEVERE_ERR_CONFIG_WORKFLOW_ELEMENT_CONFIG_NOT_ACCEPTABLE_710=The configuration \
+ for the workflow element defined in configuration entry %s was not \
+ acceptable: %s
+SEVERE_ERR_CONFIG_WORKFLOW_ELEMENT_CANNOT_INITIALIZE_711=An error occurred \
+ while trying to initialize a workflow element from class %s with the \
+ information in configuration entry %s: %s. This workflow element will be \
+ disabled
+MILD_ERR_CONFIG_WORKFLOW_ELEMENT_ALREADY_REGISTERED_712=The workflow \
+ element %s is already registered with the Directory Server. This workflow \
+ element will be ignored
+SEVERE_ERR_CONFIG_WORKFLOW_CANNOT_CONFIGURE_MANUAL_713=An error occurred \
+ while trying to configure in manual mode the workflows in the \
+ Directory Server, and rollback to automatic configuration mode has failed \
+ too. If the server is in an unstable state restart it with the last \
+ valid configuration
+SEVERE_ERR_CONFIG_WORKFLOW_CANNOT_CONFIGURE_AUTO_714=An error occurred \
+ while trying to configure in automatic mode the workflows in the \
+ Directory Server, and rollback to manual configuration mode has failed \
+ too. If the server is in an unstable state restart it with the last \
+ valid configuration
diff --git a/opends/src/server/org/opends/server/core/CoreConfigManager.java b/opends/src/server/org/opends/server/core/CoreConfigManager.java
index c170ac7..f9fa411 100644
--- a/opends/src/server/org/opends/server/core/CoreConfigManager.java
+++ b/opends/src/server/org/opends/server/core/CoreConfigManager.java
@@ -37,6 +37,7 @@
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.GlobalCfgDefn;
+import org.opends.server.admin.std.meta.GlobalCfgDefn.WorkflowConfigurationMode;
import org.opends.server.admin.std.server.GlobalCfg;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.admin.server.ServerManagementContext;
@@ -338,8 +339,25 @@
DirectoryServer.setSaveConfigOnSuccessfulStartup(
globalConfig.isSaveConfigOnSuccessfulStartup());
- }
+ // If the workflow configuration mode has changed then reconfigure
+ // the workflows-only if the server is running. If the server is not
+ // running (ie. the server is starting up) simply update the workflow
+ // configuration mode as the workflow configuration is processed
+ // elsewhere.
+ WorkflowConfigurationMode oldMode =
+ DirectoryServer.getWorkflowConfigurationMode();
+ WorkflowConfigurationMode newMode =
+ globalConfig.getWorkflowConfigurationMode();
+ if (DirectoryServer.isRunning())
+ {
+ DirectoryServer.reconfigureWorkflows(oldMode, newMode);
+ }
+ else
+ {
+ DirectoryServer.setWorkflowConfigurationMode(newMode);
+ }
+ }
/**
diff --git a/opends/src/server/org/opends/server/core/DirectoryServer.java b/opends/src/server/org/opends/server/core/DirectoryServer.java
index 4807b44..3305fc7 100644
--- a/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -30,6 +30,7 @@
import org.opends.server.admin.ClassLoaderProvider;
import org.opends.server.admin.server.ServerManagementContext;
+import org.opends.server.admin.std.meta.GlobalCfgDefn.WorkflowConfigurationMode;
import org.opends.server.admin.std.server.*;
import org.opends.server.api.AccountStatusNotificationHandler;
import org.opends.server.api.AlertGenerator;
@@ -191,6 +192,7 @@
import org.opends.server.protocols.internal.InternalConnectionHandler;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.crypto.CryptoManagerSync;
+import static org.opends.messages.ConfigMessages.*;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
@@ -707,6 +709,24 @@
// The writability mode for the Directory Server.
private WritabilityMode writabilityMode;
+ // The workflow configuration mode (auto or manual).
+ private WorkflowConfigurationMode workflowConfigurationMode;
+
+ // The network group config manager for the Directory Server.
+ // This config manager is used when the workflow configuration
+ // mode is 'manual'.
+ private NetworkGroupConfigManager networkGroupConfigManager;
+
+ // The workflow config manager for the Directory Server.
+ // This config manager is used when the workflow configuration
+ // mode is 'manual'.
+ private WorkflowConfigManager workflowConfigManager;
+
+ // The workflow element config manager for the Directory Server.
+ // This config manager is used when the workflow configuration
+ // mode is 'manual'.
+ private WorkflowElementConfigManager workflowElementConfigManager;
+
/**
@@ -1346,14 +1366,22 @@
// Initialize the access control handler.
AccessControlConfigManager.getInstance().initializeAccessControl();
- // Initialize all the backends and their associated suffixes.
+ // Initialize all the backends and their associated suffixes
+ // and initialize the workflows when workflow configuration mode
+ // is auto.
initializeBackends();
- // A first set of workflows had been created in the registerBackend
- // method. We now need to complete the workflow creation for the
- // backends that were not registered through the registerBackend
- // method (ie. cn=config and RootDSE).
- createAndRegisterRemainingWorkflows();
+ // When workflow configuration mode is manual, do configure the
+ // workflows now, else just configure the remaining workflows
+ // (rootDSE and config backend).
+ if (workflowConfigurationModeIsAuto())
+ {
+ createAndRegisterRemainingWorkflows();
+ }
+ else
+ {
+ configureWorkflowsManual();
+ }
// Check for and initialize user configured entry cache if any,
// if not stick with default entry cache initialized earlier.
@@ -2582,51 +2610,32 @@
/**
- * Deregisters a set of workflows each of which is identified with
- * a baseDN.
- *
- * In the first implementation, workflows are stored in the default network
- * group only.
- *
- * @param baseDNs the DNs of the workflows to deregister
- */
- private static void deregisterWorkflows(
- DN[] baseDNs
- )
- {
- for (DN baseDN: baseDNs)
- {
- deregisterWorkflow(baseDN);
- }
- }
-
-
- /**
- * Deregisters one workflow with the appropriate network group.
- *
- * In the first implementation, workflows are stored in the default network
- * group only.
+ * Deregisters a workflow with the default network group and
+ * deregisters the workflow with the server. This method is
+ * intended to be called when workflow configuration mode is
+ * auto.
*
* @param baseDN the DN of the workflow to deregister
*/
- private static void deregisterWorkflow(
+ private static void deregisterWorkflowWithDefaultNetworkGroup(
DN baseDN
)
{
// Get the default network group and deregister all the workflows
- // being configured for the backend (reminder: there is one worklfow
- // per base DN configured in the backend).
+ // being configured for the backend (there is one worklfow per
+ // backend base DN).
NetworkGroup defaultNetworkGroup = NetworkGroup.getDefaultNetworkGroup();
- defaultNetworkGroup.deregisterWorkflow (baseDN);
+ Workflow workflow = defaultNetworkGroup.deregisterWorkflow(baseDN);
+ WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
+ workflowImpl.deregister();
}
/**
- * Creates a set of workflows for a given backend. There are as many
- * workflows as base DNs defined in the backend. Each workflow is
- * registered with the appropriate network group.
- *
- * TODO implement the registration with the appropriate network group.
+ * Creates a set of workflows for a given backend and registers the
+ * workflows with the default network group. There are as many workflows
+ * as base DNs defined in the backend. This method is intended
+ * to be called when workflow configuration mode is auto.
*
* @param backend the backend handled by the workflow
*
@@ -2634,35 +2643,33 @@
* workflow conflicts with the workflow
* ID of an existing workflow.
*/
- public static void createAndRegisterWorkflows(
+ public static void createAndRegisterWorkflowsWithDefaultNetworkGroup(
Backend backend
) throws DirectoryException
{
- // Create a worklfow for each baseDN being configured
- // in the backend and register the workflow with the network groups.
- // In the automatic configuration mode, the workflow identifier is
- // set to the backend ID.
+ // Create a worklfow for each backend base DN and register the workflow
+ // with the default network group.
for (DN curBaseDN: backend.getBaseDNs())
{
- createAndRegisterWorkflow(curBaseDN, backend);
+ WorkflowImpl workflowImpl = createWorkflow(curBaseDN, backend);
+ registerWorkflowWithDefaultNetworkGroup(workflowImpl);
}
}
/**
- * Creates one workflow for a given base DN in a backend. The workflow
- * is registered with the appropriate network group.
- *
- * TODO implement the registration with the appropriate network group.
+ * Creates one workflow for a given base DN in a backend.
*
* @param baseDN the base DN of the workflow to create
* @param backend the backend handled by the workflow
*
+ * @return the newly created workflow
+ *
* @throws DirectoryException If the workflow ID for the provided
* workflow conflicts with the workflow
* ID of an existing workflow.
*/
- public static void createAndRegisterWorkflow(
+ public static WorkflowImpl createWorkflow(
DN baseDN,
Backend backend
) throws DirectoryException
@@ -2671,49 +2678,52 @@
// Create a root workflow element to encapsulate the backend
LocalBackendWorkflowElement rootWE =
- LocalBackendWorkflowElement.create(backendID, backend);
+ LocalBackendWorkflowElement.createAndRegister(backendID, backend);
+
+ // The workflow ID is "backendID + baseDN".
+ // We cannot use backendID as workflow identifier because a backend
+ // may handle several base DNs. We cannot use baseDN either because
+ // we might want to configure several workflows handling the same
+ // baseDN through different network groups. So a mix of both
+ // backendID and baseDN should be ok.
+ String workflowID = backend.getBackendID() + "#" + baseDN.toString();
// Create the worklfow for the base DN and register the workflow with
- // the appropriate network groups.
+ // the server.
WorkflowImpl workflowImpl = new WorkflowImpl(
- baseDN.toString(), baseDN, (WorkflowElement) rootWE);
- registerWorkflowInNetworkGroups(workflowImpl);
+ workflowID, baseDN, (WorkflowElement) rootWE);
+ workflowImpl.register();
+
+ return workflowImpl;
}
/**
- * Registers a workflow with the appropriate network groups.
+ * Registers a workflow with the default network group. This method
+ * is intended to be called when workflow configuration mode is auto.
*
- * In the first implementation, the workflow is registered with the
- * default network group only.
+ * @param workflowImpl The workflow to register with the
+ * default network group
*
- * TODO implement the registration with the appropriate network group.
- *
- * @param workflowImpl the workflow to register
- *
- * @throws DirectoryException If the workflow ID for the provided
- * workflow conflicts with the workflow
- * ID of an existing workflow in a
- * network group.
+ * @throws DirectoryException If the workflow is already registered with
+ * the default network group
*/
- private static void registerWorkflowInNetworkGroups(
+ private static void registerWorkflowWithDefaultNetworkGroup(
WorkflowImpl workflowImpl
) throws DirectoryException
{
NetworkGroup defaultNetworkGroup = NetworkGroup.getDefaultNetworkGroup();
defaultNetworkGroup.registerWorkflow(workflowImpl);
-
- // Now for each network group that exposes the baseDN of the workflow
- // create an instance of the workflow and register it with the network
- // group.
- // TODO jdemendi - we need the network group configuration to configure
- // the workflows per network group.
}
/**
- * Creates the workflows for the backends whose baseDNs were not registered
- * with registerBaseDN method, namely config backend and RootDSE backend.
+ * Creates the missing workflows, one for the config backend and one for
+ * the rootDSE backend.
+ *
+ * This method should be invoked whatever may be the workflow
+ * configuration mode because config backend and rootDSE backend
+ * will not have any configuration section, ever.
*
* @throws ConfigException If there is a configuration problem with any of
* the workflows.
@@ -2723,8 +2733,8 @@
{
try
{
- createAndRegisterWorkflows (configHandler);
- createAndRegisterWorkflows (rootDSEBackend);
+ createAndRegisterWorkflowsWithDefaultNetworkGroup (configHandler);
+ createAndRegisterWorkflowsWithDefaultNetworkGroup (rootDSEBackend);
}
catch (DirectoryException de)
{
@@ -2734,6 +2744,151 @@
/**
+ * Reconfigures the workflows when configuration mode has changed.
+ * This method is invoked when workflows need to be reconfigured
+ * while the server is running. If the reconfiguration is valid
+ * then the method update the workflow configuration mode.
+ *
+ * @param oldMode the current workflow configuration mode
+ * @param newMode the new workflow configuration mode
+ */
+ public static void reconfigureWorkflows(
+ WorkflowConfigurationMode oldMode,
+ WorkflowConfigurationMode newMode)
+ {
+ if ((oldMode == WorkflowConfigurationMode.AUTO)
+ && (newMode == WorkflowConfigurationMode.MANUAL))
+ {
+ // move to manual mode
+ try
+ {
+ directoryServer.configureWorkflowsManual();
+ setWorkflowConfigurationMode(newMode);
+ }
+ catch (Exception e)
+ {
+ // rollback to auto mode
+ try
+ {
+ directoryServer.configureWorkflowsAuto();
+ }
+ catch (Exception ee)
+ {
+ // rollback to auto mode is failing too!!
+ // well, just log an error message and suggest the admin
+ // to restart the server with the last valid config...
+ Message message = ERR_CONFIG_WORKFLOW_CANNOT_CONFIGURE_MANUAL.get();
+ logError(message);
+ }
+ }
+ }
+ else if ((oldMode == WorkflowConfigurationMode.MANUAL)
+ && (newMode == WorkflowConfigurationMode.AUTO))
+ {
+ // move to auto mode
+ try
+ {
+ directoryServer.configureWorkflowsAuto();
+ setWorkflowConfigurationMode(newMode);
+ }
+ catch (Exception e)
+ {
+ // rollback to manual mode
+ try
+ {
+ directoryServer.configureWorkflowsManual();
+ }
+ catch (Exception ee)
+ {
+ // rollback to auto mode is failing too!!
+ // well, just log an error message and suggest the admin
+ // to restart the server with the last valid config...
+ Message message = ERR_CONFIG_WORKFLOW_CANNOT_CONFIGURE_AUTO.get();
+ logError(message);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Configures the workflows when configuration mode is manual.
+ *
+ * @throws ConfigException If there is a problem with the Directory Server
+ * configuration that prevents a critical component
+ * from being instantiated.
+ *
+ * @throws InitializationException If some other problem occurs while
+ * attempting to initialize and start the
+ * Directory Server.
+ */
+ private void configureWorkflowsManual()
+ throws ConfigException, InitializationException
+ {
+ // First of all re-initialize the current workflow configuration
+ NetworkGroup.resetConfig();
+ WorkflowImpl.resetConfig();
+ WorkflowElement.resetConfig();
+
+ // Then configure the workflows
+ workflowElementConfigManager = new WorkflowElementConfigManager();
+ workflowElementConfigManager.initializeWorkflowElements();
+
+ workflowConfigManager = new WorkflowConfigManager();
+ workflowConfigManager.initializeWorkflows();
+
+ networkGroupConfigManager = new NetworkGroupConfigManager();
+ networkGroupConfigManager.initializeNetworkGroups();
+
+ // We now need to complete the workflow creation for the
+ // config backend and rootDSE backend.
+ createAndRegisterRemainingWorkflows();
+ }
+
+
+ /**
+ * Configures the workflows when configuration mode is auto.
+ *
+ * @throws ConfigException If there is a problem with the Directory Server
+ * configuration that prevents a critical component
+ * from being instantiated.
+ */
+ private void configureWorkflowsAuto() throws ConfigException
+ {
+ // First of all re-initialize the current workflow configuration
+ NetworkGroup.resetConfig();
+ WorkflowImpl.resetConfig();
+ WorkflowElement.resetConfig();
+
+ // For each base DN in a backend create a workflow and register
+ // the workflow with the default network group
+ Map<String, Backend> backends = getBackends();
+ for (String backendID: backends.keySet())
+ {
+ Backend backend = backends.get(backendID);
+ for (DN baseDN: backend.getBaseDNs())
+ {
+ WorkflowImpl workflowImpl;
+ try
+ {
+ workflowImpl = createWorkflow(baseDN, backend);
+ registerWorkflowWithDefaultNetworkGroup(workflowImpl);
+ }
+ catch (DirectoryException e)
+ {
+ // TODO Auto-generated catch block
+ throw new ConfigException(e.getMessageObject());
+ }
+ }
+ }
+
+ // We now need to complete the workflow creation for the
+ // config backend and rootDSE backend.
+ createAndRegisterRemainingWorkflows();
+ }
+
+
+ /**
* Initializes the Directory Server group manager.
*
* @throws ConfigException If there is a configuration problem with any of
@@ -6246,8 +6401,14 @@
directoryServer.backends = newBackends;
- // Don't need anymore the local backend workflow element
- LocalBackendWorkflowElement.remove(backend.getBackendID());
+ // Don't need anymore the local backend workflow element so we
+ // can remove it. We do remove the workflow element only when
+ // the workflow configuration mode is auto because in manual
+ // mode the config manager is doing the job.
+ if (workflowConfigurationModeIsAuto())
+ {
+ LocalBackendWorkflowElement.remove(backend.getBackendID());
+ }
BackendMonitor monitor = backend.getBackendMonitor();
@@ -6409,13 +6570,21 @@
}
}
- // Now create a workflow for the registered baseDN and register
- // the workflow with the network groups, but don't register the
- // workflow if the backend happens to be the configuration backend
- // because it's too soon.
- if (! baseDN.equals(DN.decode("cn=config")))
+ // When a new baseDN is registered with the server we have to create
+ // a new workflow to handle the base DN. We do not need to create
+ // the workflow in manual mode because in that case the workflows
+ // are created explicitely.
+ if (workflowConfigurationModeIsAuto())
{
- createAndRegisterWorkflow(baseDN, backend);
+ // Now create a workflow for the registered baseDN and register
+ // the workflow with the default network group, but don't register
+ // the workflow if the backend happens to be the configuration
+ // backend because it's too soon for the config backend.
+ if (! baseDN.equals(DN.decode("cn=config")))
+ {
+ WorkflowImpl workflowImpl = createWorkflow(baseDN, backend);
+ registerWorkflowWithDefaultNetworkGroup(workflowImpl);
+ }
}
}
}
@@ -6449,8 +6618,14 @@
}
}
- // Now deregister the workflow that was associated with the base DN.
- deregisterWorkflow(baseDN);
+ // Now we need to deregister the workflow that was associated with
+ // the base DN but we can do it only when the workflow configuration
+ // mode is auto, because in manual mode the deregistration is done
+ // by the workflow config manager.
+ if (workflowConfigurationModeIsAuto())
+ {
+ deregisterWorkflowWithDefaultNetworkGroup(baseDN);
+ }
}
}
@@ -9610,5 +9785,48 @@
}
return isRunningAsWindowsService;
}
+
+
+ /**
+ * Specifies whether the workflows are configured automatically or manually.
+ * In auto configuration mode one workflow is created for each and every
+ * base DN in the local backends. In the auto configuration mode the
+ * workflows are created according to their description in the configuration
+ * file.
+ *
+ * @param workflowConfigurationMode Indicates whether the workflows are
+ * configured automatically or manually
+ */
+ public static void setWorkflowConfigurationMode(
+ WorkflowConfigurationMode workflowConfigurationMode)
+ {
+ directoryServer.workflowConfigurationMode = workflowConfigurationMode;
+ }
+
+
+ /**
+ * Indicates whether the workflow configuration mode is 'auto' or not.
+ *
+ * @return the workflow configuration mode
+ */
+ public static boolean workflowConfigurationModeIsAuto()
+ {
+ boolean isAuto =
+ (directoryServer.workflowConfigurationMode
+ == WorkflowConfigurationMode.AUTO);
+ return isAuto;
+ }
+
+
+
+ /**
+ * Retrieves the workflow configuration mode.
+ *
+ * @return the workflow configuration mode
+ */
+ public static WorkflowConfigurationMode getWorkflowConfigurationMode()
+ {
+ return directoryServer.workflowConfigurationMode;
+ }
}
diff --git a/opends/src/server/org/opends/server/core/NetworkGroup.java b/opends/src/server/org/opends/server/core/NetworkGroup.java
index aef2519..64eb290 100644
--- a/opends/src/server/org/opends/server/core/NetworkGroup.java
+++ b/opends/src/server/org/opends/server/core/NetworkGroup.java
@@ -56,7 +56,7 @@
// A lock to protect concurrent access to the registered Workflow nodes.
- private static Object registeredWorkflowNodesLock = new Object();
+ private Object registeredWorkflowNodesLock = new Object();
// The workflow node for the rootDSE entry. The RootDSE workflow node
@@ -107,6 +107,17 @@
/**
+ * Performs any finalization that might be required when this
+ * network group is unloaded. No action is taken in the
+ * default implementation.
+ */
+ public void finalizeNetworkGroup()
+ {
+ // No action is required by default.
+ }
+
+
+ /**
* Registers the current network group (this) with the server.
*
* @throws DirectoryException If the network group ID for the provided
@@ -188,9 +199,6 @@
WorkflowElement[] postWorkflowElements
) throws DirectoryException
{
- // true as soon as the workflow has been registered
- boolean registered = false;
-
// Is it the rootDSE workflow?
DN baseDN = workflow.getBaseDN();
if (baseDN.isNullDN())
@@ -198,7 +206,6 @@
// NOTE - The rootDSE workflow is stored with the registeredWorkflows.
rootDSEWorkflowNode =
new RootDseWorkflowTopology(workflow, namingContexts);
- registered = true;
}
else
{
@@ -210,7 +217,6 @@
// Register the workflow node with the network group. If the workflow
// ID is already existing then an exception is raised.
registerWorkflowNode(workflowNode);
- registered = true;
// Now add the workflow in the workflow topology...
for (WorkflowTopologyNode curNode: registeredWorkflowNodes.values())
@@ -234,17 +240,6 @@
// Rebuild the list of naming context handled by the network group
rebuildNamingContextList();
}
-
- // If the workflow has been registered successfully then register it
- // with the default network group
- if (registered)
- {
- if (this != defaultNetworkGroup)
- {
- defaultNetworkGroup.registerWorkflow(
- workflow, preWorkflowElements, postWorkflowElements);
- }
- }
}
@@ -253,20 +248,25 @@
* deregister is identified by its baseDN.
*
* @param baseDN the baseDN of the workflow to deregister, may be null
+ *
+ * @return the deregistered workflow
*/
- public void deregisterWorkflow(
+ public Workflow deregisterWorkflow(
DN baseDN
)
{
+ Workflow workflow = null;
+
if (baseDN == null)
{
- return;
+ return workflow;
}
if (baseDN.isNullDN())
{
// deregister the rootDSE
deregisterWorkflow(rootDSEWorkflowNode);
+ workflow = rootDSEWorkflowNode.getWorkflowImpl();
}
else
{
@@ -281,6 +281,7 @@
// Call deregisterWorkflow() instead of deregisterWorkflowNode()
// because we want the naming context list to be updated as well.
deregisterWorkflow(node);
+ workflow = node.getWorkflowImpl();
// Only one workflow can match the baseDN, so we can break
// the loop here.
@@ -289,6 +290,8 @@
}
}
}
+
+ return workflow;
}
@@ -505,38 +508,6 @@
/**
- * Checks whether a base DN has been already registered with
- * the network group.
- *
- * @param baseDN the base DN to check
- * @return <code>false</code> if the base DN is registered with the
- * network group, <code>false</code> otherwise
- */
- private boolean baseDNAlreadyRegistered(
- DN baseDN
- )
- {
- // returned result
- boolean alreadyRegistered = false;
-
- // go through the list of registered workflow and check whether a base DN
- // has already been used in a registered workflow
- for (WorkflowTopologyNode workflowNode: registeredWorkflowNodes.values())
- {
- DN curDN = workflowNode.getBaseDN();
- if (baseDN.equals (curDN))
- {
- alreadyRegistered = true;
- break;
- }
- }
-
- // check done
- return alreadyRegistered;
- }
-
-
- /**
* Returns the list of naming contexts handled by the network group.
*
* @return the list of naming contexts
@@ -614,5 +585,47 @@
namingContexts = null;
networkGroupID = null;
rootDSEWorkflowNode = null;
+ registeredWorkflowNodes = null;
+ }
+
+
+ /**
+ * Provides the list of network group registered with the server.
+ *
+ * @return the list of registered network groups
+ */
+ public static Collection<NetworkGroup> getRegisteredNetworkGroups()
+ {
+ return registeredNetworkGroups.values();
+ }
+
+
+ /**
+ * Resets the configuration of all the registered network groups.
+ */
+ public static void resetConfig()
+ {
+ // Reset the default network group
+ defaultNetworkGroup.reset();
+
+ // Reset all the registered network group
+ synchronized (registeredNetworkGroupsLock)
+ {
+ registeredNetworkGroups = new TreeMap<String, NetworkGroup>();
+ }
+ }
+
+
+ /**
+ * Resets the configuration of the current network group.
+ */
+ public void reset()
+ {
+ synchronized (registeredWorkflowNodesLock)
+ {
+ registeredWorkflowNodes = new TreeMap<String, WorkflowTopologyNode>();
+ rootDSEWorkflowNode = null;
+ namingContexts = new NetworkGroupNamingContexts();
+ }
}
}
diff --git a/opends/src/server/org/opends/server/core/NetworkGroupConfigManager.java b/opends/src/server/org/opends/server/core/NetworkGroupConfigManager.java
new file mode 100644
index 0000000..c44db66
--- /dev/null
+++ b/opends/src/server/org/opends/server/core/NetworkGroupConfigManager.java
@@ -0,0 +1,305 @@
+/*
+ * 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.core;
+
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opends.messages.Message;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.admin.server.ServerManagementContext;
+import org.opends.server.admin.std.server.NetworkGroupCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+
+
+/**
+ * This class defines a utility that will be used to manage the configuration
+ * for the set of network groups defined in the Directory Server.
+ * It will perform the necessary initialization of those network groups when
+ * the server is first started, and then will manage any changes to them while
+ * the server is running.
+ */
+public class NetworkGroupConfigManager
+ implements ConfigurationChangeListener<NetworkGroupCfg>,
+ ConfigurationAddListener<NetworkGroupCfg>,
+ ConfigurationDeleteListener<NetworkGroupCfg>
+
+{
+ // A mapping between the DNs of the config entries and the associated
+ // network groups.
+ private ConcurrentHashMap<DN, NetworkGroup> networkGroups;
+
+
+
+ /**
+ * Creates a new instance of this network group config manager.
+ */
+ public NetworkGroupConfigManager()
+ {
+ networkGroups = new ConcurrentHashMap<DN, NetworkGroup>();
+ }
+
+
+
+ /**
+ * Initializes all network groups currently defined in the Directory
+ * Server configuration. This should only be called at Directory Server
+ * startup.
+ *
+ * @throws ConfigException If a configuration problem causes the network
+ * group initialization process to fail.
+ */
+ public void initializeNetworkGroups()
+ throws ConfigException
+ {
+ // Get the root configuration object.
+ ServerManagementContext managementContext =
+ ServerManagementContext.getInstance();
+ RootCfg rootConfiguration =
+ managementContext.getRootConfiguration();
+
+
+ // Register as an add and delete listener with the root configuration so we
+ // can be notified if any network group entries are added or removed.
+ rootConfiguration.addNetworkGroupAddListener(this);
+ rootConfiguration.addNetworkGroupDeleteListener(this);
+
+
+ //Initialize the existing network groups.
+ for (String networkGroupName : rootConfiguration.listNetworkGroups())
+ {
+ NetworkGroupCfg networkGroupConfiguration =
+ rootConfiguration.getNetworkGroup(networkGroupName);
+ networkGroupConfiguration.addChangeListener(this);
+
+ if (networkGroupConfiguration.isEnabled())
+ {
+ try
+ {
+ createAndRegisterNetworkGroup(networkGroupConfiguration);
+ }
+ catch (DirectoryException de)
+ {
+ throw new ConfigException(de.getMessageObject());
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(
+ NetworkGroupCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ // Nothing to check.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(
+ NetworkGroupCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<Message> messages = new ArrayList<Message>();
+
+ configuration.addChangeListener(this);
+
+ // If the new network group is enabled then create it and register it.
+ if (configuration.isEnabled())
+ {
+ try
+ {
+ createAndRegisterNetworkGroup(configuration);
+ }
+ catch (DirectoryException de)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(de.getMessageObject());
+ }
+
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(
+ NetworkGroupCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(
+ NetworkGroupCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<Message> messages = new ArrayList<Message>();
+
+
+ NetworkGroup networkGroup = networkGroups.remove(configuration.dn());
+ if (networkGroup != null)
+ {
+ networkGroup.deregister();
+ networkGroup.finalizeNetworkGroup();
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ NetworkGroupCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ // Nothing to check.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ NetworkGroupCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<Message> messages = new ArrayList<Message>();
+
+ ConfigChangeResult configChangeResult =
+ new ConfigChangeResult(resultCode, adminActionRequired, messages);
+
+
+ // Get the existing network group if it's already enabled.
+ NetworkGroup existingNetworkGroup = networkGroups.get(configuration.dn());
+
+ // If the new configuration has the network group disabled, then disable
+ // it if it is enabled, or do nothing if it's already disabled.
+ if (! configuration.isEnabled())
+ {
+ if (existingNetworkGroup != null)
+ {
+ networkGroups.remove(configuration.dn());
+ existingNetworkGroup.deregister();
+ existingNetworkGroup.finalizeNetworkGroup();
+ }
+
+ return configChangeResult;
+ }
+
+ // If the network group is disabled then create it and register it.
+ if (existingNetworkGroup == null)
+ {
+ try
+ {
+ createAndRegisterNetworkGroup(configuration);
+ }
+ catch (DirectoryException de)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(de.getMessageObject());
+ }
+ }
+
+ return configChangeResult;
+ }
+
+
+ /**
+ * Creates and registers a network group.
+ *
+ * @param networkGroupCfg the network group configuration
+ *
+ * @throws DirectoryException If a problem occurs while trying to
+ * register a network group.
+ */
+ private void createAndRegisterNetworkGroup(
+ NetworkGroupCfg networkGroupCfg
+ ) throws DirectoryException
+ {
+ // create the network group
+ String networkGroupId = networkGroupCfg.getNetworkGroupId();
+ NetworkGroup networkGroup = new NetworkGroup(networkGroupId);
+
+ // register the workflows with the network group
+ for (String workflowID: networkGroupCfg.getWorkflow())
+ {
+ WorkflowImpl workflowImpl =
+ (WorkflowImpl) WorkflowImpl.getWorkflow(workflowID);
+ networkGroup.registerWorkflow(workflowImpl);
+ }
+
+ // finally register the network group with the server
+ networkGroups.put(networkGroupCfg.dn(), networkGroup);
+ networkGroup.register();
+ }
+
+}
+
diff --git a/opends/src/server/org/opends/server/core/RootDseWorkflowTopology.java b/opends/src/server/org/opends/server/core/RootDseWorkflowTopology.java
index eb0ff47..7ebb1a8 100644
--- a/opends/src/server/org/opends/server/core/RootDseWorkflowTopology.java
+++ b/opends/src/server/org/opends/server/core/RootDseWorkflowTopology.java
@@ -166,8 +166,10 @@
{
StringBuilder sb = new StringBuilder();
- // display the baseDN
- sb.append(leftMargin + "Workflow baseDN:[ \"\" ]\n");
+ // display the identifier and baseDN
+ String workflowID = this.getWorkflowImpl().getWorkflowId();
+ sb.append(leftMargin + "Workflow ID = " + workflowID + "\n");
+ sb.append(leftMargin + " baseDN:[ \"\" ]\n");
return sb;
}
diff --git a/opends/src/server/org/opends/server/core/WorkflowConfigManager.java b/opends/src/server/org/opends/server/core/WorkflowConfigManager.java
new file mode 100644
index 0000000..cca4243
--- /dev/null
+++ b/opends/src/server/org/opends/server/core/WorkflowConfigManager.java
@@ -0,0 +1,313 @@
+/*
+ * 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.core;
+
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opends.messages.Message;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.admin.server.ServerManagementContext;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.std.server.WorkflowCfg;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.workflowelement.WorkflowElement;
+
+
+/**
+ * This class defines a utility that will be used to manage the configuration
+ * for the set of workflows defined in the Directory Server. It will perform
+ * the necessary initialization of those workflows when the server is first
+ * started, and then will manage any changes to them while the server is
+ * running.
+ */
+public class WorkflowConfigManager
+ implements ConfigurationChangeListener<WorkflowCfg>,
+ ConfigurationAddListener<WorkflowCfg>,
+ ConfigurationDeleteListener<WorkflowCfg>
+
+{
+ // A mapping between the DNs of the config entries and the associated
+ // workflows.
+ private ConcurrentHashMap<DN, WorkflowImpl> workflows;
+
+
+
+ /**
+ * Creates a new instance of this workflow config manager.
+ */
+ public WorkflowConfigManager()
+ {
+ workflows = new ConcurrentHashMap<DN, WorkflowImpl>();
+ }
+
+
+
+ /**
+ * Initializes all workflows currently defined in the Directory
+ * Server configuration. This should only be called at Directory Server
+ * startup.
+ *
+ * @throws ConfigException If a configuration problem causes the workflow
+ * initialization process to fail.
+ */
+ public void initializeWorkflows()
+ throws ConfigException
+ {
+ // Get the root configuration object.
+ ServerManagementContext managementContext =
+ ServerManagementContext.getInstance();
+ RootCfg rootConfiguration =
+ managementContext.getRootConfiguration();
+
+
+ // Register as an add and delete listener with the root configuration so we
+ // can be notified if any workflow entries are added or removed.
+ rootConfiguration.addWorkflowAddListener(this);
+ rootConfiguration.addWorkflowDeleteListener(this);
+
+
+ //Initialize the existing workflows.
+ for (String workflowName : rootConfiguration.listWorkflows())
+ {
+ WorkflowCfg workflowConfiguration =
+ rootConfiguration.getWorkflow(workflowName);
+ workflowConfiguration.addChangeListener(this);
+
+ if (workflowConfiguration.isEnabled())
+ {
+ try
+ {
+ createAndRegisterWorkflow(workflowConfiguration);
+ }
+ catch (DirectoryException de)
+ {
+ throw new ConfigException(de.getMessageObject());
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(
+ WorkflowCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ // Nothing to check.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(
+ WorkflowCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<Message> messages = new ArrayList<Message>();
+
+ configuration.addChangeListener(this);
+
+ // If the new network group is enabled then create it and register it.
+ if (configuration.isEnabled())
+ {
+ try
+ {
+ createAndRegisterWorkflow(configuration);
+ }
+ catch (DirectoryException de)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(de.getMessageObject());
+ }
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(
+ WorkflowCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(
+ WorkflowCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<Message> messages = new ArrayList<Message>();
+
+
+ WorkflowImpl workflow = workflows.remove(configuration.dn());
+ if (workflow != null)
+ {
+ workflow.deregister();
+ workflow.finalizeWorkflow();
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ WorkflowCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ // Nothing to check.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ WorkflowCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<Message> messages = new ArrayList<Message>();
+
+ ConfigChangeResult configChangeResult =
+ new ConfigChangeResult(resultCode, adminActionRequired, messages);
+
+
+ // Get the existing network group if it's already enabled.
+ WorkflowImpl existingWorkflow = workflows.get(configuration.dn());
+
+ // If the new configuration has the validator disabled, then disable it if
+ // it is enabled, or do nothing if it's already disabled.
+ if (! configuration.isEnabled())
+ {
+ if (existingWorkflow != null)
+ {
+ workflows.remove(configuration.dn());
+ existingWorkflow.deregister();
+ existingWorkflow.finalizeWorkflow();
+ }
+
+ return configChangeResult;
+ }
+
+ // If the network group is disabled then create and register it.
+ if (existingWorkflow == null)
+ {
+ try
+ {
+ createAndRegisterWorkflow(configuration);
+ }
+ catch (DirectoryException de)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(de.getMessageObject());
+ }
+ }
+
+ return configChangeResult;
+ }
+
+
+ /**
+ * Creates a workflow, registers the workflow with the server
+ * and registers the workflow with the default network group.
+ *
+ * @param workflowCfg the workflow configuration
+ *
+ * @throws DirectoryException If a problem occurs while trying to
+ * decode a provided string as a DN or if
+ * the workflow ID for a provided workflow
+ * conflicts with the workflow ID of an existing
+ * workflow during workflow registration.
+ */
+ private void createAndRegisterWorkflow(
+ WorkflowCfg workflowCfg
+ ) throws DirectoryException
+ {
+ // The ID of the workflow to create
+ String workflowId = workflowCfg.getWorkflowId();
+
+ // Create the root workflow element to associate with the workflow
+ String rootWorkflowElementID = workflowCfg.getWorkflowElement();
+ WorkflowElement rootWorkflowElement =
+ WorkflowElement.getWorkflowElement(rootWorkflowElementID);
+
+ // Get the base DN targeted by the workflow
+ DN baseDN = DN.decode(workflowCfg.getBaseDN());
+
+ // Create the workflow and register it with the server
+ WorkflowImpl workflowImpl =
+ new WorkflowImpl(workflowId, baseDN, rootWorkflowElement);
+ workflows.put(workflowCfg.dn(), workflowImpl);
+ workflowImpl.register();
+
+ // Register the workflow with the default network group
+ NetworkGroup.getDefaultNetworkGroup().registerWorkflow(workflowImpl);
+ }
+
+}
+
diff --git a/opends/src/server/org/opends/server/core/WorkflowImpl.java b/opends/src/server/org/opends/server/core/WorkflowImpl.java
index dd1f551..0d09a43 100644
--- a/opends/src/server/org/opends/server/core/WorkflowImpl.java
+++ b/opends/src/server/org/opends/server/core/WorkflowImpl.java
@@ -30,6 +30,7 @@
import org.opends.messages.Message;
import static org.opends.server.util.Validator.ensureNotNull;
+import java.util.Collection;
import java.util.TreeMap;
import org.opends.server.types.DN;
@@ -108,6 +109,17 @@
/**
+ * Performs any finalization that might be required when this
+ * workflow is unloaded. No action is taken in the default
+ * implementation.
+ */
+ public void finalizeWorkflow()
+ {
+ // No action is required by default.
+ }
+
+
+ /**
* Gets the base DN of the data set being handled by the workflow.
*
* @return the workflow base DN
@@ -230,6 +242,7 @@
return workflowToDeregister;
}
+
/**
* Deregisters all Workflows that have been registered. This should be
* called when the server is shutting down.
@@ -242,4 +255,52 @@
new TreeMap<String, Workflow>();
}
}
+
+
+ /**
+ * Gets a workflow that was registered with the server.
+ *
+ * @param workflowID the ID of the workflow to get
+ * @return the requested workflow
+ */
+ public static Workflow getWorkflow(
+ String workflowID)
+ {
+ return registeredWorkflows.get(workflowID);
+ }
+
+
+ /**
+ * Gets all the workflows that were registered with the server.
+ *
+ * @return the list of registered workflows
+ */
+ public static Collection<Workflow> getWorkflows()
+ {
+ return registeredWorkflows.values();
+ }
+
+
+ /**
+ * Gets the root workflow element for test purpose only.
+ *
+ * @return the root workflow element.
+ */
+ WorkflowElement getRootWorkflowElement()
+ {
+ return rootWorkflowElement;
+ }
+
+
+ /**
+ * Resets all the registered workflows.
+ */
+ public static void resetConfig()
+ {
+ synchronized (registeredWorkflowsLock)
+ {
+ registeredWorkflows = new TreeMap<String, Workflow>();
+ }
+ }
+
}
diff --git a/opends/src/server/org/opends/server/core/WorkflowTopologyNode.java b/opends/src/server/org/opends/server/core/WorkflowTopologyNode.java
index fa5457f..e86bac5 100644
--- a/opends/src/server/org/opends/server/core/WorkflowTopologyNode.java
+++ b/opends/src/server/org/opends/server/core/WorkflowTopologyNode.java
@@ -500,7 +500,9 @@
// display the baseDN
DN baseDN = getBaseDN();
- sb.append(leftMargin + "Workflow baseDN:[");
+ String workflowID = this.getWorkflowImpl().getWorkflowId();
+ sb.append(leftMargin + "Workflow ID = " + workflowID + "\n");
+ sb.append(leftMargin + " baseDN:[");
if (baseDN.isNullDN())
{
sb.append(" \"\"");
@@ -511,21 +513,26 @@
}
sb.append(" ]\n");
+ // display the root workflow element
+ sb.append(leftMargin
+ + " Root Workflow Element: "
+ + getWorkflowImpl().getRootWorkflowElement() + "\n");
+
// display parent workflow
- sb.append(leftMargin + "Parent: " + getParent() + "\n");
+ sb.append(leftMargin + " Parent: " + getParent() + "\n");
// dump each subordinate
- sb.append(leftMargin + "List of subordinates:\n");
+ sb.append(leftMargin + " List of subordinates:\n");
ArrayList<WorkflowTopologyNode> subordinates = getSubordinates();
if (subordinates.isEmpty())
{
- sb.append(leftMargin + " NONE\n");
+ sb.append(leftMargin + " NONE\n");
}
else
{
for (WorkflowTopologyNode subordinate: getSubordinates())
{
- sb.append(subordinate.toString(leftMargin + " "));
+ sb.append(subordinate.toString(leftMargin + " "));
}
}
diff --git a/opends/src/server/org/opends/server/workflowelement/LeafWorkflowElement.java b/opends/src/server/org/opends/server/workflowelement/LeafWorkflowElement.java
index 47a377b..192a9a4 100644
--- a/opends/src/server/org/opends/server/workflowelement/LeafWorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/LeafWorkflowElement.java
@@ -26,24 +26,21 @@
*/
package org.opends.server.workflowelement;
+import org.opends.server.admin.std.server.WorkflowElementCfg;
+
/**
- * This class gathers all the workflow elements that are encapsulating
- * physical repositories such as local database, remote LDAP servers,
- * JDBC repository or LDIF flat file.
+ * This class defines the super class for all the workflow elements
+ * used to wrap physical repositories. A physical repository contains
+ * data (for example, a local backend, a remote LDAP servers or an
+ * LDIF flat file). Such workflow element is a leaf in the sense that
+ * the workflow element can be used by another workflow element but
+ * cannot use an other workflow element.
+ *
+ * @param <T> The type of configuration handled by this workflow elelemnt.
*/
-public abstract class LeafWorkflowElement
- extends WorkflowElement
+public abstract class LeafWorkflowElement <T extends WorkflowElementCfg>
+ extends WorkflowElement<WorkflowElementCfg>
{
- /**
- * Creates a new instance of the leaf workflow element.
- *
- * @param workflowElementID the workflow element identifier as defined
- * in the configuration.
- */
- protected LeafWorkflowElement(String workflowElementID)
- {
- super(workflowElementID);
- }
}
diff --git a/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java b/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
index ce81dd2..eb9eeaa 100644
--- a/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
@@ -26,6 +26,15 @@
*/
package org.opends.server.workflowelement;
+import static org.opends.server.util.Validator.ensureNotNull;
+import static org.opends.messages.ConfigMessages.*;
+
+import java.util.List;
+import java.util.TreeMap;
+
+import org.opends.messages.Message;
+import org.opends.server.admin.std.server.WorkflowElementCfg;
+import org.opends.server.config.ConfigException;
import org.opends.server.types.Operation;
@@ -37,25 +46,48 @@
* case for load balancing and distribution. And workflow element can be used
* in a virtual environment to transform data (DN and attribute renaming,
* attribute value renaming...).
+ *
+ * @param <T> The type of configuration handled by this workflow elelemnt.
*/
public abstract class WorkflowElement
+ <T extends WorkflowElementCfg>
{
// Indicates whether the workflow element encapsulates a private local
// backend.
private boolean isPrivate = false;
+
// The workflow element identifier.
private String workflowElementID = null;
+ // The set of workflow elements registered with the server.
+ // The workflow element identifier is used as a key in the map.
+ private static TreeMap<String, WorkflowElement> registeredWorkflowElements =
+ new TreeMap<String, WorkflowElement>();
+
+
+ // A lock to protect access to the registered workflow elements.
+ private static Object registeredWorkflowElementsLock = new Object();
+
/**
* Creates a new instance of the workflow element.
+ */
+ public WorkflowElement()
+ {
+ // There is nothing to do in the constructor.
+ }
+
+
+
+ /**
+ * Initializes the instance of the workflow element.
*
* @param workflowElementID the workflow element identifier as defined
* in the configuration.
*/
- public WorkflowElement(String workflowElementID)
+ public void initialize(String workflowElementID)
{
this.workflowElementID = workflowElementID;
}
@@ -63,6 +95,41 @@
/**
+ * Indicates whether the provided configuration is acceptable for
+ * this workflow elelement.
+ *
+ * @param configuration The workflow element configuration for
+ * which to make the determination.
+ * @param unacceptableReasons A list that may be used to hold the
+ * reasons that the provided
+ * configuration is not acceptable.
+ *
+ * @return {@code true} if the provided configuration is acceptable
+ * for this workflow element, or {@code false} if not.
+ */
+ public boolean isConfigurationAcceptable(
+ WorkflowElementCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ // This default implementation does not perform any special
+ // validation. It should be overridden by workflow element
+ // implementations that wish to perform more detailed validation.
+ return true;
+ }
+
+
+ /**
+ * Performs any finalization that might be required when this
+ * workflow element is unloaded. No action is taken in the default
+ * implementation.
+ */
+ public void finalizeWorkflowElement()
+ {
+ // No action is required by default.
+ }
+
+
+ /**
* Executes the workflow element for an operation.
*
* @param operation the operation to execute
@@ -108,5 +175,78 @@
{
return workflowElementID;
}
+
+
+ /**
+ * Registers the workflow element (this) with the server.
+ *
+ * @throws ConfigException If the workflow element ID for the provided
+ * workflow element conflicts with the workflow
+ * element ID of an existing workflow element.
+ */
+ public void register()
+ throws ConfigException
+ {
+ ensureNotNull(workflowElementID);
+
+ synchronized (registeredWorkflowElementsLock)
+ {
+ // the workflow element must not be already registered
+ if (registeredWorkflowElements.containsKey(workflowElementID))
+ {
+ Message message = ERR_CONFIG_WORKFLOW_ELEMENT_ALREADY_REGISTERED.get(
+ workflowElementID);
+ throw new ConfigException(message);
+ }
+
+ TreeMap<String, WorkflowElement> newWorkflowElements =
+ new TreeMap<String, WorkflowElement>(registeredWorkflowElements);
+ newWorkflowElements.put(workflowElementID, this);
+ registeredWorkflowElements = newWorkflowElements;
+ }
+ }
+
+
+ /**
+ * Deregisters the workflow element (this) with the server.
+ */
+ public void deregister()
+ {
+ ensureNotNull(workflowElementID);
+
+ synchronized (registeredWorkflowElementsLock)
+ {
+ TreeMap<String, WorkflowElement> newWorkflowElements =
+ new TreeMap<String, WorkflowElement>(registeredWorkflowElements);
+ newWorkflowElements.remove(workflowElementID);
+ registeredWorkflowElements = newWorkflowElements;
+ }
+ }
+
+
+ /**
+ * Gets a workflow element that was registered with the server.
+ *
+ * @param workflowElementID the ID of the workflow element to get
+ * @return the requested workflow element
+ */
+ public static WorkflowElement getWorkflowElement(
+ String workflowElementID)
+ {
+ return registeredWorkflowElements.get(workflowElementID);
+ }
+
+
+ /**
+ * Resets all the registered workflows.
+ */
+ public static void resetConfig()
+ {
+ synchronized (registeredWorkflowElementsLock)
+ {
+ registeredWorkflowElements = new TreeMap<String, WorkflowElement>();
+ }
+ }
+
}
diff --git a/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java b/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
new file mode 100644
index 0000000..115e0e3
--- /dev/null
+++ b/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
@@ -0,0 +1,448 @@
+/*
+ * 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.workflowelement;
+
+
+
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import static org.opends.messages.ConfigMessages.*;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opends.messages.Message;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.admin.server.ServerManagementContext;
+import org.opends.server.admin.std.meta.WorkflowElementCfgDefn;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.std.server.WorkflowElementCfg;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.InitializationException;
+import org.opends.server.types.ResultCode;
+
+
+/**
+ * This class defines a utility that will be used to manage the configuration
+ * for the set of workflow elements defined in the Directory Server.
+ * It will perform the necessary initialization of those backends when the
+ * server is first started, and then will manage any changes to them while
+ * the server is running.
+ */
+public class WorkflowElementConfigManager
+ implements ConfigurationChangeListener<WorkflowElementCfg>,
+ ConfigurationAddListener <WorkflowElementCfg>,
+ ConfigurationDeleteListener<WorkflowElementCfg>
+
+{
+ // A mapping between the DNs of the config entries and the associated
+ // workflow elements.
+ private ConcurrentHashMap<DN, WorkflowElement> workflowElements;
+
+
+
+ /**
+ * Creates a new instance of this workflow config manager.
+ */
+ public WorkflowElementConfigManager()
+ {
+ workflowElements = new ConcurrentHashMap<DN, WorkflowElement>();
+ }
+
+
+
+ /**
+ * Initializes all workflow elements currently defined in the Directory
+ * Server configuration. This should only be called at Directory Server
+ * startup.
+ *
+ * @throws ConfigException If a configuration problem causes the workflow
+ * element initialization process to fail.
+ * @throws InitializationException If a problem occurs while the workflow
+ * element is loaded and registered with
+ * the server
+ */
+ public void initializeWorkflowElements()
+ throws ConfigException, InitializationException
+ {
+ // Get the root configuration object.
+ ServerManagementContext managementContext =
+ ServerManagementContext.getInstance();
+ RootCfg rootConfiguration =
+ managementContext.getRootConfiguration();
+
+
+ // Register as an add and delete listener with the root configuration so we
+ // can be notified if any workflow element entries are added or removed.
+ rootConfiguration.addWorkflowElementAddListener(this);
+ rootConfiguration.addWorkflowElementDeleteListener(this);
+
+
+ //Initialize the existing workflows.
+ for (String workflowName : rootConfiguration.listWorkflowElements())
+ {
+ WorkflowElementCfg workflowConfiguration =
+ rootConfiguration.getWorkflowElement(workflowName);
+ workflowConfiguration.addChangeListener(this);
+
+ if (workflowConfiguration.isEnabled())
+ {
+ loadAndRegisterWorkflowElement(workflowConfiguration);
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(
+ WorkflowElementCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ boolean isAcceptable = true;
+
+ if (configuration.isEnabled())
+ {
+ // Get the name of the class and make sure we can instantiate it as
+ // a workflow element.
+ String className = configuration.getJavaClass();
+ try
+ {
+ // Load the class but don't initialize it.
+ loadWorkflowElement(className, configuration, false);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add (ie.getMessageObject());
+ isAcceptable = false;
+ }
+ }
+
+ return isAcceptable;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(
+ WorkflowElementCfg configuration)
+ {
+ // Returned result.
+ ConfigChangeResult changeResult = new ConfigChangeResult(
+ ResultCode.SUCCESS, false, new ArrayList<Message>()
+ );
+
+ configuration.addChangeListener(this);
+
+ // If the new workflow element is enabled then create it and register it.
+ if (configuration.isEnabled())
+ {
+ try
+ {
+ loadAndRegisterWorkflowElement(configuration);
+ }
+ catch (InitializationException de)
+ {
+ if (changeResult.getResultCode() == ResultCode.SUCCESS)
+ {
+ changeResult.setResultCode(
+ DirectoryServer.getServerErrorResultCode());
+ }
+ changeResult.addMessage(de.getMessageObject());
+ }
+ }
+
+ return changeResult;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(
+ WorkflowElementCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ // FIXME -- We should try to perform some check to determine whether the
+ // worklfow element is in use.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(
+ WorkflowElementCfg configuration)
+ {
+ // Returned result.
+ ConfigChangeResult changeResult = new ConfigChangeResult(
+ ResultCode.SUCCESS, false, new ArrayList<Message>()
+ );
+
+
+ WorkflowElement workflowElement =
+ workflowElements.remove(configuration.dn());
+ if (workflowElement != null)
+ {
+ workflowElement.deregister();
+ workflowElement.finalizeWorkflowElement();
+ }
+
+
+ return changeResult;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ WorkflowElementCfg configuration,
+ List<Message> unacceptableReasons)
+ {
+ boolean isAcceptable = true;
+
+ if (configuration.isEnabled())
+ {
+ // Get the name of the class and make sure we can instantiate it as
+ // a workflow element.
+ String className = configuration.getJavaClass();
+ try
+ {
+ // Load the class but don't initialize it.
+ loadWorkflowElement(className, configuration, false);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add (ie.getMessageObject());
+ isAcceptable = false;
+ }
+ }
+
+ return isAcceptable;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ WorkflowElementCfg configuration)
+ {
+ // Returned result.
+ ConfigChangeResult changeResult = new ConfigChangeResult(
+ ResultCode.SUCCESS, false, new ArrayList<Message>()
+ );
+
+
+ // Get the existing workflow element if it's already enabled.
+ WorkflowElement existingWorkflowElement =
+ workflowElements.get(configuration.dn());
+
+ // If the new configuration has the workflow element disabled,
+ // then disable it if it is enabled, or do nothing if it's already disabled.
+ if (! configuration.isEnabled())
+ {
+ if (existingWorkflowElement != null)
+ {
+ workflowElements.remove(configuration.dn());
+ existingWorkflowElement.deregister();
+ existingWorkflowElement.finalizeWorkflowElement();
+ }
+
+ return changeResult;
+ }
+
+ // If the workflow element is disabled then create it and register it.
+ if (existingWorkflowElement == null)
+ {
+ try
+ {
+ loadAndRegisterWorkflowElement(configuration);
+ }
+ catch (InitializationException de)
+ {
+ if (changeResult.getResultCode() == ResultCode.SUCCESS)
+ {
+ changeResult.setResultCode(
+ DirectoryServer.getServerErrorResultCode());
+ }
+ changeResult.addMessage(de.getMessageObject());
+ }
+ }
+
+ return changeResult;
+ }
+
+
+ /**
+ * Loads a class and instanciates it as a workflow element. The workflow
+ * element is initialized and registered with the server.
+ *
+ * @param workflowCfg the workflow element configuration
+ *
+ * @throws InitializationException If a problem occurs while trying to
+ * decode a provided string as a DN or if
+ * the workflow element ID for a provided
+ * workflow element conflicts with the workflow
+ * ID of an existing workflow during workflow
+ * registration.
+ */
+ private void loadAndRegisterWorkflowElement(
+ WorkflowElementCfg workflowElementCfg
+ ) throws InitializationException
+ {
+ // Load the workflow element class
+ String className = workflowElementCfg.getJavaClass();
+ WorkflowElement workflowElement =
+ loadWorkflowElement(className, workflowElementCfg, true);
+
+ try
+ {
+ // register the workflow element
+ workflowElement.register();
+
+ // keep the workflow element in the list of configured workflow
+ // elements
+ workflowElements.put(workflowElementCfg.dn(), workflowElement);
+ }
+ catch (ConfigException de)
+ {
+ throw new InitializationException(de.getMessageObject());
+ }
+ }
+
+
+ /**
+ * Loads a class and instanciates it as a workflow element. If requested
+ * initializes the newly created instance.
+ *
+ * @param className The fully-qualified name of the workflow element
+ * class to load, instantiate, and initialize.
+ * @param configuration The configuration to use to initialize the workflow
+ * element. It must not be {@code null}.
+ * @param initialize Indicates whether the workflow element instance
+ * should be initialized.
+ *
+ * @return The possibly initialized workflow element.
+ *
+ * @throws InitializationException If a problem occurred while attempting
+ * to initialize the workflow element.
+ */
+ private WorkflowElement loadWorkflowElement(
+ String className,
+ WorkflowElementCfg configuration,
+ boolean initialize
+ ) throws InitializationException
+ {
+ try
+ {
+ WorkflowElementCfgDefn definition;
+ ClassPropertyDefinition propertyDefinition;
+ Class<? extends WorkflowElement> workflowElementClass;
+ WorkflowElement<? extends WorkflowElementCfg> workflowElement;
+
+ definition = WorkflowElementCfgDefn.getInstance();
+ propertyDefinition =
+ definition.getJavaClassPropertyDefinition();
+ workflowElementClass =
+ propertyDefinition.loadClass(className, WorkflowElement.class);
+ workflowElement =
+ (WorkflowElement<? extends WorkflowElementCfg>)
+ workflowElementClass.newInstance();
+
+ if (initialize)
+ {
+ Method method = workflowElement.getClass().getMethod(
+ "initializeWorkflowElement",
+ configuration.definition().getServerConfigurationClass()
+ );
+ method.invoke(workflowElement, configuration);
+ }
+ else
+ {
+ Method method = workflowElement.getClass().getMethod(
+ "isConfigurationAcceptable",
+ WorkflowElementCfg.class,
+ List.class);
+
+ List<String> unacceptableReasons = new ArrayList<String>();
+ Boolean acceptable = (Boolean) method.invoke(
+ workflowElement, configuration, unacceptableReasons);
+
+ if (! acceptable)
+ {
+ StringBuilder buffer = new StringBuilder();
+ if (! unacceptableReasons.isEmpty())
+ {
+ Iterator<String> iterator = unacceptableReasons.iterator();
+ buffer.append(iterator.next());
+ while (iterator.hasNext())
+ {
+ buffer.append(". ");
+ buffer.append(iterator.next());
+ }
+ }
+
+ Message message =
+ ERR_CONFIG_WORKFLOW_ELEMENT_CONFIG_NOT_ACCEPTABLE.get(
+ String.valueOf(configuration.dn()), buffer.toString());
+ throw new InitializationException(message);
+ }
+ }
+
+ return workflowElement;
+ }
+ catch (Exception e)
+ {
+ Message message =
+ ERR_CONFIG_WORKFLOW_ELEMENT_CANNOT_INITIALIZE.get(
+ className, String.valueOf(configuration.dn()),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(message);
+ }
+ }
+
+}
+
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 2cfc903..5a4d1dc 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -32,15 +32,23 @@
import java.util.List;
import java.util.TreeMap;
+import org.opends.messages.Message;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.LocalBackendWorkflowElementCfg;
import org.opends.server.api.Backend;
+import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
import org.opends.server.core.BindOperation;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.SearchOperation;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.InitializationException;
import org.opends.server.types.Operation;
+import org.opends.server.types.ResultCode;
import org.opends.server.workflowelement.LeafWorkflowElement;
@@ -49,37 +57,152 @@
* This class defines a local backend workflow element; e-g an entity that
* handle the processing of an operation aginst a local backend.
*/
-public class LocalBackendWorkflowElement extends LeafWorkflowElement
+public class LocalBackendWorkflowElement extends
+ LeafWorkflowElement<LocalBackendWorkflowElementCfg>
+ implements ConfigurationChangeListener<LocalBackendWorkflowElementCfg>
{
// the backend associated with the local workflow element
private Backend backend;
+
// the set of local backend workflow elements registered with the server
private static TreeMap<String, LocalBackendWorkflowElement>
registeredLocalBackends =
new TreeMap<String, LocalBackendWorkflowElement>();
+
// a lock to guarantee safe concurrent access to the registeredLocalBackends
// variable
private static Object registeredLocalBackendsLock = new Object();
-
/**
* Creates a new instance of the local backend workflow element.
+ */
+ public LocalBackendWorkflowElement()
+ {
+ // There is nothing to do in this constructor.
+ }
+
+
+ /**
+ * Initializes a new instance of the local backend workflow element.
+ * This method is intended to be called by DirectoryServer when
+ * workflow configuration mode is auto as opposed to
+ * initializeWorkflowElement which is invoked when workflow
+ * configuration mode is manual.
*
* @param workflowElementID the workflow element identifier
* @param backend the backend associated to that workflow element
*/
- private LocalBackendWorkflowElement(String workflowElementID, Backend backend)
+ private void initialize(String workflowElementID, Backend backend)
{
- super(workflowElementID);
+ // Initialize the workflow ID
+ super.initialize(workflowElementID);
this.backend = backend;
- setPrivate(backend.isPrivateBackend());
+
+ if (this.backend != null)
+ {
+ setPrivate(this.backend.isPrivateBackend());
+ }
}
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeWorkflowElement(
+ LocalBackendWorkflowElementCfg configuration
+ ) throws ConfigException, InitializationException
+ {
+ configuration.addLocalBackendChangeListener(this);
+
+ // Read configuration and apply changes.
+ processWorkflowElementConfig(configuration, true);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void finalizeWorkflowElement()
+ {
+ // null all fields so that any use of the finalized object will raise
+ // an NPE
+ super.initialize(null);
+ backend = null;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ LocalBackendWorkflowElementCfg configuration,
+ List<Message> unacceptableReasons
+ )
+ {
+ boolean isAcceptable =
+ processWorkflowElementConfig(configuration, false);
+
+ return isAcceptable;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ LocalBackendWorkflowElementCfg configuration
+ )
+ {
+ // Returned result.
+ ConfigChangeResult changeResult = new ConfigChangeResult(
+ ResultCode.SUCCESS, false, new ArrayList<Message>()
+ );
+
+ processWorkflowElementConfig(configuration, true);
+
+ return changeResult;
+ }
+
+
+ /**
+ * Parses the provided configuration and configure the workflow element.
+ *
+ * @param configuration The new configuration containing the changes.
+ * @param applyChanges If true then take into account the new configuration.
+ *
+ * @return <code>true</code> if the configuration is acceptable.
+ */
+ private boolean processWorkflowElementConfig(
+ LocalBackendWorkflowElementCfg configuration,
+ boolean applyChanges
+ )
+ {
+ // returned status
+ boolean isAcceptable = true;
+
+ // If the workflow element is disabled then do nothing. Note that the
+ // config manager could have finalized the object right before.
+ if (configuration.isEnabled())
+ {
+ // Read configuration.
+ String newBackendID = configuration.getBackend();
+ Backend newBackend = DirectoryServer.getBackend(newBackendID);
+
+ // Get the new config
+ if (applyChanges)
+ {
+ super.initialize(configuration.getWorkflowElementId());
+ backend = newBackend;
+ }
+ }
+
+ return isAcceptable;
+ }
+
/**
* Creates and registers a local backend with the server.
@@ -92,8 +215,9 @@
* already created or a newly created local backend workflow
* element.
*/
- public static LocalBackendWorkflowElement create(String workflowElementID,
- Backend backend)
+ public static LocalBackendWorkflowElement createAndRegister(
+ String workflowElementID,
+ Backend backend)
{
LocalBackendWorkflowElement localBackend = null;
@@ -101,8 +225,8 @@
localBackend = registeredLocalBackends.get(workflowElementID);
if (localBackend == null)
{
- localBackend = new LocalBackendWorkflowElement(workflowElementID,
- backend);
+ localBackend = new LocalBackendWorkflowElement();
+ localBackend.initialize(workflowElementID, backend);
// store the new local backend in the list of registered backends
registerLocalBackend(localBackend);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ValidateConfigDefinitionsTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ValidateConfigDefinitionsTest.java
index ef3e60b..72d879d 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ValidateConfigDefinitionsTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ValidateConfigDefinitionsTest.java
@@ -133,6 +133,10 @@
"backend-id",
"plugin-type",
"replication-server-id",
+ "network-group-id",
+ "workflow-id",
+ "workflow-element-id",
+ "workflow-element"
// e.g. "prop-name-starting-with-object-prefix"
});
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
new file mode 100644
index 0000000..7eea3ad
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
@@ -0,0 +1,689 @@
+/*
+ * 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.core;
+
+
+import static org.opends.server.util.StaticUtils.createEntry;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.ArrayList;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
+import org.opends.server.config.ConfigConstants;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPAttribute;
+import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.ldap.LDAPModification;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DereferencePolicy;
+import org.opends.server.types.Entry;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.RawModification;
+import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchScope;
+import org.opends.server.util.StaticUtils;
+import org.opends.server.util.UtilTestCase;
+import org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class tests the 'manual' workflow configuration mode. The 'auto'
+ * configuration mode does not require any specific unit test because by
+ * default the server is running with the 'auto' mode.
+ *
+ * With the manual configuration mode, all the network groups, workflows
+ * and workflow elements must be defined in the configuration file.
+ */
+public class WorkflowConfigurationTest extends UtilTestCase
+{
+ // The base DN of the config backend
+ private static final String configBaseDN = ConfigConstants.DN_CONFIG_ROOT;
+
+ // The base DN of the rootDSE backend
+ private static final String rootDSEBaseDN = "";
+
+ // The workflow configuration mode attribute
+ private static final String workflowModeAttributeType =
+ "ds-cfg-workflow-configuration-mode";
+
+ // The suffix attribute in a backend
+ private static final String suffixAttributeType =
+ "ds-cfg-base-dn";
+
+ // The auto/manual modes
+ private static final String workflowConfigModeAuto = "auto";
+ private static final String workflowConfigModeManual = "manual";
+
+
+
+ //===========================================================================
+ // B E F O R E C L A S S
+ //===========================================================================
+
+ /**
+ * Set up the environment for performing the tests in this suite.
+ *
+ * @throws Exception if the environment could not be set up.
+ */
+ @BeforeClass
+ public void setUp()
+ throws Exception
+ {
+ // Start the server so that we can update the configuration and execute
+ // some LDAP operations
+ TestCaseUtils.startServer();
+
+ // Add the attribute ds-cfg-workflow-configuration-mode with the
+ // value 'auto
+ initializeConfigurationMode();
+ checkBackendIsAccessible("o=test");
+ }
+
+
+
+ //===========================================================================
+ // D A T A P R O V I D E R
+ //===========================================================================
+
+
+
+ //===========================================================================
+ // U T I L S
+ //===========================================================================
+
+ /**
+ * Adds an attribute ds-cfg-workflow-configuration-mode in the entry
+ * cn=config. The added value is 'auto'.
+ */
+ private void initializeConfigurationMode()
+ throws Exception
+ {
+ // Add the ds-cfg-workflow-configuration-mode attribute and set
+ // its value to "auto"
+ ModifyOperationBasis modifyOperation = getModifyOperation(
+ configBaseDN,
+ ModificationType.ADD,
+ workflowModeAttributeType,
+ workflowConfigModeAuto);
+
+ modifyOperation.run();
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Checks that test backend is accessible as well as config backend
+ * and rootDSE backend.
+ *
+ * @param baseDN the baseDN of the backend to check
+ */
+ private void checkBackendIsAccessible(String baseDN)
+ throws Exception
+ {
+ // The config backend and rootDSE backend should always be accessible
+ doSearch(rootDSEBaseDN, SearchScope.BASE_OBJECT, ResultCode.SUCCESS);
+ doSearch(configBaseDN, SearchScope.BASE_OBJECT, ResultCode.SUCCESS);
+
+ // The test backend should be accessible
+ doSearch(baseDN, SearchScope.BASE_OBJECT, ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Checks that test backend is not accessible while config backend
+ * and rootDSE backend are.
+ *
+ * @param baseDN the baseDN of the backend to check
+ */
+ private void checkBackendIsNotAccessible(String baseDN)
+ throws Exception
+ {
+ // The config backend and rootDSE should always be accessible
+ doSearch(rootDSEBaseDN, SearchScope.BASE_OBJECT, ResultCode.SUCCESS);
+ doSearch(configBaseDN, SearchScope.BASE_OBJECT, ResultCode.SUCCESS);
+
+ // The test backend should be accessible
+ doSearch(baseDN, SearchScope.BASE_OBJECT, ResultCode.NO_SUCH_OBJECT);
+ }
+
+
+ /**
+ * Sets the ds-cfg-workflow-configuration-mode attribute to 'auto'
+ */
+ private void setModeAuto() throws Exception
+ {
+ ModifyOperationBasis modifyOperation = getModifyOperation(
+ configBaseDN,
+ ModificationType.REPLACE,
+ workflowModeAttributeType,
+ workflowConfigModeAuto);
+
+ modifyOperation.run();
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Sets the ds-cfg-workflow-configuration-mode attribute to 'auto'
+ */
+ private void setModeManual() throws Exception
+ {
+ ModifyOperationBasis modifyOperation = getModifyOperation(
+ configBaseDN,
+ ModificationType.REPLACE,
+ workflowModeAttributeType,
+ workflowConfigModeManual);
+
+ modifyOperation.run();
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Performs a search on a provided base DN.
+ *
+ * @param baseDN the search base DN
+ * @param scope the scope of the search
+ * @param expectedResultCode the expected result code
+ *
+ * @return the search operation used for the test
+ */
+ private InternalSearchOperation doSearch(
+ String baseDN,
+ SearchScope scope,
+ ResultCode expectedResultCode
+ ) throws Exception
+ {
+ InternalSearchOperation searchOperation = new InternalSearchOperation(
+ InternalClientConnection.getRootConnection(),
+ InternalClientConnection.nextOperationID(),
+ InternalClientConnection.nextMessageID(),
+ new ArrayList<Control>(),
+ new ASN1OctetString(baseDN),
+ scope,
+ DereferencePolicy.NEVER_DEREF_ALIASES,
+ Integer.MAX_VALUE,
+ Integer.MAX_VALUE,
+ false,
+ LDAPFilter.decode("(objectClass=*)"),
+ null, null);
+
+ searchOperation.run();
+ assertEquals(searchOperation.getResultCode(), expectedResultCode);
+
+ return searchOperation;
+ }
+
+
+ /**
+ * Provides a modify operation.
+ *
+ * @param entryDN the DN of the entry targeted by the modify operation
+ * @param modType the type of the modification
+ * @param attributeType the type of the attribute to modify
+ * @param attributeValue the value of the attribute to modify
+ */
+ private static ModifyOperationBasis getModifyOperation(
+ String entryDN,
+ ModificationType modType,
+ String attributeType,
+ String attributeValue)
+ {
+ ArrayList<ASN1OctetString> ldapValues = new ArrayList<ASN1OctetString>();
+ ldapValues.add(new ASN1OctetString(attributeValue));
+
+ LDAPAttribute ldapAttr = new LDAPAttribute(attributeType, ldapValues);
+
+ ArrayList<RawModification> ldapMods = new ArrayList<RawModification>();
+ ldapMods.add(new LDAPModification(modType, ldapAttr));
+
+ ModifyOperationBasis modifyOperation = new ModifyOperationBasis(
+ InternalClientConnection.getRootConnection(),
+ InternalClientConnection.nextOperationID(),
+ InternalClientConnection.nextMessageID(),
+ new ArrayList<Control>(),
+ new ASN1OctetString(entryDN),
+ ldapMods);
+
+ return modifyOperation;
+ }
+
+
+ /**
+ * Creates a workflow to handle a local backend. The default network
+ * group is used.
+ *
+ * @param baseDN the base DN of the workflow
+ * @param backendID the backend which contains the baseDN
+ *
+ * @return the newly created workflow
+ */
+ private WorkflowImpl createWorkflow(String baseDN, String backendID)
+ throws Exception
+ {
+ // Get the backend
+ Backend backend = DirectoryServer.getBackend(backendID);
+ assertNotNull(backend);
+
+ // Create the workflow element that wraps the local backend
+ String workflowElementID = baseDN + "#" + backendID;
+ LocalBackendWorkflowElement workflowElement =
+ LocalBackendWorkflowElement.createAndRegister(workflowElementID, backend);
+
+ // Create a workflow and register it with the server
+ String workflowID = baseDN + "#" + backendID;
+ WorkflowImpl workflowImpl = new WorkflowImpl(
+ workflowID, DN.decode(baseDN), workflowElement);
+ workflowImpl.register();
+
+ // Register the workflow with the default network group
+ NetworkGroup.getDefaultNetworkGroup().registerWorkflow(workflowImpl);
+
+ return workflowImpl;
+ }
+
+
+ /**
+ * Removes a workflow.
+ *
+ * @param baseDN the base DN of the workflow
+ * @param backendID the backend which contains the baseDN
+ */
+ private void removeWorkflow(String baseDN, String backendID)
+ throws Exception
+ {
+ // Elaborate the workflow ID
+ String workflowID = baseDN + "#" + backendID;
+
+ // Deregister the workflow with the default network group
+ NetworkGroup.getDefaultNetworkGroup().deregisterWorkflow(workflowID);
+
+ // Deregister the workflow with the server
+ Workflow workflow = WorkflowImpl.getWorkflow(workflowID);
+ WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
+ workflowImpl.deregister();
+ }
+
+
+ /**
+ * Adds a new suffix in a backend.
+ *
+ * @param baseDN the DN of the suffix to add
+ * @param backendID the identifier of the backend to which the suffix
+ * is added
+ */
+ private void addSuffix(String baseDN, String backendID)
+ throws Exception
+ {
+ // Elaborate the DN of the backend config entry
+ String backendDN = elaborateBackendDN(backendID);
+
+ // Add a new suffix in the backend
+ ModifyOperationBasis modifyOperation = getModifyOperation(
+ backendDN,
+ ModificationType.ADD,
+ suffixAttributeType,
+ baseDN);
+
+ modifyOperation.run();
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Create a base entry for a new suffix.
+ *
+ * @param baseDN the DN of the new base entry
+ * @param backendID the identifier of the backend
+ */
+ private void createBaseEntry(String baseDN, String backendID)
+ throws Exception
+ {
+ Entry entry = StaticUtils.createEntry(DN.decode(baseDN));
+
+ AddOperationBasis addOperation = new AddOperationBasis(
+ InternalClientConnection.getRootConnection(),
+ InternalClientConnection.nextOperationID(),
+ InternalClientConnection.nextMessageID(),
+ null,
+ entry.getDN(),
+ entry.getObjectClasses(),
+ entry.getUserAttributes(),
+ entry.getOperationalAttributes());
+
+ addOperation.run();
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Removes a new suffix in a backend.
+ *
+ * @param baseDN the DN of the suffix to remove
+ * @param backendID the identifier of the backend to which the suffix
+ * is removed
+ *
+ * @throw Exception if the backend does not exist or if the suffix
+ * already exist in the backend
+ */
+ private void removeSuffix(String baseDN, String backendID)
+ throws Exception
+ {
+ // Elaborate the DN of the backend config entry
+ String backendDN = elaborateBackendDN(backendID);
+
+ // Add a new suffix in the backend
+ ModifyOperationBasis modifyOperation = getModifyOperation(
+ backendDN,
+ ModificationType.DELETE,
+ suffixAttributeType,
+ baseDN);
+
+ modifyOperation.run();
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Elaborates a DN for a backend config entry.
+ *
+ * @param backendID the identifier of the backend to retrieve
+ */
+ private String elaborateBackendDN(String backendID)
+ {
+ String backendDN =
+ "ds-cfg-backend-id=" + backendID + ",cn=Backends,cn=config";
+ return backendDN;
+ }
+
+
+ /**
+ * Initializes a memory-based backend.
+ *
+ * @param backendID the identifier of the backend to create
+ * @param baseDN the DN of the suffix to create
+ * @param createBaseEntry indicate whether to automatically create the base
+ * entry and add it to the backend.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ private static void createBackend(
+ String backendID,
+ String baseDN,
+ boolean createBaseEntry
+ ) throws Exception
+ {
+ TestCaseUtils.dsconfig(
+ "create-backend",
+ "--backend-name", backendID,
+ "--type", "memory",
+ "--set", "base-dn:" + baseDN,
+ "--set", "writability-mode:enabled",
+ "--set", "enabled:true");
+
+ if (createBaseEntry)
+ {
+ Backend backend = DirectoryServer.getBackend(backendID);
+ Entry e = createEntry(DN.decode(baseDN));
+ backend.addEntry(e, null);
+ }
+ }
+
+
+ /**
+ * Remove a backend.
+ *
+ * @param backendID the identifier of the backend to remove
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ private static void removeMemoryBackend(
+ String backendID
+ ) throws Exception
+ {
+ TestCaseUtils.dsconfig(
+ "delete-backend",
+ "--backend-name", backendID);
+ }
+
+
+
+ //===========================================================================
+ // T E S T C A S E S
+ //===========================================================================
+
+ /**
+ * This test checks the transition from mode 'auto' to 'manual' and
+ * 'manual' back to 'auto'. In this test there is no configuration for
+ * network group, workflow and workflow element.
+ */
+ @Test
+ public void transitionAutoManualAuto() throws Exception
+ {
+ // Settings
+ String testBaseDN = "o=test";
+
+ // The ds-cfg-workflow-configuration-mode attribute value is "auto"
+ // (default value), let's put the same value again. Putting the same
+ // value should have no impact and we should be able to perform a search
+ // on the test backend.
+ setModeAuto();
+ checkBackendIsAccessible(testBaseDN);
+
+ // Change the ds-cfg-workflow-configuration-mode attribute value
+ // to "manual". The workflows should be fully reconfigured. But as
+ // there is no configuration for the workflows, only cn=config and
+ // rootDSE should be accessible.
+ setModeManual();
+ checkBackendIsNotAccessible(testBaseDN);
+
+ // Change the ds-cfg-workflow-configuration-mode attribute value
+ // back to "auto". All the local backends should be accessible again.
+ setModeAuto();
+ checkBackendIsAccessible(testBaseDN);
+ }
+
+
+ /**
+ * This test checks the basic operation routing when configuration
+ * mode is 'manual'. Few workflows are configured for the test.
+ */
+ @Test
+ public void basicRoutingManualMode() throws Exception
+ {
+ // Settings
+ String testBaseDN = "o=test";
+ String testBackendID = "test";
+
+ // Workflow configuration mode is auto, so test backend should
+ // be accessible
+ checkBackendIsAccessible(testBaseDN);
+
+ // Set the workflow configuration mode to manual. In this mode
+ // no there is no workflow by default (but the config and rootDSE
+ // workflows) so seaarches on the test backend should fail.
+ setModeManual();
+ checkBackendIsNotAccessible(testBaseDN);
+
+ // Create a workflow to handle o=test backend then check that test
+ // backend is now accessible
+ createWorkflow(testBaseDN, testBackendID);
+ checkBackendIsAccessible(testBaseDN);
+
+ // Change workflow configuration mode back to auto and check that
+ // test backend is still accessible
+ setModeAuto();
+ checkBackendIsAccessible(testBaseDN);
+ }
+
+
+ /**
+ * This test checks the add/remove of suffix in a backend in manual
+ * configuration mode.
+ */
+ @Test
+ public void addRemoveSuffix() throws Exception
+ {
+ // Settings
+ String testBaseDN2 = "o=addRemoveSuffix_1";
+ String testBaseDN3 = "o=addRemoveSuffix_2";
+ String testBackendID2 = "userRoot";
+
+ // make sure we are in auto mode and check that the new suffixes are
+ // not already defined on the server.
+ setModeAuto();
+ checkBackendIsNotAccessible(testBaseDN2);
+ checkBackendIsNotAccessible(testBaseDN3);
+
+ // Add a new suffix to the test backend and check that the new
+ // suffix is accessible (we are in auto mode).
+ addSuffix(testBaseDN2, testBackendID2);
+ createBaseEntry(testBaseDN2, testBackendID2);
+ checkBackendIsAccessible(testBaseDN2);
+
+ // Remove the suffix and check that the removed suffix is no
+ // more accessible.
+ removeSuffix(testBaseDN2, testBackendID2);
+ checkBackendIsNotAccessible(testBaseDN2);
+
+ // Now move to the manual mode.
+ setModeManual();
+
+ // Add a new suffix and configure a workflow to route operation
+ // to this new suffix, then check that the new suffix is accessible.
+ // Note that before we can create a base entry we need to configure
+ // first a workflow to route the ADD operation to the right suffix.
+ // This need not be to be done in auto mode because with the auto mode
+ // the workflow is automatically created when a new suffix is added.
+ addSuffix(testBaseDN3, testBackendID2);
+ createWorkflow(testBaseDN3, testBackendID2);
+ createBaseEntry(testBaseDN3, testBackendID2);
+ checkBackendIsAccessible(testBaseDN3);
+
+ // Finally remove the new workflow and suffix and check that the suffix
+ // is no more accessible.
+ removeWorkflow(testBaseDN3, testBackendID2);
+ removeSuffix(testBaseDN3, testBackendID2);
+ checkBackendIsNotAccessible(testBaseDN3);
+ }
+
+
+ /**
+ * This test checks the add/remove of a backend in manual configuration
+ * mode.
+ */
+ @Test
+ public void addRemoveBackend() throws Exception
+ {
+ // Local settings
+ String backendID1 = "addRemoveBackend_1";
+ String backendID2 = "addRemoveBackend_2";
+ String baseDN1 = "o=addRemoveBackendBaseDN_1";
+ String baseDN2 = "o=addRemoveBackendBaseDN_2";
+
+ // Make sure we are in auto mode and check the suffix is not accessible
+ setModeAuto();
+ checkBackendIsNotAccessible(baseDN1);
+
+ // Create a backend and check that the base entry is accessible.
+ createBackend(backendID1, baseDN1, true);
+ checkBackendIsAccessible(baseDN1);
+
+ // Remove the backend and check that the suffix is no more accessible.
+ removeMemoryBackend(backendID1);
+ checkBackendIsNotAccessible(baseDN1);
+
+ // Now move to the manual mode
+ setModeManual();
+ checkBackendIsNotAccessible(baseDN2);
+
+ // Create a backend and create a workflow to route operations to that
+ // new backend. Then check that the base entry is accessible.
+ createBackend(backendID2, baseDN2, true);
+ createWorkflow(baseDN2, backendID2);
+ checkBackendIsAccessible(baseDN2);
+
+ // Remove the workflow and the backend and check that the base entry
+ // is no more accessible.
+ removeWorkflow(baseDN2, backendID2);
+ removeMemoryBackend(backendID2);
+ checkBackendIsNotAccessible(baseDN2);
+ }
+
+
+ /**
+ * This test checks the creation and utilization of network group
+ * in the route process.
+ */
+ @Test
+ public void useNetworkGroup() throws Exception
+ {
+ // Local settings
+ String backendID = "test";
+ String baseDN = "o=test";
+
+ // Now move to the manual mode
+ setModeManual();
+
+ // Create a route for o=test suffix in the default network group.
+ // Search on o=test should succeed.
+ WorkflowImpl workflowImpl = createWorkflow(baseDN, backendID);
+ InternalSearchOperation searchOperation =
+ doSearch(baseDN, SearchScope.BASE_OBJECT, ResultCode.SUCCESS);
+
+ // Create a network group and store it in the client connection.
+ // As the network group is empty, all searches should fail with a
+ // no such object result code.
+ String networkGroupID = "useNetworkGroupID";
+ NetworkGroup networkGroup = new NetworkGroup(networkGroupID);
+ ClientConnection clientConnection = searchOperation.getClientConnection();
+ clientConnection.setNetworkGroup(networkGroup);
+ searchOperation.run();
+ assertEquals(searchOperation.getResultCode(), ResultCode.NO_SUCH_OBJECT);
+
+ // Now register the o=test workflow and search again. The search
+ // should succeed.
+ networkGroup.registerWorkflow(workflowImpl);
+ searchOperation.run();
+ assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+
+ // Put back the default network group in the client conenction
+ // and check that searches are still working.
+ clientConnection.setNetworkGroup(NetworkGroup.getDefaultNetworkGroup());
+ searchOperation.run();
+ assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+}
--
Gitblit v1.10.0